summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Gregory <james@james.id.au>2013-08-19 14:01:32 -0700
committerJames Gregory <james@james.id.au>2013-08-19 14:01:32 -0700
commitafcdfff09f8557ce6810546628733f48d6c45408 (patch)
tree9c556c29a0556429dc1b421b2d5abade1915a034
parent46c82708d50e839945fa24094fe352241be6a22e (diff)
parentcd38275faf739ba151c0aa7abe13703c9b8d8235 (diff)
Merge remote-tracking branch 'origin/incoming' into touch_handling
-rw-r--r--AUTHORS1
-rwxr-xr-xem++2
-rwxr-xr-xemcc61
-rwxr-xr-xemscripten.py21
-rwxr-xr-xscons-tools/emscripten.py17
-rwxr-xr-xscons-tools/llvm.py7
-rw-r--r--src/analyzer.js26
-rw-r--r--src/compiler.js5
-rw-r--r--src/intertyper.js19
-rw-r--r--src/jsifier.js93
-rw-r--r--src/library.js2392
-rw-r--r--src/library_browser.js20
-rw-r--r--src/library_egl.js14
-rw-r--r--src/library_fs.js1381
-rw-r--r--src/library_gl.js281
-rw-r--r--src/library_glut.js2
-rw-r--r--src/library_memfs.js243
-rw-r--r--src/library_openal.js265
-rw-r--r--src/library_sdl.js144
-rw-r--r--src/library_sockfs.js18
-rw-r--r--src/library_tty.js121
-rw-r--r--src/modules.js26
-rw-r--r--src/parseTools.js25
-rw-r--r--src/postamble.js70
-rw-r--r--src/preamble.js17
-rw-r--r--src/settings.js148
-rw-r--r--src/shell.js60
-rw-r--r--system/include/compat/math.h14
-rw-r--r--system/include/compat/stdlib.h16
-rw-r--r--system/include/compat/string.h17
-rw-r--r--system/include/compat/sys/stat.h20
-rw-r--r--system/include/compat/sys/timeb.h (renamed from system/include/libc/sys/timeb.h)0
-rw-r--r--system/include/compat/unistd.h16
-rw-r--r--system/include/compat/xlocale.h21
-rw-r--r--system/include/emscripten/emscripten.h13
-rw-r--r--system/include/libc/stdlib.h2
-rw-r--r--system/include/libc/string.h2
-rw-r--r--system/include/libc/sys/signal.h4
-rw-r--r--system/include/libc/sys/unistd.h1
-rw-r--r--system/include/libcxx/CREDITS.TXT24
-rw-r--r--system/include/libcxx/__bit_reference35
-rw-r--r--system/include/libcxx/__config77
-rw-r--r--system/include/libcxx/__debug6
-rw-r--r--system/include/libcxx/__functional_0348
-rw-r--r--system/include/libcxx/__functional_base26
-rw-r--r--system/include/libcxx/__hash_table620
-rw-r--r--system/include/libcxx/__locale14
-rw-r--r--system/include/libcxx/__split_buffer12
-rw-r--r--system/include/libcxx/__std_stream88
-rw-r--r--system/include/libcxx/__tree109
-rw-r--r--system/include/libcxx/__tuple18
-rw-r--r--system/include/libcxx/algorithm236
-rw-r--r--system/include/libcxx/array35
-rw-r--r--system/include/libcxx/atomic20
-rw-r--r--system/include/libcxx/cctype4
-rw-r--r--system/include/libcxx/chrono167
-rw-r--r--system/include/libcxx/cmath77
-rw-r--r--system/include/libcxx/complex98
-rw-r--r--system/include/libcxx/cstdio4
-rw-r--r--system/include/libcxx/cstdlib10
-rw-r--r--system/include/libcxx/cstring4
-rw-r--r--system/include/libcxx/cwchar35
-rw-r--r--system/include/libcxx/deque41
-rw-r--r--system/include/libcxx/forward_list71
-rw-r--r--system/include/libcxx/fstream16
-rw-r--r--system/include/libcxx/functional371
-rw-r--r--system/include/libcxx/future66
-rw-r--r--system/include/libcxx/ios27
-rw-r--r--system/include/libcxx/istream6
-rw-r--r--system/include/libcxx/iterator26
-rw-r--r--system/include/libcxx/limits4
-rw-r--r--system/include/libcxx/list270
-rw-r--r--system/include/libcxx/locale197
-rw-r--r--system/include/libcxx/map389
-rw-r--r--system/include/libcxx/memory167
-rw-r--r--system/include/libcxx/random31
-rw-r--r--system/include/libcxx/readme.txt2
-rw-r--r--system/include/libcxx/regex75
-rw-r--r--system/include/libcxx/sstream164
-rw-r--r--system/include/libcxx/string527
-rw-r--r--system/include/libcxx/support/win32/limits_win32.h6
-rw-r--r--system/include/libcxx/support/win32/locale_win32.h17
-rw-r--r--system/include/libcxx/support/win32/math_win32.h6
-rw-r--r--system/include/libcxx/support/win32/support.h21
-rw-r--r--system/include/libcxx/thread4
-rw-r--r--system/include/libcxx/tuple199
-rw-r--r--system/include/libcxx/type_traits256
-rw-r--r--system/include/libcxx/unordered_map475
-rw-r--r--system/include/libcxx/unordered_set162
-rw-r--r--system/include/libcxx/utility265
-rw-r--r--system/include/libcxx/vector109
-rw-r--r--system/include/net/if.h21
-rw-r--r--system/include/net/netinet/in.h67
-rw-r--r--system/include/netdb.h36
-rw-r--r--system/include/sys/ioctl.h58
-rw-r--r--system/include/sys/select.h2
-rw-r--r--system/include/sys/socket.h211
-rw-r--r--system/include/xlocale.h7
-rw-r--r--system/lib/dlmalloc.c22
-rw-r--r--system/lib/libc/musl/src/stdlib/ecvt.c19
-rw-r--r--system/lib/libc/musl/src/stdlib/fcvt.c25
-rw-r--r--system/lib/libc/musl/src/stdlib/gcvt.c8
-rw-r--r--system/lib/libcextra.symbols3
-rw-r--r--system/lib/libcxx/CREDITS.TXT24
-rw-r--r--system/lib/libcxx/debug.cpp20
-rw-r--r--system/lib/libcxx/exception.cpp9
-rw-r--r--system/lib/libcxx/hash.cpp6
-rw-r--r--system/lib/libcxx/iostream.cpp8
-rw-r--r--system/lib/libcxx/locale.cpp133
-rw-r--r--system/lib/libcxx/readme.txt2
-rw-r--r--system/lib/libcxx/stdexcept.cpp2
-rw-r--r--system/lib/libcxx/string.cpp823
-rw-r--r--system/lib/libcxx/support/win32/locale_win32.cpp6
-rw-r--r--system/lib/libcxx/support/win32/support.cpp181
-rw-r--r--system/lib/libcxx/symbols265
-rw-r--r--system/lib/libcxx/system_error.cpp3
-rw-r--r--system/lib/libcxx/thread.cpp19
-rw-r--r--system/lib/libcxx/typeinfo.cpp14
-rw-r--r--tests/aniso.c10
-rw-r--r--tests/cases/phi24_ta2.ll4
-rwxr-xr-xtests/runner.py15088
-rw-r--r--tests/sdl_image.c8
-rw-r--r--tests/sdl_image_jpeg.c45
-rw-r--r--tests/sdl_ogl_proc_alias.c180
-rw-r--r--tests/sdl_pumpevents.c54
-rw-r--r--tests/sockets/socket_relay.py (renamed from tests/socket_relay.py)0
-rw-r--r--tests/sockets/test_enet_client.c (renamed from tests/enet_client.c)24
-rw-r--r--tests/sockets/test_enet_server.c (renamed from tests/enet_server.c)15
-rw-r--r--tests/sockets/test_sockets_echo_client.c148
-rw-r--r--tests/sockets/test_sockets_echo_server.c160
-rw-r--r--tests/sockets/test_sockets_gethostbyname.c49
-rw-r--r--tests/sockets/test_sockets_msg.h78
-rw-r--r--tests/sockets/test_sockets_partial_client.c119
-rw-r--r--tests/sockets/test_sockets_partial_server.c128
-rw-r--r--tests/sockets/test_sockets_select_server_closes_connection_client_rw.c217
-rw-r--r--tests/sockets/test_sockets_select_server_no_accept_client.c98
-rw-r--r--tests/sockets/test_sockets_select_server_no_accept_server.c86
-rw-r--r--tests/sockets/webrtc_host.c89
-rw-r--r--tests/sockets/webrtc_peer.c81
-rw-r--r--tests/stdio/test_rename.c3
-rw-r--r--tests/test_benchmark.py507
-rw-r--r--tests/test_browser.py1385
-rw-r--r--tests/test_core.py10069
-rw-r--r--tests/test_other.py1913
-rw-r--r--tests/test_sanity.py522
-rw-r--r--tests/test_sockets.py268
-rw-r--r--tests/websockets.c147
-rw-r--r--tests/websockets_bi.c140
-rw-r--r--tests/websockets_bi_bigdata.c137
-rw-r--r--tests/websockets_bi_listener.c151
-rw-r--r--tests/websockets_bi_side.c76
-rw-r--r--tests/websockets_bi_side_bigdata.c69
-rw-r--r--tests/websockets_bigdata.h20
-rw-r--r--tests/websockets_gethostbyname.c132
-rw-r--r--tests/websockets_partial.c127
-rw-r--r--tests/websockets_select.c95
-rw-r--r--tests/websockets_select_server_closes_connection.c126
-rw-r--r--tests/websockets_select_server_closes_connection_rw.c213
-rw-r--r--tools/asm_module.py4
-rwxr-xr-xtools/exec_llvm.py4
-rw-r--r--tools/file_packager.py15
-rw-r--r--tools/find_bigfuncs.py4
-rw-r--r--tools/find_bigvars.py24
-rw-r--r--tools/js-optimizer.js73
-rwxr-xr-xtools/nativize_llvm.py4
-rw-r--r--tools/response_file.py4
-rw-r--r--tools/settings_template_readonly.py2
-rw-r--r--tools/shared.py212
-rwxr-xr-xtools/source-maps/sourcemapper.js43
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js304
-rw-r--r--tools/test-js-optimizer-asm-outline2-output.js576
171 files changed, 25557 insertions, 21829 deletions
diff --git a/AUTHORS b/AUTHORS
index d3cdd156..5161f7ad 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -92,4 +92,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Michael Lelli <toadking@toadking.com>
* Yu Kobayashi <yukoba@accelart.jp>
* Pin Zhang <zhangpin04@gmail.com>
+* Nick Bray <ncbray@chromium.org> (copyright owned by Google, Inc.)
diff --git a/em++ b/em++
index ba09e1a2..810b7aec 100755
--- a/em++
+++ b/em++
@@ -8,5 +8,7 @@ import os, subprocess, sys
from tools import shared
os.environ['EMMAKEN_CXX'] = '1'
+if not os.path.exists(shared.PYTHON):
+ print >> sys.stderr, 'warning: PYTHON does not seem to be defined properly in ~/.emscripten (%s)' % shared.PYTHON
exit(subprocess.call([shared.PYTHON, shared.EMCC] + sys.argv[1:]))
diff --git a/emcc b/emcc
index 8f71883d..df2ef38c 100755
--- a/emcc
+++ b/emcc
@@ -137,7 +137,7 @@ Options that are modified or new in %s include:
opt levels, see apply_opt_level() in
tools/shared.py and also src/settings.js.)
-O2 As -O1, plus the relooper (loop recreation),
- LLVM -O2 optimizations, and
+ LLVM -O3 optimizations, and
-s ALIASING_FUNCTION_POINTERS=1
@@ -219,6 +219,9 @@ Options that are modified or new in %s include:
1: Parallel typed arrays
2: Shared (C-like) typed arrays (default)
+ --js-opts 0: Prevent JS optimizer from running
+ 1: Use JS optimizer (default)
+
--llvm-opts <level> 0: No LLVM optimizations (default in -O0)
1: -O1 LLVM optimizations (default in -O1)
2: -O2 LLVM optimizations
@@ -462,6 +465,12 @@ Options that are modified or new in %s include:
memory initialization data embedded inside
JavaScript as text. (default is off)
+ -Wno-warn-absolute-paths If not specified, the compiler will warn about any
+ uses of absolute paths in -I and -L command line
+ directives. Pass this flag on the command line
+ to hide these warnings and acknowledge that the
+ explicit use of absolute paths is intentional.
+
The target file, if specified (-o <target>), defines what will
be generated:
@@ -706,6 +715,7 @@ try:
opt_level = 0
debug_level = 0
+ js_opts = None
llvm_opts = None
llvm_lto = None
closure = None
@@ -735,6 +745,12 @@ try:
absolute_warning_shown = False
+ # Scan for warning suppression message in advance from other cmdline flags, so that it works even if -I or -L directives are present before this.
+ for i in range(len(newargs)):
+ if newargs[i] == '-Wno-warn-absolute-paths':
+ newargs[i] = ''
+ absolute_warning_shown = True
+
settings_changes = []
def validate_arg_level(level_string, max_level, err_msg):
@@ -755,6 +771,11 @@ try:
settings_changes.append('INLINING_LIMIT=50')
opt_level = validate_arg_level(requested_level, 3, 'Invalid optimization level: ' + newargs[i])
newargs[i] = ''
+ elif newargs[i].startswith('--js-opts'):
+ check_bad_eq(newargs[i])
+ js_opts = eval(newargs[i+1])
+ newargs[i] = ''
+ newargs[i+1] = ''
elif newargs[i].startswith('--llvm-opts'):
check_bad_eq(newargs[i])
llvm_opts = eval(newargs[i+1])
@@ -879,7 +900,7 @@ try:
elif newargs[i].startswith(('-I', '-L')):
path_name = newargs[i][2:]
if not absolute_warning_shown and os.path.isabs(path_name):
- logging.warning ('-I or -L of an absolute path "' + newargs[i] + '" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)') # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not
+ logging.warning ('-I or -L of an absolute path "' + newargs[i] + '" encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript). Pass \'-Wno-warn-absolute-paths\' to emcc to hide this warning.') # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not
absolute_warning_shown = True
newargs = [ arg for arg in newargs if arg is not '' ]
@@ -887,6 +908,7 @@ try:
if default_cxx_std:
newargs = newargs + [default_cxx_std]
+ if js_opts is None: js_opts = True
if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level]
if llvm_lto is None and opt_level >= 3: llvm_lto = 3
if opt_level == 0: debug_level = 4
@@ -1285,6 +1307,11 @@ try:
'wctob.c',
'wctomb.c',
]],
+ ['stdlib', [
+ 'ecvt.c',
+ 'fcvt.c',
+ 'gcvt.c',
+ ]],
['string', [
'wcpcpy.c',
'wcpncpy.c',
@@ -1577,7 +1604,7 @@ try:
js_optimizer_queue = []
js_optimizer_extra_info = {}
- if opt_level >= 1:
+ if opt_level >= 1 and js_opts:
logging.debug('running pre-closure post-opts')
if DEBUG == '2':
@@ -1594,9 +1621,6 @@ try:
js_optimizer_queue += [get_eliminate(), 'simplifyExpressions']
- if shared.Settings.RELOOP and not shared.Settings.ASM_JS:
- js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches
-
if closure and not shared.Settings.ASM_JS:
flush_js_optimizer_queue()
@@ -1606,23 +1630,24 @@ try:
final = shared.Building.closure_compiler(final)
if DEBUG: save_intermediate('closure')
- if shared.Settings.OUTLINING_LIMIT > 0:
- js_optimizer_queue += ['outline']
- js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT
+ if js_opts:
+ if shared.Settings.OUTLINING_LIMIT > 0:
+ js_optimizer_queue += ['outline']
+ js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT
- if (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3:
- js_optimizer_queue += ['registerize']
+ if (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3:
+ js_optimizer_queue += ['registerize']
- if opt_level > 0:
- if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue = map(lambda p: p if p != 'registerize' else 'registerizeAndMinify', js_optimizer_queue)
- if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
+ if opt_level > 0:
+ if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue = map(lambda p: p if p != 'registerize' else 'registerizeAndMinify', js_optimizer_queue)
+ if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
- if closure and shared.Settings.ASM_JS:
- js_optimizer_queue += ['closure']
+ if closure and shared.Settings.ASM_JS:
+ js_optimizer_queue += ['closure']
- if not shared.Settings.SIDE_MODULE: js_optimizer_queue += ['last'] # side modules are not finalized until after relocation
+ if not shared.Settings.SIDE_MODULE: js_optimizer_queue += ['last'] # side modules are not finalized until after relocation
- flush_js_optimizer_queue()
+ flush_js_optimizer_queue()
# Remove some trivial whitespace # TODO: do not run when compress has already been done on all parts of the code
src = open(final).read()
diff --git a/emscripten.py b/emscripten.py
index ab68fcaa..a156ca73 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -11,7 +11,6 @@ headers, for the libc implementation in JS).
import os, sys, json, optparse, subprocess, re, time, multiprocessing, string
-from tools import shared
from tools import jsrun, cache as cache_module, tempfiles
from tools.response_file import read_response_file
@@ -26,6 +25,7 @@ def get_configuration():
if hasattr(get_configuration, 'configuration'):
return get_configuration.configuration
+ from tools import shared
configuration = shared.Configuration(environ=os.environ)
get_configuration.configuration = configuration
return configuration
@@ -190,6 +190,11 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
open(forwarded_file, 'w').write(forwarded_data)
if DEBUG: print >> sys.stderr, ' emscript: phase 1 took %s seconds' % (time.time() - t)
+ indexed_functions = set()
+ forwarded_json = json.loads(forwarded_data)
+ for key in forwarded_json['Functions']['indexedFunctions'].iterkeys():
+ indexed_functions.add(key)
+
# Phase 2 - func
cores = int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count())
@@ -203,8 +208,6 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
chunk_size = MAX_CHUNK_SIZE # if 1 core, just use the max chunk size
if DEBUG: t = time.time()
- forwarded_json = json.loads(forwarded_data)
- indexed_functions = set()
if settings.get('ASM_JS'):
settings['EXPORTED_FUNCTIONS'] = forwarded_json['EXPORTED_FUNCTIONS']
save_settings()
@@ -423,6 +426,8 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
math_envs = ['Math.min'] # TODO: move min to maths
asm_setup += '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs])
+ if settings['TO_FLOAT32']: maths += ['Math.toFloat32']
+
basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs]
if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall')
if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR']
@@ -469,6 +474,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
}
''' % (sig, i, args, arg_coercions, jsret))
+ from tools import shared
asm_setup += '\n' + shared.JS.make_invoke(sig) + '\n'
basic_funcs.append('invoke_%s' % sig)
@@ -628,9 +634,10 @@ Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
# Create symbol table for self-dlopen
if settings.get('DLOPEN_SUPPORT'):
- symbol_table = { k:v+forwarded_json['Runtime']['GLOBAL_BASE']
- for k,v in forwarded_json['Variables']['indexedGlobals'].iteritems()
- if forwarded_json['Variables']['globals'][k]['named'] }
+ symbol_table = {}
+ for k, v in forwarded_json['Variables']['indexedGlobals'].iteritems():
+ if forwarded_json['Variables']['globals'][k]['named']:
+ symbol_table[k] = v + forwarded_json['Runtime']['GLOBAL_BASE']
for raw in last_forwarded_json['Functions']['tables'].itervalues():
if raw == '': continue
table = map(string.strip, raw[raw.find('[')+1:raw.find(']')].split(","))
@@ -807,7 +814,7 @@ WARNING: You should normally never use this! Use emcc instead.
'''
if len(positional) != 1:
- raise RuntimeError('Must provide exactly one positional argument.')
+ raise RuntimeError('Must provide exactly one positional argument. Got ' + str(len(positional)) + ': "' + '", "'.join(positional) + '"')
keywords.infile = os.path.abspath(positional[0])
if isinstance(keywords.outfile, basestring):
keywords.outfile = open(keywords.outfile, 'w')
diff --git a/scons-tools/emscripten.py b/scons-tools/emscripten.py
index 473c51ad..b4912aaa 100755
--- a/scons-tools/emscripten.py
+++ b/scons-tools/emscripten.py
@@ -24,6 +24,7 @@ def build_version_file(env):
EMSCRIPTEN_DEPENDENCIES = [
env.Glob('${EMSCRIPTEN_HOME}/src/*.js'),
+ env.Glob('${EMSCRIPTEN_HOME}/src/embind/*.js'),
env.Glob('${EMSCRIPTEN_HOME}/tools/*.py'),
'${EMSCRIPTEN_HOME}/emscripten.py',
]
@@ -141,7 +142,7 @@ def emscripten(env, target_js, source_bc):
[global_emscripten_min_js] = env.JSOptimizer(
buildName('global.min.js'),
closure_js,
- JS_OPTIMIZER_PASSES=['simplifyExpressionsPost', 'compress', 'last'])
+ JS_OPTIMIZER_PASSES=['simplifyExpressionsPost', 'minifyWhitespace', 'last'])
[emscripten_iteration_js] = env.WrapInModule(
buildName('iteration.js'),
@@ -155,8 +156,6 @@ def emscripten(env, target_js, source_bc):
buildName('min.js'),
global_emscripten_min_js)
- env.InstallAs(buildName('js'), emscripten_js)
-
return [emscripten_iteration_js, emscripten_js, emscripten_min_js]
LIBC_SOURCES = [
@@ -265,9 +264,9 @@ def generate(env):
)
env.Replace(
- CC='${LLVM_ROOT}/${CLANG}',
- CXX='${LLVM_ROOT}/${CLANGXX}',
- AR='${LLVM_ROOT}/${LLVM_LINK}',
+ CC=os.path.join('${LLVM_ROOT}', '${CLANG}'),
+ CXX=os.path.join('${LLVM_ROOT}', '${CLANGXX}'),
+ AR=os.path.join('${LLVM_ROOT}', '${LLVM_LINK}'),
ARCOM='$AR -o $TARGET $SOURCES',
OBJSUFFIX='.bc',
LIBPREFIX='',
@@ -301,6 +300,12 @@ def generate(env):
'__IEEE_LITTLE_ENDIAN',
])
+ env.Append(
+ CPPPATH=[
+ env.Dir('${EMSCRIPTEN_HOME}/system/include'),
+ ]
+ )
+
env['BUILDERS']['Emscripten'] = Builder(
action='$PYTHON ${EMSCRIPTEN_HOME}/emscripten.py $EMSCRIPTEN_FLAGS $_EMSCRIPTEN_SETTINGS_FLAGS --temp-dir=$EMSCRIPTEN_TEMP_DIR --compiler $JS_ENGINE --relooper=third-party/relooper.js $SOURCE > $TARGET',
target_scanner=EmscriptenScanner)
diff --git a/scons-tools/llvm.py b/scons-tools/llvm.py
index f272bd16..8fecb40a 100755
--- a/scons-tools/llvm.py
+++ b/scons-tools/llvm.py
@@ -1,5 +1,6 @@
from SCons.Scanner.Prog import scan
from SCons.Builder import Builder
+import os
def exists(env):
return True
@@ -23,11 +24,11 @@ def generate(env):
LLVM_LINK='llvm-link')
env['BUILDERS']['LLVMDis'] = Builder(
- action='${LLVM_ROOT}/$LLVM_DIS -o=$TARGET $SOURCE')
+ action=os.path.join('${LLVM_ROOT}', '$LLVM_DIS') + ' -o $TARGET $SOURCE')
env['BUILDERS']['LLVMOpt'] = Builder(
- action='${LLVM_ROOT}/$LLVM_OPT $LLVM_OPT_FLAGS $LLVM_OPT_PASSES -o=$TARGET $SOURCE')
+ action=os.path.join('${LLVM_ROOT}', '$LLVM_OPT') + ' $LLVM_OPT_FLAGS $LLVM_OPT_PASSES -o $TARGET $SOURCE')
env['BUILDERS']['LLVMLink'] = Builder(
- action='${LLVM_ROOT}/$LLVM_LINK -o=$TARGET $SOURCES',
+ action=os.path.join('${LLVM_ROOT}', '$LLVM_LINK') + ' -o $TARGET $SOURCES',
emitter=add_libraries)
diff --git a/src/analyzer.js b/src/analyzer.js
index 1a752305..2a7d64f5 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -765,7 +765,15 @@ function analyzer(data, sidePass) {
}
break;
}
- case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem':
+ case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem': {
+ if (sourceBits < 32) {
+ // when we add illegal types like i24, we must work on the singleton chunks
+ item.assignTo += '$0';
+ item.params[0].ident += '$0';
+ item.params[1].ident += '$0';
+ }
+ // fall through
+ }
case 'uitofp': case 'sitofp': case 'fptosi': case 'fptoui': {
// We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop
i++;
@@ -945,9 +953,23 @@ function analyzer(data, sidePass) {
if (type[0] == '{' || type[0] == '<') {
type = nonPointing;
var packed = type[0] == '<';
+ var internal = type;
+ if (packed) {
+ if (internal[internal.length-1] != '>') {
+ warnOnce('ignoring type ' + internal);
+ return; // function pointer or such
+ }
+ internal = internal.substr(1, internal.length-2);
+ }
+ assert(internal[0] == '{', internal);
+ if (internal[internal.length-1] != '}') {
+ warnOnce('ignoring type ' + internal);
+ return; // function pointer or such
+ }
+ internal = internal.substr(2, internal.length-4);
Types.types[type] = {
name_: type,
- fields: splitTokenList(tokenize(type.substr(2 + packed, type.length - 4 - 2*packed)).tokens).map(function(segment) {
+ fields: splitTokenList(tokenize(internal).tokens).map(function(segment) {
return segment[0].text;
}),
packed: packed,
diff --git a/src/compiler.js b/src/compiler.js
index 365ff32f..0baec95e 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -185,8 +185,7 @@ if (ASM_JS) {
assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap');
assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2');
}
-assert(!BUILD_AS_SHARED_LIB, 'shared libs are deprecated');
-//assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals');
+assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals');
// Output some info and warnings based on settings
@@ -203,6 +202,8 @@ if (phase == 'pre') {
}
}
+if (VERBOSE) printErr('VERBOSE is on, this generates a lot of output and can slow down compilation');
+
// Load compiler code
load('framework.js');
diff --git a/src/intertyper.js b/src/intertyper.js
index abfbdacb..31e97bd0 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -360,11 +360,22 @@ function intertyper(data, sidePass, baseLineNums) {
warn('Ignoring module asm: ' + item.tokens[2].text);
return '/dev/null';
}
+ if (token0Text == 'attributes')
+ return '/dev/null';
}
if (tokensLength >= 3 && (token0Text == 'call' || token1Text == 'call'))
return 'Call';
- if (token0Text == 'target')
+ if (token0Text == 'target') {
+ if (token1Text == 'triple') {
+ var triple = item.tokens[3].text;
+ triple = triple.substr(1, triple.length-2);
+ var expected = TARGET_LE32 ? 'le32-unknown-nacl' : 'i386-pc-linux-gnu';
+ if (triple !== expected) {
+ warn('using an unexpected LLVM triple: ' + [triple, ' !== ', expected] + ' (are you using emcc for everything and not clang?)');
+ }
+ }
return '/dev/null';
+ }
if (token0Text == ';')
return '/dev/null';
if (tokensLength >= 3 && token0Text == 'invoke')
@@ -700,6 +711,12 @@ function intertyper(data, sidePass, baseLineNums) {
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
+ var i = 0;
+ splitTokenList(tokensLeft[3].item.tokens).map(function(element) {
+ var ident = toNiceIdent(element[1].text);
+ var type = element[0].text;
+ item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident);
+ });
return { forward: null, ret: [item], item: item };
}
if (item.ident.substr(-2) == '()') {
diff --git a/src/jsifier.js b/src/jsifier.js
index b377202d..8884e24f 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -16,6 +16,8 @@ var SETJMP_LABEL = -1;
var INDENTATION = ' ';
+var functionStubSigs = {};
+
// JSifier
function JSify(data, functionsOnly, givenFunctions) {
var mainPass = !functionsOnly;
@@ -278,7 +280,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// they would shadow similarly-named globals in the parent.
item.JS = '';
} else {
- item.JS = makeGlobalDef(item.ident);
+ item.JS = makeGlobalDef(item.ident);
}
if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) {
@@ -407,6 +409,11 @@ function JSify(data, functionsOnly, givenFunctions) {
// functionStub
substrate.addActor('FunctionStub', {
processItem: function(item) {
+ // note the signature
+ if (item.returnType && item.params) {
+ functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false);
+ }
+
function addFromLibrary(ident) {
if (ident in addedLibraryItems) return '';
addedLibraryItems[ident] = true;
@@ -658,6 +665,10 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
+ if (func.hasVarArgsCall) {
+ func.JS += INDENTATION + 'var tempVarArgs = 0;\n';
+ }
+
// Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up.
func.JS += INDENTATION + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n';
@@ -1234,6 +1245,7 @@ function JSify(data, functionsOnly, givenFunctions) {
+ (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
+ 'return null } })();';
}
+ ret = makeVarArgsCleanup(ret);
if (item.assignTo) {
ret = 'var ' + item.assignTo + ' = ' + ret;
@@ -1446,12 +1458,13 @@ function JSify(data, functionsOnly, givenFunctions) {
});
if (hasVarArgs && !useJSArgs) {
+ funcData.hasVarArgsCall = true;
if (varargs.length === 0) {
varargs = [0];
varargsTypes = ['i32'];
}
var offset = 0;
- varargs = '(tempInt=' + RuntimeGenerator.stackAlloc(varargs.length, ',') + ',' +
+ varargs = '(tempVarArgs=' + RuntimeGenerator.stackAlloc(varargs.length, ',') + ',' +
varargs.map(function(arg, i) {
var type = varargsTypes[i];
if (type == 0) return null;
@@ -1459,17 +1472,17 @@ function JSify(data, functionsOnly, givenFunctions) {
var ret;
assert(offset % Runtime.STACK_ALIGN == 0); // varargs must be aligned
if (!varargsByVals[i]) {
- ret = makeSetValue(getFastValue('tempInt', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ',');
+ ret = makeSetValue(getFastValue('tempVarArgs', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ',');
offset += Runtime.alignMemory(Runtime.getNativeFieldSize(type), Runtime.STACK_ALIGN);
} else {
var size = calcAllocatedSize(removeAllPointing(type));
- ret = makeCopyValues(getFastValue('tempInt', '+', offset), arg, size, null, null, varargsByVals[i], ',');
+ ret = makeCopyValues(getFastValue('tempVarArgs', '+', offset), arg, size, null, null, varargsByVals[i], ',');
offset += Runtime.forceAlign(size, Runtime.STACK_ALIGN);
}
return ret;
}).filter(function(arg) {
return arg !== null;
- }).join(',') + ',tempInt)';
+ }).join(',') + ',tempVarArgs)';
varargs = asmCoercion(varargs, 'i32');
}
@@ -1531,7 +1544,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// 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
if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig;
- args.unshift(byPointerForced ? Functions.getIndex(callIdent, undefined, sig) : asmCoercion(callIdent, 'i32'));
+ args.unshift(byPointerForced ? Functions.getIndex(callIdent, sig) : asmCoercion(callIdent, 'i32'));
callIdent = 'invoke_' + sig;
}
} else if (SAFE_DYNCALLS) {
@@ -1557,10 +1570,24 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret;
}
+
+ function makeVarArgsCleanup(js) {
+ if (js.indexOf('(tempVarArgs=') >= 0) {
+ if (js[js.length-1] == ';') {
+ return js + ' STACKTOP=tempVarArgs;';
+ } else {
+ assert(js.indexOf(';') < 0);
+ return '((' + js + '), STACKTOP=tempVarArgs)';
+ }
+ }
+ return js;
+ }
+
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
makeFuncLineActor('call', function(item) {
if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';';
- return makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
+ var ret = makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
+ return makeVarArgsCleanup(ret);
});
makeFuncLineActor('unreachable', function(item) {
@@ -1608,7 +1635,7 @@ function JSify(data, functionsOnly, givenFunctions) {
//
if (!mainPass) {
- if (phase == 'pre' && !Variables.generatedGlobalBase) {
+ if (phase == 'pre' && !Variables.generatedGlobalBase && !BUILD_AS_SHARED_LIB) {
Variables.generatedGlobalBase = true;
// Globals are done, here is the rest of static memory
assert((TARGET_LE32 && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules
@@ -1652,24 +1679,26 @@ function JSify(data, functionsOnly, givenFunctions) {
print('}\n');
if (USE_TYPED_ARRAYS == 2) {
- print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n');
- print('assert(tempDoublePtr % 8 == 0);\n');
- print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n');
- print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
- print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
- print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
- print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
- print('}\n');
- print('function copyTempDouble(ptr) {\n');
- print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
- print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
- print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
- print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
- print(' HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n');
- print(' HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n');
- print(' HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n');
- print(' HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n');
- print('}\n');
+ if (!BUILD_AS_SHARED_LIB) {
+ print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n');
+ print('assert(tempDoublePtr % 8 == 0);\n');
+ print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n');
+ print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
+ print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
+ print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
+ print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
+ print('}\n');
+ print('function copyTempDouble(ptr) {\n');
+ print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
+ print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
+ print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
+ print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
+ print(' HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n');
+ print(' HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n');
+ print(' HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n');
+ print(' HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n');
+ print('}\n');
+ }
}
}
@@ -1704,11 +1733,13 @@ function JSify(data, functionsOnly, givenFunctions) {
legalizedI64s = legalizedI64sDefault;
- print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n');
- print('staticSealed = true; // seal the static portion of memory\n');
- print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n');
- print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n');
- print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n');
+ if (!BUILD_AS_SHARED_LIB) {
+ print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n');
+ print('staticSealed = true; // seal the static portion of memory\n');
+ print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n');
+ print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n');
+ print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n');
+ }
if (asmLibraryFunctions.length > 0) {
print('// ASM_LIBRARY FUNCTIONS');
diff --git a/src/library.js b/src/library.js
index f21d5777..9e78db13 100644
--- a/src/library.js
+++ b/src/library.js
@@ -18,1726 +18,12 @@
// Memory allocated during startup, in postsets, should only be ALLOC_STATIC
LibraryManager.library = {
- // ==========================================================================
- // File system base.
- // ==========================================================================
-
// keep this low in memory, because we flatten arrays with them in them
stdin: 'allocate(1, "i32*", ALLOC_STATIC)',
stdout: 'allocate(1, "i32*", ALLOC_STATIC)',
stderr: 'allocate(1, "i32*", ALLOC_STATIC)',
_impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)',
- $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', 'stdin', 'stdout', 'stderr', 'fflush'],
- $FS__postset: 'FS.staticInit();' +
- '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
- '__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' +
- '__ATEXIT__.push({ func: function() { FS.quit() } });' +
- // export some names through closure
- 'Module["FS_createFolder"] = FS.createFolder;' +
- 'Module["FS_createPath"] = FS.createPath;' +
- 'Module["FS_createDataFile"] = FS.createDataFile;' +
- 'Module["FS_createPreloadedFile"] = FS.createPreloadedFile;' +
- 'Module["FS_createLazyFile"] = FS.createLazyFile;' +
- 'Module["FS_createLink"] = FS.createLink;' +
- 'Module["FS_createDevice"] = FS.createDevice;',
- $FS: {
- root: null,
- nodes: [null],
- devices: [null],
- streams: [null],
- nextInode: 1,
- name_table: new Array(4096),
- currentPath: '/',
- initialized: false,
- // Whether we are currently ignoring permissions. Useful when preparing the
- // filesystem and creating files inside read-only folders.
- // This is set to false when the runtime is initialized, allowing you
- // to modify the filesystem freely before run() is called.
- ignorePermissions: true,
-
- ErrnoError: function(errno) {
- this.errno = errno;
- for (var key in ERRNO_CODES) {
- if (ERRNO_CODES[key] === errno) {
- this.code = key;
- break;
- }
- }
- this.message = ERRNO_MESSAGES[errno];
- },
-
- handleFSError: function(e) {
- if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + new Error().stack;
- return ___setErrNo(e.errno);
- },
-
- //
- // nodes
- //
- hashName: function(parentid, name) {
- var hash = 0;
- for (var i = 0; i < name.length; i++) {
- hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
- }
- return (parentid + hash) % FS.name_table.length;
- },
- hashAddNode: function(node) {
- var hash = FS.hashName(node.parent.id, node.name);
- node.name_next = FS.name_table[hash];
- FS.name_table[hash] = node;
- },
- hashRemoveNode: function(node) {
- var hash = FS.hashName(node.parent.id, node.name);
- if (FS.name_table[hash] === node) {
- FS.name_table[hash] = node.name_next;
- } else {
- var current = FS.name_table[hash];
- while (current) {
- if (current.name_next === node) {
- current.name_next = node.name_next;
- break;
- }
- current = current.name_next;
- }
- }
- },
- lookupNode: function(parent, name) {
- var err = FS.mayLookup(parent);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- var hash = FS.hashName(parent.id, name);
- for (var node = FS.name_table[hash]; node; node = node.name_next) {
- if (node.parent.id === parent.id && node.name === name) {
- return node;
- }
- }
- // if we failed to find it in the cache, call into the VFS
- return VFS.lookup(parent, name);
- },
- createNode: function(parent, name, mode, rdev) {
- var node = {
- id: FS.nextInode++,
- name: name,
- mode: mode,
- node_ops: {},
- stream_ops: {},
- rdev: rdev,
- parent: null,
- mount: null
- };
- if (!parent) {
- parent = node; // root node sets parent to itself
- }
- node.parent = parent;
- node.mount = parent.mount;
- // compatibility
- var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
- var writeMode = {{{ cDefine('S_IWUGO') }}};
- Object.defineProperty(node, 'read', {
- get: function() { return (node.mode & readMode) === readMode; },
- set: function(val) { val ? node.mode |= readMode : node.mode &= ~readMode; }
- });
- Object.defineProperty(node, 'write', {
- get: function() { return (node.mode & writeMode) === writeMode; },
- set: function(val) { val ? node.mode |= writeMode : node.mode &= ~writeMode; }
- });
- // TODO add:
- // isFolder
- // isDevice
- FS.hashAddNode(node);
- return node;
- },
- destroyNode: function(node) {
- FS.hashRemoveNode(node);
- },
- isRoot: function(node) {
- return node === node.parent;
- },
- isMountpoint: function(node) {
- return node.mounted;
- },
- isFile: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFREG') }}};
- },
- isDir: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFDIR') }}};
- },
- isLink: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFLNK') }}};
- },
- isChrdev: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFCHR') }}};
- },
- isBlkdev: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFBLK') }}};
- },
- isFIFO: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFIFO') }}};
- },
-
- //
- // paths
- //
- cwd: function() {
- return FS.currentPath;
- },
- lookupPath: function(path, opts) {
- path = PATH.resolve(FS.currentPath, path);
- opts = opts || { recurse_count: 0 };
-
- if (opts.recurse_count > 8) { // max recursive lookup of 8
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
-
- // split the path
- var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
- return !!p;
- }), false);
-
- // start at the root
- var current = FS.root;
- var current_path = '/';
-
- for (var i = 0; i < parts.length; i++) {
- var islast = (i === parts.length-1);
- if (islast && opts.parent) {
- // stop resolving
- break;
- }
-
- current = FS.lookupNode(current, parts[i]);
- current_path = PATH.join(current_path, parts[i]);
-
- // jump to the mount's root node if this is a mountpoint
- if (FS.isMountpoint(current)) {
- current = current.mount.root;
- }
-
- // follow symlinks
- // by default, lookupPath will not follow a symlink if it is the final path component.
- // setting opts.follow = true will override this behavior.
- if (!islast || opts.follow) {
- var count = 0;
- while (FS.isLink(current.mode)) {
- var link = VFS.readlink(current_path);
- current_path = PATH.resolve(PATH.dirname(current_path), link);
-
- var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
- current = lookup.node;
-
- if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
- }
- }
- }
-
- return { path: current_path, node: current };
- },
- getPath: function(node) {
- var path;
- while (true) {
- if (FS.isRoot(node)) {
- return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint;
- }
- path = path ? PATH.join(node.name, path) : node.name;
- node = node.parent;
- }
- },
-
- //
- // permissions
- //
- flagModes: {
- '"r"': {{{ cDefine('O_RDONLY') }}},
- '"rs"': {{{ cDefine('O_RDONLY') }}} | {{{ cDefine('O_SYNC') }}},
- '"r+"': {{{ cDefine('O_RDWR') }}},
- '"w"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}},
- '"wx"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"xw"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"w+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}},
- '"wx+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
- '"xw+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
- '"a"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}},
- '"ax"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"xa"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"a+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}},
- '"ax+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
- '"xa+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}}
- },
- // convert the 'r', 'r+', etc. to it's corresponding set of O_* flags
- modeStringToFlags: function(str) {
- var flags = FS.flagModes[str];
- if (typeof flags === 'undefined') {
- throw new Error('Unknown file open mode: ' + str);
- }
- return flags;
- },
- // convert O_* bitmask to a string for nodePermissions
- flagsToPermissionString: function(flag) {
- var accmode = flag & {{{ cDefine('O_ACCMODE') }}};
- var perms = ['r', 'w', 'rw'][accmode];
- if ((flag & {{{ cDefine('O_TRUNC') }}})) {
- perms += 'w';
- }
- return perms;
- },
- nodePermissions: function(node, perms) {
- if (FS.ignorePermissions) {
- return 0;
- }
- // return 0 if any user, group or owner bits are set.
- if (perms.indexOf('r') !== -1 && !(node.mode & {{{ cDefine('S_IRUGO') }}})) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf('w') !== -1 && !(node.mode & {{{ cDefine('S_IWUGO') }}})) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf('x') !== -1 && !(node.mode & {{{ cDefine('S_IXUGO') }}})) {
- return ERRNO_CODES.EACCES;
- }
- return 0;
- },
- mayLookup: function(dir) {
- return FS.nodePermissions(dir, 'x');
- },
- mayMknod: function(mode) {
- switch (mode & {{{ cDefine('S_IFMT') }}}) {
- case {{{ cDefine('S_IFREG') }}}:
- case {{{ cDefine('S_IFCHR') }}}:
- case {{{ cDefine('S_IFBLK') }}}:
- case {{{ cDefine('S_IFIFO') }}}:
- case {{{ cDefine('S_IFSOCK') }}}:
- return 0;
- default:
- return ERRNO_CODES.EINVAL;
- }
- },
- mayCreate: function(dir, name) {
- try {
- var node = FS.lookupNode(dir, name);
- return ERRNO_CODES.EEXIST;
- } catch (e) {
- }
- return FS.nodePermissions(dir, 'wx');
- },
- mayDelete: function(dir, name, isdir) {
- var node;
- try {
- node = FS.lookupNode(dir, name);
- } catch (e) {
- return e.errno;
- }
- var err = FS.nodePermissions(dir, 'wx');
- if (err) {
- return err;
- }
- if (isdir) {
- if (!FS.isDir(node.mode)) {
- return ERRNO_CODES.ENOTDIR;
- }
- if (FS.isRoot(node) || FS.getPath(node) === FS.currentPath) {
- return ERRNO_CODES.EBUSY;
- }
- } else {
- if (FS.isDir(node.mode)) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return 0;
- },
- mayOpen: function(node, flags) {
- if (!node) {
- return ERRNO_CODES.ENOENT;
- }
- if (FS.isLink(node.mode)) {
- return ERRNO_CODES.ELOOP;
- } else if (FS.isDir(node.mode)) {
- if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY')}}} || // opening for write
- (flags & {{{ cDefine('O_TRUNC') }}})) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
- },
-
- //
- // devices
- //
- // each character device consists of a device id + stream operations.
- // when a character device node is created (e.g. /dev/stdin) it is
- // assigned a device id that lets us map back to the actual device.
- // by default, each character device stream (e.g. _stdin) uses chrdev_stream_ops.
- // however, once opened, the stream's operations are overridden with
- // the operations of the device its underlying node maps back to.
- chrdev_stream_ops: {
- open: function(stream) {
- var device = FS.getDevice(stream.node.rdev);
- // override node's stream ops with the device's
- stream.stream_ops = device.stream_ops;
- // forward the open call
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- },
- llseek: function() {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- },
- major: function(dev) {
- return ((dev) >> 8);
- },
- minor: function(dev) {
- return ((dev) & 0xff);
- },
- makedev: function(ma, mi) {
- return ((ma) << 8 | (mi));
- },
- registerDevice: function(dev, ops) {
- FS.devices[dev] = { stream_ops: ops };
- },
- getDevice: function(dev) {
- return FS.devices[dev];
- },
-
- //
- // streams
- //
- MAX_OPEN_FDS: 4096,
- nextfd: function(fd_start, fd_end) {
- fd_start = fd_start || 1;
- fd_end = fd_end || FS.MAX_OPEN_FDS;
- for (var fd = fd_start; fd <= fd_end; fd++) {
- if (!FS.streams[fd]) {
- return fd;
- }
- }
- throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
- },
- getStream: function(fd) {
- return FS.streams[fd];
- },
- createStream: function(stream, fd_start, fd_end) {
- var fd = FS.nextfd(fd_start, fd_end);
- stream.fd = fd;
- // compatibility
- Object.defineProperty(stream, 'object', {
- get: function() { return stream.node; },
- set: function(val) { stream.node = val; }
- });
- Object.defineProperty(stream, 'isRead', {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
- });
- Object.defineProperty(stream, 'isWrite', {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
- });
- Object.defineProperty(stream, 'isAppend', {
- get: function() { return (stream.flags & {{{ cDefine('O_APPEND') }}}); }
- });
- FS.streams[fd] = stream;
- return stream;
- },
- closeStream: function(fd) {
- FS.streams[fd] = null;
- },
-
- //
- // general
- //
- createDefaultDirectories: function() {
- VFS.mkdir('/tmp', 0777);
- },
- createDefaultDevices: function() {
- // create /dev
- VFS.mkdir('/dev', 0777);
- // setup /dev/null
- FS.registerDevice(FS.makedev(1, 3), {
- read: function() { return 0; },
- write: function() { return 0; }
- });
- VFS.mkdev('/dev/null', 0666, FS.makedev(1, 3));
- // setup /dev/tty and /dev/tty1
- // stderr needs to print output using Module['printErr']
- // so we register a second tty just for it.
- TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
- TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
- VFS.mkdev('/dev/tty', 0666, FS.makedev(5, 0));
- VFS.mkdev('/dev/tty1', 0666, FS.makedev(6, 0));
- // we're not going to emulate the actual shm device,
- // just create the tmp dirs that reside in it commonly
- VFS.mkdir('/dev/shm', 0777);
- VFS.mkdir('/dev/shm/tmp', 0777);
- },
- createStandardStreams: function() {
- // TODO deprecate the old functionality of a single
- // input / output callback and that utilizes FS.createDevice
- // and instead require a unique set of stream ops
-
- // by default, we symlink the standard streams to the
- // default tty devices. however, if the standard streams
- // have been overwritten we create a unique device for
- // them instead.
- if (Module['stdin']) {
- FS.createDevice('/dev', 'stdin', Module['stdin']);
- } else {
- VFS.symlink('/dev/tty', '/dev/stdin');
- }
- if (Module['stdout']) {
- FS.createDevice('/dev', 'stdout', null, Module['stdout']);
- } else {
- VFS.symlink('/dev/tty', '/dev/stdout');
- }
- if (Module['stderr']) {
- FS.createDevice('/dev', 'stderr', null, Module['stderr']);
- } else {
- VFS.symlink('/dev/tty1', '/dev/stderr');
- }
-
- // open default streams for the stdin, stdout and stderr devices
- var stdin = VFS.open('/dev/stdin', 'r');
- {{{ makeSetValue(makeGlobalUse('_stdin'), 0, 'stdin.fd', 'void*') }}};
- assert(stdin.fd === 1, 'invalid handle for stdin (' + stdin.fd + ')');
-
- var stdout = VFS.open('/dev/stdout', 'w');
- {{{ makeSetValue(makeGlobalUse('_stdout'), 0, 'stdout.fd', 'void*') }}};
- assert(stdout.fd === 2, 'invalid handle for stdout (' + stdout.fd + ')');
-
- var stderr = VFS.open('/dev/stderr', 'w');
- {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 'stderr.fd', 'void*') }}};
- assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')');
- },
- staticInit: function() {
- FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
- VFS.mount(MEMFS, {}, '/');
-
- FS.createDefaultDirectories();
- FS.createDefaultDevices();
- },
- init: function(input, output, error) {
- assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
- FS.init.initialized = true;
-
- // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
- Module['stdin'] = input || Module['stdin'];
- Module['stdout'] = output || Module['stdout'];
- Module['stderr'] = error || Module['stderr'];
-
- FS.createStandardStreams();
- },
- quit: function() {
- FS.init.initialized = false;
- for (var i = 0; i < FS.streams.length; i++) {
- var stream = FS.streams[i];
- if (!stream) {
- continue;
- }
- VFS.close(stream);
- }
- },
-
- //
- // compatibility
- //
- getMode: function(canRead, canWrite) {
- var mode = 0;
- if (canRead) mode |= {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
- if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}};
- return mode;
- },
- joinPath: function(parts, forceRelative) {
- var path = PATH.join.apply(null, parts);
- if (forceRelative && path[0] == '/') path = path.substr(1);
- return path;
- },
- absolutePath: function(relative, base) {
- return PATH.resolve(base, relative);
- },
- standardizePath: function(path) {
- return PATH.normalize(path);
- },
- findObject: function(path, dontResolveLastLink) {
- var ret = FS.analyzePath(path, dontResolveLastLink);
- if (ret.exists) {
- return ret.object;
- } else {
- ___setErrNo(ret.error);
- return null;
- }
- },
- analyzePath: function(path, dontResolveLastLink) {
- // operate from within the context of the symlink's target
- try {
- var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
- path = lookup.path;
- } catch (e) {
- }
- var ret = {
- isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
- parentExists: false, parentPath: null, parentObject: null
- };
- try {
- var lookup = FS.lookupPath(path, { parent: true });
- ret.parentExists = true;
- ret.parentPath = lookup.path;
- ret.parentObject = lookup.node;
- ret.name = PATH.basename(path);
- lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
- ret.exists = true;
- ret.path = lookup.path;
- ret.object = lookup.node;
- ret.name = lookup.node.name;
- ret.isRoot = lookup.path === '/';
- } catch (e) {
- ret.error = e.errno;
- };
- return ret;
- },
- createFolder: function(parent, name, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return VFS.mkdir(path, mode);
- },
- createPath: function(parent, path, canRead, canWrite) {
- parent = typeof parent === 'string' ? parent : FS.getPath(parent);
- var parts = path.split('/').reverse();
- while (parts.length) {
- var part = parts.pop();
- if (!part) continue;
- var current = PATH.join(parent, part);
- try {
- VFS.mkdir(current, 0777);
- } catch (e) {
- // ignore EEXIST
- }
- parent = current;
- }
- return current;
- },
- createFile: function(parent, name, properties, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return VFS.create(path, mode);
- },
- createDataFile: function(parent, name, data, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- var node = VFS.create(path, mode);
- if (data) {
- if (typeof data === 'string') {
- var arr = new Array(data.length);
- for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
- data = arr;
- }
- // make sure we can write to the file
- VFS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}});
- var stream = VFS.open(path, 'w');
- VFS.write(stream, data, 0, data.length, 0);
- VFS.close(stream);
- VFS.chmod(path, mode);
- }
- return node;
- },
- createDevice: function(parent, name, input, output) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = input && output ? 0777 : (input ? 0333 : 0555);
- if (!FS.createDevice.major) FS.createDevice.major = 64;
- var dev = FS.makedev(FS.createDevice.major++, 0);
- // Create a fake device that a set of stream ops to emulate
- // the old behavior.
- FS.registerDevice(dev, {
- open: function(stream) {
- stream.seekable = false;
- },
- close: function(stream) {
- // flush any pending line data
- if (output.buffer && output.buffer.length) {
- output({{{ charCode('\n') }}});
- }
- },
- read: function(stream, buffer, offset, length, pos /* ignored */) {
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = input();
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset+i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- },
- write: function(stream, buffer, offset, length, pos) {
- for (var i = 0; i < length; i++) {
- try {
- output(buffer[offset+i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- }
- });
- return VFS.mkdev(path, mode, dev);
- },
- createLink: function(parent, name, target, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- return VFS.symlink(target, path);
- },
- // Makes sure a file's contents are loaded. Returns whether the file has
- // been loaded successfully. No-op for files that have been loaded already.
- forceLoadFile: function(obj) {
- if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
- var success = true;
- if (typeof XMLHttpRequest !== 'undefined') {
- throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
- } else if (Module['read']) {
- // Command-line.
- try {
- // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
- // read() will try to parse UTF8.
- obj.contents = intArrayFromString(Module['read'](obj.url), true);
- } catch (e) {
- success = false;
- }
- } else {
- throw new Error('Cannot load without read() or XMLHttpRequest.');
- }
- if (!success) ___setErrNo(ERRNO_CODES.EIO);
- return success;
- },
- // Creates a file record for lazy-loading from a URL. XXX This requires a synchronous
- // XHR, which is not possible in browsers except in a web worker! Use preloading,
- // either --preload-file in emcc or FS.createPreloadedFile
- createLazyFile: function(parent, name, url, canRead, canWrite) {
- if (typeof XMLHttpRequest !== 'undefined') {
- if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
- // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
- var LazyUint8Array = function() {
- this.lengthKnown = false;
- this.chunks = []; // Loaded chunks. Index is the chunk number
- }
- LazyUint8Array.prototype.get = function(idx) {
- if (idx > this.length-1 || idx < 0) {
- return undefined;
- }
- var chunkOffset = idx % this.chunkSize;
- var chunkNum = Math.floor(idx / this.chunkSize);
- return this.getter(chunkNum)[chunkOffset];
- }
- LazyUint8Array.prototype.setDataGetter = function(getter) {
- this.getter = getter;
- }
- LazyUint8Array.prototype.cacheLength = function() {
- // Find length
- var xhr = new XMLHttpRequest();
- xhr.open('HEAD', url, false);
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- var datalength = Number(xhr.getResponseHeader("Content-length"));
- var header;
- var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
-#if SMALL_XHR_CHUNKS
- var chunkSize = 1024; // Chunk size in bytes
-#else
- var chunkSize = 1024*1024; // Chunk size in bytes
-#endif
-
- if (!hasByteServing) chunkSize = datalength;
-
- // Function to get a range from the remote URL.
- var doXHR = (function(from, to) {
- if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
- if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
-
- // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, false);
- if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
-
- // Some hints to the browser that we want binary data.
- if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- }
-
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- if (xhr.response !== undefined) {
- return new Uint8Array(xhr.response || []);
- } else {
- return intArrayFromString(xhr.responseText || '', true);
- }
- });
- var lazyArray = this;
- lazyArray.setDataGetter(function(chunkNum) {
- var start = chunkNum * chunkSize;
- var end = (chunkNum+1) * chunkSize - 1; // including this byte
- end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
- lazyArray.chunks[chunkNum] = doXHR(start, end);
- }
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
- return lazyArray.chunks[chunkNum];
- });
-
- this._length = datalength;
- this._chunkSize = chunkSize;
- this.lengthKnown = true;
- }
-
- var lazyArray = new LazyUint8Array();
- Object.defineProperty(lazyArray, "length", {
- get: function() {
- if(!this.lengthKnown) {
- this.cacheLength();
- }
- return this._length;
- }
- });
- Object.defineProperty(lazyArray, "chunkSize", {
- get: function() {
- if(!this.lengthKnown) {
- this.cacheLength();
- }
- return this._chunkSize;
- }
- });
-
- var properties = { isDevice: false, contents: lazyArray };
- } else {
- var properties = { isDevice: false, url: url };
- }
-
- var node = FS.createFile(parent, name, properties, canRead, canWrite);
- // This is a total hack, but I want to get this lazy file code out of the
- // core of MEMFS. If we want to keep this lazy file concept I feel it should
- // be its own thin LAZYFS proxying calls to MEMFS.
- if (properties.contents) {
- node.contents = properties.contents;
- } else if (properties.url) {
- node.contents = null;
- node.url = properties.url;
- }
- // override each stream op with one that tries to force load the lazy file first
- var stream_ops = {};
- var keys = Object.keys(node.stream_ops);
- keys.forEach(function(key) {
- var fn = node.stream_ops[key];
- stream_ops[key] = function() {
- if (!FS.forceLoadFile(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- return fn.apply(null, arguments);
- };
- });
- // use a custom read function
- stream_ops.read = function(stream, buffer, offset, length, position) {
- var contents = stream.node.contents;
- var size = Math.min(contents.length - position, length);
- if (contents.slice) { // normal array
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents[position + i];
- }
- } else {
- for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
- buffer[offset + i] = contents.get(position + i);
- }
- }
- return size;
- };
- node.stream_ops = stream_ops;
- return node;
- },
- // Preloads a file asynchronously. You can call this before run, for example in
- // preRun. run will be delayed until this file arrives and is set up.
- // If you call it after run(), you may want to pause the main loop until it
- // completes, if so, you can use the onload parameter to be notified when
- // that happens.
- // In addition to normally creating the file, we also asynchronously preload
- // the browser-friendly versions of it: For an image, we preload an Image
- // element and for an audio, and Audio. These are necessary for SDL_Image
- // and _Mixer to find the files in preloadedImages/Audios.
- // You can also call this with a typed array instead of a url. It will then
- // do preloading for the Image/Audio part, as if the typed array were the
- // result of an XHR that you did manually.
- createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) {
- Browser.init();
- var fullname = FS.joinPath([parent, name], true);
- function processData(byteArray) {
- function finish(byteArray) {
- if (!dontCreateFile) {
- FS.createDataFile(parent, name, byteArray, canRead, canWrite);
- }
- if (onload) onload();
- removeRunDependency('cp ' + fullname);
- }
- var handled = false;
- Module['preloadPlugins'].forEach(function(plugin) {
- if (handled) return;
- if (plugin['canHandle'](fullname)) {
- plugin['handle'](byteArray, fullname, finish, function() {
- if (onerror) onerror();
- removeRunDependency('cp ' + fullname);
- });
- handled = true;
- }
- });
- if (!handled) finish(byteArray);
- }
- addRunDependency('cp ' + fullname);
- if (typeof url == 'string') {
- Browser.asyncLoad(url, function(byteArray) {
- processData(byteArray);
- }, onerror);
- } else {
- processData(url);
- }
- }
- },
-
- $VFS__deps: ['$FS'],
- $VFS: {
- mount: function(type, opts, mountpoint) {
- var mount = {
- type: type,
- opts: opts,
- mountpoint: mountpoint,
- root: null
- };
- var lookup;
- if (mountpoint) {
- lookup = FS.lookupPath(mountpoint, { follow: false });
- }
- // create a root node for the fs
- var root = type.mount(mount);
- root.mount = mount;
- mount.root = root;
- // assign the mount info to the mountpoint's node
- if (lookup) {
- lookup.node.mount = mount;
- lookup.node.mounted = true;
- // compatibility update FS.root if we mount to /
- if (mountpoint === '/') {
- FS.root = mount.root;
- }
- }
- return root;
- },
- lookup: function(parent, name) {
- return parent.node_ops.lookup(parent, name);
- },
- // generic function for all node creation
- mknod: function(path, mode, dev) {
- var lookup = FS.lookupPath(path, { parent: true });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var err = FS.mayCreate(parent, name);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.mknod) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return parent.node_ops.mknod(parent, name, mode, dev);
- },
- // helpers to create specific types of nodes
- create: function(path, mode) {
- mode &= {{{ cDefine('S_IALLUGO') }}};
- mode |= {{{ cDefine('S_IFREG') }}};
- return VFS.mknod(path, mode, 0);
- },
- mkdir: function(path, mode) {
- mode &= {{{ cDefine('S_IRWXUGO') }}} | {{{ cDefine('S_ISVTX') }}};
- mode |= {{{ cDefine('S_IFDIR') }}};
- return VFS.mknod(path, mode, 0);
- },
- mkdev: function(path, mode, dev) {
- mode |= {{{ cDefine('S_IFCHR') }}};
- return VFS.mknod(path, mode, dev);
- },
- symlink: function(oldpath, newpath) {
- var lookup = FS.lookupPath(newpath, { parent: true });
- var parent = lookup.node;
- var newname = PATH.basename(newpath);
- var err = FS.mayCreate(parent, newname);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.symlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return parent.node_ops.symlink(parent, newname, oldpath);
- },
- rename: function(old_path, new_path) {
- var old_dirname = PATH.dirname(old_path);
- var new_dirname = PATH.dirname(new_path);
- var old_name = PATH.basename(old_path);
- var new_name = PATH.basename(new_path);
- // parents must exist
- var lookup, old_dir, new_dir;
- try {
- lookup = FS.lookupPath(old_path, { parent: true });
- old_dir = lookup.node;
- lookup = FS.lookupPath(new_path, { parent: true });
- new_dir = lookup.node;
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- // need to be part of the same mount
- if (old_dir.mount !== new_dir.mount) {
- throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
- }
- // source must exist
- var old_node = FS.lookupNode(old_dir, old_name);
- // old path should not be an ancestor of the new path
- var relative = PATH.relative(old_path, new_dirname);
- if (relative.charAt(0) !== '.') {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- // new path should not be an ancestor of the old path
- relative = PATH.relative(new_path, old_dirname);
- if (relative.charAt(0) !== '.') {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- // see if the new path alreay exists
- var new_node;
- try {
- new_node = FS.lookupNode(new_dir, new_name);
- } catch (e) {
- // not fatal
- }
- // early out if nothing needs to changews
- if (old_node === new_node) {
- return;
- }
- // we'll need to delete the old entry
- var isdir = FS.isDir(old_node.mode);
- var err = FS.mayDelete(old_dir, old_name, isdir);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- // need delete permissions if we'll be overwriting.
- // need create permissions if new doesn't already exist.
- err = new_node ?
- FS.mayDelete(new_dir, new_name, isdir) :
- FS.mayCreate(new_dir, new_name);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!old_dir.node_ops.rename) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- // if we are going to change the parent, check write permissions
- if (new_dir !== old_dir) {
- err = FS.nodePermissions(old_dir, 'w');
- if (err) {
- throw new FS.ErrnoError(err);
- }
- }
- // remove the node from the lookup hash
- FS.hashRemoveNode(old_node);
- // do the underlying fs rename
- try {
- old_node.node_ops.rename(old_node, new_dir, new_name);
- } catch (e) {
- throw e;
- } finally {
- // add the node back to the hash (in case node_ops.rename
- // changed its name)
- FS.hashAddNode(old_node);
- }
- },
- rmdir: function(path) {
- var lookup = FS.lookupPath(path, { parent: true });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var node = FS.lookupNode(parent, name);
- var err = FS.mayDelete(parent, name, true);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.rmdir) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- parent.node_ops.rmdir(parent, name);
- FS.destroyNode(node);
- },
- unlink: function(path) {
- var lookup = FS.lookupPath(path, { parent: true });
- var parent = lookup.node;
- var name = PATH.basename(path);
- var node = FS.lookupNode(parent, name);
- var err = FS.mayDelete(parent, name, false);
- if (err) {
- // POSIX says unlink should set EPERM, not EISDIR
- if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
- throw new FS.ErrnoError(err);
- }
- if (!parent.node_ops.unlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isMountpoint(node)) {
- throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
- }
- parent.node_ops.unlink(parent, name);
- FS.destroyNode(node);
- },
- readlink: function(path) {
- var lookup = FS.lookupPath(path, { follow: false });
- var link = lookup.node;
- if (!link.node_ops.readlink) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return link.node_ops.readlink(link);
- },
- stat: function(path, dontFollow) {
- var lookup = FS.lookupPath(path, { follow: !dontFollow });
- var node = lookup.node;
- if (!node.node_ops.getattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- return node.node_ops.getattr(node);
- },
- lstat: function(path) {
- return VFS.stat(path, true);
- },
- chmod: function(path, mode, dontFollow) {
- var node;
- if (typeof path === 'string') {
- var lookup = FS.lookupPath(path, { follow: !dontFollow });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- node.node_ops.setattr(node, {
- mode: (mode & {{{ cDefine('S_IALLUGO') }}}) | (node.mode & ~{{{ cDefine('S_IALLUGO') }}}),
- timestamp: Date.now()
- });
- },
- lchmod: function(path, mode) {
- VFS.chmod(path, mode, true);
- },
- fchmod: function(fd, mode) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- VFS.chmod(stream.node, mode);
- },
- chown: function(path, uid, gid, dontFollow) {
- var node;
- if (typeof path === 'string') {
- var lookup = FS.lookupPath(path, { follow: !dontFollow });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- node.node_ops.setattr(node, {
- timestamp: Date.now()
- // we ignore the uid / gid for now
- });
- },
- lchown: function(path, uid, gid) {
- VFS.chown(path, uid, gid, true);
- },
- fchown: function(fd, uid, gid) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- VFS.chown(stream.node, uid, gid);
- },
- truncate: function(path, len) {
- if (len < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var node;
- if (typeof path === 'string') {
- var lookup = FS.lookupPath(path, { follow: true });
- node = lookup.node;
- } else {
- node = path;
- }
- if (!node.node_ops.setattr) {
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- if (FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!FS.isFile(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var err = FS.nodePermissions(node, 'w');
- if (err) {
- throw new FS.ErrnoError(err);
- }
- node.node_ops.setattr(node, {
- size: len,
- timestamp: Date.now()
- });
- },
- ftruncate: function(fd, len) {
- var stream = FS.getStream(fd);
- if (!stream) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- VFS.truncate(stream.node, len);
- },
- utime: function(path, atime, mtime) {
- var lookup = FS.lookupPath(path, { follow: true });
- var node = lookup.node;
- node.node_ops.setattr(node, {
- timestamp: Math.max(atime, mtime)
- });
- },
- open: function(path, flags, mode, fd_start, fd_end) {
- path = PATH.normalize(path);
- flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
- if ((flags & {{{ cDefine('O_CREAT') }}})) {
- mode = (mode & {{{ cDefine('S_IALLUGO') }}}) | {{{ cDefine('S_IFREG') }}};
- } else {
- mode = 0;
- }
- var node;
- try {
- var lookup = FS.lookupPath(path, {
- follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
- });
- node = lookup.node;
- path = lookup.path;
- } catch (e) {
- // ignore
- }
- // perhaps we need to create the node
- if ((flags & {{{ cDefine('O_CREAT') }}})) {
- if (node) {
- // if O_CREAT and O_EXCL are set, error out if the node already exists
- if ((flags & {{{ cDefine('O_EXCL') }}})) {
- throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
- }
- } else {
- // node doesn't exist, try to create it
- node = VFS.mknod(path, mode, 0);
- }
- }
- if (!node) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- }
- // can't truncate a device
- if (FS.isChrdev(node.mode)) {
- flags &= ~{{{ cDefine('O_TRUNC') }}};
- }
- // check permissions
- var err = FS.mayOpen(node, flags);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- // do truncation if necessary
- if ((flags & {{{ cDefine('O_TRUNC')}}})) {
- VFS.truncate(node, 0);
- }
- // register the stream with the filesystem
- var stream = FS.createStream({
- path: path,
- node: node,
- flags: flags,
- seekable: true,
- position: 0,
- stream_ops: node.stream_ops,
- // used by the file family libc calls (fopen, fwrite, ferror, etc.)
- ungotten: [],
- error: false
- }, fd_start, fd_end);
- // call the new stream's open function
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- return stream;
- },
- close: function(stream) {
- try {
- if (stream.stream_ops.close) {
- stream.stream_ops.close(stream);
- }
- } catch (e) {
- throw e;
- } finally {
- FS.closeStream(stream.fd);
- }
- },
- llseek: function(stream, offset, whence) {
- if (!stream.seekable || !stream.stream_ops.llseek) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- return stream.stream_ops.llseek(stream, offset, whence);
- },
- readdir: function(stream) {
- if (!stream.stream_ops.readdir) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
- }
- return stream.stream_ops.readdir(stream);
- },
- read: function(stream, buffer, offset, length, position) {
- if (length < 0 || position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!stream.stream_ops.read) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var seeking = true;
- if (typeof position === 'undefined') {
- position = stream.position;
- seeking = false;
- } else if (!stream.seekable) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
- if (!seeking) stream.position += bytesRead;
- return bytesRead;
- },
- write: function(stream, buffer, offset, length, position) {
- if (length < 0 || position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (FS.isDir(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
- }
- if (!stream.stream_ops.write) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- var seeking = true;
- if (typeof position === 'undefined') {
- position = stream.position;
- seeking = false;
- } else if (!stream.seekable) {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- if (stream.flags & {{{ cDefine('O_APPEND') }}}) {
- // seek to the end before writing in append mode
- VFS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}});
- }
- var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position);
- if (!seeking) stream.position += bytesWritten;
- return bytesWritten;
- },
- allocate: function(stream, offset, length) {
- if (offset < 0 || length <= 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
- throw new FS.ErrnoError(ERRNO_CODES.EBADF);
- }
- if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- if (!stream.stream_ops.allocate) {
- throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
- }
- stream.stream_ops.allocate(stream, offset, length);
- },
- mmap: function(stream, buffer, offset, length, position, prot, flags) {
- // TODO if PROT is PROT_WRITE, make sure we have write acccess
- if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) {
- throw new FS.ErrnoError(ERRNO_CODES.EACCES);
- }
- if (!stream.stream_ops.mmap) {
- throw new FS.errnoError(ERRNO_CODES.ENODEV);
- }
- return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
- }
- },
-
- $MEMFS__deps: ['$FS'],
- $MEMFS: {
- mount: function(mount) {
- return MEMFS.create_node(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
- },
- create_node: function(parent, name, mode, dev) {
- if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
- // no supported
- throw new FS.ErrnoError(ERRNO_CODES.EPERM);
- }
- var node = FS.createNode(parent, name, mode, dev);
- node.node_ops = MEMFS.node_ops;
- if (FS.isDir(node.mode)) {
- node.stream_ops = MEMFS.stream_ops;
- node.contents = {};
- } else if (FS.isFile(node.mode)) {
- node.stream_ops = MEMFS.stream_ops;
- node.contents = [];
- } else if (FS.isLink(node.mode)) {
- node.stream_ops = MEMFS.stream_ops;
- } else if (FS.isChrdev(node.mode)) {
- node.stream_ops = FS.chrdev_stream_ops;
- }
- node.timestamp = Date.now();
- // add the new node to the parent
- if (parent) {
- parent.contents[name] = node;
- }
- return node;
- },
- node_ops: {
- getattr: function(node) {
- var attr = {};
- // device numbers reuse inode numbers.
- attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
- attr.ino = node.id;
- attr.mode = node.mode;
- attr.nlink = 1;
- attr.uid = 0;
- attr.gid = 0;
- attr.rdev = node.rdev;
- if (FS.isDir(node.mode)) {
- attr.size = 4096;
- } else if (FS.isFile(node.mode)) {
- attr.size = node.contents.length;
- } else if (FS.isLink(node.mode)) {
- attr.size = node.link.length;
- } else {
- attr.size = 0;
- }
- attr.atime = new Date(node.timestamp);
- attr.mtime = new Date(node.timestamp);
- attr.ctime = new Date(node.timestamp);
- // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
- // but this is not required by the standard.
- attr.blksize = 4096;
- attr.blocks = Math.ceil(attr.size / attr.blksize);
- return attr;
- },
- setattr: function(node, attr) {
- if (attr.mode !== undefined) {
- node.mode = attr.mode;
- }
- if (attr.timestamp !== undefined) {
- node.timestamp = attr.timestamp;
- }
- if (attr.size !== undefined) {
- var contents = node.contents;
- if (attr.size < contents.length) contents.length = attr.size;
- else while (attr.size > contents.length) contents.push(0);
- }
- },
- lookup: function(parent, name) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
- },
- mknod: function(parent, name, mode, dev) {
- return MEMFS.create_node(parent, name, mode, dev);
- },
- rename: function(old_node, new_dir, new_name) {
- // if we're overwriting a directory at new_name, make sure it's empty.
- if (FS.isDir(old_node.mode)) {
- var new_node;
- try {
- new_node = FS.lookupNode(new_dir, new_name);
- } catch (e) {
- }
- if (new_node) {
- for (var i in new_node.contents) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- }
- }
- // do the internal rewiring
- delete old_node.parent.contents[old_node.name];
- old_node.name = new_name;
- new_dir.contents[new_name] = old_node;
- },
- unlink: function(parent, name) {
- delete parent.contents[name];
- },
- rmdir: function(parent, name) {
- var node = FS.lookupNode(parent, name);
- for (var i in node.contents) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
- }
- delete parent.contents[name];
- },
- symlink: function(parent, newname, oldpath) {
- var node = MEMFS.create_node(parent, newname, 0777 | {{{ cDefine('S_IFLNK') }}}, 0);
- node.link = oldpath;
- return node;
- },
- readlink: function(node) {
- if (!FS.isLink(node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- return node.link;
- },
- },
- stream_ops: {
- open: function(stream) {
- if (FS.isDir(stream.node.mode)) {
- // cache off the directory entries when open'd
- var entries = ['.', '..']
- for (var key in stream.node.contents) {
- if (!stream.node.contents.hasOwnProperty(key)) {
- continue;
- }
- entries.push(key);
- }
- stream.entries = entries;
- }
- },
- read: function(stream, buffer, offset, length, position) {
- var contents = stream.node.contents;
- var size = Math.min(contents.length - position, length);
-#if USE_TYPED_ARRAYS == 2
- if (contents.subarray) { // typed array
- buffer.set(contents.subarray(position, position + size), offset);
- } else
-#endif
- {
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents[position + i];
- }
- }
- return size;
- },
- write: function(stream, buffer, offset, length, position) {
- var contents = stream.node.contents;
- while (contents.length < position) contents.push(0);
- for (var i = 0; i < length; i++) {
- contents[position + i] = buffer[offset + i];
- }
- stream.node.timestamp = Date.now();
- return length;
- },
- llseek: function(stream, offset, whence) {
- var position = offset;
- if (whence === 1) { // SEEK_CUR.
- position += stream.position;
- } else if (whence === 2) { // SEEK_END.
- if (FS.isFile(stream.node.mode)) {
- position += stream.node.contents.length;
- }
- }
- if (position < 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
- }
- stream.ungotten = [];
- stream.position = position;
- return position;
- },
- readdir: function(stream) {
- return stream.entries;
- },
- allocate: function(stream, offset, length) {
- var contents = stream.node.contents;
- var limit = offset + length;
- while (limit > contents.length) contents.push(0);
- },
- mmap: function(stream, buffer, offset, length, position, prot, flags) {
- if (!FS.isFile(stream.node.mode)) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- var ptr;
- var allocated;
- var contents = stream.node.contents;
- // Only make a new copy when MAP_PRIVATE is specified.
- if (!(flags & {{{ cDefine('MAP_PRIVATE') }}})) {
- // We can't emulate MAP_SHARED when the file is not backed by the buffer
- // we're mapping to (e.g. the HEAP buffer).
- assert(contents.buffer === buffer || contents.buffer === buffer.buffer);
- allocated = false;
- ptr = contents.byteOffset;
- } else {
- // Try to avoid unnecessary slices.
- if (position > 0 || position + length < contents.length) {
- if (contents.subarray) {
- contents = contents.subarray(position, position + length);
- } else {
- contents = Array.prototype.slice.call(contents, position, position + length);
- }
- }
- allocated = true;
- ptr = _malloc(length);
- if (!ptr) {
- throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
- }
- buffer.set(contents, ptr);
- }
- return { ptr: ptr, allocated: allocated };
- },
- }
- },
-
- $SOCKFS__postset: '__ATINIT__.push({ func: function() { SOCKFS.root = VFS.mount(SOCKFS, {}, null); } });',
- $SOCKFS__deps: ['$FS'],
- $SOCKFS: {
- mount: function(mount) {
- var node = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
- node.node_ops = SOCKFS.node_ops;
- node.stream_ops = SOCKFS.stream_ops;
- return node;
- },
- node_ops: {
- },
- stream_ops: {
- },
- websocket_sock_ops: {
- }
- },
-
- $TTY__deps: ['$FS'],
- $TTY: {
- ttys: [],
- register: function(dev, ops) {
- TTY.ttys[dev] = { input: [], output: [], ops: ops };
- FS.registerDevice(dev, TTY.stream_ops);
- },
- stream_ops: {
- open: function(stream) {
- // this wouldn't be required if the library wasn't eval'd at first...
- if (!TTY.utf8) {
- TTY.utf8 = new Runtime.UTF8Processor();
- }
- var tty = TTY.ttys[stream.node.rdev];
- if (!tty) {
- throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
- }
- stream.tty = tty;
- stream.seekable = false;
- },
- close: function(stream) {
- // flush any pending line data
- if (stream.tty.output.length) {
- stream.tty.ops.put_char(stream.tty, {{{ charCode('\n') }}});
- }
- },
- read: function(stream, buffer, offset, length, pos /* ignored */) {
- if (!stream.tty || !stream.tty.ops.get_char) {
- throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
- }
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = stream.tty.ops.get_char(stream.tty);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset+i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- },
- write: function(stream, buffer, offset, length, pos) {
- if (!stream.tty || !stream.tty.ops.put_char) {
- throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
- }
- for (var i = 0; i < length; i++) {
- try {
- stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- }
- },
- // NOTE: This is weird to support stdout and stderr
- // overrides in addition to print and printErr orverrides.
- default_tty_ops: {
- get_char: function(tty) {
- if (!tty.input.length) {
- var result = null;
- if (ENVIRONMENT_IS_NODE) {
- if (process.stdin.destroyed) {
- return undefined;
- }
- result = process.stdin.read();
- } else if (typeof window != 'undefined' &&
- typeof window.prompt == 'function') {
- // Browser.
- result = window.prompt('Input: '); // returns null on cancel
- if (result !== null) {
- result += '\n';
- }
- } else if (typeof readline == 'function') {
- // Command line.
- result = readline();
- if (result !== null) {
- result += '\n';
- }
- }
- if (!result) {
- return null;
- }
- tty.input = intArrayFromString(result, true);
- }
- return tty.input.shift();
- },
- put_char: function(tty, val) {
- if (val === null || val === {{{ charCode('\n') }}}) {
- Module['print'](tty.output.join(''));
- tty.output = [];
- } else {
- tty.output.push(TTY.utf8.processCChar(val));
- }
- }
- },
- default_tty1_ops: {
- put_char: function(tty, val) {
- if (val === null || val === {{{ charCode('\n') }}}) {
- Module['printErr'](tty.output.join(''));
- tty.output = [];
- } else {
- tty.output.push(TTY.utf8.processCChar(val));
- }
- }
- }
- },
-#endif
-
-
// ==========================================================================
// dirent.h
// ==========================================================================
@@ -1814,13 +100,13 @@ LibraryManager.library = {
}
var entries;
try {
- entries = VFS.readdir(stream);
+ entries = FS.readdir(stream.path);
} catch (e) {
return FS.handleFSError(e);
}
if (stream.position < 0 || stream.position >= entries.length) {
{{{ makeSetValue('result', '0', '0', 'i8*') }}}
- return;
+ return 0;
}
var id;
var type;
@@ -1893,7 +179,7 @@ LibraryManager.library = {
}
path = Pointer_stringify(path);
try {
- VFS.utime(path, time, time);
+ FS.utime(path, time, time);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -1993,7 +279,7 @@ LibraryManager.library = {
// used in client code.
path = typeof path !== 'string' ? Pointer_stringify(path) : path;
try {
- var stat = dontResolveLastLink ? VFS.lstat(path) : VFS.stat(path);
+ var stat = dontResolveLastLink ? FS.lstat(path) : FS.stat(path);
{{{ makeSetValue('buf', '___stat_struct_layout.st_dev', 'stat.dev', 'i32') }}};
{{{ makeSetValue('buf', '___stat_struct_layout.st_ino', 'stat.ino', 'i32') }}}
{{{ makeSetValue('buf', '___stat_struct_layout.st_mode', 'stat.mode', 'i32') }}}
@@ -2043,7 +329,7 @@ LibraryManager.library = {
return -1;
}
try {
- VFS.mknod(path, mode, dev);
+ FS.mknod(path, mode, dev);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2056,7 +342,7 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
path = Pointer_stringify(path);
try {
- VFS.mkdir(path, mode, 0);
+ FS.mkdir(path, mode, 0);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2082,7 +368,7 @@ LibraryManager.library = {
// used in client code.
path = typeof path !== 'string' ? Pointer_stringify(path) : path;
try {
- VFS.chmod(path, mode);
+ FS.chmod(path, mode);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2094,7 +380,7 @@ LibraryManager.library = {
// int fchmod(int fildes, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html
try {
- VFS.fchmod(fildes, mode);
+ FS.fchmod(fildes, mode);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2105,7 +391,7 @@ LibraryManager.library = {
lchmod: function(path, mode) {
path = Pointer_stringify(path);
try {
- VFS.lchmod(path, mode);
+ FS.lchmod(path, mode);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2192,12 +478,10 @@ LibraryManager.library = {
open: function(path, oflag, varargs) {
// int open(const char *path, int oflag, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
- // NOTE: This implementation tries to mimic glibc rather than strictly
- // following the POSIX standard.
var mode = {{{ makeGetValue('varargs', 0, 'i32') }}};
path = Pointer_stringify(path);
try {
- var stream = VFS.open(path, oflag, mode);
+ var stream = FS.open(path, oflag, mode);
return stream.fd;
} catch (e) {
FS.handleFSError(e);
@@ -2237,7 +521,7 @@ LibraryManager.library = {
}
var newStream;
try {
- newStream = VFS.open(stream.path, stream.flags, 0, arg);
+ newStream = FS.open(stream.path, stream.flags, 0, arg);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2294,7 +578,7 @@ LibraryManager.library = {
return -1;
}
try {
- VFS.allocate(stream, offset, len);
+ FS.allocate(stream, offset, len);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2412,7 +696,7 @@ LibraryManager.library = {
// used in client code.
if (typeof path !== 'string') path = Pointer_stringify(path);
try {
- VFS.chown(path, owner, group);
+ FS.chown(path, owner, group);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2436,7 +720,7 @@ LibraryManager.library = {
return -1;
}
try {
- VFS.close(stream);
+ FS.close(stream);
return 0;
} catch (e) {
FS.handleFSError(e);;
@@ -2462,7 +746,7 @@ LibraryManager.library = {
} else {
_close(fildes2);
try {
- var stream2 = VFS.open(stream.path, stream.flags, 0, fildes2, fildes2);
+ var stream2 = FS.open(stream.path, stream.flags, 0, fildes2, fildes2);
return stream2.fd;
} catch (e) {
FS.handleFSError(e);
@@ -2475,7 +759,7 @@ LibraryManager.library = {
// int fchown(int fildes, uid_t owner, gid_t group);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fchown.html
try {
- VFS.fchown(fildes, owner, group);
+ FS.fchown(fildes, owner, group);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2578,7 +862,7 @@ LibraryManager.library = {
// NOTE: The path argument may be a string, to simplify ftruncate().
if (typeof path !== 'string') path = Pointer_stringify(path);
try {
- VFS.truncate(path, length);
+ FS.truncate(path, length);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2590,7 +874,7 @@ LibraryManager.library = {
// int ftruncate(int fildes, off_t length);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ftruncate.html
try {
- VFS.ftruncate(fildes, length);
+ FS.ftruncate(fildes, length);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2675,7 +959,7 @@ LibraryManager.library = {
return -1;
}
try {
- return VFS.llseek(stream, offset, whence);
+ return FS.llseek(stream, offset, whence);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2701,7 +985,12 @@ LibraryManager.library = {
}
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
- return VFS.read(stream, slab, buf, nbyte, offset);
+#if SAFE_HEAP
+#if USE_TYPED_ARRAYS == 0
+ SAFE_HEAP_FILL_HISTORY(buf, buf+nbyte, 'i8'); // VFS does not use makeSetValues, so we need to do it manually
+#endif
+#endif
+ return FS.read(stream, slab, buf, nbyte, offset);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2723,7 +1012,12 @@ LibraryManager.library = {
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
- return VFS.read(stream, slab, buf, nbyte);
+#if SAFE_HEAP
+#if USE_TYPED_ARRAYS == 0
+ SAFE_HEAP_FILL_HISTORY(buf, buf+nbyte, 'i8'); // VFS does not use makeSetValues, so we need to do it manually
+#endif
+#endif
+ return FS.read(stream, slab, buf, nbyte);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2740,7 +1034,7 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
path = Pointer_stringify(path);
try {
- VFS.rmdir(path);
+ FS.rmdir(path);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2753,7 +1047,7 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
path = Pointer_stringify(path);
try {
- VFS.unlink(path);
+ FS.unlink(path);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2790,7 +1084,7 @@ LibraryManager.library = {
path1 = Pointer_stringify(path1);
path2 = Pointer_stringify(path2);
try {
- VFS.symlink(path1, path2);
+ FS.symlink(path1, path2);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -2804,7 +1098,7 @@ LibraryManager.library = {
path = Pointer_stringify(path);
var str;
try {
- str = VFS.readlink(path);
+ str = FS.readlink(path);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2824,7 +1118,12 @@ LibraryManager.library = {
}
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
- return VFS.write(stream, slab, buf, nbyte, offset);
+#if SAFE_HEAP
+#if USE_TYPED_ARRAYS == 0
+ SAFE_HEAP_FILL_HISTORY(buf, buf+nbyte, 'i8'); // VFS does not use makeSetValues, so we need to do it manually
+#endif
+#endif
+ return FS.write(stream, slab, buf, nbyte, offset);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2841,12 +1140,17 @@ LibraryManager.library = {
}
if (stream && ('socket' in stream)) {
- return _send(fildes, buf, nbyte, 0);
+ return _send(fildes, buf, nbyte, 0);
}
try {
var slab = {{{ makeGetSlabs('buf', 'i8', true) }}};
- return VFS.write(stream, slab, buf, nbyte);
+#if SAFE_HEAP
+#if USE_TYPED_ARRAYS == 0
+ SAFE_HEAP_FILL_HISTORY(buf, buf+nbyte, 'i8'); // VFS does not use makeSetValues, so we need to do it manually
+#endif
+#endif
+ return FS.write(stream, slab, buf, nbyte);
} catch (e) {
FS.handleFSError(e);
return -1;
@@ -2870,7 +1174,7 @@ LibraryManager.library = {
value = ENV['PATH'] || '/';
break;
case {{{ cDefine('_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS') }}}:
- // Mimicing glibc.
+ // Mimicking glibc.
value = 'POSIX_V6_ILP32_OFF32\nPOSIX_V6_ILP32_OFFBIG';
break;
case {{{ cDefine('_CS_GNU_LIBC_VERSION') }}}:
@@ -2930,6 +1234,7 @@ LibraryManager.library = {
_exit: function(status) {
// void _exit(int status);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
+ Module.print('exit(' + status + ') called');
Module['exit'](status);
},
fork__deps: ['__setErrNo', '$ERRNO_CODES'],
@@ -3106,9 +1411,16 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/usleep.html
// We're single-threaded, so use a busy loop. Super-ugly.
var msec = useconds / 1000;
- var start = Date.now();
- while (Date.now() - start < msec) {
- // Do nothing.
+ if (ENVIRONMENT_IS_WEB && window['performance'] && window['performance']['now']) {
+ var start = window['performance']['now']();
+ while (window['performance']['now']() - start < msec) {
+ // Do nothing.
+ }
+ } else {
+ var start = Date.now();
+ while (Date.now() - start < msec) {
+ // Do nothing.
+ }
}
return 0;
},
@@ -4315,7 +2627,7 @@ LibraryManager.library = {
old_path = Pointer_stringify(old_path);
new_path = Pointer_stringify(new_path);
try {
- VFS.rename(old_path, new_path);
+ FS.rename(old_path, new_path);
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -4579,7 +2891,7 @@ LibraryManager.library = {
var info = FS.getStream(stream);
if (!info) return -1;
try {
- var res = VFS.mmap(info, HEAPU8, start, num, offset, prot, flags);
+ var res = FS.mmap(info, HEAPU8, start, num, offset, prot, flags);
ptr = res.ptr;
allocated = res.allocated;
} catch (e) {
@@ -8117,262 +6429,250 @@ LibraryManager.library = {
// ==========================================================================
$ERRNO_CODES: {
- EPERM: 1,
- ENOENT: 2,
- ESRCH: 3,
- EINTR: 4,
- EIO: 5,
- ENXIO: 6,
- E2BIG: 7,
- ENOEXEC: 8,
- EBADF: 9,
- ECHILD: 10,
- EAGAIN: 11,
- EWOULDBLOCK: 11,
- ENOMEM: 12,
- EACCES: 13,
- EFAULT: 14,
- ENOTBLK: 15,
- EBUSY: 16,
- EEXIST: 17,
- EXDEV: 18,
- ENODEV: 19,
- ENOTDIR: 20,
- EISDIR: 21,
- EINVAL: 22,
- ENFILE: 23,
- EMFILE: 24,
- ENOTTY: 25,
- ETXTBSY: 26,
- EFBIG: 27,
- ENOSPC: 28,
- ESPIPE: 29,
- EROFS: 30,
- EMLINK: 31,
- EPIPE: 32,
- EDOM: 33,
- ERANGE: 34,
- ENOMSG: 35,
- EIDRM: 36,
- ECHRNG: 37,
- EL2NSYNC: 38,
- EL3HLT: 39,
- EL3RST: 40,
- ELNRNG: 41,
- EUNATCH: 42,
- ENOCSI: 43,
- EL2HLT: 44,
- EDEADLK: 45,
- ENOLCK: 46,
- EBADE: 50,
- EBADR: 51,
- EXFULL: 52,
- ENOANO: 53,
- EBADRQC: 54,
- EBADSLT: 55,
- EDEADLOCK: 56,
- EBFONT: 57,
- ENOSTR: 60,
- ENODATA: 61,
- ETIME: 62,
- ENOSR: 63,
- ENONET: 64,
- ENOPKG: 65,
- EREMOTE: 66,
- ENOLINK: 67,
- EADV: 68,
- ESRMNT: 69,
- ECOMM: 70,
- EPROTO: 71,
- EMULTIHOP: 74,
- ELBIN: 75,
- EDOTDOT: 76,
- EBADMSG: 77,
- EFTYPE: 79,
- ENOTUNIQ: 80,
- EBADFD: 81,
- EREMCHG: 82,
- ELIBACC: 83,
- ELIBBAD: 84,
- ELIBSCN: 85,
- ELIBMAX: 86,
- ELIBEXEC: 87,
- ENOSYS: 88,
- ENMFILE: 89,
- ENOTEMPTY: 90,
- ENAMETOOLONG: 91,
- ELOOP: 92,
- EOPNOTSUPP: 95,
- EPFNOSUPPORT: 96,
- ECONNRESET: 104,
- ENOBUFS: 105,
- EAFNOSUPPORT: 106,
- EPROTOTYPE: 107,
- ENOTSOCK: 108,
- ENOPROTOOPT: 109,
- ESHUTDOWN: 110,
- ECONNREFUSED: 111,
- EADDRINUSE: 112,
- ECONNABORTED: 113,
- ENETUNREACH: 114,
- ENETDOWN: 115,
- ETIMEDOUT: 116,
- EHOSTDOWN: 117,
- EHOSTUNREACH: 118,
- EINPROGRESS: 119,
- EALREADY: 120,
- EDESTADDRREQ: 121,
- EMSGSIZE: 122,
- EPROTONOSUPPORT: 123,
- ESOCKTNOSUPPORT: 124,
- EADDRNOTAVAIL: 125,
- ENETRESET: 126,
- EISCONN: 127,
- ENOTCONN: 128,
- ETOOMANYREFS: 129,
- EPROCLIM: 130,
- EUSERS: 131,
- EDQUOT: 132,
- ESTALE: 133,
- ENOTSUP: 134,
- ENOMEDIUM: 135,
- ENOSHARE: 136,
- ECASECLASH: 137,
- EILSEQ: 138,
- EOVERFLOW: 139,
- ECANCELED: 140,
- ENOTRECOVERABLE: 141,
- EOWNERDEAD: 142,
- ESTRPIPE: 143
+ EPERM: {{{ cDefine('EPERM') }}},
+ ENOENT: {{{ cDefine('ENOENT') }}},
+ ESRCH: {{{ cDefine('ESRCH') }}},
+ EINTR: {{{ cDefine('EINTR') }}},
+ EIO: {{{ cDefine('EIO') }}},
+ ENXIO: {{{ cDefine('ENXIO') }}},
+ E2BIG: {{{ cDefine('E2BIG') }}},
+ ENOEXEC: {{{ cDefine('ENOEXEC') }}},
+ EBADF: {{{ cDefine('EBADF') }}},
+ ECHILD: {{{ cDefine('ECHILD') }}},
+ EAGAIN: {{{ cDefine('EAGAIN') }}},
+ EWOULDBLOCK: {{{ cDefine('EWOULDBLOCK') }}},
+ ENOMEM: {{{ cDefine('ENOMEM') }}},
+ EACCES: {{{ cDefine('EACCES') }}},
+ EFAULT: {{{ cDefine('EFAULT') }}},
+ ENOTBLK: {{{ cDefine('ENOTBLK') }}},
+ EBUSY: {{{ cDefine('EBUSY') }}},
+ EEXIST: {{{ cDefine('EEXIST') }}},
+ EXDEV: {{{ cDefine('EXDEV') }}},
+ ENODEV: {{{ cDefine('ENODEV') }}},
+ ENOTDIR: {{{ cDefine('ENOTDIR') }}},
+ EISDIR: {{{ cDefine('EISDIR') }}},
+ EINVAL: {{{ cDefine('EINVAL') }}},
+ ENFILE: {{{ cDefine('ENFILE') }}},
+ EMFILE: {{{ cDefine('EMFILE') }}},
+ ENOTTY: {{{ cDefine('ENOTTY') }}},
+ ETXTBSY: {{{ cDefine('ETXTBSY') }}},
+ EFBIG: {{{ cDefine('EFBIG') }}},
+ ENOSPC: {{{ cDefine('ENOSPC') }}},
+ ESPIPE: {{{ cDefine('ESPIPE') }}},
+ EROFS: {{{ cDefine('EROFS') }}},
+ EMLINK: {{{ cDefine('EMLINK') }}},
+ EPIPE: {{{ cDefine('EPIPE') }}},
+ EDOM: {{{ cDefine('EDOM') }}},
+ ERANGE: {{{ cDefine('ERANGE') }}},
+ ENOMSG: {{{ cDefine('ENOMSG') }}},
+ EIDRM: {{{ cDefine('EIDRM') }}},
+ ECHRNG: {{{ cDefine('ECHRNG') }}},
+ EL2NSYNC: {{{ cDefine('EL2NSYNC') }}},
+ EL3HLT: {{{ cDefine('EL3HLT') }}},
+ EL3RST: {{{ cDefine('EL3RST') }}},
+ ELNRNG: {{{ cDefine('ELNRNG') }}},
+ EUNATCH: {{{ cDefine('EUNATCH') }}},
+ ENOCSI: {{{ cDefine('ENOCSI') }}},
+ EL2HLT: {{{ cDefine('EL2HLT') }}},
+ EDEADLK: {{{ cDefine('EDEADLK') }}},
+ ENOLCK: {{{ cDefine('ENOLCK') }}},
+ EBADE: {{{ cDefine('EBADE') }}},
+ EBADR: {{{ cDefine('EBADR') }}},
+ EXFULL: {{{ cDefine('EXFULL') }}},
+ ENOANO: {{{ cDefine('ENOANO') }}},
+ EBADRQC: {{{ cDefine('EBADRQC') }}},
+ EBADSLT: {{{ cDefine('EBADSLT') }}},
+ EDEADLOCK: {{{ cDefine('EDEADLOCK') }}},
+ EBFONT: {{{ cDefine('EBFONT') }}},
+ ENOSTR: {{{ cDefine('ENOSTR') }}},
+ ENODATA: {{{ cDefine('ENODATA') }}},
+ ETIME: {{{ cDefine('ETIME') }}},
+ ENOSR: {{{ cDefine('ENOSR') }}},
+ ENONET: {{{ cDefine('ENONET') }}},
+ ENOPKG: {{{ cDefine('ENOPKG') }}},
+ EREMOTE: {{{ cDefine('EREMOTE') }}},
+ ENOLINK: {{{ cDefine('ENOLINK') }}},
+ EADV: {{{ cDefine('EADV') }}},
+ ESRMNT: {{{ cDefine('ESRMNT') }}},
+ ECOMM: {{{ cDefine('ECOMM') }}},
+ EPROTO: {{{ cDefine('EPROTO') }}},
+ EMULTIHOP: {{{ cDefine('EMULTIHOP') }}},
+ EDOTDOT: {{{ cDefine('EDOTDOT') }}},
+ EBADMSG: {{{ cDefine('EBADMSG') }}},
+ ENOTUNIQ: {{{ cDefine('ENOTUNIQ') }}},
+ EBADFD: {{{ cDefine('EBADFD') }}},
+ EREMCHG: {{{ cDefine('EREMCHG') }}},
+ ELIBACC: {{{ cDefine('ELIBACC') }}},
+ ELIBBAD: {{{ cDefine('ELIBBAD') }}},
+ ELIBSCN: {{{ cDefine('ELIBSCN') }}},
+ ELIBMAX: {{{ cDefine('ELIBMAX') }}},
+ ELIBEXEC: {{{ cDefine('ELIBEXEC') }}},
+ ENOSYS: {{{ cDefine('ENOSYS') }}},
+ ENOTEMPTY: {{{ cDefine('ENOTEMPTY') }}},
+ ENAMETOOLONG: {{{ cDefine('ENAMETOOLONG') }}},
+ ELOOP: {{{ cDefine('ELOOP') }}},
+ EOPNOTSUPP: {{{ cDefine('EOPNOTSUPP') }}},
+ EPFNOSUPPORT: {{{ cDefine('EPFNOSUPPORT') }}},
+ ECONNRESET: {{{ cDefine('ECONNRESET') }}},
+ ENOBUFS: {{{ cDefine('ENOBUFS') }}},
+ EAFNOSUPPORT: {{{ cDefine('EAFNOSUPPORT') }}},
+ EPROTOTYPE: {{{ cDefine('EPROTOTYPE') }}},
+ ENOTSOCK: {{{ cDefine('ENOTSOCK') }}},
+ ENOPROTOOPT: {{{ cDefine('ENOPROTOOPT') }}},
+ ESHUTDOWN: {{{ cDefine('ESHUTDOWN') }}},
+ ECONNREFUSED: {{{ cDefine('ECONNREFUSED') }}},
+ EADDRINUSE: {{{ cDefine('EADDRINUSE') }}},
+ ECONNABORTED: {{{ cDefine('ECONNABORTED') }}},
+ ENETUNREACH: {{{ cDefine('ENETUNREACH') }}},
+ ENETDOWN: {{{ cDefine('ENETDOWN') }}},
+ ETIMEDOUT: {{{ cDefine('ETIMEDOUT') }}},
+ EHOSTDOWN: {{{ cDefine('EHOSTDOWN') }}},
+ EHOSTUNREACH: {{{ cDefine('EHOSTUNREACH') }}},
+ EINPROGRESS: {{{ cDefine('EINPROGRESS') }}},
+ EALREADY: {{{ cDefine('EALREADY') }}},
+ EDESTADDRREQ: {{{ cDefine('EDESTADDRREQ') }}},
+ EMSGSIZE: {{{ cDefine('EMSGSIZE') }}},
+ EPROTONOSUPPORT: {{{ cDefine('EPROTONOSUPPORT') }}},
+ ESOCKTNOSUPPORT: {{{ cDefine('ESOCKTNOSUPPORT') }}},
+ EADDRNOTAVAIL: {{{ cDefine('EADDRNOTAVAIL') }}},
+ ENETRESET: {{{ cDefine('ENETRESET') }}},
+ EISCONN: {{{ cDefine('EISCONN') }}},
+ ENOTCONN: {{{ cDefine('ENOTCONN') }}},
+ ETOOMANYREFS: {{{ cDefine('ETOOMANYREFS') }}},
+ EUSERS: {{{ cDefine('EUSERS') }}},
+ EDQUOT: {{{ cDefine('EDQUOT') }}},
+ ESTALE: {{{ cDefine('ESTALE') }}},
+ ENOTSUP: {{{ cDefine('ENOTSUP') }}},
+ ENOMEDIUM: {{{ cDefine('ENOMEDIUM') }}},
+ EILSEQ: {{{ cDefine('EILSEQ') }}},
+ EOVERFLOW: {{{ cDefine('EOVERFLOW') }}},
+ ECANCELED: {{{ cDefine('ECANCELED') }}},
+ ENOTRECOVERABLE: {{{ cDefine('ENOTRECOVERABLE') }}},
+ EOWNERDEAD: {{{ cDefine('EOWNERDEAD') }}},
+ ESTRPIPE: {{{ cDefine('ESTRPIPE') }}},
},
$ERRNO_MESSAGES: {
0: 'Success',
- 1: 'Not super-user',
- 2: 'No such file or directory',
- 3: 'No such process',
- 4: 'Interrupted system call',
- 5: 'I/O error',
- 6: 'No such device or address',
- 7: 'Arg list too long',
- 8: 'Exec format error',
- 9: 'Bad file number',
- 10: 'No children',
- 11: 'No more processes',
- 12: 'Not enough core',
- 13: 'Permission denied',
- 14: 'Bad address',
- 15: 'Block device required',
- 16: 'Mount device busy',
- 17: 'File exists',
- 18: 'Cross-device link',
- 19: 'No such device',
- 20: 'Not a directory',
- 21: 'Is a directory',
- 22: 'Invalid argument',
- 23: 'Too many open files in system',
- 24: 'Too many open files',
- 25: 'Not a typewriter',
- 26: 'Text file busy',
- 27: 'File too large',
- 28: 'No space left on device',
- 29: 'Illegal seek',
- 30: 'Read only file system',
- 31: 'Too many links',
- 32: 'Broken pipe',
- 33: 'Math arg out of domain of func',
- 34: 'Math result not representable',
- 35: 'No message of desired type',
- 36: 'Identifier removed',
- 37: 'Channel number out of range',
- 38: 'Level 2 not synchronized',
- 39: 'Level 3 halted',
- 40: 'Level 3 reset',
- 41: 'Link number out of range',
- 42: 'Protocol driver not attached',
- 43: 'No CSI structure available',
- 44: 'Level 2 halted',
- 45: 'Deadlock condition',
- 46: 'No record locks available',
- 50: 'Invalid exchange',
- 51: 'Invalid request descriptor',
- 52: 'Exchange full',
- 53: 'No anode',
- 54: 'Invalid request code',
- 55: 'Invalid slot',
- 56: 'File locking deadlock error',
- 57: 'Bad font file fmt',
- 60: 'Device not a stream',
- 61: 'No data (for no delay io)',
- 62: 'Timer expired',
- 63: 'Out of streams resources',
- 64: 'Machine is not on the network',
- 65: 'Package not installed',
- 66: 'The object is remote',
- 67: 'The link has been severed',
- 68: 'Advertise error',
- 69: 'Srmount error',
- 70: 'Communication error on send',
- 71: 'Protocol error',
- 74: 'Multihop attempted',
- 75: 'Inode is remote (not really error)',
- 76: 'Cross mount point (not really error)',
- 77: 'Trying to read unreadable message',
- 79: 'Inappropriate file type or format',
- 80: 'Given log. name not unique',
- 81: 'f.d. invalid for this operation',
- 82: 'Remote address changed',
- 83: 'Can\t access a needed shared lib',
- 84: 'Accessing a corrupted shared lib',
- 85: '.lib section in a.out corrupted',
- 86: 'Attempting to link in too many libs',
- 87: 'Attempting to exec a shared library',
- 88: 'Function not implemented',
- 89: 'No more files',
- 90: 'Directory not empty',
- 91: 'File or path name too long',
- 92: 'Too many symbolic links',
- 95: 'Operation not supported on transport endpoint',
- 96: 'Protocol family not supported',
- 104: 'Connection reset by peer',
- 105: 'No buffer space available',
- 106: 'Address family not supported by protocol family',
- 107: 'Protocol wrong type for socket',
- 108: 'Socket operation on non-socket',
- 109: 'Protocol not available',
- 110: 'Can\'t send after socket shutdown',
- 111: 'Connection refused',
- 112: 'Address already in use',
- 113: 'Connection aborted',
- 114: 'Network is unreachable',
- 115: 'Network interface is not configured',
- 116: 'Connection timed out',
- 117: 'Host is down',
- 118: 'Host is unreachable',
- 119: 'Connection already in progress',
- 120: 'Socket already connected',
- 121: 'Destination address required',
- 122: 'Message too long',
- 123: 'Unknown protocol',
- 124: 'Socket type not supported',
- 125: 'Address not available',
- 126: 'ENETRESET',
- 127: 'Socket is already connected',
- 128: 'Socket is not connected',
- 129: 'TOOMANYREFS',
- 130: 'EPROCLIM',
- 131: 'EUSERS',
- 132: 'EDQUOT',
- 133: 'ESTALE',
- 134: 'Not supported',
- 135: 'No medium (in tape drive)',
- 136: 'No such host or network path',
- 137: 'Filename exists with different case',
- 138: 'EILSEQ',
- 139: 'Value too large for defined data type',
- 140: 'Operation canceled',
- 141: 'State not recoverable',
- 142: 'Previous owner died',
- 143: 'Streams pipe error',
+ {{{ cDefine('EPERM') }}}: 'Not super-user',
+ {{{ cDefine('ENOENT') }}}: 'No such file or directory',
+ {{{ cDefine('ESRCH') }}}: 'No such process',
+ {{{ cDefine('EINTR') }}}: 'Interrupted system call',
+ {{{ cDefine('EIO') }}}: 'I/O error',
+ {{{ cDefine('ENXIO') }}}: 'No such device or address',
+ {{{ cDefine('E2BIG') }}}: 'Arg list too long',
+ {{{ cDefine('ENOEXEC') }}}: 'Exec format error',
+ {{{ cDefine('EBADF') }}}: 'Bad file number',
+ {{{ cDefine('ECHILD') }}}: 'No children',
+ {{{ cDefine('EWOULDBLOCK') }}}: 'No more processes',
+ {{{ cDefine('ENOMEM') }}}: 'Not enough core',
+ {{{ cDefine('EACCES') }}}: 'Permission denied',
+ {{{ cDefine('EFAULT') }}}: 'Bad address',
+ {{{ cDefine('ENOTBLK') }}}: 'Block device required',
+ {{{ cDefine('EBUSY') }}}: 'Mount device busy',
+ {{{ cDefine('EEXIST') }}}: 'File exists',
+ {{{ cDefine('EXDEV') }}}: 'Cross-device link',
+ {{{ cDefine('ENODEV') }}}: 'No such device',
+ {{{ cDefine('ENOTDIR') }}}: 'Not a directory',
+ {{{ cDefine('EISDIR') }}}: 'Is a directory',
+ {{{ cDefine('EINVAL') }}}: 'Invalid argument',
+ {{{ cDefine('ENFILE') }}}: 'Too many open files in system',
+ {{{ cDefine('EMFILE') }}}: 'Too many open files',
+ {{{ cDefine('ENOTTY') }}}: 'Not a typewriter',
+ {{{ cDefine('ETXTBSY') }}}: 'Text file busy',
+ {{{ cDefine('EFBIG') }}}: 'File too large',
+ {{{ cDefine('ENOSPC') }}}: 'No space left on device',
+ {{{ cDefine('ESPIPE') }}}: 'Illegal seek',
+ {{{ cDefine('EROFS') }}}: 'Read only file system',
+ {{{ cDefine('EMLINK') }}}: 'Too many links',
+ {{{ cDefine('EPIPE') }}}: 'Broken pipe',
+ {{{ cDefine('EDOM') }}}: 'Math arg out of domain of func',
+ {{{ cDefine('ERANGE') }}}: 'Math result not representable',
+ {{{ cDefine('ENOMSG') }}}: 'No message of desired type',
+ {{{ cDefine('EIDRM') }}}: 'Identifier removed',
+ {{{ cDefine('ECHRNG') }}}: 'Channel number out of range',
+ {{{ cDefine('EL2NSYNC') }}}: 'Level 2 not synchronized',
+ {{{ cDefine('EL3HLT') }}}: 'Level 3 halted',
+ {{{ cDefine('EL3RST') }}}: 'Level 3 reset',
+ {{{ cDefine('ELNRNG') }}}: 'Link number out of range',
+ {{{ cDefine('EUNATCH') }}}: 'Protocol driver not attached',
+ {{{ cDefine('ENOCSI') }}}: 'No CSI structure available',
+ {{{ cDefine('EL2HLT') }}}: 'Level 2 halted',
+ {{{ cDefine('EDEADLK') }}}: 'Deadlock condition',
+ {{{ cDefine('ENOLCK') }}}: 'No record locks available',
+ {{{ cDefine('EBADE') }}}: 'Invalid exchange',
+ {{{ cDefine('EBADR') }}}: 'Invalid request descriptor',
+ {{{ cDefine('EXFULL') }}}: 'Exchange full',
+ {{{ cDefine('ENOANO') }}}: 'No anode',
+ {{{ cDefine('EBADRQC') }}}: 'Invalid request code',
+ {{{ cDefine('EBADSLT') }}}: 'Invalid slot',
+ {{{ cDefine('EDEADLOCK') }}}: 'File locking deadlock error',
+ {{{ cDefine('EBFONT') }}}: 'Bad font file fmt',
+ {{{ cDefine('ENOSTR') }}}: 'Device not a stream',
+ {{{ cDefine('ENODATA') }}}: 'No data (for no delay io)',
+ {{{ cDefine('ETIME') }}}: 'Timer expired',
+ {{{ cDefine('ENOSR') }}}: 'Out of streams resources',
+ {{{ cDefine('ENONET') }}}: 'Machine is not on the network',
+ {{{ cDefine('ENOPKG') }}}: 'Package not installed',
+ {{{ cDefine('EREMOTE') }}}: 'The object is remote',
+ {{{ cDefine('ENOLINK') }}}: 'The link has been severed',
+ {{{ cDefine('EADV') }}}: 'Advertise error',
+ {{{ cDefine('ESRMNT') }}}: 'Srmount error',
+ {{{ cDefine('ECOMM') }}}: 'Communication error on send',
+ {{{ cDefine('EPROTO') }}}: 'Protocol error',
+ {{{ cDefine('EMULTIHOP') }}}: 'Multihop attempted',
+ {{{ cDefine('EDOTDOT') }}}: 'Cross mount point (not really error)',
+ {{{ cDefine('EBADMSG') }}}: 'Trying to read unreadable message',
+ {{{ cDefine('ENOTUNIQ') }}}: 'Given log. name not unique',
+ {{{ cDefine('EBADFD') }}}: 'f.d. invalid for this operation',
+ {{{ cDefine('EREMCHG') }}}: 'Remote address changed',
+ {{{ cDefine('ELIBACC') }}}: 'Can access a needed shared lib',
+ {{{ cDefine('ELIBBAD') }}}: 'Accessing a corrupted shared lib',
+ {{{ cDefine('ELIBSCN') }}}: '.lib section in a.out corrupted',
+ {{{ cDefine('ELIBMAX') }}}: 'Attempting to link in too many libs',
+ {{{ cDefine('ELIBEXEC') }}}: 'Attempting to exec a shared library',
+ {{{ cDefine('ENOSYS') }}}: 'Function not implemented',
+ {{{ cDefine('ENOTEMPTY') }}}: 'Directory not empty',
+ {{{ cDefine('ENAMETOOLONG') }}}: 'File or path name too long',
+ {{{ cDefine('ELOOP') }}}: 'Too many symbolic links',
+ {{{ cDefine('EOPNOTSUPP') }}}: 'Operation not supported on transport endpoint',
+ {{{ cDefine('EPFNOSUPPORT') }}}: 'Protocol family not supported',
+ {{{ cDefine('ECONNRESET') }}}: 'Connection reset by peer',
+ {{{ cDefine('ENOBUFS') }}}: 'No buffer space available',
+ {{{ cDefine('EAFNOSUPPORT') }}}: 'Address family not supported by protocol family',
+ {{{ cDefine('EPROTOTYPE') }}}: 'Protocol wrong type for socket',
+ {{{ cDefine('ENOTSOCK') }}}: 'Socket operation on non-socket',
+ {{{ cDefine('ENOPROTOOPT') }}}: 'Protocol not available',
+ {{{ cDefine('ESHUTDOWN') }}}: 'Can\'t send after socket shutdown',
+ {{{ cDefine('ECONNREFUSED') }}}: 'Connection refused',
+ {{{ cDefine('EADDRINUSE') }}}: 'Address already in use',
+ {{{ cDefine('ECONNABORTED') }}}: 'Connection aborted',
+ {{{ cDefine('ENETUNREACH') }}}: 'Network is unreachable',
+ {{{ cDefine('ENETDOWN') }}}: 'Network interface is not configured',
+ {{{ cDefine('ETIMEDOUT') }}}: 'Connection timed out',
+ {{{ cDefine('EHOSTDOWN') }}}: 'Host is down',
+ {{{ cDefine('EHOSTUNREACH') }}}: 'Host is unreachable',
+ {{{ cDefine('EINPROGRESS') }}}: 'Connection already in progress',
+ {{{ cDefine('EALREADY') }}}: 'Socket already connected',
+ {{{ cDefine('EDESTADDRREQ') }}}: 'Destination address required',
+ {{{ cDefine('EMSGSIZE') }}}: 'Message too long',
+ {{{ cDefine('EPROTONOSUPPORT') }}}: 'Unknown protocol',
+ {{{ cDefine('ESOCKTNOSUPPORT') }}}: 'Socket type not supported',
+ {{{ cDefine('EADDRNOTAVAIL') }}}: 'Address not available',
+ {{{ cDefine('ENETRESET') }}}: 'Connection reset by network',
+ {{{ cDefine('EISCONN') }}}: 'Socket is already connected',
+ {{{ cDefine('ENOTCONN') }}}: 'Socket is not connected',
+ {{{ cDefine('ETOOMANYREFS') }}}: 'Too many references',
+ {{{ cDefine('EUSERS') }}}: 'Too many users',
+ {{{ cDefine('EDQUOT') }}}: 'Quota exceeded',
+ {{{ cDefine('ESTALE') }}}: 'Stale file handle',
+ {{{ cDefine('ENOTSUP') }}}: 'Not supported',
+ {{{ cDefine('ENOMEDIUM') }}}: 'No medium (in tape drive)',
+ {{{ cDefine('EILSEQ') }}}: 'Illegal byte sequence',
+ {{{ cDefine('EOVERFLOW') }}}: 'Value too large for defined data type',
+ {{{ cDefine('ECANCELED') }}}: 'Operation canceled',
+ {{{ cDefine('ENOTRECOVERABLE') }}}: 'State not recoverable',
+ {{{ cDefine('EOWNERDEAD') }}}: 'Previous owner died',
+ {{{ cDefine('ESTRPIPE') }}}: 'Streams pipe error',
},
__errno_state: 0,
__setErrNo__deps: ['__errno_state'],
@@ -8932,10 +7232,10 @@ LibraryManager.library = {
* Module['webrtc']['ondisconnect']: function(peer), invoked when an existing connection is closed
* Module['webrtc']['onerror']: function(error), invoked when an error occurs
*/
- socket__deps: ['$Sockets'],
+ socket__deps: ['$FS', '$Sockets'],
socket: function(family, type, protocol) {
var INCOMING_QUEUE_LENGTH = 64;
- var stream = FS.createStream({
+ var info = FS.createStream({
addr: null,
port: null,
inQueue: new CircularBuffer(INCOMING_QUEUE_LENGTH),
@@ -8944,7 +7244,7 @@ LibraryManager.library = {
socket: true,
stream_ops: {}
});
- assert(stream.fd < 64); // select() assumes socket fd values are in 0..63
+ assert(info.fd < 64); // select() assumes socket fd values are in 0..63
var stream = type == {{{ cDefine('SOCK_STREAM') }}};
if (protocol) {
assert(stream == (protocol == {{{ cDefine('IPPROTO_TCP') }}})); // if stream, must be tcp
@@ -9057,8 +7357,7 @@ LibraryManager.library = {
}
};
};
-
- return stream.fd;
+ return info.fd;
},
mkport__deps: ['$Sockets'],
@@ -9077,7 +7376,7 @@ LibraryManager.library = {
// Stub: connection-oriented sockets are not supported yet.
},
- bind__deps: ['$Sockets', '_inet_ntoa_raw', 'ntohs', 'mkport'],
+ bind__deps: ['$FS', '$Sockets', '_inet_ntoa_raw', 'ntohs', 'mkport'],
bind: function(fd, addr, addrlen) {
var info = FS.getStream(fd);
if (!info) return -1;
@@ -9098,7 +7397,7 @@ LibraryManager.library = {
info.bound = true;
},
- sendmsg__deps: ['$Sockets', 'bind', '_inet_ntoa_raw', 'ntohs'],
+ sendmsg__deps: ['$FS', '$Sockets', 'bind', '_inet_ntoa_raw', 'ntohs'],
sendmsg: function(fd, msg, flags) {
var info = FS.getStream(fd);
if (!info) return -1;
@@ -9152,9 +7451,10 @@ LibraryManager.library = {
buffer.set(data, info.header.byteLength);
connection.send('unreliable', buffer.buffer);
+ return ret;
},
- recvmsg__deps: ['$Sockets', 'bind', '__setErrNo', '$ERRNO_CODES', 'htons'],
+ recvmsg__deps: ['$FS', '$Sockets', 'bind', '__setErrNo', '$ERRNO_CODES', 'htons'],
recvmsg: function(fd, msg, flags) {
var info = FS.getStream(fd);
if (!info) return -1;
@@ -9206,6 +7506,7 @@ LibraryManager.library = {
return ret;
},
+ shutdown__deps: ['$FS'],
shutdown: function(fd, how) {
var stream = FS.getStream(fd);
if (!stream) return -1;
@@ -9213,6 +7514,7 @@ LibraryManager.library = {
FS.closeStream(stream);
},
+ ioctl__deps: ['$FS'],
ioctl: function(fd, request, varargs) {
var info = FS.getStream(fd);
if (!info) return -1;
@@ -9230,6 +7532,7 @@ LibraryManager.library = {
return 0;
},
+ accept__deps: ['$FS'],
accept: function(fd, addr, addrlen) {
// TODO: webrtc queued incoming connections, etc.
// For now, the model is that bind does a connect, and we "accept" that one connection,
@@ -9244,6 +7547,7 @@ LibraryManager.library = {
return fd;
},
+ select__deps: ['$FS'],
select: function(nfds, readfds, writefds, exceptfds, timeout) {
// readfds are supported,
// writefds checks socket open status
@@ -9298,7 +7602,7 @@ LibraryManager.library = {
}
},
#else
- socket__deps: ['$Sockets'],
+ socket__deps: ['$FS', '$Sockets'],
socket: function(family, type, protocol) {
var stream = type == {{{ cDefine('SOCK_STREAM') }}};
if (protocol) {
@@ -9429,17 +7733,30 @@ LibraryManager.library = {
return -1;
}
- return 0;
+ // always "fail" in non-blocking mode
+ ___setErrNo(ERRNO_CODES.EINPROGRESS);
+ return -1;
},
recv__deps: ['$FS'],
recv: function(fd, buf, len, flags) {
var info = FS.getStream(fd);
- if (!info) return -1;
- if (!info.hasData()) {
- ___setErrNo(ERRNO_CODES.EAGAIN); // no data, and all sockets are nonblocking, so this is the right behavior
+ if (!info) {
+ ___setErrNo(ERRNO_CODES.EBADF);
return -1;
}
+#if SOCKET_WEBRTC == 0
+ if (!info.hasData()) {
+ if (info.socket.readyState === WebSocket.CLOSING || info.socket.readyState === WebSocket.CLOSED) {
+ // socket has closed
+ return 0;
+ } else {
+ // else, our socket is in a valid state but truly has nothing available
+ ___setErrNo(ERRNO_CODES.EAGAIN);
+ return -1;
+ }
+ }
+#endif
var buffer = info.inQueue.shift();
#if SOCKET_DEBUG
Module.print('recv: ' + [Array.prototype.slice.call(buffer)]);
@@ -9461,7 +7778,19 @@ LibraryManager.library = {
send__deps: ['$FS'],
send: function(fd, buf, len, flags) {
var info = FS.getStream(fd);
- if (!info) return -1;
+ if (!info) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
+ }
+#if SOCKET_WEBRTC == 0
+ if (info.socket.readyState === WebSocket.CLOSING || info.socket.readyState === WebSocket.CLOSED) {
+ ___setErrNo(ERRNO_CODES.ENOTCONN);
+ return -1;
+ } else if (info.socket.readyState === WebSocket.CONNECTING) {
+ ___setErrNo(ERRNO_CODES.EAGAIN);
+ return -1;
+ }
+#endif
info.sender(HEAPU8.subarray(buf, buf+len));
return len;
},
@@ -9571,6 +7900,7 @@ LibraryManager.library = {
return _recv(fd, buf, len, flags);
},
+ shutdown__deps: ['$FS'],
shutdown: function(fd, how) {
var stream = FS.getStream(fd);
if (!stream) return -1;
@@ -9578,6 +7908,7 @@ LibraryManager.library = {
FS.closeStream(stream);
},
+ ioctl__deps: ['$FS'],
ioctl: function(fd, request, varargs) {
var info = FS.getStream(fd);
if (!info) return -1;
@@ -9597,7 +7928,8 @@ LibraryManager.library = {
bind__deps: ['connect'],
bind: function(fd, addr, addrlen) {
- return _connect(fd, addr, addrlen);
+ _connect(fd, addr, addrlen);
+ return 0;
},
listen: function(fd, backlog) {
@@ -9630,24 +7962,12 @@ LibraryManager.library = {
var errorCondition = 0;
function canRead(info) {
- // make sure hasData exists.
- // we do create it when the socket is connected,
- // but other implementations may create it lazily
- if ((info.socket.readyState == WebSocket.CLOSING || info.socket.readyState == WebSocket.CLOSED) && info.inQueue.length == 0) {
- errorCondition = -1;
- return false;
- }
- return info.hasData && info.hasData();
+ return (info.hasData && info.hasData()) ||
+ info.socket.readyState == WebSocket.CLOSING || // let recv return 0 once closed
+ info.socket.readyState == WebSocket.CLOSED;
}
function canWrite(info) {
- // make sure socket exists.
- // we do create it when the socket is connected,
- // but other implementations may create it lazily
- if ((info.socket.readyState == WebSocket.CLOSING || info.socket.readyState == WebSocket.CLOSED)) {
- errorCondition = -1;
- return false;
- }
return info.socket && (info.socket.readyState == info.socket.OPEN);
}
@@ -9666,7 +7986,11 @@ LibraryManager.library = {
if (int_ & mask) {
// index is in the set, check if it is ready for read
var info = FS.getStream(fd);
- if (info && can(info)) {
+ if (!info) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
+ }
+ if (can(info)) {
// set bit
fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
bitsSet++;
diff --git a/src/library_browser.js b/src/library_browser.js
index 2b69e5d9..558c9a59 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -3,8 +3,10 @@
// Utilities for browser environments
mergeInto(LibraryManager.library, {
+ $Browser__deps: ['$PATH'],
$Browser__postset: 'Module["requestFullScreen"] = function(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports
'Module["requestAnimationFrame"] = function(func) { Browser.requestAnimationFrame(func) };\n' +
+ 'Module["setCanvasSize"] = function(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' +
'Module["pauseMainLoop"] = function() { Browser.mainLoop.pause() };\n' +
'Module["resumeMainLoop"] = function() { Browser.mainLoop.resume() };\n' +
'Module["getUserMedia"] = function() { Browser.getUserMedia() }',
@@ -60,7 +62,11 @@ mergeInto(LibraryManager.library, {
console.log("warning: no blob constructor, cannot create blobs with mimetypes");
}
Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
- Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : console.log("warning: cannot create object URLs");
+ Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+ if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+ console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+ Module.noImageDecoding = true;
+ }
// Support for plugins that can process preloaded files. You can add more of these to
// your app by creating and appending to Module.preloadPlugins.
@@ -558,10 +564,9 @@ mergeInto(LibraryManager.library, {
emscripten_async_wget: function(url, file, onload, onerror) {
var _url = Pointer_stringify(url);
var _file = Pointer_stringify(file);
- var index = _file.lastIndexOf('/');
FS.createPreloadedFile(
- _file.substr(0, index),
- _file.substr(index +1),
+ PATH.dirname(_file),
+ PATH.basename(_file),
_url, true, true,
function() {
if (onload) Runtime.dynCall('vi', onload, [file]);
@@ -636,10 +641,9 @@ mergeInto(LibraryManager.library, {
var _file = Pointer_stringify(file);
var data = FS.analyzePath(_file);
if (!data.exists) return -1;
- var index = _file.lastIndexOf('/');
FS.createPreloadedFile(
- _file.substr(0, index),
- _file.substr(index +1),
+ PATH.dirname(_file),
+ PATH.basename(_file),
new Uint8Array(data.object.contents), true, true,
function() {
if (onload) Runtime.dynCall('vi', onload, [file]);
@@ -659,7 +663,7 @@ mergeInto(LibraryManager.library, {
var cname = _malloc(name.length+1);
writeStringToMemory(name, cname);
FS.createPreloadedFile(
- '',
+ '/',
name,
{{{ makeHEAPView('U8', 'data', 'data + size') }}},
true, true,
diff --git a/src/library_egl.js b/src/library_egl.js
index 0ccb13e6..ff912ed2 100644
--- a/src/library_egl.js
+++ b/src/library_egl.js
@@ -260,8 +260,13 @@ var LibraryEGL = {
}
EGL.windowID = _glutCreateWindow();
- EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
- return 62004; // Magic ID for Emscripten EGLContext
+ if (EGL.windowID != 0) {
+ EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
+ return 62004; // Magic ID for Emscripten EGLContext
+ } else {
+ EGL.setErrorCode(0x3009 /* EGL_BAD_MATCH */); // By the EGL 1.4 spec, an implementation that does not support GLES2 (WebGL in this case), this error code is set.
+ return 0; /* EGL_NO_CONTEXT */
+ }
},
eglDestroyContext__deps: ['glutDestroyWindow', '$GL'],
@@ -484,6 +489,11 @@ var LibraryEGL = {
eglSwapBuffers: function() {
EGL.setErrorCode(0x3000 /* EGL_SUCCESS */);
},
+
+ eglGetProcAddress__deps: ['emscripten_GetProcAddress'],
+ eglGetProcAddress: function(name_) {
+ return _emscripten_GetProcAddress(Pointer_stringify(name_));
+ },
};
autoAddDeps(LibraryEGL, '$EGL');
diff --git a/src/library_fs.js b/src/library_fs.js
new file mode 100644
index 00000000..9d1f0cfd
--- /dev/null
+++ b/src/library_fs.js
@@ -0,0 +1,1381 @@
+mergeInto(LibraryManager.library, {
+ $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', 'stdin', 'stdout', 'stderr', 'fflush'],
+ $FS__postset: 'FS.staticInit();' +
+ '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
+ '__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' +
+ '__ATEXIT__.push({ func: function() { FS.quit() } });' +
+ // export some names through closure
+ 'Module["FS_createFolder"] = FS.createFolder;' +
+ 'Module["FS_createPath"] = FS.createPath;' +
+ 'Module["FS_createDataFile"] = FS.createDataFile;' +
+ 'Module["FS_createPreloadedFile"] = FS.createPreloadedFile;' +
+ 'Module["FS_createLazyFile"] = FS.createLazyFile;' +
+ 'Module["FS_createLink"] = FS.createLink;' +
+ 'Module["FS_createDevice"] = FS.createDevice;',
+ $FS: {
+ root: null,
+ nodes: [null],
+ devices: [null],
+ streams: [null],
+ nextInode: 1,
+ name_table: null,
+ currentPath: '/',
+ initialized: false,
+ // Whether we are currently ignoring permissions. Useful when preparing the
+ // filesystem and creating files inside read-only folders.
+ // This is set to false when the runtime is initialized, allowing you
+ // to modify the filesystem freely before run() is called.
+ ignorePermissions: true,
+
+ ErrnoError: (function() {
+ function ErrnoError(errno) {
+ this.errno = errno;
+ for (var key in ERRNO_CODES) {
+ if (ERRNO_CODES[key] === errno) {
+ this.code = key;
+ break;
+ }
+ }
+ this.message = ERRNO_MESSAGES[errno];
+ };
+ ErrnoError.prototype = new Error();
+ ErrnoError.prototype.constructor = ErrnoError;
+ return ErrnoError;
+ }()),
+
+ handleFSError: function(e) {
+ if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + new Error().stack;
+ return ___setErrNo(e.errno);
+ },
+
+ //
+ // nodes
+ //
+ hashName: function(parentid, name) {
+ var hash = 0;
+ for (var i = 0; i < name.length; i++) {
+ hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+ }
+ return ((parentid + hash) >>> 0) % FS.name_table.length;
+ },
+ hashAddNode: function(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ node.name_next = FS.name_table[hash];
+ FS.name_table[hash] = node;
+ },
+ hashRemoveNode: function(node) {
+ var hash = FS.hashName(node.parent.id, node.name);
+ if (FS.name_table[hash] === node) {
+ FS.name_table[hash] = node.name_next;
+ } else {
+ var current = FS.name_table[hash];
+ while (current) {
+ if (current.name_next === node) {
+ current.name_next = node.name_next;
+ break;
+ }
+ current = current.name_next;
+ }
+ }
+ },
+ lookupNode: function(parent, name) {
+ var err = FS.mayLookup(parent);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ var hash = FS.hashName(parent.id, name);
+ for (var node = FS.name_table[hash]; node; node = node.name_next) {
+ if (node.parent.id === parent.id && node.name === name) {
+ return node;
+ }
+ }
+ // if we failed to find it in the cache, call into the VFS
+ return FS.lookup(parent, name);
+ },
+ createNode: function(parent, name, mode, rdev) {
+ var node = {
+ id: FS.nextInode++,
+ name: name,
+ mode: mode,
+ node_ops: {},
+ stream_ops: {},
+ rdev: rdev,
+ parent: null,
+ mount: null
+ };
+ if (!parent) {
+ parent = node; // root node sets parent to itself
+ }
+ node.parent = parent;
+ node.mount = parent.mount;
+ // compatibility
+ var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
+ var writeMode = {{{ cDefine('S_IWUGO') }}};
+ // NOTE we must use Object.defineProperties instead of individual calls to
+ // Object.defineProperty in order to make closure compiler happy
+ Object.defineProperties(node, {
+ read: {
+ get: function() { return (node.mode & readMode) === readMode; },
+ set: function(val) { val ? node.mode |= readMode : node.mode &= ~readMode; }
+ },
+ write: {
+ get: function() { return (node.mode & writeMode) === writeMode; },
+ set: function(val) { val ? node.mode |= writeMode : node.mode &= ~writeMode; }
+ },
+ isFolder: {
+ get: function() { return FS.isDir(node.mode); },
+ },
+ isDevice: {
+ get: function() { return FS.isChrdev(node.mode); },
+ },
+ });
+ FS.hashAddNode(node);
+ return node;
+ },
+ destroyNode: function(node) {
+ FS.hashRemoveNode(node);
+ },
+ isRoot: function(node) {
+ return node === node.parent;
+ },
+ isMountpoint: function(node) {
+ return node.mounted;
+ },
+ isFile: function(mode) {
+ return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFREG') }}};
+ },
+ isDir: function(mode) {
+ return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFDIR') }}};
+ },
+ isLink: function(mode) {
+ return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFLNK') }}};
+ },
+ isChrdev: function(mode) {
+ return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFCHR') }}};
+ },
+ isBlkdev: function(mode) {
+ return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFBLK') }}};
+ },
+ isFIFO: function(mode) {
+ return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFIFO') }}};
+ },
+
+ //
+ // paths
+ //
+ cwd: function() {
+ return FS.currentPath;
+ },
+ lookupPath: function(path, opts) {
+ path = PATH.resolve(FS.currentPath, path);
+ opts = opts || { recurse_count: 0 };
+
+ if (opts.recurse_count > 8) { // max recursive lookup of 8
+ throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+ }
+
+ // split the path
+ var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+ return !!p;
+ }), false);
+
+ // start at the root
+ var current = FS.root;
+ var current_path = '/';
+
+ for (var i = 0; i < parts.length; i++) {
+ var islast = (i === parts.length-1);
+ if (islast && opts.parent) {
+ // stop resolving
+ break;
+ }
+
+ current = FS.lookupNode(current, parts[i]);
+ current_path = PATH.join(current_path, parts[i]);
+
+ // jump to the mount's root node if this is a mountpoint
+ if (FS.isMountpoint(current)) {
+ current = current.mount.root;
+ }
+
+ // follow symlinks
+ // by default, lookupPath will not follow a symlink if it is the final path component.
+ // setting opts.follow = true will override this behavior.
+ if (!islast || opts.follow) {
+ var count = 0;
+ while (FS.isLink(current.mode)) {
+ var link = FS.readlink(current_path);
+ current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+ var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+ current = lookup.node;
+
+ if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+ throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+ }
+ }
+ }
+ }
+
+ return { path: current_path, node: current };
+ },
+ getPath: function(node) {
+ var path;
+ while (true) {
+ if (FS.isRoot(node)) {
+ return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint;
+ }
+ path = path ? PATH.join(node.name, path) : node.name;
+ node = node.parent;
+ }
+ },
+
+ //
+ // permissions
+ //
+ flagModes: {
+ '"r"': {{{ cDefine('O_RDONLY') }}},
+ '"rs"': {{{ cDefine('O_RDONLY') }}} | {{{ cDefine('O_SYNC') }}},
+ '"r+"': {{{ cDefine('O_RDWR') }}},
+ '"w"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}},
+ '"wx"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
+ '"xw"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
+ '"w+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}},
+ '"wx+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
+ '"xw+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
+ '"a"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}},
+ '"ax"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
+ '"xa"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
+ '"a+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}},
+ '"ax+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
+ '"xa+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}}
+ },
+ // convert the 'r', 'r+', etc. to it's corresponding set of O_* flags
+ modeStringToFlags: function(str) {
+ var flags = FS.flagModes[str];
+ if (typeof flags === 'undefined') {
+ throw new Error('Unknown file open mode: ' + str);
+ }
+ return flags;
+ },
+ // convert O_* bitmask to a string for nodePermissions
+ flagsToPermissionString: function(flag) {
+ var accmode = flag & {{{ cDefine('O_ACCMODE') }}};
+ var perms = ['r', 'w', 'rw'][accmode];
+ if ((flag & {{{ cDefine('O_TRUNC') }}})) {
+ perms += 'w';
+ }
+ return perms;
+ },
+ nodePermissions: function(node, perms) {
+ if (FS.ignorePermissions) {
+ return 0;
+ }
+ // return 0 if any user, group or owner bits are set.
+ if (perms.indexOf('r') !== -1 && !(node.mode & {{{ cDefine('S_IRUGO') }}})) {
+ return ERRNO_CODES.EACCES;
+ } else if (perms.indexOf('w') !== -1 && !(node.mode & {{{ cDefine('S_IWUGO') }}})) {
+ return ERRNO_CODES.EACCES;
+ } else if (perms.indexOf('x') !== -1 && !(node.mode & {{{ cDefine('S_IXUGO') }}})) {
+ return ERRNO_CODES.EACCES;
+ }
+ return 0;
+ },
+ mayLookup: function(dir) {
+ return FS.nodePermissions(dir, 'x');
+ },
+ mayMknod: function(mode) {
+ switch (mode & {{{ cDefine('S_IFMT') }}}) {
+ case {{{ cDefine('S_IFREG') }}}:
+ case {{{ cDefine('S_IFCHR') }}}:
+ case {{{ cDefine('S_IFBLK') }}}:
+ case {{{ cDefine('S_IFIFO') }}}:
+ case {{{ cDefine('S_IFSOCK') }}}:
+ return 0;
+ default:
+ return ERRNO_CODES.EINVAL;
+ }
+ },
+ mayCreate: function(dir, name) {
+ try {
+ var node = FS.lookupNode(dir, name);
+ return ERRNO_CODES.EEXIST;
+ } catch (e) {
+ }
+ return FS.nodePermissions(dir, 'wx');
+ },
+ mayDelete: function(dir, name, isdir) {
+ var node;
+ try {
+ node = FS.lookupNode(dir, name);
+ } catch (e) {
+ return e.errno;
+ }
+ var err = FS.nodePermissions(dir, 'wx');
+ if (err) {
+ return err;
+ }
+ if (isdir) {
+ if (!FS.isDir(node.mode)) {
+ return ERRNO_CODES.ENOTDIR;
+ }
+ if (FS.isRoot(node) || FS.getPath(node) === FS.currentPath) {
+ return ERRNO_CODES.EBUSY;
+ }
+ } else {
+ if (FS.isDir(node.mode)) {
+ return ERRNO_CODES.EISDIR;
+ }
+ }
+ return 0;
+ },
+ mayOpen: function(node, flags) {
+ if (!node) {
+ return ERRNO_CODES.ENOENT;
+ }
+ if (FS.isLink(node.mode)) {
+ return ERRNO_CODES.ELOOP;
+ } else if (FS.isDir(node.mode)) {
+ if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY')}}} || // opening for write
+ (flags & {{{ cDefine('O_TRUNC') }}})) {
+ return ERRNO_CODES.EISDIR;
+ }
+ }
+ return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+ },
+
+ //
+ // devices
+ //
+ // each character device consists of a device id + stream operations.
+ // when a character device node is created (e.g. /dev/stdin) it is
+ // assigned a device id that lets us map back to the actual device.
+ // by default, each character device stream (e.g. _stdin) uses chrdev_stream_ops.
+ // however, once opened, the stream's operations are overridden with
+ // the operations of the device its underlying node maps back to.
+ chrdev_stream_ops: {
+ open: function(stream) {
+ var device = FS.getDevice(stream.node.rdev);
+ // override node's stream ops with the device's
+ stream.stream_ops = device.stream_ops;
+ // forward the open call
+ if (stream.stream_ops.open) {
+ stream.stream_ops.open(stream);
+ }
+ },
+ llseek: function() {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ },
+ major: function(dev) {
+ return ((dev) >> 8);
+ },
+ minor: function(dev) {
+ return ((dev) & 0xff);
+ },
+ makedev: function(ma, mi) {
+ return ((ma) << 8 | (mi));
+ },
+ registerDevice: function(dev, ops) {
+ FS.devices[dev] = { stream_ops: ops };
+ },
+ getDevice: function(dev) {
+ return FS.devices[dev];
+ },
+
+ //
+ // streams
+ //
+ MAX_OPEN_FDS: 4096,
+ nextfd: function(fd_start, fd_end) {
+ fd_start = fd_start || 1;
+ fd_end = fd_end || FS.MAX_OPEN_FDS;
+ for (var fd = fd_start; fd <= fd_end; fd++) {
+ if (!FS.streams[fd]) {
+ return fd;
+ }
+ }
+ throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+ },
+ getStream: function(fd) {
+ return FS.streams[fd];
+ },
+ createStream: function(stream, fd_start, fd_end) {
+ var fd = FS.nextfd(fd_start, fd_end);
+ stream.fd = fd;
+ // compatibility
+ Object.defineProperties(stream, {
+ object: {
+ get: function() { return stream.node; },
+ set: function(val) { stream.node = val; }
+ },
+ isRead: {
+ get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
+ },
+ isWrite: {
+ get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
+ },
+ isAppend: {
+ get: function() { return (stream.flags & {{{ cDefine('O_APPEND') }}}); }
+ }
+ });
+ FS.streams[fd] = stream;
+ return stream;
+ },
+ closeStream: function(fd) {
+ FS.streams[fd] = null;
+ },
+
+ //
+ // compatibility
+ //
+ getMode: function(canRead, canWrite) {
+ var mode = 0;
+ if (canRead) mode |= {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
+ if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}};
+ return mode;
+ },
+ joinPath: function(parts, forceRelative) {
+ var path = PATH.join.apply(null, parts);
+ if (forceRelative && path[0] == '/') path = path.substr(1);
+ return path;
+ },
+ absolutePath: function(relative, base) {
+ return PATH.resolve(base, relative);
+ },
+ standardizePath: function(path) {
+ return PATH.normalize(path);
+ },
+ findObject: function(path, dontResolveLastLink) {
+ var ret = FS.analyzePath(path, dontResolveLastLink);
+ if (ret.exists) {
+ return ret.object;
+ } else {
+ ___setErrNo(ret.error);
+ return null;
+ }
+ },
+ analyzePath: function(path, dontResolveLastLink) {
+ // operate from within the context of the symlink's target
+ try {
+ var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+ path = lookup.path;
+ } catch (e) {
+ }
+ var ret = {
+ isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+ parentExists: false, parentPath: null, parentObject: null
+ };
+ try {
+ var lookup = FS.lookupPath(path, { parent: true });
+ ret.parentExists = true;
+ ret.parentPath = lookup.path;
+ ret.parentObject = lookup.node;
+ ret.name = PATH.basename(path);
+ lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+ ret.exists = true;
+ ret.path = lookup.path;
+ ret.object = lookup.node;
+ ret.name = lookup.node.name;
+ ret.isRoot = lookup.path === '/';
+ } catch (e) {
+ ret.error = e.errno;
+ };
+ return ret;
+ },
+ createFolder: function(parent, name, canRead, canWrite) {
+ var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var mode = FS.getMode(canRead, canWrite);
+ return FS.mkdir(path, mode);
+ },
+ createPath: function(parent, path, canRead, canWrite) {
+ parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+ var parts = path.split('/').reverse();
+ while (parts.length) {
+ var part = parts.pop();
+ if (!part) continue;
+ var current = PATH.join(parent, part);
+ try {
+ FS.mkdir(current, 0777);
+ } catch (e) {
+ // ignore EEXIST
+ }
+ parent = current;
+ }
+ return current;
+ },
+ createFile: function(parent, name, properties, canRead, canWrite) {
+ var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var mode = FS.getMode(canRead, canWrite);
+ return FS.create(path, mode);
+ },
+ createDataFile: function(parent, name, data, canRead, canWrite) {
+ var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var mode = FS.getMode(canRead, canWrite);
+ var node = FS.create(path, mode);
+ if (data) {
+ if (typeof data === 'string') {
+ var arr = new Array(data.length);
+ for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+ data = arr;
+ }
+ // make sure we can write to the file
+ FS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}});
+ var stream = FS.open(path, 'w');
+ FS.write(stream, data, 0, data.length, 0);
+ FS.close(stream);
+ FS.chmod(path, mode);
+ }
+ return node;
+ },
+ createDevice: function(parent, name, input, output) {
+ var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var mode = input && output ? 0777 : (input ? 0333 : 0555);
+ if (!FS.createDevice.major) FS.createDevice.major = 64;
+ var dev = FS.makedev(FS.createDevice.major++, 0);
+ // Create a fake device that a set of stream ops to emulate
+ // the old behavior.
+ FS.registerDevice(dev, {
+ open: function(stream) {
+ stream.seekable = false;
+ },
+ close: function(stream) {
+ // flush any pending line data
+ if (output && output.buffer && output.buffer.length) {
+ output({{{ charCode('\n') }}});
+ }
+ },
+ read: function(stream, buffer, offset, length, pos /* ignored */) {
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = input();
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset+i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write: function(stream, buffer, offset, length, pos) {
+ for (var i = 0; i < length; i++) {
+ try {
+ output(buffer[offset+i]);
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ });
+ return FS.mkdev(path, mode, dev);
+ },
+ createLink: function(parent, name, target, canRead, canWrite) {
+ var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ return FS.symlink(target, path);
+ },
+ // Makes sure a file's contents are loaded. Returns whether the file has
+ // been loaded successfully. No-op for files that have been loaded already.
+ forceLoadFile: function(obj) {
+ if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+ var success = true;
+ if (typeof XMLHttpRequest !== 'undefined') {
+ throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+ } else if (Module['read']) {
+ // Command-line.
+ try {
+ // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+ // read() will try to parse UTF8.
+ obj.contents = intArrayFromString(Module['read'](obj.url), true);
+ } catch (e) {
+ success = false;
+ }
+ } else {
+ throw new Error('Cannot load without read() or XMLHttpRequest.');
+ }
+ if (!success) ___setErrNo(ERRNO_CODES.EIO);
+ return success;
+ },
+ // Creates a file record for lazy-loading from a URL. XXX This requires a synchronous
+ // XHR, which is not possible in browsers except in a web worker! Use preloading,
+ // either --preload-file in emcc or FS.createPreloadedFile
+ createLazyFile: function(parent, name, url, canRead, canWrite) {
+ if (typeof XMLHttpRequest !== 'undefined') {
+ if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+ // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+ var LazyUint8Array = function() {
+ this.lengthKnown = false;
+ this.chunks = []; // Loaded chunks. Index is the chunk number
+ }
+ LazyUint8Array.prototype.get = function(idx) {
+ if (idx > this.length-1 || idx < 0) {
+ return undefined;
+ }
+ var chunkOffset = idx % this.chunkSize;
+ var chunkNum = Math.floor(idx / this.chunkSize);
+ return this.getter(chunkNum)[chunkOffset];
+ }
+ LazyUint8Array.prototype.setDataGetter = function(getter) {
+ this.getter = getter;
+ }
+ LazyUint8Array.prototype.cacheLength = function() {
+ // Find length
+ var xhr = new XMLHttpRequest();
+ xhr.open('HEAD', url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+#if SMALL_XHR_CHUNKS
+ var chunkSize = 1024; // Chunk size in bytes
+#else
+ var chunkSize = 1024*1024; // Chunk size in bytes
+#endif
+
+ if (!hasByteServing) chunkSize = datalength;
+
+ // Function to get a range from the remote URL.
+ var doXHR = (function(from, to) {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+ // Some hints to the browser that we want binary data.
+ if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+ if (xhr.overrideMimeType) {
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ if (xhr.response !== undefined) {
+ return new Uint8Array(xhr.response || []);
+ } else {
+ return intArrayFromString(xhr.responseText || '', true);
+ }
+ });
+ var lazyArray = this;
+ lazyArray.setDataGetter(function(chunkNum) {
+ var start = chunkNum * chunkSize;
+ var end = (chunkNum+1) * chunkSize - 1; // including this byte
+ end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+ if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+ lazyArray.chunks[chunkNum] = doXHR(start, end);
+ }
+ if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+ return lazyArray.chunks[chunkNum];
+ });
+
+ this._length = datalength;
+ this._chunkSize = chunkSize;
+ this.lengthKnown = true;
+ }
+
+ var lazyArray = new LazyUint8Array();
+ Object.defineProperty(lazyArray, "length", {
+ get: function() {
+ if(!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._length;
+ }
+ });
+ Object.defineProperty(lazyArray, "chunkSize", {
+ get: function() {
+ if(!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._chunkSize;
+ }
+ });
+
+ var properties = { isDevice: false, contents: lazyArray };
+ } else {
+ var properties = { isDevice: false, url: url };
+ }
+
+ var node = FS.createFile(parent, name, properties, canRead, canWrite);
+ // This is a total hack, but I want to get this lazy file code out of the
+ // core of MEMFS. If we want to keep this lazy file concept I feel it should
+ // be its own thin LAZYFS proxying calls to MEMFS.
+ if (properties.contents) {
+ node.contents = properties.contents;
+ } else if (properties.url) {
+ node.contents = null;
+ node.url = properties.url;
+ }
+ // override each stream op with one that tries to force load the lazy file first
+ var stream_ops = {};
+ var keys = Object.keys(node.stream_ops);
+ keys.forEach(function(key) {
+ var fn = node.stream_ops[key];
+ stream_ops[key] = function() {
+ if (!FS.forceLoadFile(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ return fn.apply(null, arguments);
+ };
+ });
+ // use a custom read function
+ stream_ops.read = function(stream, buffer, offset, length, position) {
+ if (!FS.forceLoadFile(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ var contents = stream.node.contents;
+ var size = Math.min(contents.length - position, length);
+ if (contents.slice) { // normal array
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ } else {
+ for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+ buffer[offset + i] = contents.get(position + i);
+ }
+ }
+ return size;
+ };
+ node.stream_ops = stream_ops;
+ return node;
+ },
+ // Preloads a file asynchronously. You can call this before run, for example in
+ // preRun. run will be delayed until this file arrives and is set up.
+ // If you call it after run(), you may want to pause the main loop until it
+ // completes, if so, you can use the onload parameter to be notified when
+ // that happens.
+ // In addition to normally creating the file, we also asynchronously preload
+ // the browser-friendly versions of it: For an image, we preload an Image
+ // element and for an audio, and Audio. These are necessary for SDL_Image
+ // and _Mixer to find the files in preloadedImages/Audios.
+ // You can also call this with a typed array instead of a url. It will then
+ // do preloading for the Image/Audio part, as if the typed array were the
+ // result of an XHR that you did manually.
+ createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) {
+ Browser.init();
+ // TODO we should allow people to just pass in a complete filename instead
+ // of parent and name being that we just join them anyways
+ var fullname = PATH.resolve(PATH.join(parent, name));
+ function processData(byteArray) {
+ function finish(byteArray) {
+ if (!dontCreateFile) {
+ FS.createDataFile(parent, name, byteArray, canRead, canWrite);
+ }
+ if (onload) onload();
+ removeRunDependency('cp ' + fullname);
+ }
+ var handled = false;
+ Module['preloadPlugins'].forEach(function(plugin) {
+ if (handled) return;
+ if (plugin['canHandle'](fullname)) {
+ plugin['handle'](byteArray, fullname, finish, function() {
+ if (onerror) onerror();
+ removeRunDependency('cp ' + fullname);
+ });
+ handled = true;
+ }
+ });
+ if (!handled) finish(byteArray);
+ }
+ addRunDependency('cp ' + fullname);
+ if (typeof url == 'string') {
+ Browser.asyncLoad(url, function(byteArray) {
+ processData(byteArray);
+ }, onerror);
+ } else {
+ processData(url);
+ }
+ },
+
+ //
+ // general
+ //
+ createDefaultDirectories: function() {
+ FS.mkdir('/tmp', 0777);
+ },
+ createDefaultDevices: function() {
+ // create /dev
+ FS.mkdir('/dev', 0777);
+ // setup /dev/null
+ FS.registerDevice(FS.makedev(1, 3), {
+ read: function() { return 0; },
+ write: function() { return 0; }
+ });
+ FS.mkdev('/dev/null', 0666, FS.makedev(1, 3));
+ // setup /dev/tty and /dev/tty1
+ // stderr needs to print output using Module['printErr']
+ // so we register a second tty just for it.
+ TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+ TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+ FS.mkdev('/dev/tty', 0666, FS.makedev(5, 0));
+ FS.mkdev('/dev/tty1', 0666, FS.makedev(6, 0));
+ // we're not going to emulate the actual shm device,
+ // just create the tmp dirs that reside in it commonly
+ FS.mkdir('/dev/shm', 0777);
+ FS.mkdir('/dev/shm/tmp', 0777);
+ },
+ createStandardStreams: function() {
+ // TODO deprecate the old functionality of a single
+ // input / output callback and that utilizes FS.createDevice
+ // and instead require a unique set of stream ops
+
+ // by default, we symlink the standard streams to the
+ // default tty devices. however, if the standard streams
+ // have been overwritten we create a unique device for
+ // them instead.
+ if (Module['stdin']) {
+ FS.createDevice('/dev', 'stdin', Module['stdin']);
+ } else {
+ FS.symlink('/dev/tty', '/dev/stdin');
+ }
+ if (Module['stdout']) {
+ FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+ } else {
+ FS.symlink('/dev/tty', '/dev/stdout');
+ }
+ if (Module['stderr']) {
+ FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+ } else {
+ FS.symlink('/dev/tty1', '/dev/stderr');
+ }
+
+ // open default streams for the stdin, stdout and stderr devices
+ var stdin = FS.open('/dev/stdin', 'r');
+ {{{ makeSetValue(makeGlobalUse('_stdin'), 0, 'stdin.fd', 'void*') }}};
+ assert(stdin.fd === 1, 'invalid handle for stdin (' + stdin.fd + ')');
+
+ var stdout = FS.open('/dev/stdout', 'w');
+ {{{ makeSetValue(makeGlobalUse('_stdout'), 0, 'stdout.fd', 'void*') }}};
+ assert(stdout.fd === 2, 'invalid handle for stdout (' + stdout.fd + ')');
+
+ var stderr = FS.open('/dev/stderr', 'w');
+ {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 'stderr.fd', 'void*') }}};
+ assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')');
+ },
+ staticInit: function() {
+ FS.name_table = new Array(4096);
+
+ FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ FS.mount(MEMFS, {}, '/');
+
+ FS.createDefaultDirectories();
+ FS.createDefaultDevices();
+ },
+ init: function(input, output, error) {
+ assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+ FS.init.initialized = true;
+
+ // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+ Module['stdin'] = input || Module['stdin'];
+ Module['stdout'] = output || Module['stdout'];
+ Module['stderr'] = error || Module['stderr'];
+
+ FS.createStandardStreams();
+ },
+ quit: function() {
+ FS.init.initialized = false;
+ for (var i = 0; i < FS.streams.length; i++) {
+ var stream = FS.streams[i];
+ if (!stream) {
+ continue;
+ }
+ FS.close(stream);
+ }
+ },
+
+ //
+ // vfs functionality
+ //
+ mount: function(type, opts, mountpoint) {
+ var mount = {
+ type: type,
+ opts: opts,
+ mountpoint: mountpoint,
+ root: null
+ };
+ var lookup;
+ if (mountpoint) {
+ lookup = FS.lookupPath(mountpoint, { follow: false });
+ }
+ // create a root node for the fs
+ var root = type.mount(mount);
+ root.mount = mount;
+ mount.root = root;
+ // assign the mount info to the mountpoint's node
+ if (lookup) {
+ lookup.node.mount = mount;
+ lookup.node.mounted = true;
+ // compatibility update FS.root if we mount to /
+ if (mountpoint === '/') {
+ FS.root = mount.root;
+ }
+ }
+ return root;
+ },
+ lookup: function(parent, name) {
+ return parent.node_ops.lookup(parent, name);
+ },
+ // generic function for all node creation
+ mknod: function(path, mode, dev) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var err = FS.mayCreate(parent, name);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.mknod) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ return parent.node_ops.mknod(parent, name, mode, dev);
+ },
+ // helpers to create specific types of nodes
+ create: function(path, mode) {
+ mode &= {{{ cDefine('S_IALLUGO') }}};
+ mode |= {{{ cDefine('S_IFREG') }}};
+ return FS.mknod(path, mode, 0);
+ },
+ mkdir: function(path, mode) {
+ mode &= {{{ cDefine('S_IRWXUGO') }}} | {{{ cDefine('S_ISVTX') }}};
+ mode |= {{{ cDefine('S_IFDIR') }}};
+ return FS.mknod(path, mode, 0);
+ },
+ mkdev: function(path, mode, dev) {
+ mode |= {{{ cDefine('S_IFCHR') }}};
+ return FS.mknod(path, mode, dev);
+ },
+ symlink: function(oldpath, newpath) {
+ var lookup = FS.lookupPath(newpath, { parent: true });
+ var parent = lookup.node;
+ var newname = PATH.basename(newpath);
+ var err = FS.mayCreate(parent, newname);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.symlink) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ return parent.node_ops.symlink(parent, newname, oldpath);
+ },
+ rename: function(old_path, new_path) {
+ var old_dirname = PATH.dirname(old_path);
+ var new_dirname = PATH.dirname(new_path);
+ var old_name = PATH.basename(old_path);
+ var new_name = PATH.basename(new_path);
+ // parents must exist
+ var lookup, old_dir, new_dir;
+ try {
+ lookup = FS.lookupPath(old_path, { parent: true });
+ old_dir = lookup.node;
+ lookup = FS.lookupPath(new_path, { parent: true });
+ new_dir = lookup.node;
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ // need to be part of the same mount
+ if (old_dir.mount !== new_dir.mount) {
+ throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+ }
+ // source must exist
+ var old_node = FS.lookupNode(old_dir, old_name);
+ // old path should not be an ancestor of the new path
+ var relative = PATH.relative(old_path, new_dirname);
+ if (relative.charAt(0) !== '.') {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ // new path should not be an ancestor of the old path
+ relative = PATH.relative(new_path, old_dirname);
+ if (relative.charAt(0) !== '.') {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+ }
+ // see if the new path already exists
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {
+ // not fatal
+ }
+ // early out if nothing needs to change
+ if (old_node === new_node) {
+ return;
+ }
+ // we'll need to delete the old entry
+ var isdir = FS.isDir(old_node.mode);
+ var err = FS.mayDelete(old_dir, old_name, isdir);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ // need delete permissions if we'll be overwriting.
+ // need create permissions if new doesn't already exist.
+ err = new_node ?
+ FS.mayDelete(new_dir, new_name, isdir) :
+ FS.mayCreate(new_dir, new_name);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!old_dir.node_ops.rename) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ // if we are going to change the parent, check write permissions
+ if (new_dir !== old_dir) {
+ err = FS.nodePermissions(old_dir, 'w');
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ }
+ // remove the node from the lookup hash
+ FS.hashRemoveNode(old_node);
+ // do the underlying fs rename
+ try {
+ old_dir.node_ops.rename(old_node, new_dir, new_name);
+ } catch (e) {
+ throw e;
+ } finally {
+ // add the node back to the hash (in case node_ops.rename
+ // changed its name)
+ FS.hashAddNode(old_node);
+ }
+ },
+ rmdir: function(path) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var err = FS.mayDelete(parent, name, true);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.rmdir) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ parent.node_ops.rmdir(parent, name);
+ FS.destroyNode(node);
+ },
+ readdir: function(path) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ var node = lookup.node;
+ if (!node.node_ops.readdir) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+ }
+ return node.node_ops.readdir(node);
+ },
+ unlink: function(path) {
+ var lookup = FS.lookupPath(path, { parent: true });
+ var parent = lookup.node;
+ var name = PATH.basename(path);
+ var node = FS.lookupNode(parent, name);
+ var err = FS.mayDelete(parent, name, false);
+ if (err) {
+ // POSIX says unlink should set EPERM, not EISDIR
+ if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+ throw new FS.ErrnoError(err);
+ }
+ if (!parent.node_ops.unlink) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isMountpoint(node)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+ }
+ parent.node_ops.unlink(parent, name);
+ FS.destroyNode(node);
+ },
+ readlink: function(path) {
+ var lookup = FS.lookupPath(path, { follow: false });
+ var link = lookup.node;
+ if (!link.node_ops.readlink) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ return link.node_ops.readlink(link);
+ },
+ stat: function(path, dontFollow) {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ var node = lookup.node;
+ if (!node.node_ops.getattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ return node.node_ops.getattr(node);
+ },
+ lstat: function(path) {
+ return FS.stat(path, true);
+ },
+ chmod: function(path, mode, dontFollow) {
+ var node;
+ if (typeof path === 'string') {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ node.node_ops.setattr(node, {
+ mode: (mode & {{{ cDefine('S_IALLUGO') }}}) | (node.mode & ~{{{ cDefine('S_IALLUGO') }}}),
+ timestamp: Date.now()
+ });
+ },
+ lchmod: function(path, mode) {
+ FS.chmod(path, mode, true);
+ },
+ fchmod: function(fd, mode) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ FS.chmod(stream.node, mode);
+ },
+ chown: function(path, uid, gid, dontFollow) {
+ var node;
+ if (typeof path === 'string') {
+ var lookup = FS.lookupPath(path, { follow: !dontFollow });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ node.node_ops.setattr(node, {
+ timestamp: Date.now()
+ // we ignore the uid / gid for now
+ });
+ },
+ lchown: function(path, uid, gid) {
+ FS.chown(path, uid, gid, true);
+ },
+ fchown: function(fd, uid, gid) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ FS.chown(stream.node, uid, gid);
+ },
+ truncate: function(path, len) {
+ if (len < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var node;
+ if (typeof path === 'string') {
+ var lookup = FS.lookupPath(path, { follow: true });
+ node = lookup.node;
+ } else {
+ node = path;
+ }
+ if (!node.node_ops.setattr) {
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ if (FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+ }
+ if (!FS.isFile(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var err = FS.nodePermissions(node, 'w');
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ node.node_ops.setattr(node, {
+ size: len,
+ timestamp: Date.now()
+ });
+ },
+ ftruncate: function(fd, len) {
+ var stream = FS.getStream(fd);
+ if (!stream) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ FS.truncate(stream.node, len);
+ },
+ utime: function(path, atime, mtime) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ var node = lookup.node;
+ node.node_ops.setattr(node, {
+ timestamp: Math.max(atime, mtime)
+ });
+ },
+ open: function(path, flags, mode, fd_start, fd_end) {
+ path = PATH.normalize(path);
+ flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+ mode = typeof mode === 'undefined' ? 0666 : mode;
+ if ((flags & {{{ cDefine('O_CREAT') }}})) {
+ mode = (mode & {{{ cDefine('S_IALLUGO') }}}) | {{{ cDefine('S_IFREG') }}};
+ } else {
+ mode = 0;
+ }
+ var node;
+ try {
+ var lookup = FS.lookupPath(path, {
+ follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
+ });
+ node = lookup.node;
+ path = lookup.path;
+ } catch (e) {
+ // ignore
+ }
+ // perhaps we need to create the node
+ if ((flags & {{{ cDefine('O_CREAT') }}})) {
+ if (node) {
+ // if O_CREAT and O_EXCL are set, error out if the node already exists
+ if ((flags & {{{ cDefine('O_EXCL') }}})) {
+ throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+ }
+ } else {
+ // node doesn't exist, try to create it
+ node = FS.mknod(path, mode, 0);
+ }
+ }
+ if (!node) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+ }
+ // can't truncate a device
+ if (FS.isChrdev(node.mode)) {
+ flags &= ~{{{ cDefine('O_TRUNC') }}};
+ }
+ // check permissions
+ var err = FS.mayOpen(node, flags);
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ // do truncation if necessary
+ if ((flags & {{{ cDefine('O_TRUNC')}}})) {
+ FS.truncate(node, 0);
+ }
+ // register the stream with the filesystem
+ var stream = FS.createStream({
+ path: path,
+ node: node,
+ flags: flags,
+ seekable: true,
+ position: 0,
+ stream_ops: node.stream_ops,
+ // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+ ungotten: [],
+ error: false
+ }, fd_start, fd_end);
+ // call the new stream's open function
+ if (stream.stream_ops.open) {
+ stream.stream_ops.open(stream);
+ }
+ return stream;
+ },
+ close: function(stream) {
+ try {
+ if (stream.stream_ops.close) {
+ stream.stream_ops.close(stream);
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ FS.closeStream(stream.fd);
+ }
+ },
+ llseek: function(stream, offset, whence) {
+ if (!stream.seekable || !stream.stream_ops.llseek) {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ return stream.stream_ops.llseek(stream, offset, whence);
+ },
+ read: function(stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+ }
+ if (!stream.stream_ops.read) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var seeking = true;
+ if (typeof position === 'undefined') {
+ position = stream.position;
+ seeking = false;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesRead;
+ return bytesRead;
+ },
+ write: function(stream, buffer, offset, length, position) {
+ if (length < 0 || position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if (FS.isDir(stream.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+ }
+ if (!stream.stream_ops.write) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var seeking = true;
+ if (typeof position === 'undefined') {
+ position = stream.position;
+ seeking = false;
+ } else if (!stream.seekable) {
+ throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+ }
+ if (stream.flags & {{{ cDefine('O_APPEND') }}}) {
+ // seek to the end before writing in append mode
+ FS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}});
+ }
+ var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position);
+ if (!seeking) stream.position += bytesWritten;
+ return bytesWritten;
+ },
+ allocate: function(stream, offset, length) {
+ if (offset < 0 || length <= 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+ }
+ if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+ }
+ if (!stream.stream_ops.allocate) {
+ throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+ }
+ stream.stream_ops.allocate(stream, offset, length);
+ },
+ mmap: function(stream, buffer, offset, length, position, prot, flags) {
+ // TODO if PROT is PROT_WRITE, make sure we have write access
+ if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) {
+ throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+ }
+ if (!stream.stream_ops.mmap) {
+ throw new FS.errnoError(ERRNO_CODES.ENODEV);
+ }
+ return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+ }
+ }
+});
+
diff --git a/src/library_gl.js b/src/library_gl.js
index 8c724245..c134ad97 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -1285,10 +1285,11 @@ var LibraryGL = {
return Module.ctx.isFramebuffer(fb);
},
-#if DISABLE_GL_EMULATION == 0
+#if LEGACY_GL_EMULATION
// GL emulation: provides misc. functionality not present in OpenGL ES 2.0 or WebGL
+ $GLEmulation__deps: ['$GLImmediateSetup', 'glEnable', 'glDisable', 'glIsEnabled', 'glGetBooleanv', 'glGetIntegerv', 'glGetString', 'glCreateShader', 'glShaderSource', 'glCompileShader', 'glAttachShader', 'glDetachShader', 'glUseProgram', 'glDeleteProgram', 'glBindAttribLocation', 'glLinkProgram', 'glBindBuffer', 'glGetFloatv', 'glHint', 'glEnableVertexAttribArray', 'glDisableVertexAttribArray', 'glVertexAttribPointer', 'glActiveTexture'],
$GLEmulation__postset: 'GLEmulation.init();',
$GLEmulation: {
// Fog support. Partial, we assume shaders are used that implement fog. We just pass them uniforms
@@ -1323,7 +1324,7 @@ var LibraryGL = {
GLEmulation.fogColor = new Float32Array(4);
// Add some emulation workarounds
- Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work. (If you do not want this, build with -s DISABLE_GL_EMULATION=1)');
+ Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work.');
#if GL_UNSAFE_OPTS == 0
Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0');
#endif
@@ -1618,17 +1619,15 @@ var LibraryGL = {
var glCompileShader = _glCompileShader;
_glCompileShader = function(shader) {
Module.ctx.compileShader(GL.shaders[shader]);
+#if GL_DEBUG
if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) {
Module.printErr('Failed to compile shader: ' + Module.ctx.getShaderInfoLog(GL.shaders[shader]));
Module.printErr('Info: ' + JSON.stringify(GL.shaderInfos[shader]));
-#if GL_DEBUG
Module.printErr('Original source: ' + GL.shaderOriginalSources[shader]);
Module.printErr('Source: ' + GL.shaderSources[shader]);
throw 'Shader compilation halt';
-#else
- Module.printErr('Enable GL_DEBUG to see shader source');
-#endif
}
+#endif
};
GL.programShaders = {};
@@ -1775,170 +1774,6 @@ var LibraryGL = {
}
return attrib;
},
-
- getProcAddress: function(name) {
- name = name.replace('EXT', '').replace('ARB', '');
- // Do the translation carefully because of closure
- var ret = 0;
- switch (name) {
- case 'glCreateShaderObject': case 'glCreateShader': ret = {{{ Functions.getIndex('_glCreateShader', true) }}}; break;
- case 'glCreateProgramObject': case 'glCreateProgram': ret = {{{ Functions.getIndex('_glCreateProgram', true) }}}; break;
- case 'glAttachObject': case 'glAttachShader': ret = {{{ Functions.getIndex('_glAttachShader', true) }}}; break;
- case 'glUseProgramObject': case 'glUseProgram': ret = {{{ Functions.getIndex('_glUseProgram', true) }}}; break;
- case 'glDetachObject': case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break;
- case 'glDeleteObject': ret = {{{ Functions.getIndex('_glDeleteObject', true) }}}; break;
- case 'glGetObjectParameteriv': ret = {{{ Functions.getIndex('_glGetObjectParameteriv', true) }}}; break;
- case 'glGetInfoLog': ret = {{{ Functions.getIndex('_glGetInfoLog', true) }}}; break;
- case 'glBindProgram': ret = {{{ Functions.getIndex('_glBindProgram', true) }}}; break;
- case 'glDrawRangeElements': ret = {{{ Functions.getIndex('_glDrawRangeElements', true) }}}; break;
- case 'glShaderSource': ret = {{{ Functions.getIndex('_glShaderSource', true) }}}; break;
- case 'glCompileShader': ret = {{{ Functions.getIndex('_glCompileShader', true) }}}; break;
- case 'glLinkProgram': ret = {{{ Functions.getIndex('_glLinkProgram', true) }}}; break;
- case 'glGetUniformLocation': ret = {{{ Functions.getIndex('_glGetUniformLocation', true) }}}; break;
- case 'glUniform1f': ret = {{{ Functions.getIndex('_glUniform1f', true) }}}; break;
- case 'glUniform2f': ret = {{{ Functions.getIndex('_glUniform2f', true) }}}; break;
- case 'glUniform3f': ret = {{{ Functions.getIndex('_glUniform3f', true) }}}; break;
- case 'glUniform4f': ret = {{{ Functions.getIndex('_glUniform4f', true) }}}; break;
- case 'glUniform1fv': ret = {{{ Functions.getIndex('_glUniform1fv', true) }}}; break;
- case 'glUniform2fv': ret = {{{ Functions.getIndex('_glUniform2fv', true) }}}; break;
- case 'glUniform3fv': ret = {{{ Functions.getIndex('_glUniform3fv', true) }}}; break;
- case 'glUniform4fv': ret = {{{ Functions.getIndex('_glUniform4fv', true) }}}; break;
- case 'glUniform1i': ret = {{{ Functions.getIndex('_glUniform1i', true) }}}; break;
- case 'glUniform2i': ret = {{{ Functions.getIndex('_glUniform2i', true) }}}; break;
- case 'glUniform3i': ret = {{{ Functions.getIndex('_glUniform3i', true) }}}; break;
- case 'glUniform4i': ret = {{{ Functions.getIndex('_glUniform4i', true) }}}; break;
- case 'glUniform1iv': ret = {{{ Functions.getIndex('_glUniform1iv', true) }}}; break;
- case 'glUniform2iv': ret = {{{ Functions.getIndex('_glUniform2iv', true) }}}; break;
- case 'glUniform3iv': ret = {{{ Functions.getIndex('_glUniform3iv', true) }}}; break;
- case 'glUniform4iv': ret = {{{ Functions.getIndex('_glUniform4iv', true) }}}; break;
- case 'glBindAttribLocation': ret = {{{ Functions.getIndex('_glBindAttribLocation', true) }}}; break;
- case 'glGetActiveUniform': ret = {{{ Functions.getIndex('_glGetActiveUniform', true) }}}; break;
- case 'glGenBuffers': ret = {{{ Functions.getIndex('_glGenBuffers', true) }}}; break;
- case 'glBindBuffer': ret = {{{ Functions.getIndex('_glBindBuffer', true) }}}; break;
- case 'glBufferData': ret = {{{ Functions.getIndex('_glBufferData', true) }}}; break;
- case 'glBufferSubData': ret = {{{ Functions.getIndex('_glBufferSubData', true) }}}; break;
- case 'glDeleteBuffers': ret = {{{ Functions.getIndex('_glDeleteBuffers', true) }}}; break;
- case 'glActiveTexture': ret = {{{ Functions.getIndex('_glActiveTexture', true) }}}; break;
- case 'glClientActiveTexture': ret = {{{ Functions.getIndex('_glClientActiveTexture', true) }}}; break;
- case 'glGetProgramiv': ret = {{{ Functions.getIndex('_glGetProgramiv', true) }}}; break;
- case 'glEnableVertexAttribArray': ret = {{{ Functions.getIndex('_glEnableVertexAttribArray', true) }}}; break;
- case 'glDisableVertexAttribArray': ret = {{{ Functions.getIndex('_glDisableVertexAttribArray', true) }}}; break;
- case 'glVertexAttribPointer': ret = {{{ Functions.getIndex('_glVertexAttribPointer', true) }}}; break;
- case 'glVertexAttrib1f': ret = {{{ Functions.getIndex('_glVertexAttrib1f', true) }}}; break;
- case 'glVertexAttrib2f': ret = {{{ Functions.getIndex('_glVertexAttrib2f', true) }}}; break;
- case 'glVertexAttrib3f': ret = {{{ Functions.getIndex('_glVertexAttrib3f', true) }}}; break;
- case 'glVertexAttrib4f': ret = {{{ Functions.getIndex('_glVertexAttrib4f', true) }}}; break;
- case 'glVertexAttrib1fv': ret = {{{ Functions.getIndex('_glVertexAttrib1fv', true) }}}; break;
- case 'glVertexAttrib2fv': ret = {{{ Functions.getIndex('_glVertexAttrib2fv', true) }}}; break;
- case 'glVertexAttrib3fv': ret = {{{ Functions.getIndex('_glVertexAttrib3fv', true) }}}; break;
- case 'glVertexAttrib4fv': ret = {{{ Functions.getIndex('_glVertexAttrib4fv', true) }}}; break;
- case 'glGetVertexAttribfv': ret = {{{ Functions.getIndex('_glGetVertexAttribfv', true) }}}; break;
- case 'glGetVertexAttribiv': ret = {{{ Functions.getIndex('_glGetVertexAttribiv', true) }}}; break;
- case 'glGetVertexAttribPointerv': ret = {{{ Functions.getIndex('_glGetVertexAttribPointerv', true) }}}; break;
- case 'glGetAttribLocation': ret = {{{ Functions.getIndex('_glGetAttribLocation', true) }}}; break;
- case 'glGetActiveAttrib': ret = {{{ Functions.getIndex('_glGetActiveAttrib', true) }}}; break;
- case 'glBindRenderbuffer': ret = {{{ Functions.getIndex('_glBindRenderbuffer', true) }}}; break;
- case 'glDeleteRenderbuffers': ret = {{{ Functions.getIndex('_glDeleteRenderbuffers', true) }}}; break;
- case 'glGenRenderbuffers': ret = {{{ Functions.getIndex('_glGenRenderbuffers', true) }}}; break;
- case 'glCompressedTexImage2D': ret = {{{ Functions.getIndex('_glCompressedTexImage2D', true) }}}; break;
- case 'glCompressedTexSubImage2D': ret = {{{ Functions.getIndex('_glCompressedTexSubImage2D', true) }}}; break;
- case 'glBindFramebuffer': ret = {{{ Functions.getIndex('_glBindFramebuffer', true) }}}; break;
- case 'glGenFramebuffers': ret = {{{ Functions.getIndex('_glGenFramebuffers', true) }}}; break;
- case 'glDeleteFramebuffers': ret = {{{ Functions.getIndex('_glDeleteFramebuffers', true) }}}; break;
- case 'glFramebufferRenderbuffer': ret = {{{ Functions.getIndex('_glFramebufferRenderbuffer', true) }}}; break;
- case 'glFramebufferTexture2D': ret = {{{ Functions.getIndex('_glFramebufferTexture2D', true) }}}; break;
- case 'glGetFramebufferAttachmentParameteriv': ret = {{{ Functions.getIndex('_glGetFramebufferAttachmentParameteriv', true) }}}; break;
- case 'glIsFramebuffer': ret = {{{ Functions.getIndex('_glIsFramebuffer', true) }}}; break;
- case 'glCheckFramebufferStatus': ret = {{{ Functions.getIndex('_glCheckFramebufferStatus', true) }}}; break;
- case 'glRenderbufferStorage': ret = {{{ Functions.getIndex('_glRenderbufferStorage', true) }}}; break;
- case 'glGenVertexArrays': ret = {{{ Functions.getIndex('_glGenVertexArrays', true) }}}; break;
- case 'glDeleteVertexArrays': ret = {{{ Functions.getIndex('_glDeleteVertexArrays', true) }}}; break;
- case 'glBindVertexArray': ret = {{{ Functions.getIndex('_glBindVertexArray', true) }}}; break;
- case 'glGetString': ret = {{{ Functions.getIndex('_glGetString', true) }}}; break;
- case 'glBindTexture': ret = {{{ Functions.getIndex('_glBindTexture', true) }}}; break;
- case 'glGetBufferParameteriv': ret = {{{ Functions.getIndex('_glGetBufferParameteriv', true) }}}; break;
- case 'glIsBuffer': ret = {{{ Functions.getIndex('_glIsBuffer', true) }}}; break;
- case 'glDeleteShader': ret = {{{ Functions.getIndex('_glDeleteShader', true) }}}; break;
- case 'glUniformMatrix2fv': ret = {{{ Functions.getIndex('_glUniformMatrix2fv', true) }}}; break;
- case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break;
- case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break;
- case 'glIsRenderbuffer': ret = {{{ Functions.getIndex('_glIsRenderbuffer', true) }}}; break;
- case 'glBlendEquation': ret = {{{ Functions.getIndex('_glBlendEquation', true) }}}; break;
- case 'glBlendFunc': ret = {{{ Functions.getIndex('_glBlendFunc', true) }}}; break;
- case 'glBlendFuncSeparate': ret = {{{ Functions.getIndex('_glBlendFuncSeparate', true) }}}; break;
- case 'glBlendEquationSeparate': ret = {{{ Functions.getIndex('_glBlendEquationSeparate', true) }}}; break;
- case 'glDepthRangef': ret = {{{ Functions.getIndex('_glDepthRangef', true) }}}; break;
- case 'glClear': ret = {{{ Functions.getIndex('_glClear', true) }}}; break;
- case 'glGenerateMipmap': ret = {{{ Functions.getIndex('_glGenerateMipmap', true) }}}; break;
- case 'glBlendColor': ret = {{{ Functions.getIndex('_glBlendColor', true) }}}; break;
- case 'glClearDepthf': ret = {{{ Functions.getIndex('_glClearDepthf', true) }}}; break;
- case 'glDeleteProgram': ret = {{{ Functions.getIndex('_glDeleteProgram', true) }}}; break;
- case 'glUniformMatrix3fv': ret = {{{ Functions.getIndex('_glUniformMatrix3fv', true) }}}; break;
- case 'glClearColor': ret = {{{ Functions.getIndex('_glClearColor', true) }}}; break;
- case 'glGetRenderbufferParameteriv': ret = {{{ Functions.getIndex('_glGetRenderbufferParameteriv', true) }}}; break;
- case 'glGetShaderInfoLog': ret = {{{ Functions.getIndex('_glGetShaderInfoLog', true) }}}; break;
- case 'glUniformMatrix4fv': ret = {{{ Functions.getIndex('_glUniformMatrix4fv', true) }}}; break;
- case 'glClearStencil': ret = {{{ Functions.getIndex('_glClearStencil', true) }}}; break;
- case 'glGetProgramInfoLog': ret = {{{ Functions.getIndex('_glGetProgramInfoLog', true) }}}; break;
- case 'glGetUniformfv': ret = {{{ Functions.getIndex('_glGetUniformfv', true) }}}; break;
- case 'glStencilFuncSeparate': ret = {{{ Functions.getIndex('_glStencilFuncSeparate', true) }}}; break;
- case 'glSampleCoverage': ret = {{{ Functions.getIndex('_glSampleCoverage', true) }}}; break;
- case 'glColorMask': ret = {{{ Functions.getIndex('_glColorMask', true) }}}; break;
- case 'glGetShaderiv': ret = {{{ Functions.getIndex('_glGetShaderiv', true) }}}; break;
- case 'glGetUniformiv': ret = {{{ Functions.getIndex('_glGetUniformiv', true) }}}; break;
- case 'glCopyTexSubImage2D': ret = {{{ Functions.getIndex('_glCopyTexSubImage2D', true) }}}; break;
- case 'glDetachShader': ret = {{{ Functions.getIndex('_glDetachShader', true) }}}; break;
- case 'glGetShaderSource': ret = {{{ Functions.getIndex('_glGetShaderSource', true) }}}; break;
- case 'glDeleteTextures': ret = {{{ Functions.getIndex('_glDeleteTextures', true) }}}; break;
- case 'glGetAttachedShaders': ret = {{{ Functions.getIndex('_glGetAttachedShaders', true) }}}; break;
- case 'glValidateProgram': ret = {{{ Functions.getIndex('_glValidateProgram', true) }}}; break;
- case 'glDepthFunc': ret = {{{ Functions.getIndex('_glDepthFunc', true) }}}; break;
- case 'glIsShader': ret = {{{ Functions.getIndex('_glIsShader', true) }}}; break;
- case 'glDepthMask': ret = {{{ Functions.getIndex('_glDepthMask', true) }}}; break;
- case 'glStencilMaskSeparate': ret = {{{ Functions.getIndex('_glStencilMaskSeparate', true) }}}; break;
- case 'glIsProgram': ret = {{{ Functions.getIndex('_glIsProgram', true) }}}; break;
- case 'glDisable': ret = {{{ Functions.getIndex('_glDisable', true) }}}; break;
- case 'glStencilOpSeparate': ret = {{{ Functions.getIndex('_glStencilOpSeparate', true) }}}; break;
- case 'glDrawArrays': ret = {{{ Functions.getIndex('_glDrawArrays', true) }}}; break;
- case 'glDrawElements': ret = {{{ Functions.getIndex('_glDrawElements', true) }}}; break;
- case 'glEnable': ret = {{{ Functions.getIndex('_glEnable', true) }}}; break;
- case 'glFinish': ret = {{{ Functions.getIndex('_glFinish', true) }}}; break;
- case 'glFlush': ret = {{{ Functions.getIndex('_glFlush', true) }}}; break;
- case 'glFrontFace': ret = {{{ Functions.getIndex('_glFrontFace', true) }}}; break;
- case 'glCullFace': ret = {{{ Functions.getIndex('_glCullFace', true) }}}; break;
- case 'glGenTextures': ret = {{{ Functions.getIndex('_glGenTextures', true) }}}; break;
- case 'glGetError': ret = {{{ Functions.getIndex('_glGetError', true) }}}; break;
- case 'glGetIntegerv': ret = {{{ Functions.getIndex('_glGetIntegerv', true) }}}; break;
- case 'glGetBooleanv': ret = {{{ Functions.getIndex('_glGetBooleanv', true) }}}; break;
- case 'glGetFloatv': ret = {{{ Functions.getIndex('_glGetFloatv', true) }}}; break;
- case 'glHint': ret = {{{ Functions.getIndex('_glHint', true) }}}; break;
- case 'glIsTexture': ret = {{{ Functions.getIndex('_glIsTexture', true) }}}; break;
- case 'glPixelStorei': ret = {{{ Functions.getIndex('_glPixelStorei', true) }}}; break;
- case 'glReadPixels': ret = {{{ Functions.getIndex('_glReadPixels', true) }}}; break;
- case 'glScissor': ret = {{{ Functions.getIndex('_glScissor', true) }}}; break;
- case 'glStencilFunc': ret = {{{ Functions.getIndex('_glStencilFunc', true) }}}; break;
- case 'glStencilMask': ret = {{{ Functions.getIndex('_glStencilMask', true) }}}; break;
- case 'glStencilOp': ret = {{{ Functions.getIndex('_glStencilOp', true) }}}; break;
- case 'glTexImage2D': ret = {{{ Functions.getIndex('_glTexImage2D', true) }}}; break;
- case 'glTexParameterf': ret = {{{ Functions.getIndex('_glTexParameterf', true) }}}; break;
- case 'glTexParameterfv': ret = {{{ Functions.getIndex('_glTexParameterfv', true) }}}; break;
- case 'glTexParameteri': ret = {{{ Functions.getIndex('_glTexParameteri', true) }}}; break;
- case 'glTexParameteriv': ret = {{{ Functions.getIndex('_glTexParameteriv', true) }}}; break;
- case 'glGetTexParameterfv': ret = {{{ Functions.getIndex('_glGetTexParameterfv', true) }}}; break;
- case 'glGetTexParameteriv': ret = {{{ Functions.getIndex('_glGetTexParameteriv', true) }}}; break;
- case 'glTexSubImage2D': ret = {{{ Functions.getIndex('_glTexSubImage2D', true) }}}; break;
- case 'glCopyTexImage2D': ret = {{{ Functions.getIndex('_glCopyTexImage2D', true) }}}; break;
- case 'glViewport': ret = {{{ Functions.getIndex('_glViewport', true) }}}; break;
- case 'glIsEnabled': ret = {{{ Functions.getIndex('_glIsEnabled', true) }}}; break;
- case 'glLineWidth': ret = {{{ Functions.getIndex('_glLineWidth', true) }}}; break;
- case 'glPolygonOffset': ret = {{{ Functions.getIndex('_glPolygonOffset', true) }}}; break;
- case 'glReleaseShaderCompiler': ret = {{{ Functions.getIndex('_glReleaseShaderCompiler', true) }}}; break;
- case 'glGetShaderPrecisionFormat': ret = {{{ Functions.getIndex('_glGetShaderPrecisionFormat', true) }}}; break;
- case 'glShaderBinary': ret = {{{ Functions.getIndex('_glShaderBinary', true) }}}; break;
- }
- if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name);
- return ret;
- }
},
glGetShaderPrecisionFormat__sig: 'v',
@@ -4202,7 +4037,43 @@ var LibraryGL = {
glBindVertexArrayOES: 'glBindVertexArray',
glFramebufferTexture2DOES: 'glFramebufferTexture2D',
-#endif // DISABLE_GL_EMULATION == 0
+#else // LEGACY_GL_EMULATION
+
+ // Warn if code tries to use various emulation stuff, when emulation is disabled
+ // (do not warn if INCLUDE_FULL_LIBRARY is one, because then likely the gl code will
+ // not be called anyhow, leave only the runtime aborts)
+ glVertexPointer__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glVertexPointer: function(){ throw 'Legacy GL function (glVertexPointer) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glGenVertexArrays__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glGenVertexArrays: function(){ throw 'Legacy GL function (glGenVertexArrays) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glMatrixMode__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glMatrixMode: function(){ throw 'Legacy GL function (glMatrixMode) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glBegin__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glBegin: function(){ throw 'Legacy GL function (glBegin) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+ glLoadIdentity__deps: [function() {
+#if INCLUDE_FULL_LIBRARY == 0
+ warn('Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.');
+#endif
+ }],
+ glLoadIdentity: function(){ throw 'Legacy GL function (glLoadIdentity) called. You need to compile with -s LEGACY_GL_EMULATION=1 to enable legacy GL emulation.'; },
+
+#endif // LEGACY_GL_EMULATION
// GLU
@@ -4438,28 +4309,60 @@ var LibraryGL = {
autoAddDeps(LibraryGL, '$GL');
-if (!DISABLE_GL_EMULATION) {
- // Emulation requires everything else, potentially
- LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.slice(0); // the __deps object is shared
- var glFuncs = [];
- for (var item in LibraryGL) {
- if (item != '$GLEmulation' && item.substr(-6) != '__deps' && item.substr(-9) != '__postset' && item.substr(-5) != '__sig' && item.substr(0, 2) == 'gl') {
- glFuncs.push(item);
+// Legacy GL emulation
+if (LEGACY_GL_EMULATION) {
+ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('$GLEmulation');
+}
+
+// GL proc address retrieval
+LibraryGL.emscripten_GetProcAddress__deps = [function() {
+ // ProcAddress is used, so include everything in GL. This runs before we go to the $ProcAddressTable object,
+ // and we fill its deps just in time, and create the lookup table
+ var table = {};
+ LibraryManager.library.emscripten_procAddressTable__deps = keys(LibraryGL).map(function(x) {
+ if (x.substr(-6) == '__deps' || x.substr(-9) == '__postset' || x.substr(-5) == '__sig' || x.substr(-5) == '__asm' || x.substr(0, 2) != 'gl') return null;
+ var original = x;
+ if (('_' + x) in Functions.implementedFunctions) {
+ // a user-implemented function aliases this one, but we still want it to be accessible by name, so rename it
+ var y = x + '__procTable';
+ LibraryManager.library[y] = LibraryManager.library[x];
+ LibraryManager.library[y + '__deps'] = LibraryManager.library[x + '__deps'];
+ LibraryManager.library[y + '__postset'] = LibraryManager.library[x + '__postset'];
+ LibraryManager.library[y + '__sig'] = LibraryManager.library[x + '__sig'];//|| Functions.implementedFunctions['_' + x];
+ LibraryManager.library[y + '__asm'] = LibraryManager.library[x + '__asm'];
+ x = y;
+ assert(!(y in Functions.implementedFunctions) && !Functions.unimplementedFunctions['_' + y]);
}
- }
- LibraryGL.$GLEmulation__deps = LibraryGL.$GLEmulation__deps.concat(glFuncs);
- LibraryGL.$GLEmulation__deps.push(function() {
- for (var func in Functions.getIndex.tentative) {
- Functions.getIndex(func);
- Functions.unimplementedFunctions[func] = LibraryGL[func.substr(1) + '__sig'];
+ var longX = '_' + x;
+ var sig = LibraryManager.library[x + '__sig'] || functionStubSigs[longX];
+ if (sig) {
+ table[original] = Functions.getIndex(longX, sig);
+ if (!(longX in Functions.implementedFunctions)) Functions.unimplementedFunctions[longX] = sig;
}
- });
-
- if (FORCE_GL_EMULATION) {
- LibraryGL.glDrawElements__deps = LibraryGL.glDrawElements__deps.concat('$GLEmulation');
- LibraryGL.glDrawArrays__deps = LibraryGL.glDrawArrays__deps.concat('$GLEmulation');
+ return x;
+ }).filter(function(x) { return x !== null });
+ // convert table into function with switch, to not confuse closure compiler
+ var tableImpl = 'switch(name) {\n';
+ for (var x in table) tableImpl += 'case "' + x + '": return ' + table[x] + '; break;\n';
+ tableImpl += '}\nreturn 0;';
+ LibraryManager.library.emscripten_procAddressTable = new Function('name', tableImpl);
+}, 'emscripten_procAddressTable'];
+LibraryGL.emscripten_GetProcAddress = function(name) {
+ name = name.replace('EXT', '').replace('ARB', '');
+ switch(name) { // misc renamings
+ case 'glCreateProgramObject': name = 'glCreateProgram'; break;
+ case 'glUseProgramObject': name = 'glUseProgram'; break;
+ case 'glCreateShaderObject': name = 'glCreateShader'; break;
+ case 'glAttachObject': name = 'glAttachShader'; break;
+ case 'glDetachObject': name = 'glDetachShader'; break;
}
+ var ret = _emscripten_procAddressTable(name);
+ if (!ret) Module.printErr('WARNING: getProcAddress failed for ' + name);
+ return ret;
}
+// Final merge
mergeInto(LibraryManager.library, LibraryGL);
+assert(!(FULL_ES2 && LEGACY_GL_EMULATION), 'cannot emulate both ES2 and legacy GL');
+
diff --git a/src/library_glut.js b/src/library_glut.js
index 24474df0..60dc6540 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -399,7 +399,7 @@ var LibraryGLUT = {
glutCreateWindow__deps: ['$Browser'],
glutCreateWindow: function(name) {
Module.ctx = Browser.createContext(Module['canvas'], true, true);
- return 1;
+ return Module.ctx ? 1 /* a new GLUT window ID for the created context */ : 0 /* failure */;
},
glutDestroyWindow__deps: ['$Browser'],
diff --git a/src/library_memfs.js b/src/library_memfs.js
new file mode 100644
index 00000000..0fa6cdfb
--- /dev/null
+++ b/src/library_memfs.js
@@ -0,0 +1,243 @@
+mergeInto(LibraryManager.library, {
+ $MEMFS__deps: ['$FS'],
+ $MEMFS: {
+ mount: function(mount) {
+ return MEMFS.create_node(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ },
+ create_node: function(parent, name, mode, dev) {
+ if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+ // no supported
+ throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+ }
+ var node = FS.createNode(parent, name, mode, dev);
+ if (FS.isDir(node.mode)) {
+ node.node_ops = {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ lookup: MEMFS.node_ops.lookup,
+ mknod: MEMFS.node_ops.mknod,
+ mknod: MEMFS.node_ops.mknod,
+ rename: MEMFS.node_ops.rename,
+ unlink: MEMFS.node_ops.unlink,
+ rmdir: MEMFS.node_ops.rmdir,
+ readdir: MEMFS.node_ops.readdir,
+ symlink: MEMFS.node_ops.symlink
+ };
+ node.stream_ops = {
+ llseek: MEMFS.stream_ops.llseek
+ };
+ node.contents = {};
+ } else if (FS.isFile(node.mode)) {
+ node.node_ops = {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ };
+ node.stream_ops = {
+ llseek: MEMFS.stream_ops.llseek,
+ read: MEMFS.stream_ops.read,
+ write: MEMFS.stream_ops.write,
+ allocate: MEMFS.stream_ops.allocate,
+ mmap: MEMFS.stream_ops.mmap
+ };
+ node.contents = [];
+ } else if (FS.isLink(node.mode)) {
+ node.node_ops = {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr,
+ readlink: MEMFS.node_ops.readlink
+ };
+ node.stream_ops = {};
+ } else if (FS.isChrdev(node.mode)) {
+ node.node_ops = {
+ getattr: MEMFS.node_ops.getattr,
+ setattr: MEMFS.node_ops.setattr
+ };
+ node.stream_ops = FS.chrdev_stream_ops;
+ }
+ node.timestamp = Date.now();
+ // add the new node to the parent
+ if (parent) {
+ parent.contents[name] = node;
+ }
+ return node;
+ },
+ node_ops: {
+ getattr: function(node) {
+ var attr = {};
+ // device numbers reuse inode numbers.
+ attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+ attr.ino = node.id;
+ attr.mode = node.mode;
+ attr.nlink = 1;
+ attr.uid = 0;
+ attr.gid = 0;
+ attr.rdev = node.rdev;
+ if (FS.isDir(node.mode)) {
+ attr.size = 4096;
+ } else if (FS.isFile(node.mode)) {
+ attr.size = node.contents.length;
+ } else if (FS.isLink(node.mode)) {
+ attr.size = node.link.length;
+ } else {
+ attr.size = 0;
+ }
+ attr.atime = new Date(node.timestamp);
+ attr.mtime = new Date(node.timestamp);
+ attr.ctime = new Date(node.timestamp);
+ // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+ // but this is not required by the standard.
+ attr.blksize = 4096;
+ attr.blocks = Math.ceil(attr.size / attr.blksize);
+ return attr;
+ },
+ setattr: function(node, attr) {
+ if (attr.mode !== undefined) {
+ node.mode = attr.mode;
+ }
+ if (attr.timestamp !== undefined) {
+ node.timestamp = attr.timestamp;
+ }
+ if (attr.size !== undefined) {
+ var contents = node.contents;
+ if (attr.size < contents.length) contents.length = attr.size;
+ else while (attr.size > contents.length) contents.push(0);
+ }
+ },
+ lookup: function(parent, name) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+ },
+ mknod: function(parent, name, mode, dev) {
+ return MEMFS.create_node(parent, name, mode, dev);
+ },
+ rename: function(old_node, new_dir, new_name) {
+ // if we're overwriting a directory at new_name, make sure it's empty.
+ if (FS.isDir(old_node.mode)) {
+ var new_node;
+ try {
+ new_node = FS.lookupNode(new_dir, new_name);
+ } catch (e) {
+ }
+ if (new_node) {
+ for (var i in new_node.contents) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+ }
+ }
+ }
+ // do the internal rewiring
+ delete old_node.parent.contents[old_node.name];
+ old_node.name = new_name;
+ new_dir.contents[new_name] = old_node;
+ },
+ unlink: function(parent, name) {
+ delete parent.contents[name];
+ },
+ rmdir: function(parent, name) {
+ var node = FS.lookupNode(parent, name);
+ for (var i in node.contents) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+ }
+ delete parent.contents[name];
+ },
+ readdir: function(node) {
+ var entries = ['.', '..']
+ for (var key in node.contents) {
+ if (!node.contents.hasOwnProperty(key)) {
+ continue;
+ }
+ entries.push(key);
+ }
+ return entries;
+ },
+ symlink: function(parent, newname, oldpath) {
+ var node = MEMFS.create_node(parent, newname, 0777 | {{{ cDefine('S_IFLNK') }}}, 0);
+ node.link = oldpath;
+ return node;
+ },
+ readlink: function(node) {
+ if (!FS.isLink(node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ return node.link;
+ },
+ },
+ stream_ops: {
+ read: function(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ var size = Math.min(contents.length - position, length);
+#if USE_TYPED_ARRAYS == 2
+ if (contents.subarray) { // typed array
+ buffer.set(contents.subarray(position, position + size), offset);
+ } else
+#endif
+ {
+ for (var i = 0; i < size; i++) {
+ buffer[offset + i] = contents[position + i];
+ }
+ }
+ return size;
+ },
+ write: function(stream, buffer, offset, length, position) {
+ var contents = stream.node.contents;
+ while (contents.length < position) contents.push(0);
+ for (var i = 0; i < length; i++) {
+ contents[position + i] = buffer[offset + i];
+ }
+ stream.node.timestamp = Date.now();
+ return length;
+ },
+ llseek: function(stream, offset, whence) {
+ var position = offset;
+ if (whence === 1) { // SEEK_CUR.
+ position += stream.position;
+ } else if (whence === 2) { // SEEK_END.
+ if (FS.isFile(stream.node.mode)) {
+ position += stream.node.contents.length;
+ }
+ }
+ if (position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ stream.ungotten = [];
+ stream.position = position;
+ return position;
+ },
+ allocate: function(stream, offset, length) {
+ var contents = stream.node.contents;
+ var limit = offset + length;
+ while (limit > contents.length) contents.push(0);
+ },
+ mmap: function(stream, buffer, offset, length, position, prot, flags) {
+ if (!FS.isFile(stream.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+ }
+ var ptr;
+ var allocated;
+ var contents = stream.node.contents;
+ // Only make a new copy when MAP_PRIVATE is specified.
+ if (!(flags & {{{ cDefine('MAP_PRIVATE') }}})) {
+ // We can't emulate MAP_SHARED when the file is not backed by the buffer
+ // we're mapping to (e.g. the HEAP buffer).
+ assert(contents.buffer === buffer || contents.buffer === buffer.buffer);
+ allocated = false;
+ ptr = contents.byteOffset;
+ } else {
+ // Try to avoid unnecessary slices.
+ if (position > 0 || position + length < contents.length) {
+ if (contents.subarray) {
+ contents = contents.subarray(position, position + length);
+ } else {
+ contents = Array.prototype.slice.call(contents, position, position + length);
+ }
+ }
+ allocated = true;
+ ptr = _malloc(length);
+ if (!ptr) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+ }
+ buffer.set(contents, ptr);
+ }
+ return { ptr: ptr, allocated: allocated };
+ },
+ }
+ }
+}); \ No newline at end of file
diff --git a/src/library_openal.js b/src/library_openal.js
index c55415b8..cbb5c0bb 100644
--- a/src/library_openal.js
+++ b/src/library_openal.js
@@ -6,7 +6,128 @@ var LibraryOpenAL = {
contexts: [],
currentContext: null,
QUEUE_INTERVAL: 25,
- QUEUE_LOOKAHEAD: 100
+ QUEUE_LOOKAHEAD: 100,
+
+ updateSources: function(context) {
+ for (var i = 0; i < context.src.length; i++) {
+ AL.updateSource(context.src[i]);
+ }
+ },
+
+ updateSource: function(src) {
+#if OPENAL_DEBUG
+ var idx = AL.currentContext.src.indexOf(src);
+#endif
+ if (src.state !== 0x1012 /* AL_PLAYING */) {
+ return;
+ }
+
+ var currentTime = AL.currentContext.ctx.currentTime;
+ var startTime = src.bufferPosition;
+
+ for (var i = src.buffersPlayed; i < src.queue.length; i++) {
+ var entry = src.queue[i];
+
+ var startOffset = startTime - currentTime;
+ var endTime = startTime + entry.buffer.duration;
+
+ // Clean up old buffers.
+ if (currentTime >= endTime) {
+ // Update our location in the queue.
+ src.bufferPosition = endTime;
+ src.buffersPlayed = i + 1;
+
+ // Stop / restart the source when we hit the end.
+ if (src.buffersPlayed >= src.queue.length) {
+ if (src.loop) {
+ AL.setSourceState(src, 0x1012 /* AL_PLAYING */);
+ } else {
+ AL.setSourceState(src, 0x1014 /* AL_STOPPED */);
+ }
+ }
+ }
+ // Process all buffers that'll be played before the next tick.
+ else if (startOffset < (AL.QUEUE_LOOKAHEAD / 1000) && !entry.src) {
+ // If the start offset is negative, we need to offset the actual buffer.
+ var offset = Math.abs(Math.min(startOffset, 0));
+
+ entry.src = AL.currentContext.ctx.createBufferSource();
+ entry.src.buffer = entry.buffer;
+ entry.src.connect(src.gain);
+ entry.src.start(startTime, offset);
+
+#if OPENAL_DEBUG
+ console.log('updateSource queuing buffer ' + i + ' for source ' + idx + ' at ' + startTime + ' (offset by ' + offset + ')');
+#endif
+ }
+
+ startTime = endTime;
+ }
+ },
+
+ setSourceState: function(src, state) {
+#if OPENAL_DEBUG
+ var idx = AL.currentContext.src.indexOf(src);
+#endif
+ if (state === 0x1012 /* AL_PLAYING */) {
+ if (src.state !== 0x1013 /* AL_PAUSED */) {
+ src.state = 0x1012 /* AL_PLAYING */;
+ // Reset our position.
+ src.bufferPosition = AL.currentContext.ctx.currentTime;
+ src.buffersPlayed = 0;
+#if OPENAL_DEBUG
+ console.log('setSourceState resetting and playing source ' + idx);
+#endif
+ } else {
+ src.state = 0x1012 /* AL_PLAYING */;
+ // Use the current offset from src.bufferPosition to resume at the correct point.
+ src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
+#if OPENAL_DEBUG
+ console.log('setSourceState resuming source ' + idx + ' at ' + src.bufferPosition.toFixed(4));
+#endif
+ }
+ AL.stopSourceQueue(src);
+ AL.updateSource(src);
+ } else if (state === 0x1013 /* AL_PAUSED */) {
+ if (src.state === 0x1012 /* AL_PLAYING */) {
+ src.state = 0x1013 /* AL_PAUSED */;
+ // Store off the current offset to restore with on resume.
+ src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
+ AL.stopSourceQueue(src);
+#if OPENAL_DEBUG
+ console.log('setSourceState pausing source ' + idx + ' at ' + src.bufferPosition.toFixed(4));
+#endif
+ }
+ } else if (state === 0x1014 /* AL_STOPPED */) {
+ if (src.state !== 0x1011 /* AL_INITIAL */) {
+ src.state = 0x1014 /* AL_STOPPED */;
+ src.buffersPlayed = src.queue.length;
+ AL.stopSourceQueue(src);
+#if OPENAL_DEBUG
+ console.log('setSourceState stopping source ' + idx);
+#endif
+ }
+ } else if (state == 0x1011 /* AL_INITIAL */) {
+ if (src.state !== 0x1011 /* AL_INITIAL */) {
+ src.state = 0x1011 /* AL_INITIAL */;
+ src.bufferPosition = 0;
+ src.buffersPlayed = 0;
+#if OPENAL_DEBUG
+ console.log('setSourceState initializing source ' + idx);
+#endif
+ }
+ }
+ },
+
+ stopSourceQueue: function(src) {
+ for (var i = 0; i < src.queue.length; i++) {
+ var entry = src.queue[i];
+ if (entry.src) {
+ entry.src.stop(0);
+ entry.src = null;
+ }
+ }
+ }
},
alcProcessContext: function(context) {},
@@ -41,7 +162,7 @@ var LibraryOpenAL = {
alcDestroyContext: function(context) {
// Stop playback, etc
- clearInterval(context.interval);
+ clearInterval(AL.contexts[context - 1].interval);
},
alcCloseDevice: function(device) {
@@ -85,7 +206,7 @@ var LibraryOpenAL = {
err: 0,
src: [],
buf: [],
- interval: setInterval(function() { _updateSources(context); }, AL.QUEUE_INTERVAL)
+ interval: setInterval(function() { AL.updateSources(context); }, AL.QUEUE_INTERVAL)
};
AL.contexts.push(context);
return AL.contexts.length;
@@ -94,130 +215,6 @@ var LibraryOpenAL = {
}
},
- updateSources__deps: ['updateSource'],
- updateSources: function(context) {
- for (var i = 0; i < context.src.length; i++) {
- _updateSource(context.src[i]);
- }
- },
-
- updateSource__deps: ['setSourceState'],
- updateSource: function(src) {
-#if OPENAL_DEBUG
- var idx = AL.currentContext.src.indexOf(src);
-#endif
- if (src.state !== 0x1012 /* AL_PLAYING */) {
- return;
- }
-
- var currentTime = AL.currentContext.ctx.currentTime;
- var startTime = src.bufferPosition;
-
- for (var i = src.buffersPlayed; i < src.queue.length; i++) {
- var entry = src.queue[i];
-
- var startOffset = startTime - currentTime;
- var endTime = startTime + entry.buffer.duration;
-
- // Clean up old buffers.
- if (currentTime >= endTime) {
- // Update our location in the queue.
- src.bufferPosition = endTime;
- src.buffersPlayed = i + 1;
-
- // Stop / restart the source when we hit the end.
- if (src.buffersPlayed >= src.queue.length) {
- if (src.loop) {
- _setSourceState(src, 0x1012 /* AL_PLAYING */);
- } else {
- _setSourceState(src, 0x1014 /* AL_STOPPED */);
- }
- }
- }
- // Process all buffers that'll be played before the next tick.
- else if (startOffset < (AL.QUEUE_LOOKAHEAD / 1000) && !entry.src) {
- // If the start offset is negative, we need to offset the actual buffer.
- var offset = Math.abs(Math.min(startOffset, 0));
-
- entry.src = AL.currentContext.ctx.createBufferSource();
- entry.src.buffer = entry.buffer;
- entry.src.connect(src.gain);
- entry.src.start(startTime, offset);
-
-#if OPENAL_DEBUG
- console.log('updateSource queuing buffer ' + i + ' for source ' + idx + ' at ' + startTime + ' (offset by ' + offset + ')');
-#endif
- }
-
- startTime = endTime;
- }
- },
-
- setSourceState__deps: ['updateSource', 'stopSourceQueue'],
- setSourceState: function(src, state) {
-#if OPENAL_DEBUG
- var idx = AL.currentContext.src.indexOf(src);
-#endif
- if (state === 0x1012 /* AL_PLAYING */) {
- if (src.state !== 0x1013 /* AL_PAUSED */) {
- src.state = 0x1012 /* AL_PLAYING */;
- // Reset our position.
- src.bufferPosition = AL.currentContext.ctx.currentTime;
- src.buffersPlayed = 0;
-#if OPENAL_DEBUG
- console.log('setSourceState resetting and playing source ' + idx);
-#endif
- } else {
- src.state = 0x1012 /* AL_PLAYING */;
- // Use the current offset from src.bufferPosition to resume at the correct point.
- src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
-#if OPENAL_DEBUG
- console.log('setSourceState resuming source ' + idx + ' at ' + src.bufferPosition.toFixed(4));
-#endif
- }
- _stopSourceQueue(src);
- _updateSource(src);
- } else if (state === 0x1013 /* AL_PAUSED */) {
- if (src.state === 0x1012 /* AL_PLAYING */) {
- src.state = 0x1013 /* AL_PAUSED */;
- // Store off the current offset to restore with on resume.
- src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
- _stopSourceQueue(src);
-#if OPENAL_DEBUG
- console.log('setSourceState pausing source ' + idx + ' at ' + src.bufferPosition.toFixed(4));
-#endif
- }
- } else if (state === 0x1014 /* AL_STOPPED */) {
- if (src.state !== 0x1011 /* AL_INITIAL */) {
- src.state = 0x1014 /* AL_STOPPED */;
- src.buffersPlayed = src.queue.length;
- _stopSourceQueue(src);
-#if OPENAL_DEBUG
- console.log('setSourceState stopping source ' + idx);
-#endif
- }
- } else if (state == 0x1011 /* AL_INITIAL */) {
- if (src.state !== 0x1011 /* AL_INITIAL */) {
- src.state = 0x1011 /* AL_INITIAL */;
- src.bufferPosition = 0;
- src.buffersPlayed = 0;
-#if OPENAL_DEBUG
- console.log('setSourceState initializing source ' + idx);
-#endif
- }
- }
- },
-
- stopSourceQueue: function(src) {
- for (var i = 0; i < src.queue.length; i++) {
- var entry = src.queue[i];
- if (entry.src) {
- entry.src.stop(0);
- entry.src = null;
- }
- }
- },
-
alGetError: function() {
if (!AL.currentContext) {
return 0xA004 /* AL_INVALID_OPERATION */;
@@ -336,7 +333,7 @@ var LibraryOpenAL = {
} else {
src.queue = [{ buffer: buffer }];
}
- _updateSource(src);
+ AL.updateSource(src);
break;
case 0x202 /* AL_SOURCE_RELATIVE */:
if (value === 1 /* AL_TRUE */) {
@@ -505,7 +502,7 @@ var LibraryOpenAL = {
src.queue.push({ buffer: buffer, src: null });
}
- _updateSource(src);
+ AL.updateSource(src);
},
alSourceUnqueueBuffers__deps: ["updateSource"],
@@ -544,7 +541,7 @@ var LibraryOpenAL = {
src.buffersPlayed--;
}
- _updateSource(src);
+ AL.updateSource(src);
},
alDeleteBuffers: function(count, buffers)
@@ -687,7 +684,7 @@ var LibraryOpenAL = {
AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- _setSourceState(src, 0x1012 /* AL_PLAYING */);
+ AL.setSourceState(src, 0x1012 /* AL_PLAYING */);
},
alSourceStop__deps: ['setSourceState'],
@@ -707,7 +704,7 @@ var LibraryOpenAL = {
AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- _setSourceState(src, 0x1014 /* AL_STOPPED */);
+ AL.setSourceState(src, 0x1014 /* AL_STOPPED */);
},
alSourcePause__deps: ['setSourceState'],
@@ -727,7 +724,7 @@ var LibraryOpenAL = {
AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- _setSourceState(src, 0x1013 /* AL_PAUSED */);
+ AL.setSourceState(src, 0x1013 /* AL_PAUSED */);
},
alGetSourcei__deps: ['updateSource'],
@@ -754,7 +751,7 @@ var LibraryOpenAL = {
// so we also forcefully update the source when alGetSourcei is queried
// to aid in the common scenario of application calling alGetSourcei(AL_BUFFERS_PROCESSED)
// to recycle buffers.
- _updateSource(src);
+ AL.updateSource(src);
switch (param) {
case 0x202 /* AL_SOURCE_RELATIVE */:
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 19152646..5b2f8379 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -10,7 +10,7 @@
// or otherwise).
var LibrarySDL = {
- $SDL__deps: ['$FS', '$Browser'],
+ $SDL__deps: ['$FS', '$PATH', '$Browser'],
$SDL: {
defaults: {
width: 320,
@@ -258,7 +258,7 @@ var LibrarySDL = {
makeSurface: function(width, height, flags, usePageCanvas, source, rmask, gmask, bmask, amask) {
flags = flags || 0;
- var surf = _malloc(14*Runtime.QUANTUM_SIZE); // SDL_Surface has 14 fields of quantum size
+ var surf = _malloc(15*Runtime.QUANTUM_SIZE); // SDL_Surface has 15 fields of quantum size
var buffer = _malloc(width*height*4); // TODO: only allocate when locked the first time
var pixelFormat = _malloc(18*Runtime.QUANTUM_SIZE);
flags |= 1; // SDL_HWSURFACE - this tells SDL_MUSTLOCK that this needs to be locked
@@ -379,7 +379,8 @@ var LibrarySDL = {
SDL.surfaces[surf] = null;
},
- touchX:0, touchY: 0,
+ touchX: 0, touchY: 0,
+ savedKeydown: null,
receiveEvent: function(event) {
switch(event.type) {
@@ -466,11 +467,29 @@ var LibrarySDL = {
SDL.DOMButtons[event.button] = 0;
}
- if (event.type == 'keypress' && !SDL.textInput) {
- break;
+ // SDL expects a unicode character to be passed to its keydown events.
+ // Unfortunately, the browser APIs only provide a charCode property on
+ // keypress events, so we must backfill in keydown events with their
+ // subsequent keypress event's charCode.
+ if (event.type === 'keypress' && SDL.savedKeydown) {
+ // charCode is read-only
+ SDL.savedKeydown.keypressCharCode = event.charCode;
+ SDL.savedKeydown = null;
+ } else if (event.type === 'keydown') {
+ SDL.savedKeydown = event;
+ }
+
+ // If we preventDefault on keydown events, the subsequent keypress events
+ // won't fire. However, it's fine (and in some cases necessary) to
+ // preventDefault for keys that don't generate a character.
+ if (event.type !== 'keydown' || (event.keyCode === 8 /* backspace */ || event.keyCode === 9 /* tab */)) {
+ event.preventDefault();
+ }
+
+ // Don't push keypress events unless SDL_StartTextInput has been called.
+ if (event.type !== 'keypress' || SDL.textInput) {
+ SDL.events.push(event);
}
-
- SDL.events.push(event);
break;
case 'mouseout':
// Un-press all pressed mouse buttons, because we might miss the release outside of the canvas
@@ -485,6 +504,7 @@ var LibrarySDL = {
SDL.DOMButtons[i] = 0;
}
}
+ event.preventDefault();
break;
case 'blur':
case 'visibilitychange': {
@@ -495,6 +515,7 @@ var LibrarySDL = {
keyCode: SDL.keyboardMap[code]
});
}
+ event.preventDefault();
break;
}
case 'unload':
@@ -506,19 +527,59 @@ var LibrarySDL = {
return;
case 'resize':
SDL.events.push(event);
+ // manually triggered resize event doesn't have a preventDefault member
+ if (event.preventDefault) {
+ event.preventDefault();
+ }
break;
}
if (SDL.events.length >= 10000) {
Module.printErr('SDL event queue full, dropping events');
SDL.events = SDL.events.slice(0, 10000);
}
- // manually triggered resize event doesn't have a preventDefault member
- if (event.preventDefault) {
- event.preventDefault();
- }
return;
},
+ handleEvent: function(event) {
+ if (event.handled) return;
+ event.handled = true;
+
+ switch (event.type) {
+ case 'keydown': case 'keyup': {
+ var down = event.type === 'keydown';
+ var code = SDL.keyCodes[event.keyCode] || event.keyCode;
+
+ {{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}};
+ // TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED
+ SDL.modState = ({{{ makeGetValue('SDL.keyboardState', '1248', 'i8') }}} ? 0x0040 | 0x0080 : 0) | // KMOD_LCTRL & KMOD_RCTRL
+ ({{{ makeGetValue('SDL.keyboardState', '1249', 'i8') }}} ? 0x0001 | 0x0002 : 0) | // KMOD_LSHIFT & KMOD_RSHIFT
+ ({{{ makeGetValue('SDL.keyboardState', '1250', 'i8') }}} ? 0x0100 | 0x0200 : 0); // KMOD_LALT & KMOD_RALT
+
+ if (down) {
+ SDL.keyboardMap[code] = event.keyCode; // save the DOM input, which we can use to unpress it during blur
+ } else {
+ delete SDL.keyboardMap[code];
+ }
+
+ break;
+ }
+ case 'mousedown': case 'mouseup':
+ if (event.type == 'mousedown') {
+ // SDL_BUTTON(x) is defined as (1 << ((x)-1)). SDL buttons are 1-3,
+ // and DOM buttons are 0-2, so this means that the below formula is
+ // correct.
+ SDL.buttonState |= 1 << event.button;
+ } else if (event.type == 'mouseup') {
+ SDL.buttonState &= ~(1 << event.button);
+ }
+ // fall through
+ case 'mousemove': {
+ Browser.calculateMouseEvent(event);
+ break;
+ }
+ }
+ },
+
makeCEvent: function(event, ptr) {
if (typeof event === 'number') {
// This is a pointer to a native C event that was SDL_PushEvent'ed
@@ -526,7 +587,9 @@ var LibrarySDL = {
return;
}
- switch(event.type) {
+ SDL.handleEvent(event);
+
+ switch (event.type) {
case 'keydown': case 'keyup': {
var down = event.type === 'keydown';
//Module.print('Received key event: ' + event.keyCode);
@@ -543,26 +606,14 @@ var LibrarySDL = {
scan = SDL.scanCodes[key] || key;
}
- var code = SDL.keyCodes[event.keyCode] || event.keyCode;
- {{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}};
- if (down) {
- SDL.keyboardMap[code] = event.keyCode; // save the DOM input, which we can use to unpress it during blur
- } else {
- delete SDL.keyboardMap[code];
- }
-
- // TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED
- SDL.modState = ({{{ makeGetValue('SDL.keyboardState', '1248', 'i8') }}} ? 0x0040 | 0x0080 : 0) | // KMOD_LCTRL & KMOD_RCTRL
- ({{{ makeGetValue('SDL.keyboardState', '1249', 'i8') }}} ? 0x0001 | 0x0002 : 0) | // KMOD_LSHIFT & KMOD_RSHIFT
- ({{{ makeGetValue('SDL.keyboardState', '1250', 'i8') }}} ? 0x0100 | 0x0200 : 0); // KMOD_LALT & KMOD_RALT
-
{{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
{{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.state', 'down ? 1 : 0', 'i8') }}}
{{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.repeat', '0', 'i8') }}} // TODO
{{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.scancode', 'scan', 'i32') }}}
{{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.sym', 'key', 'i32') }}}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.mod', 'SDL.modState', 'i32') }}}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.unicode', 'key', 'i32') }}}
+ {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.mod', 'SDL.modState', 'i16') }}}
+ // some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode.
+ {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.unicode', 'event.keypressCharCode || key', 'i32') }}}
break;
}
@@ -575,18 +626,7 @@ var LibrarySDL = {
}
break;
}
- case 'mousedown': case 'mouseup':
- if (event.type == 'mousedown') {
- // SDL_BUTTON(x) is defined as (1 << ((x)-1)). SDL buttons are 1-3,
- // and DOM buttons are 0-2, so this means that the below formula is
- // correct.
- SDL.buttonState |= 1 << event.button;
- } else if (event.type == 'mouseup') {
- SDL.buttonState &= ~(1 << event.button);
- }
- // fall through
- case 'mousemove': {
- Browser.calculateMouseEvent(event);
+ case 'mousedown': case 'mouseup': case 'mousemove': {
if (event.type != 'mousemove') {
var down = event.type === 'mousedown';
{{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
@@ -737,6 +777,11 @@ var LibrarySDL = {
return depth; // all modes are ok.
},
+ SDL_AudioDriverName__deps: ['SDL_VideoDriverName'],
+ SDL_AudioDriverName: function(buf, max_size) {
+ return _SDL_VideoDriverName(buf, max_size);
+ },
+
SDL_VideoDriverName: function(buf, max_size) {
if (SDL.startTime === null) {
return 0; //return NULL
@@ -1174,7 +1219,11 @@ var LibrarySDL = {
}
},
- SDL_PumpEvents: function(){},
+ SDL_PumpEvents: function(){
+ SDL.events.forEach(function(event) {
+ SDL.handleEvent(event);
+ });
+ },
SDL_SetColors: function(surf, colors, firstColor, nColors) {
var surfData = SDL.surfaces[surf];
@@ -1291,11 +1340,7 @@ var LibrarySDL = {
}
if (!raw) {
- filename = FS.standardizePath(filename);
- if (filename[0] == '/') {
- // Convert the path to relative
- filename = filename.substr(1);
- }
+ filename = PATH.resolve(filename);
var raw = Module["preloadedImages"][filename];
if (!raw) {
if (raw === null) Module.printErr('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!');
@@ -1513,8 +1558,7 @@ var LibrarySDL = {
var bytes;
if (rwops.filename !== undefined) {
- filename = rwops.filename;
- filename = FS.standardizePath(filename);
+ filename = PATH.resolve(rwops.filename);
var raw = Module["preloadedAudios"][filename];
if (!raw) {
if (raw === null) Module.printErr('Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!');
@@ -1527,7 +1571,7 @@ var LibrarySDL = {
// We found the file. Load the contents
if (fileObject && !fileObject.isFolder && fileObject.read) {
- bytes = fileObject.contents
+ bytes = fileObject.contents;
} else {
return 0;
}
@@ -2045,9 +2089,9 @@ var LibrarySDL = {
console.log('TODO: SDL_GL_SetAttribute');
},
- SDL_GL_GetProcAddress__deps: ['$GLEmulation'],
+ SDL_GL_GetProcAddress__deps: ['emscripten_GetProcAddress'],
SDL_GL_GetProcAddress: function(name_) {
- return GLEmulation.getProcAddress(Pointer_stringify(name_));
+ return _emscripten_GetProcAddress(Pointer_stringify(name_));
},
SDL_GL_SwapBuffers: function() {},
diff --git a/src/library_sockfs.js b/src/library_sockfs.js
new file mode 100644
index 00000000..13118b71
--- /dev/null
+++ b/src/library_sockfs.js
@@ -0,0 +1,18 @@
+mergeInto(LibraryManager.library, {
+ $SOCKFS__postset: '__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });',
+ $SOCKFS__deps: ['$FS'],
+ $SOCKFS: {
+ mount: function(mount) {
+ var node = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ node.node_ops = SOCKFS.node_ops;
+ node.stream_ops = SOCKFS.stream_ops;
+ return node;
+ },
+ node_ops: {
+ },
+ stream_ops: {
+ },
+ websocket_sock_ops: {
+ }
+ }
+}); \ No newline at end of file
diff --git a/src/library_tty.js b/src/library_tty.js
new file mode 100644
index 00000000..8f44cd07
--- /dev/null
+++ b/src/library_tty.js
@@ -0,0 +1,121 @@
+mergeInto(LibraryManager.library, {
+ $TTY__deps: ['$FS'],
+ $TTY: {
+ ttys: [],
+ register: function(dev, ops) {
+ TTY.ttys[dev] = { input: [], output: [], ops: ops };
+ FS.registerDevice(dev, TTY.stream_ops);
+ },
+ stream_ops: {
+ open: function(stream) {
+ // this wouldn't be required if the library wasn't eval'd at first...
+ if (!TTY.utf8) {
+ TTY.utf8 = new Runtime.UTF8Processor();
+ }
+ var tty = TTY.ttys[stream.node.rdev];
+ if (!tty) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+ }
+ stream.tty = tty;
+ stream.seekable = false;
+ },
+ close: function(stream) {
+ // flush any pending line data
+ if (stream.tty.output.length) {
+ stream.tty.ops.put_char(stream.tty, {{{ charCode('\n') }}});
+ }
+ },
+ read: function(stream, buffer, offset, length, pos /* ignored */) {
+ if (!stream.tty || !stream.tty.ops.get_char) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+ }
+ var bytesRead = 0;
+ for (var i = 0; i < length; i++) {
+ var result;
+ try {
+ result = stream.tty.ops.get_char(stream.tty);
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ if (result === undefined && bytesRead === 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+ }
+ if (result === null || result === undefined) break;
+ bytesRead++;
+ buffer[offset+i] = result;
+ }
+ if (bytesRead) {
+ stream.node.timestamp = Date.now();
+ }
+ return bytesRead;
+ },
+ write: function(stream, buffer, offset, length, pos) {
+ if (!stream.tty || !stream.tty.ops.put_char) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+ }
+ for (var i = 0; i < length; i++) {
+ try {
+ stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES.EIO);
+ }
+ }
+ if (length) {
+ stream.node.timestamp = Date.now();
+ }
+ return i;
+ }
+ },
+ // NOTE: This is weird to support stdout and stderr
+ // overrides in addition to print and printErr overrides.
+ default_tty_ops: {
+ get_char: function(tty) {
+ if (!tty.input.length) {
+ var result = null;
+ if (ENVIRONMENT_IS_NODE) {
+ if (process.stdin.destroyed) {
+ return undefined;
+ }
+ result = process.stdin.read();
+ } else if (typeof window != 'undefined' &&
+ typeof window.prompt == 'function') {
+ // Browser.
+ result = window.prompt('Input: '); // returns null on cancel
+ if (result !== null) {
+ result += '\n';
+ }
+ } else if (typeof readline == 'function') {
+ // Command line.
+ result = readline();
+ if (result !== null) {
+ result += '\n';
+ }
+ }
+ if (!result) {
+ return null;
+ }
+ tty.input = intArrayFromString(result, true);
+ }
+ return tty.input.shift();
+ },
+ put_char: function(tty, val) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
+ Module['print'](tty.output.join(''));
+ tty.output = [];
+ } else {
+ tty.output.push(TTY.utf8.processCChar(val));
+ }
+ }
+ },
+ default_tty1_ops: {
+ put_char: function(tty, val) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
+ Module['printErr'](tty.output.join(''));
+ tty.output = [];
+ } else {
+ tty.output.push(TTY.utf8.processCChar(val));
+ }
+ }
+ }
+ }
+}); \ No newline at end of file
diff --git a/src/modules.js b/src/modules.js
index f85e7d0e..fa6c0983 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -46,7 +46,9 @@ var Debugging = {
var form3ab = new RegExp(/^!(\d+) = metadata !{i32 \d+, (?:metadata !\d+|i32 \d+|null), metadata !(\d+).*$/);
var form3ac = new RegExp(/^!(\d+) = metadata !{i32 \d+, (?:metadata !\d+|null), metadata !"[^"]*", metadata !(\d+)[^\[]*.*$/);
var form3ad = new RegExp(/^!(\d+) = metadata !{i32 \d+, (?:i32 \d+|null), (?:i32 \d+|null), metadata !"[^"]*", metadata !"[^"]*", metadata !"[^"]*", metadata !(\d+),.*$/);
- var form3b = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !"([^"]+)", metadata !"([^"]*)", (metadata !\d+|null)}.*$/);
+ var form3ae = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !(\d+).*$/);
+ // LLVM 3.3 drops the first and last parameters.
+ var form3b = new RegExp(/^!(\d+) = metadata !{(?:i32 \d+, )?metadata !"([^"]+)", metadata !"([^"]*)"(?:, (metadata !\d+|null))?}.*$/);
var form3c = new RegExp(/^!(\d+) = metadata !{\w+\d* !?(\d+)[^\d].*$/);
var form4 = new RegExp(/^!llvm.dbg.[\w\.]+ = .*$/);
var form5 = new RegExp(/^!(\d+) = metadata !{.*$/);
@@ -75,7 +77,7 @@ var Debugging = {
lines[i] = ';'; // return an empty line, to keep line numbers of subsequent lines the same
continue;
}
- calc = form3a.exec(line) || form3ab.exec(line) || form3ac.exec(line) || form3ad.exec(line);
+ calc = form3a.exec(line) || form3ab.exec(line) || form3ac.exec(line) || form3ad.exec(line) || form3ae.exec(line);
if (calc) {
metadataToParentMetadata[calc[1]] = calc[2];
lines[i] = ';';
@@ -273,20 +275,15 @@ var Functions = {
},
// Mark a function as needing indexing. Python will coordinate them all
- getIndex: function(ident, doNotCreate, sig) {
- if (doNotCreate && !(ident in this.indexedFunctions)) {
- if (!Functions.getIndex.tentative) Functions.getIndex.tentative = {}; // only used by GL emulation; TODO: generalize when needed
- Functions.getIndex.tentative[ident] = 0;
- }
+ getIndex: function(ident, sig) {
var ret;
if (phase != 'post' && singlePhase) {
- if (!doNotCreate) this.indexedFunctions[ident] = 0; // tell python we need this indexized
ret = "'{{ FI_" + toNiceIdent(ident) + " }}'"; // something python will replace later
+ this.indexedFunctions[ident] = 0;
} else {
if (!singlePhase) return 'NO_INDEX'; // Should not index functions in post
ret = this.indexedFunctions[ident];
if (!ret) {
- if (doNotCreate) return '0';
ret = this.nextIndex;
this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test
this.indexedFunctions[ident] = ret;
@@ -324,7 +321,7 @@ var Functions = {
tables[sig][index] = ident;
}
var generated = false;
- var wrapped = {};
+ var wrapped = {}; // whether we wrapped a lib func
var maxTable = 0;
for (var t in tables) {
if (t == 'pre') continue;
@@ -347,10 +344,11 @@ var Functions = {
if (ASM_JS) {
var curr = table[i];
if (curr && curr != '0' && !Functions.implementedFunctions[curr]) {
- curr = toNiceIdent(curr); // fix Math.* to Math_*
+ var short = toNiceIdent(curr); // fix Math.* to Math_*
+ curr = t + '_' + short; // libfuncs can alias with different sigs, wrap each separately
// This is a library function, we can't just put it in the function table, need a wrapper
if (!wrapped[curr]) {
- var args = '', arg_coercions = '', call = curr + '(', retPre = '', retPost = '';
+ var args = '', arg_coercions = '', call = short + '(', retPre = '', retPost = '';
if (t[0] != 'v') {
if (t[0] == 'i') {
retPre = 'return ';
@@ -365,7 +363,7 @@ var Functions = {
call += (j > 1 ? ',' : '') + asmCoercion('a' + j, t[j] != 'i' ? 'float' : 'i32');
}
call += ')';
- if (curr == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things');
+ if (short == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things');
tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n';
wrapped[curr] = 1;
}
@@ -422,7 +420,7 @@ var LibraryManager = {
load: function() {
if (this.library) return;
- var libraries = ['library.js', 'library_path.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
+ var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_memfs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
for (var i = 0; i < libraries.length; i++) {
eval(processMacros(preprocess(read(libraries[i]))));
}
diff --git a/src/parseTools.js b/src/parseTools.js
index b7d3ea91..65e96264 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -396,12 +396,18 @@ function parseParamTokens(params) {
// handle 'byval' and 'byval align X'. We store the alignment in 'byVal'
byVal = QUANTUM_SIZE;
segment.splice(1, 1);
+ if (segment[1] && segment[1].text === 'nocapture') {
+ segment.splice(1, 1);
+ }
if (segment[1] && segment[1].text === 'align') {
assert(isNumber(segment[2].text));
byVal = parseInt(segment[2].text);
segment.splice(1, 2);
}
}
+ if (segment[1] && segment[1].text === 'nocapture') {
+ segment.splice(1, 1);
+ }
if (segment.length == 1) {
if (segment[0].text == '...') {
ret.push({
@@ -1238,7 +1244,7 @@ function indexizeFunctions(value, type) {
if (!sig) {
sig = Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : [], isVarArgsFunctionType(type));
}
- return Functions.getIndex(value, undefined, sig);
+ return Functions.getIndex(value, sig);
}
return value;
}
@@ -2014,6 +2020,13 @@ function makeIsNaN(value) {
return 'isNaN(' + value + ')';
}
+function makeFloat(value, type) {
+ if (TO_FLOAT32 && type == 'float') {
+ return 'Math.toFloat32(' + value + ')';
+ }
+ return value;
+}
+
// fptoui and fptosi are not in these, because we need to be careful about what we do there. We can't
// just sign/unsign the input first.
var UNSIGNED_OP = set('udiv', 'urem', 'uitofp', 'zext', 'lshr');
@@ -2269,11 +2282,11 @@ function processMathop(item) {
return idents[0] + ' >>> ' + idents[1];
}
// basic float ops
- case 'fadd': return getFastValue(idents[0], '+', idents[1], item.type);
- case 'fsub': return getFastValue(idents[0], '-', idents[1], item.type);
- case 'fdiv': return getFastValue(idents[0], '/', idents[1], item.type);
- case 'fmul': return getFastValue(idents[0], '*', idents[1], item.type);
- case 'frem': return getFastValue(idents[0], '%', idents[1], item.type);
+ case 'fadd': return makeFloat(getFastValue(idents[0], '+', idents[1], item.type), item.type);
+ case 'fsub': return makeFloat(getFastValue(idents[0], '-', idents[1], item.type), item.type);
+ case 'fdiv': return makeFloat(getFastValue(idents[0], '/', idents[1], item.type), item.type);
+ case 'fmul': return makeFloat(getFastValue(idents[0], '*', idents[1], item.type), item.type);
+ case 'frem': return makeFloat(getFastValue(idents[0], '%', idents[1], item.type), item.type);
case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double', op[0]);
case 'fptoui': case 'fptosi': return makeRounding(idents[0], bitsLeft, op === 'fptosi', true);
diff --git a/src/postamble.js b/src/postamble.js
index 25a50bfc..df844121 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -1,8 +1,17 @@
// === Auto-generated postamble setup entry stuff ===
+function ExitStatus(status) {
+ this.name = "ExitStatus";
+ this.message = "Program terminated with exit(" + status + ")";
+ this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
var initialStackTop;
-var inMain;
+
+var preloadStartTime = null;
Module['callMain'] = Module.callMain = function callMain(args) {
assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
@@ -10,6 +19,10 @@ Module['callMain'] = Module.callMain = function callMain(args) {
args = args || [];
+ if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+ Module.printErr('preload time: ' + (Date.now() - preloadStartTime) + ' ms');
+ }
+
ensureInitRuntime();
var argc = args.length+1;
@@ -27,40 +40,36 @@ Module['callMain'] = Module.callMain = function callMain(args) {
argv.push(0);
argv = allocate(argv, 'i32', ALLOC_NORMAL);
+ initialStackTop = STACKTOP;
+
+ try {
#if BENCHMARK
- var start = Date.now();
+ var start = Date.now();
#endif
- initialStackTop = STACKTOP;
- inMain = true;
+ var ret = Module['_main'](argc, argv, 0);
- var ret;
- try {
- ret = Module['_main'](argc, argv, 0);
+#if BENCHMARK
+ Module.realPrint('main() took ' + (Date.now() - start) + ' milliseconds');
+#endif
+
+ // if we're not running an evented main loop, it's time to exit
+ if (!Module['noExitRuntime']) {
+ exit(ret);
+ }
}
catch(e) {
- if (e && typeof e == 'object' && e.type == 'ExitStatus') {
+ if (e instanceof ExitStatus) {
// exit() throws this once it's done to make sure execution
// has been stopped completely
- Module.print('Exit Status: ' + e.value);
- return e.value;
+ return;
} else if (e == 'SimulateInfiniteLoop') {
// running an evented main loop, don't immediately exit
Module['noExitRuntime'] = true;
+ return;
} else {
throw e;
}
- } finally {
- inMain = false;
- }
-
-#if BENCHMARK
- Module.realPrint('main() took ' + (Date.now() - start) + ' milliseconds');
-#endif
-
- // if we're not running an evented main loop, it's time to exit
- if (!Module['noExitRuntime']) {
- exit(ret);
}
}
@@ -69,6 +78,8 @@ Module['callMain'] = Module.callMain = function callMain(args) {
function run(args) {
args = args || Module['arguments'];
+ if (preloadStartTime === null) preloadStartTime = Date.now();
+
if (runDependencies > 0) {
Module.printErr('run() called, but dependencies remain, so not running');
return;
@@ -110,30 +121,25 @@ Module['run'] = Module.run = run;
function exit(status) {
ABORT = true;
+ EXITSTATUS = status;
STACKTOP = initialStackTop;
- // TODO call externally added 'exit' callbacks with the status code.
- // It'd be nice to provide the same interface for all Module events (e.g.
- // prerun, premain, postmain). Perhaps an EventEmitter so we can do:
- // Module.on('exit', function (status) {});
-
// exit the runtime
exitRuntime();
-
- if (inMain) {
- // if we're still inside the callMain's try/catch, we need to throw an
- // exception in order to immediately terminate execution.
- throw { type: 'ExitStatus', value: status };
- }
+
+ // throw an exception to halt the current execution
+ throw new ExitStatus(status);
}
Module['exit'] = Module.exit = exit;
function abort(text) {
if (text) {
Module.print(text);
+ Module.printErr(text);
}
ABORT = true;
+ EXITSTATUS = 1;
throw 'abort() at ' + (new Error().stack);
}
diff --git a/src/preamble.js b/src/preamble.js
index 2955c885..0f3f52c9 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -156,6 +156,15 @@ function SAFE_HEAP_COPY_HISTORY(dest, src) {
SAFE_HEAP_ACCESS(dest, HEAP_HISTORY[dest] || null, true, false);
}
+function SAFE_HEAP_FILL_HISTORY(from, to, type) {
+#if SAFE_HEAP_LOG
+ Module.print('SAFE_HEAP fill: ' + [from, to, type]);
+#endif
+ for (var i = from; i < to; i++) {
+ HEAP_HISTORY[i] = type;
+ }
+}
+
//==========================================
#endif
@@ -232,6 +241,7 @@ var setjmpLabels = {};
#endif
var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
var undef = 0;
// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
@@ -843,6 +853,13 @@ Math['imul'] = function(a, b) {
#endif
Math.imul = Math['imul'];
+#if TO_FLOAT32
+if (!Math['toFloat32']) Math['toFloat32'] = function(x) {
+ return x;
+};
+Math.toFloat32 = Math['toFloat32'];
+#endif
+
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
// decrement it. Incrementing must happen in a place like
diff --git a/src/settings.js b/src/settings.js
index 19108f3b..cb64bfd9 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -108,6 +108,7 @@ var PRECISE_I64_MATH = 1; // If enabled, i64 addition etc. is emulated - which i
var PRECISE_I32_MUL = 1; // If enabled, i32 multiplication is done with full precision, which means it is
// correct even if the value exceeds the JS double-integer limit of ~52 bits (otherwise,
// rounding will occur above that range).
+var TO_FLOAT32 = 0; // Use Math.toFloat32
var CLOSURE_ANNOTATIONS = 0; // If set, the generated code will be annotated for the closure
// compiler. This potentially lets closure optimize the code better.
@@ -190,9 +191,8 @@ var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context,
var GL_MAX_TEMP_BUFFER_SIZE = 2097152; // How large GL emulation temp buffers are
var GL_UNSAFE_OPTS = 1; // Enables some potentially-unsafe optimizations in GL emulation code
var FULL_ES2 = 0; // Forces support for all GLES2 features, not just the WebGL-friendly subset.
-var FORCE_GL_EMULATION = 0; // Forces inclusion of full GL emulation code.
-var DISABLE_GL_EMULATION = 0; // Disable inclusion of full GL emulation code. Useful when you don't want emulation
- // but do need INCLUDE_FULL_LIBRARY or MAIN_MODULE.
+var LEGACY_GL_EMULATION = 0; // Includes code to emulate various desktop GL features. Incomplete but useful
+ // in some cases, see https://github.com/kripken/emscripten/wiki/OpenGL-support
var STB_IMAGE = 0; // Enables building of stb-image, a tiny public-domain library for decoding images, allowing
// decoding of images without using the browser's built-in decoders. The benefit is that this
@@ -315,11 +315,12 @@ var SIDE_MODULE = 0; // Corresponds to MAIN_MODULE
var BUILD_AS_SHARED_LIB = 0; // Whether to build the code as a shared library
// 0 here means this is not a shared lib: It is a main file.
- // All shared library options (1 and 2) are currently deprecated XXX
// 1 means this is a normal shared lib, load it with dlopen()
// 2 means this is a shared lib that will be linked at runtime,
// which means it will insert its functions into
// the global namespace. See STATIC_LIBS_TO_LOAD.
+ //
+ // Value 2 is currently deprecated.
var RUNTIME_LINKED_LIBS = []; // If this is a main file (BUILD_AS_SHARED_LIB == 0), then
// we will link these at runtime. They must have been built with
// BUILD_AS_SHARED_LIB == 2.
@@ -444,7 +445,7 @@ var C_DEFINES = {
'ABMON_9': '41',
'ACCESSPERMS': '0000400',
'AF_INET': '2',
- 'AF_INET6': '6',
+ 'AF_INET6': '10',
'ALLPERMS': '0004000',
'ALT_DIGITS': '49',
'AM_STR': '5',
@@ -620,8 +621,8 @@ var C_DEFINES = {
'HAVE__ULTOA': '1',
'HUGE_VAL': 'inf',
'INT_MAX': '2147483647',
- 'IPPROTO_TCP': '1',
- 'IPPROTO_UDP': '2',
+ 'IPPROTO_TCP': '6',
+ 'IPPROTO_UDP': '17',
'ITIMER_PROF': '2',
'ITIMER_REAL': '0',
'ITIMER_VIRTUAL': '1',
@@ -676,7 +677,7 @@ var C_DEFINES = {
'NOSTR': '55',
'NO_ARG': '0',
'no_argument': '0',
- 'NSIG': '32',
+ 'NSIG': '64',
'NULL': '0',
'OPTIONAL_ARG': '2',
'optional_argument': '2',
@@ -830,8 +831,8 @@ var C_DEFINES = {
'SIGPROF': '27',
'SIGPWR': '19',
'SIGQUIT': '3',
- 'SIGRTMAX': '31',
- 'SIGRTMIN': '27',
+ 'SIGRTMAX': '64',
+ 'SIGRTMIN': '32',
'SIGSEGV': '11',
'SIGSTOP': '17',
'SIGSYS': '12',
@@ -857,8 +858,8 @@ var C_DEFINES = {
'SI_QUEUE': '2',
'SI_TIMER': '3',
'SI_USER': '1',
- 'SOCK_DGRAM': '20',
- 'SOCK_STREAM': '200',
+ 'SOCK_DGRAM': '2',
+ 'SOCK_STREAM': '1',
'STDC_HEADERS': '1',
'STDERR_FILENO': '2',
'STDIN_FILENO': '0',
@@ -1322,6 +1323,127 @@ var C_DEFINES = {
'MAP_TYPE': '0x0f',
'MAP_FIXED': '0x100',
'MAP_ANONYMOUS': '0x10',
- 'O_NOFOLLOW': '0200000'
+ 'O_NOFOLLOW': '0200000',
+ 'EPERM': '1',
+ 'ENOENT': '2',
+ 'ESRCH': '3',
+ 'EINTR': '4',
+ 'EIO': '5',
+ 'ENXIO': '6',
+ 'E2BIG': '7',
+ 'ENOEXEC': '8',
+ 'EBADF': '9',
+ 'ECHILD': '10',
+ 'EAGAIN': '11',
+ 'EWOULDBLOCK': '11',
+ 'ENOMEM': '12',
+ 'EACCES': '13',
+ 'EFAULT': '14',
+ 'ENOTBLK': '15',
+ 'EBUSY': '16',
+ 'EEXIST': '17',
+ 'EXDEV': '18',
+ 'ENODEV': '19',
+ 'ENOTDIR': '20',
+ 'EISDIR': '21',
+ 'EINVAL': '22',
+ 'ENFILE': '23',
+ 'EMFILE': '24',
+ 'ENOTTY': '25',
+ 'ETXTBSY': '26',
+ 'EFBIG': '27',
+ 'ENOSPC': '28',
+ 'ESPIPE': '29',
+ 'EROFS': '30',
+ 'EMLINK': '31',
+ 'EPIPE': '32',
+ 'EDOM': '33',
+ 'ERANGE': '34',
+ 'ENOMSG': '35',
+ 'EIDRM': '36',
+ 'ECHRNG': '37',
+ 'EL2NSYNC': '38',
+ 'EL3HLT': '39',
+ 'EL3RST': '40',
+ 'ELNRNG': '41',
+ 'EUNATCH': '42',
+ 'ENOCSI': '43',
+ 'EL2HLT': '44',
+ 'EDEADLK': '45',
+ 'ENOLCK': '46',
+ 'EBADE': '50',
+ 'EBADR': '51',
+ 'EXFULL': '52',
+ 'ENOANO': '53',
+ 'EBADRQC': '54',
+ 'EBADSLT': '55',
+ 'EDEADLOCK': '56',
+ 'EBFONT': '57',
+ 'ENOSTR': '60',
+ 'ENODATA': '61',
+ 'ETIME': '62',
+ 'ENOSR': '63',
+ 'ENONET': '64',
+ 'ENOPKG': '65',
+ 'EREMOTE': '66',
+ 'ENOLINK': '67',
+ 'EADV': '68',
+ 'ESRMNT': '69',
+ 'ECOMM': '70',
+ 'EPROTO': '71',
+ 'EMULTIHOP': '74',
+ 'EDOTDOT': '76',
+ 'EBADMSG': '77',
+ 'ENOTUNIQ': '80',
+ 'EBADFD': '81',
+ 'EREMCHG': '82',
+ 'ELIBACC': '83',
+ 'ELIBBAD': '84',
+ 'ELIBSCN': '85',
+ 'ELIBMAX': '86',
+ 'ELIBEXEC': '87',
+ 'ENOSYS': '88',
+ 'ENOTEMPTY': '90',
+ 'ENAMETOOLONG': '91',
+ 'ELOOP': '92',
+ 'EOPNOTSUPP': '95',
+ 'EPFNOSUPPORT': '96',
+ 'ECONNRESET': '104',
+ 'ENOBUFS': '105',
+ 'EAFNOSUPPORT': '106',
+ 'EPROTOTYPE': '107',
+ 'ENOTSOCK': '108',
+ 'ENOPROTOOPT': '109',
+ 'ESHUTDOWN': '110',
+ 'ECONNREFUSED': '111',
+ 'EADDRINUSE': '112',
+ 'ECONNABORTED': '113',
+ 'ENETUNREACH': '114',
+ 'ENETDOWN': '115',
+ 'ETIMEDOUT': '116',
+ 'EHOSTDOWN': '117',
+ 'EHOSTUNREACH': '118',
+ 'EINPROGRESS': '119',
+ 'EALREADY': '120',
+ 'EDESTADDRREQ': '121',
+ 'EMSGSIZE': '122',
+ 'EPROTONOSUPPORT': '123',
+ 'ESOCKTNOSUPPORT': '124',
+ 'EADDRNOTAVAIL': '125',
+ 'ENETRESET': '126',
+ 'EISCONN': '127',
+ 'ENOTCONN': '128',
+ 'ETOOMANYREFS': '129',
+ 'EUSERS': '131',
+ 'EDQUOT': '132',
+ 'ESTALE': '133',
+ 'ENOTSUP': '134',
+ 'ENOMEDIUM': '135',
+ 'EILSEQ': '138',
+ 'EOVERFLOW': '139',
+ 'ECANCELED': '140',
+ 'ENOTRECOVERABLE': '141',
+ 'EOWNERDEAD': '142',
+ 'ESTRPIPE': '143'
};
diff --git a/src/shell.js b/src/shell.js
index 2082eeae..f91aa96a 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -70,12 +70,16 @@ if (ENVIRONMENT_IS_NODE) {
module.exports = Module;
}
-
-if (ENVIRONMENT_IS_SHELL) {
+else if (ENVIRONMENT_IS_SHELL) {
Module['print'] = print;
if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
- Module['read'] = read;
+ if (typeof read != 'undefined') {
+ Module['read'] = read;
+ } else {
+ Module['read'] = function() { throw 'no read() available (jsc?)' };
+ }
+
Module['readBinary'] = function(f) {
return read(f, 'binary');
};
@@ -88,20 +92,7 @@ if (ENVIRONMENT_IS_SHELL) {
this['{{{ EXPORT_NAME }}}'] = Module;
}
-
-if (ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER) {
- Module['print'] = function(x) {
- console.log(x);
- };
-
- Module['printErr'] = function(x) {
- console.log(x);
- };
-
- this['{{{ EXPORT_NAME }}}'] = Module;
-}
-
-if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
Module['read'] = function(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
@@ -112,21 +103,30 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
if (typeof arguments != 'undefined') {
Module['arguments'] = arguments;
}
-}
-
-if (ENVIRONMENT_IS_WORKER) {
- // We can do very little here...
- var TRY_USE_DUMP = false;
- Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
- dump(x);
- }) : (function(x) {
- // self.postMessage(x); // enable this if you want stdout to be sent as messages
- }));
- Module['load'] = importScripts;
+ if (ENVIRONMENT_IS_WEB) {
+ Module['print'] = function(x) {
+ console.log(x);
+ };
+
+ Module['printErr'] = function(x) {
+ console.log(x);
+ };
+
+ this['{{{ EXPORT_NAME }}}'] = Module;
+ } else if (ENVIRONMENT_IS_WORKER) {
+ // We can do very little here...
+ var TRY_USE_DUMP = false;
+ Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+ dump(x);
+ }) : (function(x) {
+ // self.postMessage(x); // enable this if you want stdout to be sent as messages
+ }));
+
+ Module['load'] = importScripts;
+ }
}
-
-if (!ENVIRONMENT_IS_WORKER && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_SHELL) {
+else {
// Unreachable because SHELL is dependant on the others
throw 'Unknown runtime environment. Where are we?';
}
diff --git a/system/include/compat/math.h b/system/include/compat/math.h
new file mode 100644
index 00000000..089cf66b
--- /dev/null
+++ b/system/include/compat/math.h
@@ -0,0 +1,14 @@
+#ifndef _COMPAT_MATH_H_
+#define _COMPAT_MATH_H_
+
+#ifndef isinff
+ #define isinff isinf
+#endif
+
+#ifndef isnanf
+ #define isnanf isnan
+#endif
+
+#include_next <math.h>
+
+#endif /* _COMPAT_MATH_H_ */
diff --git a/system/include/compat/stdlib.h b/system/include/compat/stdlib.h
new file mode 100644
index 00000000..dc01947d
--- /dev/null
+++ b/system/include/compat/stdlib.h
@@ -0,0 +1,16 @@
+#ifndef _COMPAT_STDLIB_H
+#define _COMPAT_STDLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int getloadavg(double loadavg[], int nelem);
+
+#ifdef __cplusplus
+}
+#endif
+
+#include_next <stdlib.h>
+
+#endif
diff --git a/system/include/compat/string.h b/system/include/compat/string.h
new file mode 100644
index 00000000..880089cc
--- /dev/null
+++ b/system/include/compat/string.h
@@ -0,0 +1,17 @@
+#ifndef _COMPAT_STRING_H
+#define _COMPAT_STRING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* strlwr(char *);
+extern char* strupr(char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#include_next <string.h>
+
+#endif
diff --git a/system/include/compat/sys/stat.h b/system/include/compat/sys/stat.h
new file mode 100644
index 00000000..731502ea
--- /dev/null
+++ b/system/include/compat/sys/stat.h
@@ -0,0 +1,20 @@
+#ifndef _COMPAT_STAT_H
+#define _COMPAT_STAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include_next <sys/stat.h>
+
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/system/include/libc/sys/timeb.h b/system/include/compat/sys/timeb.h
index 0a2c3de8..0a2c3de8 100644
--- a/system/include/libc/sys/timeb.h
+++ b/system/include/compat/sys/timeb.h
diff --git a/system/include/compat/unistd.h b/system/include/compat/unistd.h
new file mode 100644
index 00000000..07c3afde
--- /dev/null
+++ b/system/include/compat/unistd.h
@@ -0,0 +1,16 @@
+#ifndef _COMPAT_UNISTD_H
+#define _COMPAT_UNISTD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char * getwd(char *__buf );
+
+#ifdef __cplusplus
+}
+#endif
+
+#include_next <unistd.h>
+
+#endif
diff --git a/system/include/compat/xlocale.h b/system/include/compat/xlocale.h
new file mode 100644
index 00000000..4bafa27d
--- /dev/null
+++ b/system/include/compat/xlocale.h
@@ -0,0 +1,21 @@
+#ifndef _COMPAT_XLOCALE_H_
+#define _COMPAT_XLOCALE_H_
+
+#include <locale.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+long long strtoll_l(const char *start, char **end, int base, locale_t loc);
+unsigned long long strtoull_l(const char *start, char **end, int base, locale_t loc);
+double strtold_l(const char *start, char **end, locale_t loc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#include_next <xlocale.h>
+
+#endif /* _COMPAT_XLOCALE_H_ */
+
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index 28e6063c..f0df8dca 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -20,14 +20,13 @@ extern "C" {
/*
* Forces LLVM to not dead-code-eliminate a function. Note that
- * closure may still eliminate it at the JS level, for which you
- * should use EXPORTED_FUNCTIONS (see settings.js).
- *
- * **DEPRECATED**: Use EXPORTED_FUNCTIONS instead, which will work
- * with closure, asm.js, etc. For example
- * -s EXPORTED_FUNCTIONS=["_main", "myfunc"]
+ * you still need to use EXPORTED_FUNCTIONS so it stays alive
+ * in JS, e.g.
+ * emcc -s EXPORTED_FUNCTIONS=["_main", "_myfunc"]
+ * and in the source file
+ * void EMSCRIPTEN_KEEPALIVE myfunc() {..}
*/
-/* #define EMSCRIPTEN_KEEPALIVE __attribute__((used)) */
+#define EMSCRIPTEN_KEEPALIVE __attribute__((used))
/*
* Interface to the underlying JS engine. This function will
diff --git a/system/include/libc/stdlib.h b/system/include/libc/stdlib.h
index 888b6041..6fdef40b 100644
--- a/system/include/libc/stdlib.h
+++ b/system/include/libc/stdlib.h
@@ -223,8 +223,6 @@ extern long double strtold (const char *, char **);
extern long double wcstold (const wchar_t *, wchar_t **);
#endif /* _LDBL_EQ_DBL */
-int getloadavg(double loadavg[], int nelem); /* XXX Emscripten */
-
_END_STD_C
#endif /* _STDLIB_H_ */
diff --git a/system/include/libc/string.h b/system/include/libc/string.h
index 515c71a7..8fd9ea43 100644
--- a/system/include/libc/string.h
+++ b/system/include/libc/string.h
@@ -72,8 +72,6 @@ size_t _EXFUN(strlcpy,(char *, const char *, size_t));
int _EXFUN(strncasecmp,(const char *, const char *, size_t));
size_t _EXFUN(strnlen,(const char *, size_t));
char *_EXFUN(strsep,(char **, const char *));
-char *_EXFUN(strlwr,(char *));
-char *_EXFUN(strupr,(char *));
#if defined(__CYGWIN__) || defined(EMSCRIPTEN)
#ifndef DEFS_H /* Kludge to work around problem compiling in gdb */
char *_EXFUN(strsignal, (int __signo));
diff --git a/system/include/libc/sys/signal.h b/system/include/libc/sys/signal.h
index 49a94d80..fc9b67d5 100644
--- a/system/include/libc/sys/signal.h
+++ b/system/include/libc/sys/signal.h
@@ -298,7 +298,9 @@ int _EXFUN(sigqueue, (pid_t pid, int signo, const union sigval value));
#define SIGLOST 29 /* resource lost (eg, record-lock lost) */
#define SIGUSR1 30 /* user defined signal 1 */
#define SIGUSR2 31 /* user defined signal 2 */
-#define NSIG 32 /* signal 0 implied */
+#define NSIG 64 /* signal 0 implied */
+#define SIGRTMIN 32
+#define SIGRTMAX NSIG
#endif
#endif
diff --git a/system/include/libc/sys/unistd.h b/system/include/libc/sys/unistd.h
index 1a414b3c..a4219d4d 100644
--- a/system/include/libc/sys/unistd.h
+++ b/system/include/libc/sys/unistd.h
@@ -102,7 +102,6 @@ uid_t _EXFUN(getuid, (void ));
#endif
#if defined(EMSCRIPTEN) || defined(__CYGWIN__)
char * _EXFUN(getusershell, (void));
-char * _EXFUN(getwd, (char *__buf ));
int _EXFUN(iruserok, (unsigned long raddr, int superuser, const char *ruser, const char *luser));
#endif
int _EXFUN(isatty, (int __fildes ));
diff --git a/system/include/libcxx/CREDITS.TXT b/system/include/libcxx/CREDITS.TXT
index 52948510..5e4d14ec 100644
--- a/system/include/libcxx/CREDITS.TXT
+++ b/system/include/libcxx/CREDITS.TXT
@@ -33,6 +33,14 @@ E: mclow.lists@gmail.com
E: marshall@idio.com
D: Minor patches and bug fixes.
+N: Bill Fisher
+E: william.w.fisher@gmail.com
+D: Regex bug fixes.
+
+N: Matthew Dempsky
+E: matthew@dempsky.org
+D: Minor patches and bug fixes.
+
N: Google Inc.
D: Copyright owner and contributor of the CityHash algorithm
@@ -48,6 +56,10 @@ N: Argyrios Kyrtzidis
E: kyrtzidis@apple.com
D: Bug fixes.
+N: Bruce Mitchener, Jr.
+E: bruce.mitchener@gmail.com
+D: Emscripten-related changes.
+
N: Michel Morin
E: mimomorin@gmail.com
D: Minor patches to is_convertible.
@@ -74,6 +86,14 @@ D: Implemented Cityhash as the string hash function on 64-bit machines
N: Richard Smith
D: Minor patches.
+N: Joerg Sonnenberger
+E: joerg@NetBSD.org
+D: NetBSD port.
+
+N: Stephan Tolksdorf
+E: st@quanttec.com
+D: Minor <atomic> fix
+
N: Michael van der Westhuizen
E: r1mikey at gmail dot com
@@ -85,6 +105,10 @@ N: Zhang Xiongpang
E: zhangxiongpang@gmail.com
D: Minor patches and bug fixes.
+N: Zhihao Yuan
+E: lichray@gmail.com
+D: Standard compatibility fixes.
+
N: Jeffrey Yasskin
E: jyasskin@gmail.com
E: jyasskin@google.com
diff --git a/system/include/libcxx/__bit_reference b/system/include/libcxx/__bit_reference
index 1621deb8..857dd5a4 100644
--- a/system/include/libcxx/__bit_reference
+++ b/system/include/libcxx/__bit_reference
@@ -173,6 +173,8 @@ __find_bool_true(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type
__storage_type __b = *__first.__seg_ & __m;
if (__b)
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__ctz(__b)));
+ if (__n == __dn)
+ return _It(__first.__seg_, __first.__ctz_ + __n);
__n -= __dn;
++__first.__seg_;
}
@@ -207,6 +209,8 @@ __find_bool_false(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type
__storage_type __b = ~*__first.__seg_ & __m;
if (__b)
return _It(__first.__seg_, static_cast<unsigned>(_VSTD::__ctz(__b)));
+ if (__n == __dn)
+ return _It(__first.__seg_, __first.__ctz_ + __n);
__n -= __dn;
++__first.__seg_;
}
@@ -333,7 +337,7 @@ __fill_n_false(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n)
}
// do middle whole words
__storage_type __nw = __n / __bits_per_word;
- _VSTD::memset(__first.__seg_, 0, __nw * sizeof(__storage_type));
+ _VSTD::memset(_VSTD::__to_raw_pointer(__first.__seg_), 0, __nw * sizeof(__storage_type));
__n -= __nw * __bits_per_word;
// do last partial word
if (__n > 0)
@@ -363,7 +367,7 @@ __fill_n_true(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n)
}
// do middle whole words
__storage_type __nw = __n / __bits_per_word;
- _VSTD::memset(__first.__seg_, -1, __nw * sizeof(__storage_type));
+ _VSTD::memset(_VSTD::__to_raw_pointer(__first.__seg_), -1, __nw * sizeof(__storage_type));
__n -= __nw * __bits_per_word;
// do last partial word
if (__n > 0)
@@ -430,7 +434,9 @@ __copy_aligned(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsCon
// __first.__ctz_ == 0;
// do middle words
__storage_type __nw = __n / __bits_per_word;
- _VSTD::memmove(__result.__seg_, __first.__seg_, __nw * sizeof(__storage_type));
+ _VSTD::memmove(_VSTD::__to_raw_pointer(__result.__seg_),
+ _VSTD::__to_raw_pointer(__first.__seg_),
+ __nw * sizeof(__storage_type));
__n -= __nw * __bits_per_word;
__result.__seg_ += __nw;
// do last word
@@ -569,7 +575,9 @@ __copy_backward_aligned(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_C
__storage_type __nw = __n / __bits_per_word;
__result.__seg_ -= __nw;
__last.__seg_ -= __nw;
- _VSTD::memmove(__result.__seg_, __last.__seg_, __nw * sizeof(__storage_type));
+ _VSTD::memmove(_VSTD::__to_raw_pointer(__result.__seg_),
+ _VSTD::__to_raw_pointer(__last.__seg_),
+ __nw * sizeof(__storage_type));
__n -= __nw * __bits_per_word;
// do last word
if (__n > 0)
@@ -870,6 +878,7 @@ struct __bit_array
{
typedef typename _Cp::difference_type difference_type;
typedef typename _Cp::__storage_type __storage_type;
+ typedef typename _Cp::__storage_pointer __storage_pointer;
typedef typename _Cp::iterator iterator;
static const unsigned __bits_per_word = _Cp::__bits_per_word;
static const unsigned _Np = 4;
@@ -880,9 +889,15 @@ struct __bit_array
_LIBCPP_INLINE_VISIBILITY static difference_type capacity()
{return static_cast<difference_type>(_Np * __bits_per_word);}
_LIBCPP_INLINE_VISIBILITY explicit __bit_array(difference_type __s) : __size_(__s) {}
- _LIBCPP_INLINE_VISIBILITY iterator begin() {return iterator(__word_, 0);}
- _LIBCPP_INLINE_VISIBILITY iterator end() {return iterator(__word_ + __size_ / __bits_per_word,
- static_cast<unsigned>(__size_ % __bits_per_word));}
+ _LIBCPP_INLINE_VISIBILITY iterator begin()
+ {
+ return iterator(pointer_traits<__storage_pointer>::pointer_to(__word_[0]), 0);
+ }
+ _LIBCPP_INLINE_VISIBILITY iterator end()
+ {
+ return iterator(pointer_traits<__storage_pointer>::pointer_to(__word_[0]) + __size_ / __bits_per_word,
+ static_cast<unsigned>(__size_ % __bits_per_word));
+ }
};
template <class _Cp>
@@ -1093,7 +1108,11 @@ private:
unsigned __ctz_;
public:
- _LIBCPP_INLINE_VISIBILITY __bit_iterator() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY __bit_iterator() _NOEXCEPT
+#if _LIBCPP_STD_VER > 11
+ : __seg_(nullptr), __ctz_(0)
+#endif
+ {}
_LIBCPP_INLINE_VISIBILITY
__bit_iterator(const __bit_iterator<_Cp, false>& __it) _NOEXCEPT
diff --git a/system/include/libcxx/__config b/system/include/libcxx/__config
index 959390d5..b1f0d958 100644
--- a/system/include/libcxx/__config
+++ b/system/include/libcxx/__config
@@ -11,7 +11,7 @@
#ifndef _LIBCPP_CONFIG
#define _LIBCPP_CONFIG
-#ifndef _MSC_VER // explicit macro necessary because it is only defined below in this file
+#if !defined(_MSC_VER) || defined(__clang__)
#pragma GCC system_header
#endif
@@ -56,19 +56,36 @@
# endif // __LONG_LONG_SUPPORTED
#endif // __FreeBSD__
+#ifdef __NetBSD__
+# include <sys/endian.h>
+# if _BYTE_ORDER == _LITTLE_ENDIAN
+# define _LIBCPP_LITTLE_ENDIAN 1
+# define _LIBCPP_BIG_ENDIAN 0
+# else // _BYTE_ORDER == _LITTLE_ENDIAN
+# define _LIBCPP_LITTLE_ENDIAN 0
+# define _LIBCPP_BIG_ENDIAN 1
+# endif // _BYTE_ORDER == _LITTLE_ENDIAN
+# define _LIBCPP_HAS_QUICK_EXIT
+#endif // __NetBSD__
+
#ifdef _WIN32
# define _LIBCPP_LITTLE_ENDIAN 1
# define _LIBCPP_BIG_ENDIAN 0
// Compiler intrinsics (GCC or MSVC)
-# if (defined(_MSC_VER) && _MSC_VER >= 1400) \
+# if defined(__clang__) \
+ || (defined(_MSC_VER) && _MSC_VER >= 1400) \
|| (defined(__GNUC__) && _GNUC_VER > 403)
-# define _LIBCP_HAS_IS_BASE_OF
+# define _LIBCPP_HAS_IS_BASE_OF
# endif
+# if defined(_MSC_VER) && !defined(__clang__)
+# define _LIBCPP_MSVC // Using Microsoft Visual C++ compiler
+# endif
+# define _LIBCPP_MSVCRT // Using Microsoft's C Runtime library
#endif // _WIN32
#ifdef __linux__
# if defined(__GNUC__) && _GNUC_VER >= 403
-# define _LIBCP_HAS_IS_BASE_OF
+# define _LIBCPP_HAS_IS_BASE_OF
# endif
#endif
@@ -116,7 +133,7 @@
#endif
#ifndef _LIBCPP_INLINE_VISIBILITY
-# ifdef _MSC_VER
+# ifdef _LIBCPP_MSVC
# define _LIBCPP_INLINE_VISIBILITY __forceinline
# else // MinGW GCC and Clang
# define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__always_inline__))
@@ -128,13 +145,17 @@
#endif
#ifndef _LIBCPP_ALWAYS_INLINE
-# ifdef _MSC_VER
+# ifdef _LIBCPP_MSVC
# define _LIBCPP_ALWAYS_INLINE __forceinline
# endif
#endif
#endif // _WIN32
+#ifndef __has_attribute
+#define __has_attribute(__x) 0
+#endif
+
#ifndef _LIBCPP_HIDDEN
#define _LIBCPP_HIDDEN __attribute__ ((__visibility__("hidden")))
#endif
@@ -212,7 +233,9 @@ typedef __char32_t char32_t;
# define _LIBCPP_NORETURN __attribute__ ((noreturn))
#endif
+#if !(__has_feature(cxx_defaulted_functions))
#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif // !(__has_feature(cxx_defaulted_functions))
#if !(__has_feature(cxx_deleted_functions))
#define _LIBCPP_HAS_NO_DELETED_FUNCTIONS
@@ -255,7 +278,7 @@ typedef __char32_t char32_t;
#endif
#if __has_feature(is_base_of)
-# define _LIBCP_HAS_IS_BASE_OF
+# define _LIBCPP_HAS_IS_BASE_OF
#endif
// Objective-C++ features (opt-in)
@@ -272,9 +295,19 @@ typedef __char32_t char32_t;
#define _LIBCPP_HAS_NO_CONSTEXPR
#endif
-#if defined(__FreeBSD__) && (__ISO_C_VISIBLE >= 2011 || __cplusplus >= 201103L)
+#if __ISO_C_VISIBLE >= 2011 || __cplusplus >= 201103L
+#if defined(__FreeBSD__)
#define _LIBCPP_HAS_QUICK_EXIT
#define _LIBCPP_HAS_C11_FEATURES
+#elif defined(__linux__)
+#include <features.h>
+#if __GLIBC_PREREQ(2, 15)
+#define _LIBCPP_HAS_QUICK_EXIT
+#endif
+#if __GLIBC_PREREQ(2, 17)
+#define _LIBCPP_HAS_C11_FEATURES
+#endif
+#endif
#endif
#if (__has_feature(cxx_noexcept))
@@ -368,7 +401,7 @@ namespace _LIBCPP_NAMESPACE {
using namespace _LIBCPP_NAMESPACE __attribute__((__strong__));
}
-#elif defined(_MSC_VER)
+#elif defined(_LIBCPP_MSVC)
#define _LIBCPP_HAS_NO_TEMPLATE_ALIASES
#define _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
@@ -390,7 +423,7 @@ using namespace _LIBCPP_NAMESPACE __attribute__((__strong__));
namespace std {
}
-#endif // __clang__ || __GNUC___ || _MSC_VER
+#endif // __clang__ || __GNUC__ || _LIBCPP_MSVC
#ifdef _LIBCPP_HAS_NO_UNICODE_CHARS
typedef unsigned short char16_t;
@@ -418,8 +451,14 @@ template <unsigned> struct __static_assert_check {};
#define _LIBCPP_CONSTEXPR constexpr
#endif
+#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#define _LIBCPP_DEFAULT {}
+#else
+#define _LIBCPP_DEFAULT = default;
+#endif
+
#ifdef __GNUC__
-#define _NOALIAS __attribute__((malloc))
+#define _NOALIAS __attribute__((__malloc__))
#else
#define _NOALIAS
#endif
@@ -451,7 +490,7 @@ template <unsigned> struct __static_assert_check {};
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
#endif
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_WIN32) || defined(__sun__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_WIN32) || defined(__sun__) || defined(__NetBSD__)
#define _LIBCPP_LOCALE__L_EXTENSIONS 1
#endif
#ifdef __FreeBSD__
@@ -476,10 +515,18 @@ template <unsigned> struct __static_assert_check {};
# endif
#endif
-#ifdef _LIBCPP_DEBUG2
-# include <__debug>
+#ifndef _LIBCPP_STD_VER
+# if __cplusplus <= 201103L
+# define _LIBCPP_STD_VER 11
+# else
+# define _LIBCPP_STD_VER 13 // current year, or date of c++14 ratification
+# endif
+#endif // _LIBCPP_STD_VER
+
+#if _LIBCPP_STD_VER <= 11
+#define _LIBCPP_CONSTEXPR_AFTER_CXX11
#else
-# define _LIBCPP_ASSERT(x, m) ((void)0)
+#define _LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr
#endif
#endif // _LIBCPP_CONFIG
diff --git a/system/include/libcxx/__debug b/system/include/libcxx/__debug
index 0d631bf0..bac580cf 100644
--- a/system/include/libcxx/__debug
+++ b/system/include/libcxx/__debug
@@ -24,6 +24,10 @@
#if _LIBCPP_DEBUG_LEVEL >= 2
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
_LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_TYPE_VIS __c_node;
@@ -171,7 +175,7 @@ public:
bool __decrementable(const void* __i) const;
bool __addable(const void* __i, ptrdiff_t __n) const;
bool __subscriptable(const void* __i, ptrdiff_t __n) const;
- bool __comparable(const void* __i, const void* __j) const;
+ bool __less_than_comparable(const void* __i, const void* __j) const;
private:
_LIBCPP_HIDDEN
__i_node* __insert_iterator(void* __i);
diff --git a/system/include/libcxx/__functional_03 b/system/include/libcxx/__functional_03
index b52d6926..662928d8 100644
--- a/system/include/libcxx/__functional_03
+++ b/system/include/libcxx/__functional_03
@@ -102,98 +102,98 @@ mem_fn(_Rp (_Tp::* __pm)(_A0, _A1, _A2))
template<class _Rp, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)()>
+__mem_fn<_Rp (_Tp::*)() const>
mem_fn(_Rp (_Tp::* __pm)() const)
{
- return __mem_fn<_Rp (_Tp::*)()>(__pm);
+ return __mem_fn<_Rp (_Tp::*)() const>(__pm);
}
template<class _Rp, class _Tp, class _A0>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0)>
+__mem_fn<_Rp (_Tp::*)(_A0) const>
mem_fn(_Rp (_Tp::* __pm)(_A0) const)
{
- return __mem_fn<_Rp (_Tp::*)(_A0)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0) const>(__pm);
}
template<class _Rp, class _Tp, class _A0, class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0, _A1)>
+__mem_fn<_Rp (_Tp::*)(_A0, _A1) const>
mem_fn(_Rp (_Tp::* __pm)(_A0, _A1) const)
{
- return __mem_fn<_Rp (_Tp::*)(_A0, _A1)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0, _A1) const>(__pm);
}
template<class _Rp, class _Tp, class _A0, class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2)>
+__mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2) const>
mem_fn(_Rp (_Tp::* __pm)(_A0, _A1, _A2) const)
{
- return __mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2) const>(__pm);
}
template<class _Rp, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)()>
+__mem_fn<_Rp (_Tp::*)() volatile>
mem_fn(_Rp (_Tp::* __pm)() volatile)
{
- return __mem_fn<_Rp (_Tp::*)()>(__pm);
+ return __mem_fn<_Rp (_Tp::*)() volatile>(__pm);
}
template<class _Rp, class _Tp, class _A0>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0)>
+__mem_fn<_Rp (_Tp::*)(_A0) volatile>
mem_fn(_Rp (_Tp::* __pm)(_A0) volatile)
{
- return __mem_fn<_Rp (_Tp::*)(_A0)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0) volatile>(__pm);
}
template<class _Rp, class _Tp, class _A0, class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0, _A1)>
+__mem_fn<_Rp (_Tp::*)(_A0, _A1) volatile>
mem_fn(_Rp (_Tp::* __pm)(_A0, _A1) volatile)
{
- return __mem_fn<_Rp (_Tp::*)(_A0, _A1)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0, _A1) volatile>(__pm);
}
template<class _Rp, class _Tp, class _A0, class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2)>
+__mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2) volatile>
mem_fn(_Rp (_Tp::* __pm)(_A0, _A1, _A2) volatile)
{
- return __mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2) volatile>(__pm);
}
template<class _Rp, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)()>
+__mem_fn<_Rp (_Tp::*)() const volatile>
mem_fn(_Rp (_Tp::* __pm)() const volatile)
{
- return __mem_fn<_Rp (_Tp::*)()>(__pm);
+ return __mem_fn<_Rp (_Tp::*)() const volatile>(__pm);
}
template<class _Rp, class _Tp, class _A0>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0)>
+__mem_fn<_Rp (_Tp::*)(_A0) const volatile>
mem_fn(_Rp (_Tp::* __pm)(_A0) const volatile)
{
- return __mem_fn<_Rp (_Tp::*)(_A0)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0) const volatile>(__pm);
}
template<class _Rp, class _Tp, class _A0, class _A1>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0, _A1)>
+__mem_fn<_Rp (_Tp::*)(_A0, _A1) const volatile>
mem_fn(_Rp (_Tp::* __pm)(_A0, _A1) const volatile)
{
- return __mem_fn<_Rp (_Tp::*)(_A0, _A1)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0, _A1) const volatile>(__pm);
}
template<class _Rp, class _Tp, class _A0, class _A1, class _A2>
inline _LIBCPP_INLINE_VISIBILITY
-__mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2)>
+__mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2) const volatile>
mem_fn(_Rp (_Tp::* __pm)(_A0, _A1, _A2) const volatile)
{
- return __mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2)>(__pm);
+ return __mem_fn<_Rp (_Tp::*)(_A0, _A1, _A2) const volatile>(__pm);
}
// bad_function_call
diff --git a/system/include/libcxx/__functional_base b/system/include/libcxx/__functional_base
index 40a63a85..2bc2d2c1 100644
--- a/system/include/libcxx/__functional_base
+++ b/system/include/libcxx/__functional_base
@@ -50,13 +50,27 @@ public:
static const bool value = sizeof(__test<_Tp>(0)) == 1;
};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS less : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x < __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS less<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) < _VSTD::forward<_T2>(__u); }
+};
+#endif
+
#ifdef _LIBCPP_HAS_NO_VARIADICS
#include <__functional_base_03>
@@ -292,7 +306,8 @@ struct __weak_result_type<_Rp (_Cp::*)(_A1, _A2, _A3...) const volatile>
// bullets 1 and 2
-template <class _Fp, class _A0, class ..._Args>
+template <class _Fp, class _A0, class ..._Args,
+ class>
inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
@@ -301,7 +316,8 @@ __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
return (_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...);
}
-template <class _Fp, class _A0, class ..._Args>
+template <class _Fp, class _A0, class ..._Args,
+ class>
inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
@@ -312,7 +328,8 @@ __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
// bullets 3 and 4
-template <class _Fp, class _A0>
+template <class _Fp, class _A0,
+ class>
inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0)
@@ -321,7 +338,8 @@ __invoke(_Fp&& __f, _A0&& __a0)
return _VSTD::forward<_A0>(__a0).*__f;
}
-template <class _Fp, class _A0>
+template <class _Fp, class _A0,
+ class>
inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0)
diff --git a/system/include/libcxx/__hash_table b/system/include/libcxx/__hash_table
index 6f6050d3..6157fcd9 100644
--- a/system/include/libcxx/__hash_table
+++ b/system/include/libcxx/__hash_table
@@ -20,6 +20,12 @@
#include <__undef_min_max>
+#ifdef _LIBCPP_DEBUG2
+# include <__debug>
+#else
+# define _LIBCPP_ASSERT(x, m) ((void)0)
+#endif
+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
@@ -33,7 +39,6 @@ template <class _NodePtr>
struct __hash_node_base
{
typedef __hash_node_base __first_node;
- // typedef _NodePtr pointer;
_NodePtr __next_;
@@ -106,16 +111,70 @@ public:
#endif
pointer;
- _LIBCPP_INLINE_VISIBILITY __hash_iterator() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY __hash_iterator() _NOEXCEPT
+#if _LIBCPP_STD_VER > 11
+ : __node_(nullptr)
+#endif
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_i(this);
+#endif
+ }
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_iterator(const __hash_iterator& __i)
+ : __node_(__i.__node_)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ ~__hash_iterator()
+ {
+ __get_db()->__erase_i(this);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_iterator& operator=(const __hash_iterator& __i)
+ {
+ if (this != &__i)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ __node_ = __i.__node_;
+ }
+ return *this;
+ }
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return __node_->__value_;}
+ reference operator*() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container iterator");
+#endif
+ return __node_->__value_;
+ }
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return _VSTD::addressof(__node_->__value_);}
+ pointer operator->() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container iterator");
+#endif
+ return pointer_traits<pointer>::pointer_to(__node_->__value_);
+ }
_LIBCPP_INLINE_VISIBILITY
__hash_iterator& operator++()
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to increment non-incrementable unordered container iterator");
+#endif
__node_ = __node_->__next_;
return *this;
}
@@ -130,16 +189,27 @@ public:
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(const __hash_iterator& __x, const __hash_iterator& __y)
- {return __x.__node_ == __y.__node_;}
+ {
+ return __x.__node_ == __y.__node_;
+ }
friend _LIBCPP_INLINE_VISIBILITY
bool operator!=(const __hash_iterator& __x, const __hash_iterator& __y)
- {return __x.__node_ != __y.__node_;}
+ {return !(__x == __y);}
private:
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_iterator(__node_pointer __node, const void* __c) _NOEXCEPT
+ : __node_(__node)
+ {
+ __get_db()->__insert_ic(this, __c);
+ }
+#else
_LIBCPP_INLINE_VISIBILITY
__hash_iterator(__node_pointer __node) _NOEXCEPT
: __node_(__node)
{}
+#endif
template <class, class, class, class> friend class __hash_table;
template <class> friend class _LIBCPP_TYPE_VIS __hash_const_iterator;
@@ -180,20 +250,78 @@ public:
__non_const_node_pointer;
typedef __hash_iterator<__non_const_node_pointer> __non_const_iterator;
- _LIBCPP_INLINE_VISIBILITY __hash_const_iterator() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY __hash_const_iterator() _NOEXCEPT
+#if _LIBCPP_STD_VER > 11
+ : __node_(nullptr)
+#endif
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_i(this);
+#endif
+ }
_LIBCPP_INLINE_VISIBILITY
__hash_const_iterator(const __non_const_iterator& __x) _NOEXCEPT
: __node_(__x.__node_)
- {}
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__iterator_copy(this, &__x);
+#endif
+ }
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return __node_->__value_;}
+ __hash_const_iterator(const __hash_const_iterator& __i)
+ : __node_(__i.__node_)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ ~__hash_const_iterator()
+ {
+ __get_db()->__erase_i(this);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_const_iterator& operator=(const __hash_const_iterator& __i)
+ {
+ if (this != &__i)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ __node_ = __i.__node_;
+ }
+ return *this;
+ }
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
+ _LIBCPP_INLINE_VISIBILITY
+ reference operator*() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container const_iterator");
+#endif
+ return __node_->__value_;
+ }
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return _VSTD::addressof(__node_->__value_);}
+ pointer operator->() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container const_iterator");
+#endif
+ return pointer_traits<pointer>::pointer_to(__node_->__value_);
+ }
_LIBCPP_INLINE_VISIBILITY
__hash_const_iterator& operator++()
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to increment non-incrementable unordered container const_iterator");
+#endif
__node_ = __node_->__next_;
return *this;
}
@@ -208,16 +336,27 @@ public:
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(const __hash_const_iterator& __x, const __hash_const_iterator& __y)
- {return __x.__node_ == __y.__node_;}
+ {
+ return __x.__node_ == __y.__node_;
+ }
friend _LIBCPP_INLINE_VISIBILITY
bool operator!=(const __hash_const_iterator& __x, const __hash_const_iterator& __y)
- {return __x.__node_ != __y.__node_;}
+ {return !(__x == __y);}
private:
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_const_iterator(__node_pointer __node, const void* __c) _NOEXCEPT
+ : __node_(__node)
+ {
+ __get_db()->__insert_ic(this, __c);
+ }
+#else
_LIBCPP_INLINE_VISIBILITY
__hash_const_iterator(__node_pointer __node) _NOEXCEPT
: __node_(__node)
{}
+#endif
template <class, class, class, class> friend class __hash_table;
template <class> friend class _LIBCPP_TYPE_VIS __hash_map_const_iterator;
@@ -250,16 +389,71 @@ public:
#endif
pointer;
- _LIBCPP_INLINE_VISIBILITY __hash_local_iterator() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY __hash_local_iterator() _NOEXCEPT
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_i(this);
+#endif
+ }
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_local_iterator(const __hash_local_iterator& __i)
+ : __node_(__i.__node_),
+ __bucket_(__i.__bucket_),
+ __bucket_count_(__i.__bucket_count_)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ }
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return __node_->__value_;}
+ ~__hash_local_iterator()
+ {
+ __get_db()->__erase_i(this);
+ }
+
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return &__node_->__value_;}
+ __hash_local_iterator& operator=(const __hash_local_iterator& __i)
+ {
+ if (this != &__i)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ __node_ = __i.__node_;
+ __bucket_ = __i.__bucket_;
+ __bucket_count_ = __i.__bucket_count_;
+ }
+ return *this;
+ }
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
+ _LIBCPP_INLINE_VISIBILITY
+ reference operator*() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container local_iterator");
+#endif
+ return __node_->__value_;
+ }
+ _LIBCPP_INLINE_VISIBILITY
+ pointer operator->() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container local_iterator");
+#endif
+ return pointer_traits<pointer>::pointer_to(__node_->__value_);
+ }
_LIBCPP_INLINE_VISIBILITY
__hash_local_iterator& operator++()
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to increment non-incrementable unordered container local_iterator");
+#endif
__node_ = __node_->__next_;
if (__node_ != nullptr && __constrain_hash(__node_->__hash_, __bucket_count_) != __bucket_)
__node_ = nullptr;
@@ -276,12 +470,27 @@ public:
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(const __hash_local_iterator& __x, const __hash_local_iterator& __y)
- {return __x.__node_ == __y.__node_;}
+ {
+ return __x.__node_ == __y.__node_;
+ }
friend _LIBCPP_INLINE_VISIBILITY
bool operator!=(const __hash_local_iterator& __x, const __hash_local_iterator& __y)
- {return __x.__node_ != __y.__node_;}
+ {return !(__x == __y);}
private:
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_local_iterator(__node_pointer __node, size_t __bucket,
+ size_t __bucket_count, const void* __c) _NOEXCEPT
+ : __node_(__node),
+ __bucket_(__bucket),
+ __bucket_count_(__bucket_count)
+ {
+ __get_db()->__insert_ic(this, __c);
+ if (__node_ != nullptr)
+ __node_ = __node_->__next_;
+ }
+#else
_LIBCPP_INLINE_VISIBILITY
__hash_local_iterator(__node_pointer __node, size_t __bucket,
size_t __bucket_count) _NOEXCEPT
@@ -292,7 +501,7 @@ private:
if (__node_ != nullptr)
__node_ = __node_->__next_;
}
-
+#endif
template <class, class, class, class> friend class __hash_table;
template <class> friend class _LIBCPP_TYPE_VIS __hash_const_local_iterator;
template <class> friend class _LIBCPP_TYPE_VIS __hash_map_iterator;
@@ -334,22 +543,82 @@ public:
#endif
pointer;
- _LIBCPP_INLINE_VISIBILITY __hash_const_local_iterator() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY __hash_const_local_iterator() _NOEXCEPT
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_i(this);
+#endif
+ }
+
_LIBCPP_INLINE_VISIBILITY
__hash_const_local_iterator(const __non_const_iterator& __x) _NOEXCEPT
: __node_(__x.__node_),
__bucket_(__x.__bucket_),
__bucket_count_(__x.__bucket_count_)
- {}
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__iterator_copy(this, &__x);
+#endif
+ }
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_const_local_iterator(const __hash_const_local_iterator& __i)
+ : __node_(__i.__node_),
+ __bucket_(__i.__bucket_),
+ __bucket_count_(__i.__bucket_count_)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ ~__hash_const_local_iterator()
+ {
+ __get_db()->__erase_i(this);
+ }
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return __node_->__value_;}
+ __hash_const_local_iterator& operator=(const __hash_const_local_iterator& __i)
+ {
+ if (this != &__i)
+ {
+ __get_db()->__iterator_copy(this, &__i);
+ __node_ = __i.__node_;
+ __bucket_ = __i.__bucket_;
+ __bucket_count_ = __i.__bucket_count_;
+ }
+ return *this;
+ }
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
+ _LIBCPP_INLINE_VISIBILITY
+ reference operator*() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container const_local_iterator");
+#endif
+ return __node_->__value_;
+ }
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return &__node_->__value_;}
+ pointer operator->() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable unordered container const_local_iterator");
+#endif
+ return pointer_traits<pointer>::pointer_to(__node_->__value_);
+ }
_LIBCPP_INLINE_VISIBILITY
__hash_const_local_iterator& operator++()
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to increment non-incrementable unordered container const_local_iterator");
+#endif
__node_ = __node_->__next_;
if (__node_ != nullptr && __constrain_hash(__node_->__hash_, __bucket_count_) != __bucket_)
__node_ = nullptr;
@@ -366,12 +635,27 @@ public:
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y)
- {return __x.__node_ == __y.__node_;}
+ {
+ return __x.__node_ == __y.__node_;
+ }
friend _LIBCPP_INLINE_VISIBILITY
bool operator!=(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y)
- {return __x.__node_ != __y.__node_;}
+ {return !(__x == __y);}
private:
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_INLINE_VISIBILITY
+ __hash_const_local_iterator(__node_pointer __node, size_t __bucket,
+ size_t __bucket_count, const void* __c) _NOEXCEPT
+ : __node_(__node),
+ __bucket_(__bucket),
+ __bucket_count_(__bucket_count)
+ {
+ __get_db()->__insert_ic(this, __c);
+ if (__node_ != nullptr)
+ __node_ = __node_->__next_;
+ }
+#else
_LIBCPP_INLINE_VISIBILITY
__hash_const_local_iterator(__node_pointer __node, size_t __bucket,
size_t __bucket_count) _NOEXCEPT
@@ -382,7 +666,7 @@ private:
if (__node_ != nullptr)
__node_ = __node_->__next_;
}
-
+#endif
template <class, class, class, class> friend class __hash_table;
template <class> friend class _LIBCPP_TYPE_VIS __hash_map_const_iterator;
};
@@ -505,8 +789,15 @@ public:
__node_allocator;
typedef allocator_traits<__node_allocator> __node_traits;
typedef typename __node_traits::pointer __node_pointer;
- typedef typename __node_traits::const_pointer __node_const_pointer;
+ typedef typename __node_traits::pointer __node_const_pointer;
typedef __hash_node_base<__node_pointer> __first_node;
+ typedef typename pointer_traits<__node_pointer>::template
+#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
+ rebind<__first_node>
+#else
+ rebind<__first_node>::other
+#endif
+ __node_base_pointer;
private:
@@ -558,9 +849,9 @@ public:
public:
typedef __hash_iterator<__node_pointer> iterator;
- typedef __hash_const_iterator<__node_const_pointer> const_iterator;
+ typedef __hash_const_iterator<__node_pointer> const_iterator;
typedef __hash_local_iterator<__node_pointer> local_iterator;
- typedef __hash_const_local_iterator<__node_const_pointer> const_local_iterator;
+ typedef __hash_const_local_iterator<__node_pointer> const_local_iterator;
__hash_table()
_NOEXCEPT_(
@@ -658,7 +949,11 @@ public:
template <class _Key>
_LIBCPP_INLINE_VISIBILITY
size_type bucket(const _Key& __k) const
- {return __constrain_hash(hash_function()(__k), bucket_count());}
+ {
+ _LIBCPP_ASSERT(bucket_count() > 0,
+ "unordered container::bucket(key) called when bucket_count() == 0");
+ return __constrain_hash(hash_function()(__k), bucket_count());
+ }
template <class _Key>
iterator find(const _Key& __x);
@@ -706,7 +1001,7 @@ public:
_LIBCPP_INLINE_VISIBILITY
size_type max_bucket_count() const _NOEXCEPT
- {return __bucket_list_.get_deleter().__alloc().max_size();}
+ {return __pointer_alloc_traits::max_size(__bucket_list_.get_deleter().__alloc());}
size_type bucket_size(size_type __n) const;
_LIBCPP_INLINE_VISIBILITY float load_factor() const _NOEXCEPT
{
@@ -714,16 +1009,73 @@ public:
return __bc != 0 ? (float)size() / __bc : 0.f;
}
_LIBCPP_INLINE_VISIBILITY void max_load_factor(float __mlf) _NOEXCEPT
- {max_load_factor() = _VSTD::max(__mlf, load_factor());}
-
- _LIBCPP_INLINE_VISIBILITY local_iterator begin(size_type __n)
- {return local_iterator(__bucket_list_[__n], __n, bucket_count());}
- _LIBCPP_INLINE_VISIBILITY local_iterator end(size_type __n)
- {return local_iterator(nullptr, __n, bucket_count());}
- _LIBCPP_INLINE_VISIBILITY const_local_iterator cbegin(size_type __n) const
- {return const_local_iterator(__bucket_list_[__n], __n, bucket_count());}
- _LIBCPP_INLINE_VISIBILITY const_local_iterator cend(size_type __n) const
- {return const_local_iterator(nullptr, __n, bucket_count());}
+ {
+ _LIBCPP_ASSERT(__mlf > 0,
+ "unordered container::max_load_factor(lf) called with lf <= 0");
+ max_load_factor() = _VSTD::max(__mlf, load_factor());
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ local_iterator
+ begin(size_type __n)
+ {
+ _LIBCPP_ASSERT(__n < bucket_count(),
+ "unordered container::begin(n) called with n >= bucket_count()");
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return local_iterator(__bucket_list_[__n], __n, bucket_count(), this);
+#else
+ return local_iterator(__bucket_list_[__n], __n, bucket_count());
+#endif
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ local_iterator
+ end(size_type __n)
+ {
+ _LIBCPP_ASSERT(__n < bucket_count(),
+ "unordered container::end(n) called with n >= bucket_count()");
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return local_iterator(nullptr, __n, bucket_count(), this);
+#else
+ return local_iterator(nullptr, __n, bucket_count());
+#endif
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ const_local_iterator
+ cbegin(size_type __n) const
+ {
+ _LIBCPP_ASSERT(__n < bucket_count(),
+ "unordered container::cbegin(n) called with n >= bucket_count()");
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return const_local_iterator(__bucket_list_[__n], __n, bucket_count(), this);
+#else
+ return const_local_iterator(__bucket_list_[__n], __n, bucket_count());
+#endif
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ const_local_iterator
+ cend(size_type __n) const
+ {
+ _LIBCPP_ASSERT(__n < bucket_count(),
+ "unordered container::cend(n) called with n >= bucket_count()");
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return const_local_iterator(nullptr, __n, bucket_count(), this);
+#else
+ return const_local_iterator(nullptr, __n, bucket_count());
+#endif
+ }
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ bool __dereferenceable(const const_iterator* __i) const;
+ bool __decrementable(const const_iterator* __i) const;
+ bool __addable(const const_iterator* __i, ptrdiff_t __n) const;
+ bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const;
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
private:
void __rehash(size_type __n);
@@ -807,6 +1159,9 @@ private:
void __deallocate(__node_pointer __np) _NOEXCEPT;
__node_pointer __detach() _NOEXCEPT;
+
+ template <class, class, class, class, class> friend class _LIBCPP_TYPE_VIS unordered_map;
+ template <class, class, class, class, class> friend class _LIBCPP_TYPE_VIS unordered_multimap;
};
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -893,7 +1248,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u)
if (size() > 0)
{
__bucket_list_[__constrain_hash(__p1_.first().__next_->__hash_, bucket_count())] =
- static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
__u.__p1_.first().__next_ = nullptr;
__u.size() = 0;
}
@@ -917,7 +1272,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u,
__p1_.first().__next_ = __u.__p1_.first().__next_;
__u.__p1_.first().__next_ = nullptr;
__bucket_list_[__constrain_hash(__p1_.first().__next_->__hash_, bucket_count())] =
- static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
size() = __u.size();
__u.size() = 0;
}
@@ -930,6 +1285,9 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
__hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()
{
__deallocate(__p1_.first().__next_);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__erase_c(this);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -971,6 +1329,21 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate(__node_pointer __np)
while (__np != nullptr)
{
__node_pointer __next = __np->__next_;
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __c_node* __c = __get_db()->__find_c_and_lock(this);
+ for (__i_node** __p = __c->end_; __p != __c->beg_; )
+ {
+ --__p;
+ iterator* __i = static_cast<iterator*>((*__p)->__i_);
+ if (__i->__node_ == __np)
+ {
+ (*__p)->__c_ = nullptr;
+ if (--__c->end_ != __p)
+ memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*));
+ }
+ }
+ __get_db()->unlock();
+#endif
__node_traits::destroy(__na, _VSTD::addressof(__np->__value_));
__node_traits::deallocate(__na, __np, 1);
__np = __next;
@@ -1014,10 +1387,13 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
if (size() > 0)
{
__bucket_list_[__constrain_hash(__p1_.first().__next_->__hash_, bucket_count())] =
- static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
__u.__p1_.first().__next_ = nullptr;
__u.size() = 0;
}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->swap(this, &__u);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1158,7 +1534,11 @@ inline _LIBCPP_INLINE_VISIBILITY
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() _NOEXCEPT
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(__p1_.first().__next_, this);
+#else
return iterator(__p1_.first().__next_);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1166,7 +1546,11 @@ inline _LIBCPP_INLINE_VISIBILITY
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(nullptr, this);
+#else
return iterator(nullptr);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1174,7 +1558,11 @@ inline _LIBCPP_INLINE_VISIBILITY
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const _NOEXCEPT
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return const_iterator(__p1_.first().__next_, this);
+#else
return const_iterator(__p1_.first().__next_);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1182,7 +1570,11 @@ inline _LIBCPP_INLINE_VISIBILITY
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return const_iterator(nullptr, this);
+#else
return const_iterator(nullptr);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1236,7 +1628,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique(__node_pointer __
__node_pointer __pn = __bucket_list_[__chash];
if (__pn == nullptr)
{
- __pn = static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ __pn = static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
__nd->__next_ = __pn->__next_;
__pn->__next_ = __nd;
// fix up __bucket_list_
@@ -1255,7 +1647,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique(__node_pointer __
__inserted = true;
}
__done:
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return pair<iterator, bool>(iterator(__ndptr, this), __inserted);
+#else
return pair<iterator, bool>(iterator(__ndptr), __inserted);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1274,7 +1670,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(__node_pointer __c
__node_pointer __pn = __bucket_list_[__chash];
if (__pn == nullptr)
{
- __pn = static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ __pn = static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
__cp->__next_ = __pn->__next_;
__pn->__next_ = __cp;
// fix up __bucket_list_
@@ -1312,7 +1708,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(__node_pointer __c
}
}
++size();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(__cp, this);
+#else
return iterator(__cp);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1320,9 +1720,14 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(
const_iterator __p, __node_pointer __cp)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered container::emplace_hint(const_iterator, args...) called with an iterator not"
+ " referring to this unordered container");
+#endif
if (__p != end() && key_eq()(*__p, __cp->__value_))
{
- __node_pointer __np = const_cast<__node_pointer>(__p.__node_);
+ __node_pointer __np = __p.__node_;
__cp->__hash_ = __np->__hash_;
size_type __bc = bucket_count();
if (size()+1 > __bc * max_load_factor() || __bc == 0)
@@ -1338,7 +1743,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(
__cp->__next_ = __np;
__pp->__next_ = __cp;
++size();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(__cp, this);
+#else
return iterator(__cp);
+#endif
}
return __node_insert_multi(__cp);
}
@@ -1380,7 +1789,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(const value_type& __x)
__node_pointer __pn = __bucket_list_[__chash];
if (__pn == nullptr)
{
- __pn = static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ __pn = static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
__h->__next_ = __pn->__next_;
__pn->__next_ = __h.get();
// fix up __bucket_list_
@@ -1399,7 +1808,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(const value_type& __x)
__inserted = true;
}
__done:
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return pair<iterator, bool>(iterator(__nd, this), __inserted);
+#else
return pair<iterator, bool>(iterator(__nd), __inserted);
+#endif
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1434,6 +1847,11 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_hint_multi(
const_iterator __p, _Args&&... __args)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered container::emplace_hint(const_iterator, args...) called with an iterator not"
+ " referring to this unordered container");
+#endif
__node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
iterator __r = __node_insert_multi(__p, __h.get());
__h.release();
@@ -1475,6 +1893,11 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
_Pp&& __x)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered container::insert(const_iterator, rvalue) called with an iterator not"
+ " referring to this unordered container");
+#endif
__node_holder __h = __construct_node(_VSTD::forward<_Pp>(__x));
iterator __r = __node_insert_multi(__p, __h.get());
__h.release();
@@ -1498,6 +1921,11 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
const value_type& __x)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered container::insert(const_iterator, lvalue) called with an iterator not"
+ " referring to this unordered container");
+#endif
__node_holder __h = __construct_node(__x);
iterator __r = __node_insert_multi(__p, __h.get());
__h.release();
@@ -1534,6 +1962,9 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
void
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__invalidate_all(this);
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
__pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();
__bucket_list_.reset(__nbc > 0 ?
__pointer_alloc_traits::allocate(__npa, __nbc) : nullptr);
@@ -1542,7 +1973,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)
{
for (size_type __i = 0; __i < __nbc; ++__i)
__bucket_list_[__i] = nullptr;
- __node_pointer __pp(static_cast<__node_pointer>(_VSTD::addressof(__p1_.first())));
+ __node_pointer __pp(static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first())));
__node_pointer __cp = __pp->__next_;
if (__cp != nullptr)
{
@@ -1599,7 +2030,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k)
__nd = __nd->__next_)
{
if (key_eq()(__nd->__value_, __k))
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(__nd, this);
+#else
return iterator(__nd);
+#endif
}
}
}
@@ -1624,7 +2059,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const
__nd = __nd->__next_)
{
if (key_eq()(__nd->__value_, __k))
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return const_iterator(__nd, this);
+#else
return const_iterator(__nd);
+#endif
}
}
@@ -1700,8 +2139,17 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p)
{
- __node_pointer __np = const_cast<__node_pointer>(__p.__node_);
+ __node_pointer __np = __p.__node_;
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered container erase(iterator) called with an iterator not"
+ " referring to this container");
+ _LIBCPP_ASSERT(__p != end(),
+ "unordered container erase(iterator) called with a non-dereferenceable iterator");
+ iterator __r(__np, this);
+#else
iterator __r(__np);
+#endif
++__r;
remove(__p);
return __r;
@@ -1712,13 +2160,25 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first,
const_iterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__first) == this,
+ "unodered container::erase(iterator, iterator) called with an iterator not"
+ " referring to this unodered container");
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__last) == this,
+ "unodered container::erase(iterator, iterator) called with an iterator not"
+ " referring to this unodered container");
+#endif
for (const_iterator __p = __first; __first != __last; __p = __first)
{
++__first;
erase(__p);
}
- __node_pointer __np = const_cast<__node_pointer>(__last.__node_);
+ __node_pointer __np = __last.__node_;
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator (__np, this);
+#else
return iterator (__np);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1757,7 +2217,7 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
__hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT
{
// current node
- __node_pointer __cn = const_cast<__node_pointer>(__p.__node_);
+ __node_pointer __cn = __p.__node_;
size_type __bc = bucket_count();
size_t __chash = __constrain_hash(__cn->__hash_, __bc);
// find previous node
@@ -1767,7 +2227,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT
// Fix up __bucket_list_
// if __pn is not in same bucket (before begin is not in same bucket) &&
// if __cn->__next_ is not in same bucket (nullptr is not in same bucket)
- if (__pn == _VSTD::addressof(__p1_.first()) || __constrain_hash(__pn->__hash_, __bc) != __chash)
+ if (__pn == static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()))
+ || __constrain_hash(__pn->__hash_, __bc) != __chash)
{
if (__cn->__next_ == nullptr || __constrain_hash(__cn->__next_->__hash_, __bc) != __chash)
__bucket_list_[__chash] = nullptr;
@@ -1783,6 +2244,21 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT
__pn->__next_ = __cn->__next_;
__cn->__next_ = nullptr;
--size();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __c_node* __c = __get_db()->__find_c_and_lock(this);
+ for (__i_node** __p = __c->end_; __p != __c->beg_; )
+ {
+ --__p;
+ iterator* __i = static_cast<iterator*>((*__p)->__i_);
+ if (__i->__node_ == __cn)
+ {
+ (*__p)->__c_ = nullptr;
+ if (--__c->end_ != __p)
+ memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*));
+ }
+ }
+ __get_db()->unlock();
+#endif
return __node_holder(__cn, _Dp(__node_alloc(), true));
}
@@ -1907,16 +2383,21 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
__p3_.swap(__u.__p3_);
if (size() > 0)
__bucket_list_[__constrain_hash(__p1_.first().__next_->__hash_, bucket_count())] =
- static_cast<__node_pointer>(_VSTD::addressof(__p1_.first()));
+ static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__p1_.first()));
if (__u.size() > 0)
__u.__bucket_list_[__constrain_hash(__u.__p1_.first().__next_->__hash_, __u.bucket_count())] =
- static_cast<__node_pointer>(_VSTD::addressof(__u.__p1_.first()));
+ static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(__u.__p1_.first()));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->swap(this, &__u);
+#endif
}
template <class _Tp, class _Hash, class _Equal, class _Alloc>
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
__hash_table<_Tp, _Hash, _Equal, _Alloc>::bucket_size(size_type __n) const
{
+ _LIBCPP_ASSERT(__n < bucket_count(),
+ "unordered container::bucket_size(n) called with n >= bucket_count()");
__node_const_pointer __np = __bucket_list_[__n];
size_type __bc = bucket_count();
size_type __r = 0;
@@ -1940,6 +2421,37 @@ swap(__hash_table<_Tp, _Hash, _Equal, _Alloc>& __x,
__x.swap(__y);
}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+template <class _Tp, class _Hash, class _Equal, class _Alloc>
+bool
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__dereferenceable(const const_iterator* __i) const
+{
+ return __i->__node_ != nullptr;
+}
+
+template <class _Tp, class _Hash, class _Equal, class _Alloc>
+bool
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__decrementable(const const_iterator*) const
+{
+ return false;
+}
+
+template <class _Tp, class _Hash, class _Equal, class _Alloc>
+bool
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__addable(const const_iterator*, ptrdiff_t) const
+{
+ return false;
+}
+
+template <class _Tp, class _Hash, class _Equal, class _Alloc>
+bool
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__subscriptable(const const_iterator*, ptrdiff_t) const
+{
+ return false;
+}
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP__HASH_TABLE
diff --git a/system/include/libcxx/__locale b/system/include/libcxx/__locale
index 24d565b6..93147ec0 100644
--- a/system/include/libcxx/__locale
+++ b/system/include/libcxx/__locale
@@ -19,7 +19,7 @@
#include <cstdint>
#include <cctype>
#include <locale.h>
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
# include <support/win32/locale_win32.h>
#elif (defined(__GLIBC__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun__)) || defined(EMSCRIPTEN)
# include <xlocale.h>
@@ -339,12 +339,12 @@ public:
static const mask punct = _PUNCT;
static const mask xdigit = _HEX;
static const mask blank = _BLANK;
-#elif (defined(__APPLE__) || defined(__FreeBSD__)) || defined(EMSCRIPTEN)
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(EMSCRIPTEN) || defined(__NetBSD__)
#ifdef __APPLE__
typedef __uint32_t mask;
#elif defined(__FreeBSD__)
typedef unsigned long mask;
-#elif defined(EMSCRIPTEN)
+#elif defined(EMSCRIPTEN) || defined(__NetBSD__)
typedef unsigned short mask;
#endif
static const mask space = _CTYPE_S;
@@ -356,7 +356,11 @@ public:
static const mask digit = _CTYPE_D;
static const mask punct = _CTYPE_P;
static const mask xdigit = _CTYPE_X;
+# if defined(__NetBSD__)
+ static const mask blank = _CTYPE_BL;
+# else
static const mask blank = _CTYPE_B;
+# endif
#elif defined(__sun__)
typedef unsigned int mask;
static const mask space = _ISSPACE;
@@ -596,6 +600,10 @@ public:
static const int* __classic_upper_table() _NOEXCEPT;
static const int* __classic_lower_table() _NOEXCEPT;
#endif
+#if defined(__NetBSD__)
+ static const short* __classic_upper_table() _NOEXCEPT;
+ static const short* __classic_lower_table() _NOEXCEPT;
+#endif
protected:
~ctype();
diff --git a/system/include/libcxx/__split_buffer b/system/include/libcxx/__split_buffer
index e0aa13b8..f1c404f7 100644
--- a/system/include/libcxx/__split_buffer
+++ b/system/include/libcxx/__split_buffer
@@ -290,7 +290,7 @@ void
__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type)
{
while (__begin_ != __new_begin)
- __alloc_traits::destroy(__alloc(), __begin_++);
+ __alloc_traits::destroy(__alloc(), __to_raw_pointer(__begin_++));
}
template <class _Tp, class _Allocator>
@@ -307,7 +307,7 @@ void
__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT
{
while (__new_last != __end_)
- __alloc_traits::destroy(__alloc(), --__end_);
+ __alloc_traits::destroy(__alloc(), __to_raw_pointer(--__end_));
}
template <class _Tp, class _Allocator>
@@ -320,7 +320,7 @@ __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type
template <class _Tp, class _Allocator>
__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
- : __end_cap_(0, __a)
+ : __end_cap_(nullptr, __a)
{
__first_ = __cap != 0 ? __alloc_traits::allocate(__alloc(), __cap) : nullptr;
__begin_ = __end_ = __first_ + __start;
@@ -331,21 +331,21 @@ template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
__split_buffer<_Tp, _Allocator>::__split_buffer()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __first_(0), __begin_(0), __end_(0), __end_cap_(0)
+ : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr)
{
}
template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
__split_buffer<_Tp, _Allocator>::__split_buffer(__alloc_rr& __a)
- : __first_(0), __begin_(0), __end_(0), __end_cap_(0, __a)
+ : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a)
{
}
template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
__split_buffer<_Tp, _Allocator>::__split_buffer(const __alloc_rr& __a)
- : __first_(0), __begin_(0), __end_(0), __end_cap_(0, __a)
+ : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a)
{
}
diff --git a/system/include/libcxx/__std_stream b/system/include/libcxx/__std_stream
index 8ca413eb..cff43317 100644
--- a/system/include/libcxx/__std_stream
+++ b/system/include/libcxx/__std_stream
@@ -55,6 +55,8 @@ private:
const codecvt<char_type, char, state_type>* __cv_;
state_type* __st_;
int __encoding_;
+ int_type __last_consumed_;
+ bool __last_consumed_is_next_;
bool __always_noconv_;
__stdinbuf(const __stdinbuf&);
@@ -66,7 +68,9 @@ private:
template <class _CharT>
__stdinbuf<_CharT>::__stdinbuf(FILE* __fp, state_type* __st)
: __file_(__fp),
- __st_(__st)
+ __st_(__st),
+ __last_consumed_(traits_type::eof()),
+ __last_consumed_is_next_(false)
{
imbue(this->getloc());
}
@@ -100,6 +104,16 @@ template <class _CharT>
typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::__getchar(bool __consume)
{
+ if (__last_consumed_is_next_)
+ {
+ int_type __result = __last_consumed_;
+ if (__consume)
+ {
+ __last_consumed_ = traits_type::eof();
+ __last_consumed_is_next_ = false;
+ }
+ return __result;
+ }
char __extbuf[__limit];
int __nread = _VSTD::max(1, __encoding_);
for (int __i = 0; __i < __nread; ++__i)
@@ -154,6 +168,8 @@ __stdinbuf<_CharT>::__getchar(bool __consume)
return traits_type::eof();
}
}
+ else
+ __last_consumed_ = traits_type::to_int_type(__1buf);
return traits_type::to_int_type(__1buf);
}
@@ -162,28 +178,41 @@ typename __stdinbuf<_CharT>::int_type
__stdinbuf<_CharT>::pbackfail(int_type __c)
{
if (traits_type::eq_int_type(__c, traits_type::eof()))
- return __c;
- char __extbuf[__limit];
- char* __enxt;
- const char_type __ci = traits_type::to_char_type(__c);
- const char_type* __inxt;
- switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
- __extbuf, __extbuf + sizeof(__extbuf), __enxt))
{
- case _VSTD::codecvt_base::ok:
- break;
- case _VSTD::codecvt_base::noconv:
- __extbuf[0] = static_cast<char>(__c);
- __enxt = __extbuf + 1;
- break;
- case codecvt_base::partial:
- case codecvt_base::error:
- return traits_type::eof();
+ if (!__last_consumed_is_next_)
+ {
+ __c = __last_consumed_;
+ __last_consumed_is_next_ = !traits_type::eq_int_type(__last_consumed_,
+ traits_type::eof());
+ }
+ return __c;
}
- while (__enxt > __extbuf)
- if (ungetc(*--__enxt, __file_) == EOF)
+ if (__last_consumed_is_next_)
+ {
+ char __extbuf[__limit];
+ char* __enxt;
+ const char_type __ci = traits_type::to_char_type(__last_consumed_);
+ const char_type* __inxt;
+ switch (__cv_->out(*__st_, &__ci, &__ci + 1, __inxt,
+ __extbuf, __extbuf + sizeof(__extbuf), __enxt))
+ {
+ case _VSTD::codecvt_base::ok:
+ break;
+ case _VSTD::codecvt_base::noconv:
+ __extbuf[0] = static_cast<char>(__last_consumed_);
+ __enxt = __extbuf + 1;
+ break;
+ case codecvt_base::partial:
+ case codecvt_base::error:
return traits_type::eof();
- return traits_type::not_eof(__c);
+ }
+ while (__enxt > __extbuf)
+ if (ungetc(*--__enxt, __file_) == EOF)
+ return traits_type::eof();
+ }
+ __last_consumed_ = __c;
+ __last_consumed_is_next_ = true;
+ return __c;
}
// __stdoutbuf
@@ -234,30 +263,31 @@ __stdoutbuf<_CharT>::overflow(int_type __c)
char_type __1buf;
if (!traits_type::eq_int_type(__c, traits_type::eof()))
{
- this->setp(&__1buf, &__1buf+1);
- *this->pptr() = traits_type::to_char_type(__c);
- this->pbump(1);
+ __1buf = traits_type::to_char_type(__c);
if (__always_noconv_)
{
- if (fwrite(this->pbase(), sizeof(char_type), 1, __file_) != 1)
+ if (fwrite(&__1buf, sizeof(char_type), 1, __file_) != 1)
return traits_type::eof();
}
else
{
char* __extbe = __extbuf;
codecvt_base::result __r;
+ char_type* pbase = &__1buf;
+ char_type* pptr = pbase + 1;
+ char_type* epptr = pptr;
do
{
const char_type* __e;
- __r = __cv_->out(*__st_, this->pbase(), this->pptr(), __e,
+ __r = __cv_->out(*__st_, pbase, pptr, __e,
__extbuf,
__extbuf + sizeof(__extbuf),
__extbe);
- if (__e == this->pbase())
+ if (__e == pbase)
return traits_type::eof();
if (__r == codecvt_base::noconv)
{
- if (fwrite(this->pbase(), 1, 1, __file_) != 1)
+ if (fwrite(pbase, 1, 1, __file_) != 1)
return traits_type::eof();
}
else if (__r == codecvt_base::ok || __r == codecvt_base::partial)
@@ -267,15 +297,13 @@ __stdoutbuf<_CharT>::overflow(int_type __c)
return traits_type::eof();
if (__r == codecvt_base::partial)
{
- this->setp((char_type*)__e, this->pptr());
- this->pbump(static_cast<int>(this->epptr() - this->pbase()));
+ pbase = (char_type*)__e;
}
}
else
return traits_type::eof();
} while (__r == codecvt_base::partial);
}
- this->setp(0, 0);
}
return traits_type::not_eof(__c);
}
diff --git a/system/include/libcxx/__tree b/system/include/libcxx/__tree
index cd6d7efa..9ffc38d2 100644
--- a/system/include/libcxx/__tree
+++ b/system/include/libcxx/__tree
@@ -644,7 +644,8 @@ public:
_LIBCPP_INLINE_VISIBILITY __tree_iterator() _NOEXCEPT {}
_LIBCPP_INLINE_VISIBILITY reference operator*() const {return __ptr_->__value_;}
- _LIBCPP_INLINE_VISIBILITY pointer operator->() const {return &__ptr_->__value_;}
+ _LIBCPP_INLINE_VISIBILITY pointer operator->() const
+ {return pointer_traits<pointer>::pointer_to(__ptr_->__value_);}
_LIBCPP_INLINE_VISIBILITY
__tree_iterator& operator++()
@@ -686,7 +687,7 @@ class _LIBCPP_TYPE_VIS __tree_const_iterator
{
typedef _ConstNodePtr __node_pointer;
typedef typename pointer_traits<__node_pointer>::element_type __node;
- typedef const typename __node::base __node_base;
+ typedef typename __node::base __node_base;
typedef typename pointer_traits<__node_pointer>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
rebind<__node_base>
@@ -729,7 +730,8 @@ public:
: __ptr_(__p.__ptr_) {}
_LIBCPP_INLINE_VISIBILITY reference operator*() const {return __ptr_->__value_;}
- _LIBCPP_INLINE_VISIBILITY pointer operator->() const {return &__ptr_->__value_;}
+ _LIBCPP_INLINE_VISIBILITY pointer operator->() const
+ {return pointer_traits<pointer>::pointer_to(__ptr_->__value_);}
_LIBCPP_INLINE_VISIBILITY
__tree_const_iterator& operator++()
@@ -779,8 +781,10 @@ public:
typedef typename __alloc_traits::size_type size_type;
typedef typename __alloc_traits::difference_type difference_type;
- typedef __tree_node<value_type, typename __alloc_traits::void_pointer> __node;
- typedef __tree_node_base<typename __alloc_traits::void_pointer> __node_base;
+ typedef typename __alloc_traits::void_pointer __void_pointer;
+
+ typedef __tree_node<value_type, __void_pointer> __node;
+ typedef __tree_node_base<__void_pointer> __node_base;
typedef typename __alloc_traits::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
rebind_alloc<__node>
@@ -790,9 +794,9 @@ public:
__node_allocator;
typedef allocator_traits<__node_allocator> __node_traits;
typedef typename __node_traits::pointer __node_pointer;
- typedef typename __node_traits::const_pointer __node_const_pointer;
+ typedef typename __node_traits::pointer __node_const_pointer;
typedef typename __node_base::pointer __node_base_pointer;
- typedef typename __node_base::const_pointer __node_base_const_pointer;
+ typedef typename __node_base::pointer __node_base_const_pointer;
private:
typedef typename __node_base::base __end_node_t;
typedef typename pointer_traits<__node_pointer>::template
@@ -804,9 +808,9 @@ private:
__end_node_ptr;
typedef typename pointer_traits<__node_pointer>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
- rebind<const __end_node_t>
+ rebind<__end_node_t>
#else
- rebind<const __end_node_t>::other
+ rebind<__end_node_t>::other
#endif
__end_node_const_ptr;
@@ -828,7 +832,7 @@ public:
{
return static_cast<__node_const_pointer>
(
- pointer_traits<__end_node_const_ptr>::pointer_to(__pair1_.first())
+ pointer_traits<__end_node_const_ptr>::pointer_to(const_cast<__end_node_t&>(__pair1_.first()))
);
}
_LIBCPP_INLINE_VISIBILITY
@@ -865,7 +869,7 @@ public:
{return static_cast<__node_const_pointer>(__end_node()->__left_);}
typedef __tree_iterator<value_type, __node_pointer, difference_type> iterator;
- typedef __tree_const_iterator<value_type, __node_const_pointer, difference_type> const_iterator;
+ typedef __tree_const_iterator<value_type, __node_pointer, difference_type> const_iterator;
explicit __tree(const value_compare& __comp)
_NOEXCEPT_(
@@ -1102,6 +1106,9 @@ private:
__node_pointer __detach();
static __node_pointer __detach(__node_pointer);
+
+ template <class, class, class, class> friend class _LIBCPP_TYPE_VIS map;
+ template <class, class, class, class> friend class _LIBCPP_TYPE_VIS multimap;
};
template <class _Tp, class _Compare, class _Allocator>
@@ -1161,7 +1168,7 @@ __tree<_Tp, _Compare, _Allocator>::__detach(__node_pointer __cache)
{
if (__cache->__parent_ == nullptr)
return nullptr;
- if (__tree_is_left_child(__cache))
+ if (__tree_is_left_child(static_cast<__node_base_pointer>(__cache)))
{
__cache->__parent_->__left_ = nullptr;
__cache = static_cast<__node_pointer>(__cache->__parent_);
@@ -1294,7 +1301,7 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t)
__begin_node() = __end_node();
else
{
- __end_node()->__left_->__parent_ = __end_node();
+ __end_node()->__left_->__parent_ = static_cast<__node_base_pointer>(__end_node());
__t.__begin_node() = __t.__end_node();
__t.__end_node()->__left_ = nullptr;
__t.size() = 0;
@@ -1314,7 +1321,7 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t, const allocator_type& __
{
__begin_node() = __t.__begin_node();
__end_node()->__left_ = __t.__end_node()->__left_;
- __end_node()->__left_->__parent_ = __end_node();
+ __end_node()->__left_->__parent_ = static_cast<__node_base_pointer>(__end_node());
size() = __t.size();
__t.__begin_node() = __t.__end_node();
__t.__end_node()->__left_ = nullptr;
@@ -1342,7 +1349,7 @@ __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
__begin_node() = __end_node();
else
{
- __end_node()->__left_->__parent_ = __end_node();
+ __end_node()->__left_->__parent_ = static_cast<__node_base_pointer>(__end_node());
__t.__begin_node() = __t.__end_node();
__t.__end_node()->__left_ = nullptr;
__t.size() = 0;
@@ -1447,11 +1454,11 @@ __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t)
if (size() == 0)
__begin_node() = __end_node();
else
- __end_node()->__left_->__parent_ = __end_node();
+ __end_node()->__left_->__parent_ = static_cast<__node_base_pointer>(__end_node());
if (__t.size() == 0)
__t.__begin_node() = __t.__end_node();
else
- __t.__end_node()->__left_->__parent_ = __t.__end_node();
+ __t.__end_node()->__left_->__parent_ = static_cast<__node_base_pointer>(__t.__end_node());
}
template <class _Tp, class _Compare, class _Allocator>
@@ -1483,7 +1490,7 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_low(typename __node_base::pointer
__nd = static_cast<__node_pointer>(__nd->__right_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__right_;
}
}
@@ -1493,13 +1500,13 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_low(typename __node_base::pointer
__nd = static_cast<__node_pointer>(__nd->__left_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__left_;
}
}
}
}
- __parent = __end_node();
+ __parent = static_cast<__node_base_pointer>(__end_node());
return __parent->__left_;
}
@@ -1522,7 +1529,7 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_high(typename __node_base::pointe
__nd = static_cast<__node_pointer>(__nd->__left_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__left_;
}
}
@@ -1532,13 +1539,13 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_high(typename __node_base::pointe
__nd = static_cast<__node_pointer>(__nd->__right_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__right_;
}
}
}
}
- __parent = __end_node();
+ __parent = static_cast<__node_base_pointer>(__end_node());
return __parent->__left_;
}
@@ -1563,12 +1570,12 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf(const_iterator __hint,
// *prev(__hint) <= __v <= *__hint
if (__hint.__ptr_->__left_ == nullptr)
{
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__hint.__ptr_);
return __parent->__left_;
}
else
{
- __parent = const_cast<__node_pointer&>(__prior.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__prior.__ptr_);
return __parent->__right_;
}
}
@@ -1600,7 +1607,7 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(typename __node_base::pointer& _
__nd = static_cast<__node_pointer>(__nd->__left_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__left_;
}
}
@@ -1610,18 +1617,18 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(typename __node_base::pointer& _
__nd = static_cast<__node_pointer>(__nd->__right_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__right_;
}
}
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent;
}
}
}
- __parent = __end_node();
+ __parent = static_cast<__node_base_pointer>(__end_node());
return __parent->__left_;
}
@@ -1648,12 +1655,12 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const_iterator __hint,
// *prev(__hint) < __v < *__hint
if (__hint.__ptr_->__left_ == nullptr)
{
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__hint.__ptr_);
return __parent->__left_;
}
else
{
- __parent = const_cast<__node_pointer&>(__prior.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__prior.__ptr_);
return __parent->__right_;
}
}
@@ -1669,12 +1676,12 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const_iterator __hint,
// *__hint < __v < *_VSTD::next(__hint)
if (__hint.__ptr_->__right_ == nullptr)
{
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__hint.__ptr_);
return __parent->__right_;
}
else
{
- __parent = const_cast<__node_pointer&>(__next.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__next.__ptr_);
return __parent->__left_;
}
}
@@ -1682,7 +1689,7 @@ __tree<_Tp, _Compare, _Allocator>::__find_equal(const_iterator __hint,
return __find_equal(__parent, __v);
}
// else __v == *__hint
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
+ __parent = static_cast<__node_base_pointer>(__hint.__ptr_);
return __parent;
}
@@ -1729,7 +1736,7 @@ __tree<_Tp, _Compare, _Allocator>::__emplace_unique(_Args&&... __args)
bool __inserted = false;
if (__child == nullptr)
{
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
__inserted = true;
}
@@ -1747,7 +1754,7 @@ __tree<_Tp, _Compare, _Allocator>::__emplace_hint_unique(const_iterator __p, _Ar
__node_pointer __r = static_cast<__node_pointer>(__child);
if (__child == nullptr)
{
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
}
return iterator(__r);
@@ -1761,7 +1768,7 @@ __tree<_Tp, _Compare, _Allocator>::__emplace_multi(_Args&&... __args)
__node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf_high(__parent, __h->__value_);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
return iterator(static_cast<__node_pointer>(__h.release()));
}
@@ -1774,7 +1781,7 @@ __tree<_Tp, _Compare, _Allocator>::__emplace_hint_multi(const_iterator __p,
__node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf(__p, __parent, __h->__value_);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
return iterator(static_cast<__node_pointer>(__h.release()));
}
@@ -1812,7 +1819,7 @@ __tree<_Tp, _Compare, _Allocator>::__insert_multi(_Vp&& __v)
__node_holder __h = __construct_node(_VSTD::forward<_Vp>(__v));
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf_high(__parent, __h->__value_);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
return iterator(__h.release());
}
@@ -1824,7 +1831,7 @@ __tree<_Tp, _Compare, _Allocator>::__insert_multi(const_iterator __p, _Vp&& __v)
__node_holder __h = __construct_node(_VSTD::forward<_Vp>(__v));
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf(__p, __parent, __h->__value_);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
return iterator(__h.release());
}
@@ -1854,7 +1861,7 @@ __tree<_Tp, _Compare, _Allocator>::__insert_unique(const value_type& __v)
if (__child == nullptr)
{
__node_holder __h = __construct_node(__v);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
__inserted = true;
}
@@ -1871,7 +1878,7 @@ __tree<_Tp, _Compare, _Allocator>::__insert_unique(const_iterator __p, const val
if (__child == nullptr)
{
__node_holder __h = __construct_node(__v);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
}
return iterator(__r);
@@ -1884,7 +1891,7 @@ __tree<_Tp, _Compare, _Allocator>::__insert_multi(const value_type& __v)
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf_high(__parent, __v);
__node_holder __h = __construct_node(__v);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
return iterator(__h.release());
}
@@ -1895,7 +1902,7 @@ __tree<_Tp, _Compare, _Allocator>::__insert_multi(const_iterator __p, const valu
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf(__p, __parent, __v);
__node_holder __h = __construct_node(__v);
- __insert_node_at(__parent, __child, __h.get());
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
return iterator(__h.release());
}
@@ -1909,7 +1916,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_insert_unique(__node_pointer __nd)
bool __inserted = false;
if (__child == nullptr)
{
- __insert_node_at(__parent, __child, __nd);
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
__r = __nd;
__inserted = true;
}
@@ -1926,7 +1933,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_insert_unique(const_iterator __p,
__node_pointer __r = static_cast<__node_pointer>(__child);
if (__child == nullptr)
{
- __insert_node_at(__parent, __child, __nd);
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
__r = __nd;
}
return iterator(__r);
@@ -1938,7 +1945,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_insert_multi(__node_pointer __nd)
{
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf_high(__parent, __nd->__value_);
- __insert_node_at(__parent, __child, __nd);
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
return iterator(__nd);
}
@@ -1949,7 +1956,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_insert_multi(const_iterator __p,
{
__node_base_pointer __parent;
__node_base_pointer& __child = __find_leaf(__p, __parent, __nd->__value_);
- __insert_node_at(__parent, __child, __nd);
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd));
return iterator(__nd);
}
@@ -1957,7 +1964,7 @@ template <class _Tp, class _Compare, class _Allocator>
typename __tree<_Tp, _Compare, _Allocator>::iterator
__tree<_Tp, _Compare, _Allocator>::erase(const_iterator __p)
{
- __node_pointer __np = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer __np = __p.__ptr_;
iterator __r(__np);
++__r;
if (__begin_node() == __np)
@@ -1977,7 +1984,7 @@ __tree<_Tp, _Compare, _Allocator>::erase(const_iterator __f, const_iterator __l)
{
while (__f != __l)
__f = erase(__f);
- return iterator(const_cast<__node_pointer>(__l.__ptr_));
+ return iterator(__l.__ptr_);
}
template <class _Tp, class _Compare, class _Allocator>
@@ -2264,7 +2271,7 @@ template <class _Tp, class _Compare, class _Allocator>
typename __tree<_Tp, _Compare, _Allocator>::__node_holder
__tree<_Tp, _Compare, _Allocator>::remove(const_iterator __p) _NOEXCEPT
{
- __node_pointer __np = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer __np = __p.__ptr_;
if (__begin_node() == __np)
{
if (__np->__right_ != nullptr)
diff --git a/system/include/libcxx/__tuple b/system/include/libcxx/__tuple
index 1213262d..9a6b6e09 100644
--- a/system/include/libcxx/__tuple
+++ b/system/include/libcxx/__tuple
@@ -79,47 +79,47 @@ template <class _T1, class _T2> struct __tuple_like<pair<_T1, _T2> > : true_type
template <class _Tp, size_t _Size> struct __tuple_like<array<_Tp, _Size> > : true_type {};
template <size_t _Ip, class ..._Tp>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, tuple<_Tp...> >::type&
get(tuple<_Tp...>&) _NOEXCEPT;
template <size_t _Ip, class ..._Tp>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const typename tuple_element<_Ip, tuple<_Tp...> >::type&
get(const tuple<_Tp...>&) _NOEXCEPT;
template <size_t _Ip, class ..._Tp>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, tuple<_Tp...> >::type&&
get(tuple<_Tp...>&&) _NOEXCEPT;
template <size_t _Ip, class _T1, class _T2>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, pair<_T1, _T2> >::type&
get(pair<_T1, _T2>&) _NOEXCEPT;
template <size_t _Ip, class _T1, class _T2>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const typename tuple_element<_Ip, pair<_T1, _T2> >::type&
get(const pair<_T1, _T2>&) _NOEXCEPT;
template <size_t _Ip, class _T1, class _T2>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, pair<_T1, _T2> >::type&&
get(pair<_T1, _T2>&&) _NOEXCEPT;
template <size_t _Ip, class _Tp, size_t _Size>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp&
get(array<_Tp, _Size>&) _NOEXCEPT;
template <size_t _Ip, class _Tp, size_t _Size>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const _Tp&
get(const array<_Tp, _Size>&) _NOEXCEPT;
template <size_t _Ip, class _Tp, size_t _Size>
-_LIBCPP_INLINE_VISIBILITY
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp&&
get(array<_Tp, _Size>&&) _NOEXCEPT;
diff --git a/system/include/libcxx/algorithm b/system/include/libcxx/algorithm
index 4adcc696..2fc1f8ab 100644
--- a/system/include/libcxx/algorithm
+++ b/system/include/libcxx/algorithm
@@ -87,30 +87,63 @@ template <class InputIterator1, class InputIterator2>
pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2);
+template <class InputIterator1, class InputIterator2>
+ pair<InputIterator1, InputIterator2>
+ mismatch(InputIterator1 first1, InputIterator1 last1,
+ InputIterator2 first2, InputIterator2 last2); // **C++14**
+
template <class InputIterator1, class InputIterator2, class BinaryPredicate>
pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, BinaryPredicate pred);
+template <class InputIterator1, class InputIterator2, class BinaryPredicate>
+ pair<InputIterator1, InputIterator2>
+ mismatch(InputIterator1 first1, InputIterator1 last1,
+ InputIterator2 first2, InputIterator2 last2,
+ BinaryPredicate pred); // **C++14**
+
template <class InputIterator1, class InputIterator2>
bool
equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2);
+template <class InputIterator1, class InputIterator2>
+ bool
+ equal(InputIterator1 first1, InputIterator1 last1,
+ InputIterator2 first2, InputIterator2 last2); // **C++14**
+
template <class InputIterator1, class InputIterator2, class BinaryPredicate>
bool
equal(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, BinaryPredicate pred);
+template <class InputIterator1, class InputIterator2, class BinaryPredicate>
+ bool
+ equal(InputIterator1 first1, InputIterator1 last1,
+ InputIterator2 first2, InputIterator2 last2,
+ BinaryPredicate pred); // **C++14**
+
template<class ForwardIterator1, class ForwardIterator2>
bool
is_permutation(ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2);
+template<class ForwardIterator1, class ForwardIterator2>
+ bool
+ is_permutation(ForwardIterator1 first1, ForwardIterator1 last1,
+ ForwardIterator2 first2, ForwardIterator2 last2); // **C++14**
+
template<class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
bool
is_permutation(ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, BinaryPredicate pred);
+template<class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
+ bool
+ is_permutation(ForwardIterator1 first1, ForwardIterator1 last1,
+ ForwardIterator2 first2, ForwardIterator2 last2,
+ BinaryPredicate pred); // **C++14**
+
template <class ForwardIterator1, class ForwardIterator2>
ForwardIterator1
search(ForwardIterator1 first1, ForwardIterator1 last1,
@@ -1087,6 +1120,32 @@ mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __fi
return _VSTD::mismatch(__first1, __last1, __first2, __equal_to<__v1, __v2>());
}
+#if _LIBCPP_STD_VER > 11
+template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
+inline _LIBCPP_INLINE_VISIBILITY
+pair<_InputIterator1, _InputIterator2>
+mismatch(_InputIterator1 __first1, _InputIterator1 __last1,
+ _InputIterator2 __first2, _InputIterator2 __last2,
+ _BinaryPredicate __pred)
+{
+ for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2)
+ if (!__pred(*__first1, *__first2))
+ break;
+ return pair<_InputIterator1, _InputIterator2>(__first1, __first2);
+}
+
+template <class _InputIterator1, class _InputIterator2>
+inline _LIBCPP_INLINE_VISIBILITY
+pair<_InputIterator1, _InputIterator2>
+mismatch(_InputIterator1 __first1, _InputIterator1 __last1,
+ _InputIterator2 __first2, _InputIterator2 __last2)
+{
+ typedef typename iterator_traits<_InputIterator1>::value_type __v1;
+ typedef typename iterator_traits<_InputIterator2>::value_type __v2;
+ return _VSTD::mismatch(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>());
+}
+#endif
+
// equal
template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
@@ -1110,6 +1169,60 @@ equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first
return _VSTD::equal(__first1, __last1, __first2, __equal_to<__v1, __v2>());
}
+#if _LIBCPP_STD_VER > 11
+template <class _BinaryPredicate, class _InputIterator1, class _InputIterator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+__equal(_InputIterator1 __first1, _InputIterator1 __last1,
+ _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __pred,
+ input_iterator_tag, input_iterator_tag )
+{
+ for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2)
+ if (!__pred(*__first1, *__first2))
+ return false;
+ return __first1 == __last1 && __first2 == __last2;
+}
+
+template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+__equal(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
+ _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _BinaryPredicate __pred,
+ random_access_iterator_tag, random_access_iterator_tag )
+{
+ if ( _VSTD::distance(__first1, __last1) != _VSTD::distance(__first2, __last2))
+ return false;
+ return _VSTD::equal<_RandomAccessIterator1, _RandomAccessIterator2,
+ typename add_lvalue_reference<_BinaryPredicate>::type>
+ (__first1, __last1, __first2, __pred );
+}
+
+template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+equal(_InputIterator1 __first1, _InputIterator1 __last1,
+ _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __pred )
+{
+ return _VSTD::__equal<typename add_lvalue_reference<_BinaryPredicate>::type>
+ (__first1, __last1, __first2, __last2, __pred,
+ typename iterator_traits<_InputIterator1>::iterator_category(),
+ typename iterator_traits<_InputIterator2>::iterator_category());
+}
+
+template <class _InputIterator1, class _InputIterator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+equal(_InputIterator1 __first1, _InputIterator1 __last1,
+ _InputIterator2 __first2, _InputIterator2 __last2)
+{
+ typedef typename iterator_traits<_InputIterator1>::value_type __v1;
+ typedef typename iterator_traits<_InputIterator2>::value_type __v2;
+ return _VSTD::__equal(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>(),
+ typename iterator_traits<_InputIterator1>::iterator_category(),
+ typename iterator_traits<_InputIterator2>::iterator_category());
+}
+#endif
+
// is_permutation
template<class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
@@ -1169,6 +1282,100 @@ is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
return _VSTD::is_permutation(__first1, __last1, __first2, __equal_to<__v1, __v2>());
}
+#if _LIBCPP_STD_VER > 11
+template<class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2>
+bool
+__is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2, _ForwardIterator2 __last2,
+ _BinaryPredicate __pred,
+ forward_iterator_tag, forward_iterator_tag )
+{
+ // shorten sequences as much as possible by lopping of any equal parts
+ for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2)
+ if (!__pred(*__first1, *__first2))
+ goto __not_done;
+ return __first1 == __last1 && __first2 == __last2;
+__not_done:
+ // __first1 != __last1 && __first2 != __last2 && *__first1 != *__first2
+ typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1;
+ _D1 __l1 = _VSTD::distance(__first1, __last1);
+
+ typedef typename iterator_traits<_ForwardIterator2>::difference_type _D2;
+ _D2 __l2 = _VSTD::distance(__first2, __last2);
+ if (__l1 != __l2)
+ return false;
+
+ // For each element in [f1, l1) see if there are the same number of
+ // equal elements in [f2, l2)
+ for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i)
+ {
+ // Have we already counted the number of *__i in [f1, l1)?
+ for (_ForwardIterator1 __j = __first1; __j != __i; ++__j)
+ if (__pred(*__j, *__i))
+ goto __next_iter;
+ {
+ // Count number of *__i in [f2, l2)
+ _D1 __c2 = 0;
+ for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
+ if (__pred(*__i, *__j))
+ ++__c2;
+ if (__c2 == 0)
+ return false;
+ // Count number of *__i in [__i, l1) (we can start with 1)
+ _D1 __c1 = 1;
+ for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j)
+ if (__pred(*__i, *__j))
+ ++__c1;
+ if (__c1 != __c2)
+ return false;
+ }
+__next_iter:;
+ }
+ return true;
+}
+
+template<class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>
+bool
+__is_permutation(_RandomAccessIterator1 __first1, _RandomAccessIterator2 __last1,
+ _RandomAccessIterator1 __first2, _RandomAccessIterator2 __last2,
+ _BinaryPredicate __pred,
+ random_access_iterator_tag, random_access_iterator_tag )
+{
+ if ( _VSTD::distance(__first1, __last1) != _VSTD::distance(__first2, __last2))
+ return false;
+ return _VSTD::is_permutation<_RandomAccessIterator1, _RandomAccessIterator2,
+ typename add_lvalue_reference<_BinaryPredicate>::type>
+ (__first1, __last1, __first2, __pred );
+}
+
+template<class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2, _ForwardIterator2 __last2,
+ _BinaryPredicate __pred )
+{
+ return _VSTD::__is_permutation<typename add_lvalue_reference<_BinaryPredicate>::type>
+ (__first1, __last1, __first2, __last2, __pred,
+ typename iterator_traits<_ForwardIterator1>::iterator_category(),
+ typename iterator_traits<_ForwardIterator2>::iterator_category());
+}
+
+template<class _ForwardIterator1, class _ForwardIterator2>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2, _ForwardIterator2 __last2)
+{
+ typedef typename iterator_traits<_ForwardIterator1>::value_type __v1;
+ typedef typename iterator_traits<_ForwardIterator2>::value_type __v2;
+ return _VSTD::__is_permutation(__first1, __last1, __first2, __last2,
+ __equal_to<__v1, __v2>(),
+ typename iterator_traits<_ForwardIterator1>::iterator_category(),
+ typename iterator_traits<_ForwardIterator2>::iterator_category());
+}
+#endif
+
// search
template <class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2>
@@ -1398,7 +1605,7 @@ __search_n(_RandomAccessIterator __first, _RandomAccessIterator __last,
// Find first element in sequence that matchs __value_, with a mininum of loop checks
while (true)
{
- if (__first == __s) // return __last if no element matches __value_
+ if (__first >= __s) // return __last if no element matches __value_
return __last;
if (__pred(*__first, __value_))
break;
@@ -1780,17 +1987,23 @@ replace_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator _
template <class _OutputIterator, class _Size, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
_OutputIterator
-__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value_, false_type)
+__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value_)
{
for (; __n > 0; ++__first, --__n)
*__first = __value_;
return __first;
}
-template <class _OutputIterator, class _Size, class _Tp>
+template <class _Tp, class _Size, class _Up>
inline _LIBCPP_INLINE_VISIBILITY
-_OutputIterator
-__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value_, true_type)
+typename enable_if
+<
+ is_integral<_Tp>::value && sizeof(_Tp) == 1 &&
+ !is_same<_Tp, bool>::value &&
+ is_integral<_Up>::value && sizeof(_Up) == 1,
+ _Tp*
+>::type
+__fill_n(_Tp* __first, _Size __n,_Up __value_)
{
if (__n > 0)
_VSTD::memset(__first, (unsigned char)__value_, (size_t)(__n));
@@ -1802,10 +2015,7 @@ inline _LIBCPP_INLINE_VISIBILITY
_OutputIterator
fill_n(_OutputIterator __first, _Size __n, const _Tp& __value_)
{
- return _VSTD::__fill_n(__first, __n, __value_, integral_constant<bool,
- is_pointer<_OutputIterator>::value &&
- is_trivially_copy_assignable<_Tp>::value &&
- sizeof(_Tp) == 1>());
+ return _VSTD::__fill_n(__first, __n, __value_);
}
// fill
@@ -3778,10 +3988,10 @@ sort(__wrap_iter<_Tp*> __first, __wrap_iter<_Tp*> __last, _Compare __comp)
_VSTD::sort<_Tp*, _Comp_ref>(__first.base(), __last.base(), __comp);
}
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVC
#pragma warning( push )
#pragma warning( disable: 4231)
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVC
_LIBCPP_EXTERN_TEMPLATE(void __sort<__less<char>&, char*>(char*, char*, __less<char>&))
_LIBCPP_EXTERN_TEMPLATE(void __sort<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&))
_LIBCPP_EXTERN_TEMPLATE(void __sort<__less<signed char>&, signed char*>(signed char*, signed char*, __less<signed char>&))
@@ -3815,9 +4025,9 @@ _LIBCPP_EXTERN_TEMPLATE(bool __insertion_sort_incomplete<__less<double>&, double
_LIBCPP_EXTERN_TEMPLATE(bool __insertion_sort_incomplete<__less<long double>&, long double*>(long double*, long double*, __less<long double>&))
_LIBCPP_EXTERN_TEMPLATE(unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&))
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVC
#pragma warning( pop )
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVC
// lower_bound
diff --git a/system/include/libcxx/array b/system/include/libcxx/array
index bcf53478..86d1fc0b 100644
--- a/system/include/libcxx/array
+++ b/system/include/libcxx/array
@@ -59,14 +59,14 @@ struct array
// element access:
reference operator[](size_type n);
- const_reference operator[](size_type n) const;
- const_reference at(size_type n) const;
+ const_reference operator[](size_type n) const; // constexpr in C++14
+ const_reference at(size_type n) const; // constexpr in C++14
reference at(size_type n);
reference front();
- const_reference front() const;
+ const_reference front() const; // constexpr in C++14
reference back();
- const_reference back() const;
+ const_reference back() const; // constexpr in C++14
T* data() noexcept;
const T* data() const noexcept;
@@ -92,9 +92,9 @@ template <class T> class tuple_size;
template <int I, class T> class tuple_element;
template <class T, size_t N> struct tuple_size<array<T, N>>;
template <int I, class T, size_t N> struct tuple_element<I, array<T, N>>;
-template <int I, class T, size_t N> T& get(array<T, N>&) noexcept;
-template <int I, class T, size_t N> const T& get(const array<T, N>&) noexcept;
-template <int I, class T, size_t N> T&& get(array<T, N>&&) noexcept;
+template <int I, class T, size_t N> T& get(array<T, N>&) noexcept; // constexpr in C++14
+template <int I, class T, size_t N> const T& get(const array<T, N>&) noexcept; // constexpr in C++14
+template <int I, class T, size_t N> T&& get(array<T, N>&&) noexcept; // constexpr in C++14
} // std
@@ -181,14 +181,14 @@ struct _LIBCPP_TYPE_VIS array
// element access:
_LIBCPP_INLINE_VISIBILITY reference operator[](size_type __n) {return __elems_[__n];}
- _LIBCPP_INLINE_VISIBILITY const_reference operator[](size_type __n) const {return __elems_[__n];}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference operator[](size_type __n) const {return __elems_[__n];}
reference at(size_type __n);
- const_reference at(size_type __n) const;
+ _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference at(size_type __n) const;
_LIBCPP_INLINE_VISIBILITY reference front() {return __elems_[0];}
- _LIBCPP_INLINE_VISIBILITY const_reference front() const {return __elems_[0];}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference front() const {return __elems_[0];}
_LIBCPP_INLINE_VISIBILITY reference back() {return __elems_[_Size > 0 ? _Size-1 : 0];}
- _LIBCPP_INLINE_VISIBILITY const_reference back() const {return __elems_[_Size > 0 ? _Size-1 : 0];}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const {return __elems_[_Size > 0 ? _Size-1 : 0];}
_LIBCPP_INLINE_VISIBILITY
value_type* data() _NOEXCEPT {return __elems_;}
@@ -210,6 +210,7 @@ array<_Tp, _Size>::at(size_type __n)
}
template <class _Tp, size_t _Size>
+_LIBCPP_CONSTEXPR_AFTER_CXX11
typename array<_Tp, _Size>::const_reference
array<_Tp, _Size>::at(size_type __n) const
{
@@ -306,32 +307,32 @@ public:
};
template <size_t _Ip, class _Tp, size_t _Size>
-_LIBCPP_INLINE_VISIBILITY inline
+_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp&
get(array<_Tp, _Size>& __a) _NOEXCEPT
{
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array)");
- return __a[_Ip];
+ return __a.__elems_[_Ip];
}
template <size_t _Ip, class _Tp, size_t _Size>
-_LIBCPP_INLINE_VISIBILITY inline
+_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR_AFTER_CXX11
const _Tp&
get(const array<_Tp, _Size>& __a) _NOEXCEPT
{
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array)");
- return __a[_Ip];
+ return __a.__elems_[_Ip];
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <size_t _Ip, class _Tp, size_t _Size>
-_LIBCPP_INLINE_VISIBILITY inline
+_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp&&
get(array<_Tp, _Size>&& __a) _NOEXCEPT
{
static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array &&)");
- return _VSTD::move(__a[_Ip]);
+ return _VSTD::move(__a.__elems_[_Ip]);
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
diff --git a/system/include/libcxx/atomic b/system/include/libcxx/atomic
index db67e762..f6ab1cba 100644
--- a/system/include/libcxx/atomic
+++ b/system/include/libcxx/atomic
@@ -622,7 +622,12 @@ struct __atomic_base // false
{return __c11_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);}
_LIBCPP_INLINE_VISIBILITY
- __atomic_base() _NOEXCEPT {} // = default;
+#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+ __atomic_base() _NOEXCEPT = default;
+#else
+ __atomic_base() _NOEXCEPT : __a_() {}
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {}
#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
@@ -645,7 +650,7 @@ struct __atomic_base<_Tp, true>
{
typedef __atomic_base<_Tp, false> __base;
_LIBCPP_INLINE_VISIBILITY
- __atomic_base() _NOEXCEPT {} // = default;
+ __atomic_base() _NOEXCEPT _LIBCPP_DEFAULT
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
@@ -726,7 +731,7 @@ struct atomic
{
typedef __atomic_base<_Tp> __base;
_LIBCPP_INLINE_VISIBILITY
- atomic() _NOEXCEPT {} // = default;
+ atomic() _NOEXCEPT _LIBCPP_DEFAULT
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {}
@@ -746,7 +751,7 @@ struct atomic<_Tp*>
{
typedef __atomic_base<_Tp*> __base;
_LIBCPP_INLINE_VISIBILITY
- atomic() _NOEXCEPT {} // = default;
+ atomic() _NOEXCEPT _LIBCPP_DEFAULT
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {}
@@ -1367,7 +1372,12 @@ typedef struct atomic_flag
{__c11_atomic_store(&__a_, false, __m);}
_LIBCPP_INLINE_VISIBILITY
- atomic_flag() _NOEXCEPT {} // = default;
+#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+ atomic_flag() _NOEXCEPT = default;
+#else
+ atomic_flag() _NOEXCEPT : __a_() {}
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
_LIBCPP_INLINE_VISIBILITY
atomic_flag(bool __b) _NOEXCEPT : __a_(__b) {}
diff --git a/system/include/libcxx/cctype b/system/include/libcxx/cctype
index e33244e7..b647903c 100644
--- a/system/include/libcxx/cctype
+++ b/system/include/libcxx/cctype
@@ -37,9 +37,9 @@ int toupper(int c);
#include <__config>
#include <ctype.h>
-#if defined(_MSC_VER)
+#if defined(_LIBCPP_MSVCRT)
#include "support/win32/support.h"
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
diff --git a/system/include/libcxx/chrono b/system/include/libcxx/chrono
index 3b96e816..da550498 100644
--- a/system/include/libcxx/chrono
+++ b/system/include/libcxx/chrono
@@ -111,16 +111,16 @@ private:
duration d_; // exposition only
public:
- time_point(); // has value "epoch"
- explicit time_point(const duration& d); // same as time_point() + d
+ time_point(); // has value "epoch" // constexpr in C++14
+ explicit time_point(const duration& d); // same as time_point() + d // constexpr in C++14
// conversions
template <class Duration2>
- time_point(const time_point<clock, Duration2>& t);
+ time_point(const time_point<clock, Duration2>& t); // constexpr in C++14
// observer
- duration time_since_epoch() const;
+ duration time_since_epoch() const; // constexpr in C++14
// arithmetic
@@ -194,7 +194,7 @@ template <class Rep1, class Period1, class Rep2, class Period2>
template <class ToDuration, class Rep, class Period>
ToDuration duration_cast(const duration<Rep, Period>& d);
-// time_point arithmetic
+// time_point arithmetic (all constexpr in C++14)
template <class Clock, class Duration1, class Rep2, class Period2>
time_point<Clock, typename common_type<Duration1, duration<Rep2, Period2>>::type>
operator+(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
@@ -208,7 +208,7 @@ template <class Clock, class Duration1, class Duration2>
typename common_type<Duration1, Duration2>::type
operator-(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
-// time_point comparisons
+// time_point comparisons (all constexpr in C++14)
template <class Clock, class Duration1, class Duration2>
bool operator==(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Duration2>
@@ -222,7 +222,7 @@ template <class Clock, class Duration1, class Duration2>
template <class Clock, class Duration1, class Duration2>
bool operator>=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
-// time_point_cast
+// time_point_cast (constexpr in C++14)
template <class ToDuration, class Clock, class Duration>
time_point<Clock, ToDuration> time_point_cast(const time_point<Clock, Duration>& t);
@@ -236,7 +236,7 @@ public:
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<system_clock> time_point;
- static const bool is_steady = false;
+ static const bool is_steady = false; // constexpr in C++14
static time_point now() noexcept;
static time_t to_time_t (const time_point& __t) noexcept;
@@ -250,7 +250,7 @@ public:
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<steady_clock, duration> time_point;
- static const bool is_steady = true;
+ static const bool is_steady = true; // constexpr in C++14
static time_point now() noexcept;
};
@@ -259,6 +259,19 @@ typedef steady_clock high_resolution_clock;
} // chrono
+constexpr chrono::hours operator "" h(unsigned long long); // C++14
+constexpr chrono::duration<unspecified , ratio<3600,1>> operator "" h(long double); // C++14
+constexpr chrono::minutes operator "" min(unsigned long long); // C++14
+constexpr chrono::duration<unspecified , ratio<60,1>> operator "" min(long double); // C++14
+constexpr chrono::seconds operator "" s(unsigned long long); // C++14
+constexpr chrono::duration<unspecified > operator "" s(long double); // C++14
+constexpr chrono::milliseconds operator "" ms(unsigned long long); // C++14
+constexpr chrono::duration<unspecified , milli> operator "" ms(long double); // C++14
+constexpr chrono::microseconds operator "" us(unsigned long long); // C++14
+constexpr chrono::duration<unspecified , micro> operator "" us(long double); // C++14
+constexpr chrono::nanoseconds operator "" ns(unsigned long long); // C++14
+constexpr chrono::duration<unspecified , nano> operator "" ns(long double); // C++14
+
} // std
*/
@@ -403,7 +416,13 @@ private:
rep __rep_;
public:
- _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR duration() {} // = default;
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+ duration() = default;
+#else
+ duration() {}
+#endif
+
template <class _Rep2>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
explicit duration(const _Rep2& __r,
@@ -468,7 +487,7 @@ template <class _LhsDuration, class _RhsDuration>
struct __duration_eq
{
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
- bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs)
+ bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs) const
{
typedef typename common_type<_LhsDuration, _RhsDuration>::type _Ct;
return _Ct(__lhs).count() == _Ct(__rhs).count();
@@ -479,7 +498,7 @@ template <class _LhsDuration>
struct __duration_eq<_LhsDuration, _LhsDuration>
{
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
- bool operator()(const _LhsDuration& __lhs, const _LhsDuration& __rhs)
+ bool operator()(const _LhsDuration& __lhs, const _LhsDuration& __rhs) const
{return __lhs.count() == __rhs.count();}
};
@@ -509,7 +528,7 @@ template <class _LhsDuration, class _RhsDuration>
struct __duration_lt
{
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
- bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs)
+ bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs) const
{
typedef typename common_type<_LhsDuration, _RhsDuration>::type _Ct;
return _Ct(__lhs).count() < _Ct(__rhs).count();
@@ -520,7 +539,7 @@ template <class _LhsDuration>
struct __duration_lt<_LhsDuration, _LhsDuration>
{
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
- bool operator()(const _LhsDuration& __lhs, const _LhsDuration& __rhs)
+ bool operator()(const _LhsDuration& __lhs, const _LhsDuration& __rhs) const
{return __lhs.count() < __rhs.count();}
};
@@ -709,12 +728,12 @@ private:
duration __d_;
public:
- _LIBCPP_INLINE_VISIBILITY time_point() : __d_(duration::zero()) {}
- _LIBCPP_INLINE_VISIBILITY explicit time_point(const duration& __d) : __d_(__d) {}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 time_point() : __d_(duration::zero()) {}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit time_point(const duration& __d) : __d_(__d) {}
// conversions
template <class _Duration2>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
time_point(const time_point<clock, _Duration2>& t,
typename enable_if
<
@@ -724,12 +743,12 @@ public:
// observer
- _LIBCPP_INLINE_VISIBILITY duration time_since_epoch() const {return __d_;}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 duration time_since_epoch() const {return __d_;}
// arithmetic
- _LIBCPP_INLINE_VISIBILITY time_point& operator+=(const duration& __d) {__d_ += __d; return *this;}
- _LIBCPP_INLINE_VISIBILITY time_point& operator-=(const duration& __d) {__d_ -= __d; return *this;}
+ _LIBCPP_INLINE_VISIBILITY time_point& operator+=(const duration& __d) {__d_ += __d; return *this;}
+ _LIBCPP_INLINE_VISIBILITY time_point& operator-=(const duration& __d) {__d_ -= __d; return *this;}
// special values
@@ -749,7 +768,7 @@ struct _LIBCPP_TYPE_VIS common_type<chrono::time_point<_Clock, _Duration1>,
namespace chrono {
template <class _ToDuration, class _Clock, class _Duration>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
time_point<_Clock, _ToDuration>
time_point_cast(const time_point<_Clock, _Duration>& __t)
{
@@ -759,7 +778,7 @@ time_point_cast(const time_point<_Clock, _Duration>& __t)
// time_point ==
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator==(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -769,7 +788,7 @@ operator==(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
// time_point !=
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator!=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -779,7 +798,7 @@ operator!=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
// time_point <
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator<(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -789,7 +808,7 @@ operator<(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
// time_point >
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -799,7 +818,7 @@ operator>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
// time_point <=
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator<=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -809,7 +828,7 @@ operator<=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
// time_point >=
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator>=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -819,20 +838,18 @@ operator>=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock,
// time_point operator+(time_point x, duration y);
template <class _Clock, class _Duration1, class _Rep2, class _Period2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type>
operator+(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs)
{
typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Tr;
- _Tr __r(__lhs.time_since_epoch());
- __r += __rhs;
- return __r;
+ return _Tr (__lhs.time_since_epoch() + __rhs);
}
// time_point operator+(duration x, time_point y);
template <class _Rep1, class _Period1, class _Clock, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
time_point<_Clock, typename common_type<duration<_Rep1, _Period1>, _Duration2>::type>
operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -842,7 +859,7 @@ operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Dura
// time_point operator-(time_point x, duration y);
template <class _Clock, class _Duration1, class _Rep2, class _Period2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type>
operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs)
{
@@ -852,7 +869,7 @@ operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Pe
// duration operator-(time_point x, time_point y);
template <class _Clock, class _Duration1, class _Duration2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename common_type<_Duration1, _Duration2>::type
operator-(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs)
{
@@ -870,7 +887,7 @@ public:
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<system_clock> time_point;
- static const bool is_steady = false;
+ static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = false;
static time_point now() _NOEXCEPT;
static time_t to_time_t (const time_point& __t) _NOEXCEPT;
@@ -884,7 +901,7 @@ public:
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<steady_clock, duration> time_point;
- static const bool is_steady = true;
+ static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = true;
static time_point now() _NOEXCEPT;
};
@@ -893,6 +910,84 @@ typedef steady_clock high_resolution_clock;
} // chrono
+#if _LIBCPP_STD_VER > 11
+// Literal suffixes for chrono types
+// inline // Deviation from N3690.
+// We believe the inline to be a defect and have submitted an LWG issue.
+// An LWG issue number has not yet been assigned.
+namespace literals
+{
+ inline namespace chrono_literals
+ {
+
+ constexpr chrono::hours operator"" h(unsigned long long __h)
+ {
+ return chrono::hours(static_cast<chrono::hours::rep>(__h));
+ }
+
+ constexpr chrono::duration<long double, ratio<3600,1>> operator"" h(long double __h)
+ {
+ return chrono::duration<long double, ratio<3600,1>>(__h);
+ }
+
+
+ constexpr chrono::minutes operator"" min(unsigned long long __m)
+ {
+ return chrono::minutes(static_cast<chrono::minutes::rep>(__m));
+ }
+
+ constexpr chrono::duration<long double, ratio<60,1>> operator"" min(long double __m)
+ {
+ return chrono::duration<long double, ratio<60,1>> (__m);
+ }
+
+
+ constexpr chrono::seconds operator"" s(unsigned long long __s)
+ {
+ return chrono::seconds(static_cast<chrono::seconds::rep>(__s));
+ }
+
+ constexpr chrono::duration<long double> operator"" s(long double __s)
+ {
+ return chrono::duration<long double> (__s);
+ }
+
+
+ constexpr chrono::milliseconds operator"" ms(unsigned long long __ms)
+ {
+ return chrono::milliseconds(static_cast<chrono::milliseconds::rep>(__ms));
+ }
+
+ constexpr chrono::duration<long double, milli> operator"" ms(long double __ms)
+ {
+ return chrono::duration<long double, milli>(__ms);
+ }
+
+
+ constexpr chrono::microseconds operator"" us(unsigned long long __us)
+ {
+ return chrono::microseconds(static_cast<chrono::microseconds::rep>(__us));
+ }
+
+ constexpr chrono::duration<long double, micro> operator"" us(long double __us)
+ {
+ return chrono::duration<long double, micro> (__us);
+ }
+
+
+ constexpr chrono::nanoseconds operator"" ns(unsigned long long __ns)
+ {
+ return chrono::nanoseconds(static_cast<chrono::nanoseconds::rep>(__ns));
+ }
+
+ constexpr chrono::duration<long double, nano> operator"" ns(long double __ns)
+ {
+ return chrono::duration<long double, nano> (__ns);
+ }
+
+}}
+#endif
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_CHRONO
diff --git a/system/include/libcxx/cmath b/system/include/libcxx/cmath
index bd603441..3e545cea 100644
--- a/system/include/libcxx/cmath
+++ b/system/include/libcxx/cmath
@@ -301,7 +301,7 @@ long double truncl(long double x);
#include <math.h>
#include <type_traits>
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVCRT
#include "support/win32/math_win32.h"
#endif
@@ -673,7 +673,7 @@ abs(long double __x) _NOEXCEPT {return fabsl(__x);}
using ::acos;
using ::acosf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float acos(float __x) _NOEXCEPT {return acosf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double acos(long double __x) _NOEXCEPT {return acosl(__x);}
#endif
@@ -688,7 +688,7 @@ acos(_A1 __x) _NOEXCEPT {return acos((double)__x);}
using ::asin;
using ::asinf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float asin(float __x) _NOEXCEPT {return asinf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double asin(long double __x) _NOEXCEPT {return asinl(__x);}
#endif
@@ -703,7 +703,7 @@ asin(_A1 __x) _NOEXCEPT {return asin((double)__x);}
using ::atan;
using ::atanf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float atan(float __x) _NOEXCEPT {return atanf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double atan(long double __x) _NOEXCEPT {return atanl(__x);}
#endif
@@ -718,7 +718,7 @@ atan(_A1 __x) _NOEXCEPT {return atan((double)__x);}
using ::atan2;
using ::atan2f;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float atan2(float __y, float __x) _NOEXCEPT {return atan2f(__y, __x);}
inline _LIBCPP_INLINE_VISIBILITY long double atan2(long double __y, long double __x) _NOEXCEPT {return atan2l(__y, __x);}
#endif
@@ -744,7 +744,7 @@ atan2(_A1 __y, _A2 __x) _NOEXCEPT
using ::ceil;
using ::ceilf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float ceil(float __x) _NOEXCEPT {return ceilf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double ceil(long double __x) _NOEXCEPT {return ceill(__x);}
#endif
@@ -759,7 +759,7 @@ ceil(_A1 __x) _NOEXCEPT {return ceil((double)__x);}
using ::cos;
using ::cosf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float cos(float __x) _NOEXCEPT {return cosf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double cos(long double __x) _NOEXCEPT {return cosl(__x);}
#endif
@@ -774,7 +774,7 @@ cos(_A1 __x) _NOEXCEPT {return cos((double)__x);}
using ::cosh;
using ::coshf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float cosh(float __x) _NOEXCEPT {return coshf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double cosh(long double __x) _NOEXCEPT {return coshl(__x);}
#endif
@@ -792,7 +792,7 @@ using ::expf;
#ifndef __sun__
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float exp(float __x) _NOEXCEPT {return expf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double exp(long double __x) _NOEXCEPT {return expl(__x);}
#endif
@@ -808,7 +808,7 @@ exp(_A1 __x) _NOEXCEPT {return exp((double)__x);}
using ::fabs;
using ::fabsf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float fabs(float __x) _NOEXCEPT {return fabsf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double fabs(long double __x) _NOEXCEPT {return fabsl(__x);}
#endif
@@ -823,7 +823,7 @@ fabs(_A1 __x) _NOEXCEPT {return fabs((double)__x);}
using ::floor;
using ::floorf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float floor(float __x) _NOEXCEPT {return floorf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double floor(long double __x) _NOEXCEPT {return floorl(__x);}
#endif
@@ -840,7 +840,7 @@ using ::fmod;
using ::fmodf;
#ifndef __sun__
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float fmod(float __x, float __y) _NOEXCEPT {return fmodf(__x, __y);}
inline _LIBCPP_INLINE_VISIBILITY long double fmod(long double __x, long double __y) _NOEXCEPT {return fmodl(__x, __y);}
#endif
@@ -867,7 +867,7 @@ fmod(_A1 __x, _A2 __y) _NOEXCEPT
using ::frexp;
using ::frexpf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float frexp(float __x, int* __e) _NOEXCEPT {return frexpf(__x, __e);}
inline _LIBCPP_INLINE_VISIBILITY long double frexp(long double __x, int* __e) _NOEXCEPT {return frexpl(__x, __e);}
#endif
@@ -882,7 +882,7 @@ frexp(_A1 __x, int* __e) _NOEXCEPT {return frexp((double)__x, __e);}
using ::ldexp;
using ::ldexpf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float ldexp(float __x, int __e) _NOEXCEPT {return ldexpf(__x, __e);}
inline _LIBCPP_INLINE_VISIBILITY long double ldexp(long double __x, int __e) _NOEXCEPT {return ldexpl(__x, __e);}
#endif
@@ -899,7 +899,7 @@ using ::log;
using ::logf;
#ifndef __sun__
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float log(float __x) _NOEXCEPT {return logf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double log(long double __x) _NOEXCEPT {return logl(__x);}
#endif
@@ -915,7 +915,7 @@ log(_A1 __x) _NOEXCEPT {return log((double)__x);}
using ::log10;
using ::log10f;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float log10(float __x) _NOEXCEPT {return log10f(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double log10(long double __x) _NOEXCEPT {return log10l(__x);}
#endif
@@ -930,7 +930,7 @@ log10(_A1 __x) _NOEXCEPT {return log10((double)__x);}
using ::modf;
using ::modff;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float modf(float __x, float* __y) _NOEXCEPT {return modff(__x, __y);}
inline _LIBCPP_INLINE_VISIBILITY long double modf(long double __x, long double* __y) _NOEXCEPT {return modfl(__x, __y);}
#endif
@@ -943,7 +943,7 @@ using ::powf;
#ifndef __sun__
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float pow(float __x, float __y) _NOEXCEPT {return powf(__x, __y);}
inline _LIBCPP_INLINE_VISIBILITY long double pow(long double __x, long double __y) _NOEXCEPT {return powl(__x, __y);}
#endif
@@ -970,7 +970,7 @@ pow(_A1 __x, _A2 __y) _NOEXCEPT
using ::sin;
using ::sinf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float sin(float __x) _NOEXCEPT {return sinf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double sin(long double __x) _NOEXCEPT {return sinl(__x);}
#endif
@@ -985,7 +985,7 @@ sin(_A1 __x) _NOEXCEPT {return sin((double)__x);}
using ::sinh;
using ::sinhf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float sinh(float __x) _NOEXCEPT {return sinhf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double sinh(long double __x) _NOEXCEPT {return sinhl(__x);}
#endif
@@ -1002,7 +1002,7 @@ using ::sqrt;
using ::sqrtf;
-#if !(defined(_MSC_VER) || defined(__sun__))
+#if !(defined(_LIBCPP_MSVCRT) || defined(__sun__))
inline _LIBCPP_INLINE_VISIBILITY float sqrt(float __x) _NOEXCEPT {return sqrtf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double sqrt(long double __x) _NOEXCEPT {return sqrtl(__x);}
#endif
@@ -1018,7 +1018,7 @@ using ::tan;
using ::tanf;
#ifndef __sun__
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float tan(float __x) _NOEXCEPT {return tanf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double tan(long double __x) _NOEXCEPT {return tanl(__x);}
#endif
@@ -1033,7 +1033,7 @@ tan(_A1 __x) _NOEXCEPT {return tan((double)__x);}
using ::tanh;
using ::tanhf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
inline _LIBCPP_INLINE_VISIBILITY float tanh(float __x) _NOEXCEPT {return tanhf(__x);}
inline _LIBCPP_INLINE_VISIBILITY long double tanh(long double __x) _NOEXCEPT {return tanhl(__x);}
#endif
@@ -1045,7 +1045,7 @@ tanh(_A1 __x) _NOEXCEPT {return tanh((double)__x);}
// acosh
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::acosh;
using ::acoshf;
@@ -1060,7 +1060,7 @@ acosh(_A1 __x) _NOEXCEPT {return acosh((double)__x);}
// asinh
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::asinh;
using ::asinhf;
@@ -1075,7 +1075,7 @@ asinh(_A1 __x) _NOEXCEPT {return asinh((double)__x);}
// atanh
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::atanh;
using ::atanhf;
@@ -1090,7 +1090,7 @@ atanh(_A1 __x) _NOEXCEPT {return atanh((double)__x);}
// cbrt
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::cbrt;
using ::cbrtf;
@@ -1127,7 +1127,7 @@ copysign(_A1 __x, _A2 __y) _NOEXCEPT
return copysign((__result_type)__x, (__result_type)__y);
}
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
// erf
@@ -1426,13 +1426,18 @@ inline _LIBCPP_INLINE_VISIBILITY
typename enable_if<is_integral<_A1>::value, long>::type
lround(_A1 __x) _NOEXCEPT {return lround((double)__x);}
-// nan
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
#endif // __sun__
+
+// nan
+
+#ifndef _LIBCPP_MSVCRT
using ::nan;
using ::nanf;
+#endif // _LIBCPP_MSVCRT
+
#ifndef __sun__
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
// nearbyint
@@ -1610,7 +1615,7 @@ inline _LIBCPP_INLINE_VISIBILITY
typename enable_if<is_integral<_A1>::value, double>::type
trunc(_A1 __x) _NOEXCEPT {return trunc((double)__x);}
-#endif // !_MSC_VER
+#endif // !_LIBCPP_MSVCRT
using ::acosl;
using ::asinl;
@@ -1633,15 +1638,15 @@ using ::sinl;
using ::sinhl;
using ::sqrtl;
using ::tanl;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::tanhl;
using ::acoshl;
using ::asinhl;
using ::atanhl;
using ::cbrtl;
-#endif // !_MSC_VER
+#endif // !_LIBCPP_MSVCRT
using ::copysignl;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::erfl;
using ::erfcl;
using ::exp2l;
@@ -1672,7 +1677,7 @@ using ::scalblnl;
using ::scalbnl;
using ::tgammal;
using ::truncl;
-#endif // !_MSC_VER
+#endif // !_LIBCPP_MSVCRT
#else
using ::lgamma;
diff --git a/system/include/libcxx/complex b/system/include/libcxx/complex
index a09bf70f..dddc58e0 100644
--- a/system/include/libcxx/complex
+++ b/system/include/libcxx/complex
@@ -23,12 +23,12 @@ class complex
public:
typedef T value_type;
- complex(const T& re = T(), const T& im = T());
- complex(const complex&);
- template<class X> complex(const complex<X>&);
+ complex(const T& re = T(), const T& im = T()); // constexpr in C++14
+ complex(const complex&); // constexpr in C++14
+ template<class X> complex(const complex<X>&); // constexpr in C++14
- T real() const;
- T imag() const;
+ T real() const; // constexpr in C++14
+ T imag() const; // constexpr in C++14
void real(T);
void imag(T);
@@ -149,12 +149,12 @@ template<class T> complex<T> operator/(const complex<T>&, const T&);
template<class T> complex<T> operator/(const T&, const complex<T>&);
template<class T> complex<T> operator+(const complex<T>&);
template<class T> complex<T> operator-(const complex<T>&);
-template<class T> bool operator==(const complex<T>&, const complex<T>&);
-template<class T> bool operator==(const complex<T>&, const T&);
-template<class T> bool operator==(const T&, const complex<T>&);
-template<class T> bool operator!=(const complex<T>&, const complex<T>&);
-template<class T> bool operator!=(const complex<T>&, const T&);
-template<class T> bool operator!=(const T&, const complex<T>&);
+template<class T> bool operator==(const complex<T>&, const complex<T>&); // constexpr in C++14
+template<class T> bool operator==(const complex<T>&, const T&); // constexpr in C++14
+template<class T> bool operator==(const T&, const complex<T>&); // constexpr in C++14
+template<class T> bool operator!=(const complex<T>&, const complex<T>&); // constexpr in C++14
+template<class T> bool operator!=(const complex<T>&, const T&); // constexpr in C++14
+template<class T> bool operator!=(const T&, const complex<T>&); // constexpr in C++14
template<class T, class charT, class traits>
basic_istream<charT, traits>&
@@ -165,17 +165,17 @@ template<class T, class charT, class traits>
// 26.3.7 values:
-template<class T> T real(const complex<T>&);
- long double real(long double);
- double real(double);
-template<Integral T> double real(T);
- float real(float);
+template<class T> T real(const complex<T>&); // constexpr in C++14
+ long double real(long double); // constexpr in C++14
+ double real(double); // constexpr in C++14
+template<Integral T> double real(T); // constexpr in C++14
+ float real(float); // constexpr in C++14
-template<class T> T imag(const complex<T>&);
- long double imag(long double);
- double imag(double);
-template<Integral T> double imag(T);
- float imag(float);
+template<class T> T imag(const complex<T>&); // constexpr in C++14
+ long double imag(long double); // constexpr in C++14
+ double imag(double); // constexpr in C++14
+template<Integral T> double imag(T); // constexpr in C++14
+ float imag(float); // constexpr in C++14
template<class T> T abs(const complex<T>&);
@@ -269,15 +269,15 @@ private:
value_type __re_;
value_type __im_;
public:
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
complex(const value_type& __re = value_type(), const value_type& __im = value_type())
: __re_(__re), __im_(__im) {}
- template<class _Xp> _LIBCPP_INLINE_VISIBILITY
+ template<class _Xp> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
complex(const complex<_Xp>& __c)
: __re_(__c.real()), __im_(__c.imag()) {}
- _LIBCPP_INLINE_VISIBILITY value_type real() const {return __re_;}
- _LIBCPP_INLINE_VISIBILITY value_type imag() const {return __im_;}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 value_type real() const {return __re_;}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 value_type imag() const {return __im_;}
_LIBCPP_INLINE_VISIBILITY void real(value_type __re) {__re_ = __re;}
_LIBCPP_INLINE_VISIBILITY void imag(value_type __im) {__im_ = __im;}
@@ -309,12 +309,12 @@ public:
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
{
- *this = *this * __c;
+ *this = *this * complex(__c.real(), __c.imag());
return *this;
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
{
- *this = *this / __c;
+ *this = *this / complex(__c.real(), __c.imag());
return *this;
}
};
@@ -368,12 +368,12 @@ public:
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
{
- *this = *this * __c;
+ *this = *this * complex(__c.real(), __c.imag());
return *this;
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
{
- *this = *this / __c;
+ *this = *this / complex(__c.real(), __c.imag());
return *this;
}
};
@@ -424,12 +424,12 @@ public:
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
{
- *this = *this * __c;
+ *this = *this * complex(__c.real(), __c.imag());
return *this;
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
{
- *this = *this / __c;
+ *this = *this / complex(__c.real(), __c.imag());
return *this;
}
};
@@ -480,12 +480,12 @@ public:
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator*=(const complex<_Xp>& __c)
{
- *this = *this * __c;
+ *this = *this * complex(__c.real(), __c.imag());
return *this;
}
template<class _Xp> _LIBCPP_INLINE_VISIBILITY complex& operator/=(const complex<_Xp>& __c)
{
- *this = *this / __c;
+ *this = *this / complex(__c.real(), __c.imag());
return *this;
}
};
@@ -740,7 +740,7 @@ operator-(const complex<_Tp>& __x)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator==(const complex<_Tp>& __x, const complex<_Tp>& __y)
{
@@ -748,7 +748,7 @@ operator==(const complex<_Tp>& __x, const complex<_Tp>& __y)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator==(const complex<_Tp>& __x, const _Tp& __y)
{
@@ -756,7 +756,7 @@ operator==(const complex<_Tp>& __x, const _Tp& __y)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator==(const _Tp& __x, const complex<_Tp>& __y)
{
@@ -764,7 +764,7 @@ operator==(const _Tp& __x, const complex<_Tp>& __y)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator!=(const complex<_Tp>& __x, const complex<_Tp>& __y)
{
@@ -772,7 +772,7 @@ operator!=(const complex<_Tp>& __x, const complex<_Tp>& __y)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator!=(const complex<_Tp>& __x, const _Tp& __y)
{
@@ -780,7 +780,7 @@ operator!=(const complex<_Tp>& __x, const _Tp& __y)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator!=(const _Tp& __x, const complex<_Tp>& __y)
{
@@ -792,21 +792,21 @@ operator!=(const _Tp& __x, const complex<_Tp>& __y)
// real
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp
real(const complex<_Tp>& __c)
{
return __c.real();
}
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
long double
real(long double __re)
{
return __re;
}
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
double
real(double __re)
{
@@ -814,7 +814,7 @@ real(double __re)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename enable_if
<
is_integral<_Tp>::value,
@@ -825,7 +825,7 @@ real(_Tp __re)
return __re;
}
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
float
real(float __re)
{
@@ -835,21 +835,21 @@ real(float __re)
// imag
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp
imag(const complex<_Tp>& __c)
{
return __c.imag();
}
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
long double
imag(long double __re)
{
return 0;
}
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
double
imag(double __re)
{
@@ -857,7 +857,7 @@ imag(double __re)
}
template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename enable_if
<
is_integral<_Tp>::value,
@@ -868,7 +868,7 @@ imag(_Tp __re)
return 0;
}
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
float
imag(float __re)
{
diff --git a/system/include/libcxx/cstdio b/system/include/libcxx/cstdio
index 718d2f71..1cde3eee 100644
--- a/system/include/libcxx/cstdio
+++ b/system/include/libcxx/cstdio
@@ -138,12 +138,12 @@ using ::scanf;
using ::snprintf;
using ::sprintf;
using ::sscanf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::vfprintf;
using ::vfscanf;
using ::vscanf;
using ::vsscanf;
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
using ::vprintf;
using ::vsnprintf;
using ::vsprintf;
diff --git a/system/include/libcxx/cstdlib b/system/include/libcxx/cstdlib
index 95e38428..0a96fb0a 100644
--- a/system/include/libcxx/cstdlib
+++ b/system/include/libcxx/cstdlib
@@ -84,9 +84,9 @@ void *aligned_alloc(size_t alignment, size_t size); // C11
#include <__config>
#include <stdlib.h>
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVCRT
#include "support/win32/locale_win32.h"
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
@@ -154,8 +154,8 @@ using ::quick_exit;
using ::aligned_alloc;
#endif
-// MSVC already has the correct prototype in <stdlib.h.h> #ifdef __cplusplus
-#if !defined(_MSC_VER) && !defined(__sun__)
+// MSVCRT already has the correct prototype in <stdlib.h> #ifdef __cplusplus
+#if !defined(_LIBCPP_MSVCRT) && !defined(__sun__)
inline _LIBCPP_INLINE_VISIBILITY long abs( long __x) _NOEXCEPT {return labs(__x);}
#ifndef _LIBCPP_HAS_NO_LONG_LONG
inline _LIBCPP_INLINE_VISIBILITY long long abs(long long __x) _NOEXCEPT {return llabs(__x);}
@@ -165,7 +165,7 @@ inline _LIBCPP_INLINE_VISIBILITY ldiv_t div( long __x, long __y) _NOEX
#ifndef _LIBCPP_HAS_NO_LONG_LONG
inline _LIBCPP_INLINE_VISIBILITY lldiv_t div(long long __x, long long __y) _NOEXCEPT {return lldiv(__x, __y);}
#endif // _LIBCPP_HAS_NO_LONG_LONG
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
_LIBCPP_END_NAMESPACE_STD
diff --git a/system/include/libcxx/cstring b/system/include/libcxx/cstring
index 13bb1189..21c9155c 100644
--- a/system/include/libcxx/cstring
+++ b/system/include/libcxx/cstring
@@ -93,8 +93,8 @@ using ::strspn;
using ::strstr;
-// MSVC, GNU libc and its derivates already have the correct prototype in <string.h> #ifdef __cplusplus
-#if !defined(__GLIBC__) && !defined(_MSC_VER) && !defined(__sun__)
+// MSVCRT, GNU libc and its derivates already have the correct prototype in <string.h> #ifdef __cplusplus
+#if !defined(__GLIBC__) && !defined(_LIBCPP_MSVCRT) && !defined(__sun__) && !defined(_STRING_H_CPLUSPLUS_98_CONFORMANCE_)
inline _LIBCPP_INLINE_VISIBILITY char* strchr( char* __s, int __c) {return ::strchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY char* strpbrk( char* __s1, const char* __s2) {return ::strpbrk(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY char* strrchr( char* __s, int __c) {return ::strrchr(__s, __c);}
diff --git a/system/include/libcxx/cwchar b/system/include/libcxx/cwchar
index caed08de..90eae75e 100644
--- a/system/include/libcxx/cwchar
+++ b/system/include/libcxx/cwchar
@@ -106,9 +106,9 @@ size_t wcsrtombs(char* restrict dst, const wchar_t** restrict src, size_t len,
#include <__config>
#include <cwctype>
#include <wchar.h>
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
#include <support/win32/support.h> // pull in *swprintf defines
-#endif // _WIN32
+#endif // _LIBCPP_MSVCRT
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
@@ -127,12 +127,12 @@ using ::swprintf;
using ::vfwprintf;
using ::vswprintf;
using ::vwprintf;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::swscanf;
using ::vfwscanf;
using ::vswscanf;
using ::vwscanf;
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
using ::wprintf;
using ::wscanf;
using ::fgetwc;
@@ -146,10 +146,10 @@ using ::putwc;
using ::putwchar;
using ::ungetwc;
using ::wcstod;
-#ifndef _MSC_VER
+#ifndef _LIBCPP_MSVCRT
using ::wcstof;
using ::wcstold;
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
using ::wcstol;
#ifndef _LIBCPP_HAS_NO_LONG_LONG
using ::wcstoll;
@@ -167,28 +167,37 @@ using ::wcscoll;
using ::wcsncmp;
using ::wcsxfrm;
+#if defined(_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_)
+
+using ::wcschr;
+using ::wcspbrk;
+using ::wcsrchr;
+using ::wcsstr;
+using ::wmemchr;
+
+#else
+
inline _LIBCPP_INLINE_VISIBILITY const wchar_t* wcschr(const wchar_t* __s, wchar_t __c) {return ::wcschr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY wchar_t* wcschr( wchar_t* __s, wchar_t __c) {return ::wcschr(__s, __c);}
-using ::wcscspn;
-using ::wcslen;
-
inline _LIBCPP_INLINE_VISIBILITY const wchar_t* wcspbrk(const wchar_t* __s1, const wchar_t* __s2) {return ::wcspbrk(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY wchar_t* wcspbrk( wchar_t* __s1, const wchar_t* __s2) {return ::wcspbrk(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY const wchar_t* wcsrchr(const wchar_t* __s, wchar_t __c) {return ::wcsrchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY wchar_t* wcsrchr( wchar_t* __s, wchar_t __c) {return ::wcsrchr(__s, __c);}
-using ::wcsspn;
-
inline _LIBCPP_INLINE_VISIBILITY const wchar_t* wcsstr(const wchar_t* __s1, const wchar_t* __s2) {return ::wcsstr(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY wchar_t* wcsstr( wchar_t* __s1, const wchar_t* __s2) {return ::wcsstr(__s1, __s2);}
-using ::wcstok;
-
inline _LIBCPP_INLINE_VISIBILITY const wchar_t* wmemchr(const wchar_t* __s, wchar_t __c, size_t __n) {return ::wmemchr(__s, __c, __n);}
inline _LIBCPP_INLINE_VISIBILITY wchar_t* wmemchr( wchar_t* __s, wchar_t __c, size_t __n) {return ::wmemchr(__s, __c, __n);}
+#endif
+
+using ::wcscspn;
+using ::wcslen;
+using ::wcsspn;
+using ::wcstok;
using ::wmemcmp;
using ::wmemcpy;
using ::wmemmove;
diff --git a/system/include/libcxx/deque b/system/include/libcxx/deque
index 8e098223..86272721 100644
--- a/system/include/libcxx/deque
+++ b/system/include/libcxx/deque
@@ -278,7 +278,11 @@ public:
typedef random_access_iterator_tag iterator_category;
typedef _Reference reference;
- _LIBCPP_INLINE_VISIBILITY __deque_iterator() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY __deque_iterator() _NOEXCEPT
+#if _LIBCPP_STD_VER > 11
+ : __m_iter_(nullptr), __ptr_(nullptr)
+#endif
+ {}
template <class _Pp, class _Rp, class _MP>
_LIBCPP_INLINE_VISIBILITY
@@ -915,7 +919,14 @@ protected:
__pointer_allocator;
typedef allocator_traits<__pointer_allocator> __map_traits;
typedef typename __map_traits::pointer __map_pointer;
- typedef typename __map_traits::const_pointer __map_const_pointer;
+ typedef typename __alloc_traits::template
+#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
+ rebind_alloc<const_pointer>
+#else
+ rebind_alloc<const_pointer>::other
+#endif
+ __const_pointer_allocator;
+ typedef typename allocator_traits<__const_pointer_allocator>::const_pointer __map_const_pointer;
typedef __split_buffer<pointer, __pointer_allocator> __map;
typedef __deque_iterator<value_type, pointer, reference, __map_pointer,
@@ -1053,7 +1064,7 @@ template <class _Tp, class _Allocator>
typename __deque_base<_Tp, _Allocator>::const_iterator
__deque_base<_Tp, _Allocator>::begin() const _NOEXCEPT
{
- __map_const_pointer __mp = __map_.begin() + __start_ / __block_size;
+ __map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __start_ / __block_size);
return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __start_ % __block_size);
}
@@ -1071,7 +1082,7 @@ typename __deque_base<_Tp, _Allocator>::const_iterator
__deque_base<_Tp, _Allocator>::end() const _NOEXCEPT
{
size_type __p = size() + __start_;
- __map_const_pointer __mp = __map_.begin() + __p / __block_size;
+ __map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __p / __block_size);
return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __p % __block_size);
}
@@ -1341,6 +1352,8 @@ public:
_LIBCPP_INLINE_VISIBILITY
bool __invariants() const {return __base::__invariants();}
private:
+ typedef typename __base::__map_const_pointer __map_const_pointer;
+
_LIBCPP_INLINE_VISIBILITY
static size_type __recommend_blocks(size_type __n)
{
@@ -2505,9 +2518,9 @@ void
deque<_Tp, _Allocator>::pop_front()
{
allocator_type& __a = __base::__alloc();
- __alloc_traits::destroy(__a, *(__base::__map_.begin() +
- __base::__start_ / __base::__block_size) +
- __base::__start_ % __base::__block_size);
+ __alloc_traits::destroy(__a, __to_raw_pointer(*(__base::__map_.begin() +
+ __base::__start_ / __base::__block_size) +
+ __base::__start_ % __base::__block_size));
--__base::size();
if (++__base::__start_ >= 2 * __base::__block_size)
{
@@ -2523,9 +2536,9 @@ deque<_Tp, _Allocator>::pop_back()
{
allocator_type& __a = __base::__alloc();
size_type __p = __base::size() + __base::__start_ - 1;
- __alloc_traits::destroy(__a, *(__base::__map_.begin() +
- __p / __base::__block_size) +
- __p % __base::__block_size);
+ __alloc_traits::destroy(__a, __to_raw_pointer(*(__base::__map_.begin() +
+ __p / __base::__block_size) +
+ __p % __base::__block_size));
--__base::size();
if (__back_spare() >= 2 * __base::__block_size)
{
@@ -2556,7 +2569,7 @@ deque<_Tp, _Allocator>::__move_and_check(iterator __f, iterator __l, iterator __
__fe = __fb + __bs;
}
if (__fb <= __vt && __vt < __fe)
- __vt = (const_iterator(__f.__m_iter_, __vt) -= __f - __r).__ptr_;
+ __vt = (const_iterator(static_cast<__map_const_pointer>(__f.__m_iter_), __vt) -= __f - __r).__ptr_;
__r = _VSTD::move(__fb, __fe, __r);
__n -= __bs;
__f += __bs;
@@ -2587,7 +2600,7 @@ deque<_Tp, _Allocator>::__move_backward_and_check(iterator __f, iterator __l, it
__lb = __le - __bs;
}
if (__lb <= __vt && __vt < __le)
- __vt = (const_iterator(__l.__m_iter_, __vt) += __r - __l - 1).__ptr_;
+ __vt = (const_iterator(static_cast<__map_const_pointer>(__l.__m_iter_), __vt) += __r - __l - 1).__ptr_;
__r = _VSTD::move_backward(__lb, __le, __r);
__n -= __bs;
__l -= __bs - 1;
@@ -2618,7 +2631,7 @@ deque<_Tp, _Allocator>::__move_construct_and_check(iterator __f, iterator __l,
__fe = __fb + __bs;
}
if (__fb <= __vt && __vt < __fe)
- __vt = (const_iterator(__f.__m_iter_, __vt) += __r - __f).__ptr_;
+ __vt = (const_iterator(static_cast<__map_const_pointer>(__f.__m_iter_), __vt) += __r - __f).__ptr_;
for (; __fb != __fe; ++__fb, ++__r, ++__base::size())
__alloc_traits::construct(__a, _VSTD::addressof(*__r), _VSTD::move(*__fb));
__n -= __bs;
@@ -2654,7 +2667,7 @@ deque<_Tp, _Allocator>::__move_construct_backward_and_check(iterator __f, iterat
__lb = __le - __bs;
}
if (__lb <= __vt && __vt < __le)
- __vt = (const_iterator(__l.__m_iter_, __vt) -= __l - __r + 1).__ptr_;
+ __vt = (const_iterator(static_cast<__map_const_pointer>(__l.__m_iter_), __vt) -= __l - __r + 1).__ptr_;
while (__le != __lb)
{
__alloc_traits::construct(__a, _VSTD::addressof(*--__r), _VSTD::move(*--__le));
diff --git a/system/include/libcxx/forward_list b/system/include/libcxx/forward_list
index 0cbf2fdb..88bf75f9 100644
--- a/system/include/libcxx/forward_list
+++ b/system/include/libcxx/forward_list
@@ -232,7 +232,7 @@ public:
typedef forward_iterator_tag iterator_category;
typedef typename pointer_traits<__node_pointer>::element_type::value_type
value_type;
- typedef value_type& reference;
+ typedef value_type& reference;
typedef typename pointer_traits<__node_pointer>::difference_type
difference_type;
typedef typename pointer_traits<__node_pointer>::template
@@ -249,7 +249,7 @@ public:
_LIBCPP_INLINE_VISIBILITY
reference operator*() const {return __ptr_->__value_;}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return &__ptr_->__value_;}
+ pointer operator->() const {return pointer_traits<pointer>::pointer_to(__ptr_->__value_);}
_LIBCPP_INLINE_VISIBILITY
__forward_list_iterator& operator++()
@@ -303,7 +303,7 @@ class _LIBCPP_TYPE_VIS __forward_list_const_iterator
public:
typedef forward_iterator_tag iterator_category;
typedef typename __node::value_type value_type;
- typedef const value_type& reference;
+ typedef const value_type& reference;
typedef typename pointer_traits<__node_const_pointer>::difference_type
difference_type;
typedef typename pointer_traits<__node_const_pointer>::template
@@ -323,7 +323,7 @@ public:
_LIBCPP_INLINE_VISIBILITY
reference operator*() const {return __ptr_->__value_;}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return &__ptr_->__value_;}
+ pointer operator->() const {return pointer_traits<pointer>::pointer_to(__ptr_->__value_);}
_LIBCPP_INLINE_VISIBILITY
__forward_list_const_iterator& operator++()
@@ -368,18 +368,27 @@ protected:
__node_allocator;
typedef allocator_traits<__node_allocator> __node_traits;
typedef typename __node_traits::pointer __node_pointer;
- typedef typename __node_traits::const_pointer __node_const_pointer;
+ typedef typename __node_traits::pointer __node_const_pointer;
+
+ typedef typename allocator_traits<allocator_type>::template
+#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
+ rebind_alloc<__begin_node>
+#else
+ rebind_alloc<__begin_node>::other
+#endif
+ __begin_node_allocator;
+ typedef typename allocator_traits<__begin_node_allocator>::pointer __begin_node_pointer;
__compressed_pair<__begin_node, __node_allocator> __before_begin_;
_LIBCPP_INLINE_VISIBILITY
__node_pointer __before_begin() _NOEXCEPT
- {return pointer_traits<__node_pointer>::pointer_to(
- static_cast<__node&>(__before_begin_.first()));}
+ {return static_cast<__node_pointer>(pointer_traits<__begin_node_pointer>::
+ pointer_to(__before_begin_.first()));}
_LIBCPP_INLINE_VISIBILITY
__node_const_pointer __before_begin() const _NOEXCEPT
- {return pointer_traits<__node_const_pointer>::pointer_to(
- static_cast<const __node&>(__before_begin_.first()));}
+ {return static_cast<__node_const_pointer>(pointer_traits<__begin_node_pointer>::
+ pointer_to(const_cast<__begin_node&>(__before_begin_.first())));}
_LIBCPP_INLINE_VISIBILITY
__node_allocator& __alloc() _NOEXCEPT
@@ -389,7 +398,7 @@ protected:
{return __before_begin_.second();}
typedef __forward_list_iterator<__node_pointer> iterator;
- typedef __forward_list_const_iterator<__node_const_pointer> const_iterator;
+ typedef __forward_list_const_iterator<__node_pointer> const_iterator;
_LIBCPP_INLINE_VISIBILITY
__forward_list_base()
@@ -1050,7 +1059,7 @@ template <class... _Args>
typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::emplace_after(const_iterator __p, _Args&&... __args)
{
- __node_pointer const __r = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer const __r = __p.__ptr_;
__node_allocator& __a = base::__alloc();
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __h(__node_traits::allocate(__a, 1), _Dp(__a, 1));
@@ -1067,7 +1076,7 @@ template <class _Tp, class _Alloc>
typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, value_type&& __v)
{
- __node_pointer const __r = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer const __r = __p.__ptr_;
__node_allocator& __a = base::__alloc();
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __h(__node_traits::allocate(__a, 1), _Dp(__a, 1));
@@ -1083,7 +1092,7 @@ template <class _Tp, class _Alloc>
typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, const value_type& __v)
{
- __node_pointer const __r = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer const __r = __p.__ptr_;
__node_allocator& __a = base::__alloc();
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __h(__node_traits::allocate(__a, 1), _Dp(__a, 1));
@@ -1098,7 +1107,7 @@ typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::insert_after(const_iterator __p, size_type __n,
const value_type& __v)
{
- __node_pointer __r = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer __r = __p.__ptr_;
if (__n > 0)
{
__node_allocator& __a = base::__alloc();
@@ -1148,7 +1157,7 @@ typename enable_if
forward_list<_Tp, _Alloc>::insert_after(const_iterator __p,
_InputIterator __f, _InputIterator __l)
{
- __node_pointer __r = const_cast<__node_pointer>(__p.__ptr_);
+ __node_pointer __r = __p.__ptr_;
if (__f != __l)
{
__node_allocator& __a = base::__alloc();
@@ -1192,7 +1201,7 @@ template <class _Tp, class _Alloc>
typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::erase_after(const_iterator __f)
{
- __node_pointer __p = const_cast<__node_pointer>(__f.__ptr_);
+ __node_pointer __p = __f.__ptr_;
__node_pointer __n = __p->__next_;
__p->__next_ = __n->__next_;
__node_allocator& __a = base::__alloc();
@@ -1205,10 +1214,10 @@ template <class _Tp, class _Alloc>
typename forward_list<_Tp, _Alloc>::iterator
forward_list<_Tp, _Alloc>::erase_after(const_iterator __f, const_iterator __l)
{
- __node_pointer __e = const_cast<__node_pointer>(__l.__ptr_);
+ __node_pointer __e = __l.__ptr_;
if (__f != __l)
{
- __node_pointer __p = const_cast<__node_pointer>(__f.__ptr_);
+ __node_pointer __p = __f.__ptr_;
__node_pointer __n = __p->__next_;
if (__n != __e)
{
@@ -1302,12 +1311,10 @@ forward_list<_Tp, _Alloc>::splice_after(const_iterator __p,
const_iterator __lm1 = __x.before_begin();
while (__lm1.__ptr_->__next_ != nullptr)
++__lm1;
- const_cast<__node_pointer>(__lm1.__ptr_)->__next_ =
- const_cast<__node_pointer>(__p.__ptr_)->__next_;
+ __lm1.__ptr_->__next_ = __p.__ptr_->__next_;
}
- const_cast<__node_pointer>(__p.__ptr_)->__next_ =
- const_cast<__node_pointer>(__x.__before_begin())->__next_;
- const_cast<__node_pointer>(__x.__before_begin())->__next_ = nullptr;
+ __p.__ptr_->__next_ = __x.__before_begin()->__next_;
+ __x.__before_begin()->__next_ = nullptr;
}
}
@@ -1320,12 +1327,9 @@ forward_list<_Tp, _Alloc>::splice_after(const_iterator __p,
const_iterator __lm1 = _VSTD::next(__i);
if (__p != __i && __p != __lm1)
{
- const_cast<__node_pointer>(__i.__ptr_)->__next_ =
- const_cast<__node_pointer>(__lm1.__ptr_)->__next_;
- const_cast<__node_pointer>(__lm1.__ptr_)->__next_ =
- const_cast<__node_pointer>(__p.__ptr_)->__next_;
- const_cast<__node_pointer>(__p.__ptr_)->__next_ =
- const_cast<__node_pointer>(__lm1.__ptr_);
+ __i.__ptr_->__next_ = __lm1.__ptr_->__next_;
+ __lm1.__ptr_->__next_ = __p.__ptr_->__next_;
+ __p.__ptr_->__next_ = __lm1.__ptr_;
}
}
@@ -1342,12 +1346,9 @@ forward_list<_Tp, _Alloc>::splice_after(const_iterator __p,
++__lm1;
if (__f != __lm1)
{
- const_cast<__node_pointer>(__lm1.__ptr_)->__next_ =
- const_cast<__node_pointer>(__p.__ptr_)->__next_;
- const_cast<__node_pointer>(__p.__ptr_)->__next_ =
- const_cast<__node_pointer>(__f.__ptr_)->__next_;
- const_cast<__node_pointer>(__f.__ptr_)->__next_ =
- const_cast<__node_pointer>(__l.__ptr_);
+ __lm1.__ptr_->__next_ = __p.__ptr_->__next_;
+ __p.__ptr_->__next_ = __f.__ptr_->__next_;
+ __f.__ptr_->__next_ = __l.__ptr_;
}
}
}
diff --git a/system/include/libcxx/fstream b/system/include/libcxx/fstream
index 0a5cf92a..e3f8306f 100644
--- a/system/include/libcxx/fstream
+++ b/system/include/libcxx/fstream
@@ -807,9 +807,15 @@ basic_filebuf<_CharT, _Traits>::seekoff(off_type __off, ios_base::seekdir __way,
default:
return pos_type(off_type(-1));
}
+#if _WIN32
+ if (fseek(__file_, __width > 0 ? __width * __off : 0, __whence))
+ return pos_type(off_type(-1));
+ pos_type __r = ftell(__file_);
+#else
if (fseeko(__file_, __width > 0 ? __width * __off : 0, __whence))
return pos_type(off_type(-1));
pos_type __r = ftello(__file_);
+#endif
__r.state(__st_);
return __r;
}
@@ -820,8 +826,13 @@ basic_filebuf<_CharT, _Traits>::seekpos(pos_type __sp, ios_base::openmode)
{
if (__file_ == 0 || sync())
return pos_type(off_type(-1));
+#if _WIN32
+ if (fseek(__file_, __sp, SEEK_SET))
+ return pos_type(off_type(-1));
+#else
if (fseeko(__file_, __sp, SEEK_SET))
return pos_type(off_type(-1));
+#endif
__st_ = __sp.state();
return __sp;
}
@@ -880,8 +891,13 @@ basic_filebuf<_CharT, _Traits>::sync()
}
}
}
+#if _WIN32
+ if (fseek(__file_, -__c, SEEK_CUR))
+ return -1;
+#else
if (fseeko(__file_, -__c, SEEK_CUR))
return -1;
+#endif
if (__update_st)
__st_ = __state;
__extbufnext_ = __extbufend_ = __extbuf_;
diff --git a/system/include/libcxx/functional b/system/include/libcxx/functional
index 995db564..2130f0e3 100644
--- a/system/include/libcxx/functional
+++ b/system/include/libcxx/functional
@@ -68,96 +68,120 @@ template <class T> reference_wrapper<const T> cref(const T& t) noexcept;
template <class T> void cref(const T&& t) = delete;
template <class T> reference_wrapper<const T> cref(reference_wrapper<T> t) noexcept;
-template <class T>
+template <class T> // <class T=void> in C++14
struct plus : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct minus : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct multiplies : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct divides : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct modulus : binary_function<T, T, T>
{
T operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct negate : unary_function<T, T>
{
T operator()(const T& x) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct equal_to : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct not_equal_to : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct greater : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct less : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct greater_equal : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct less_equal : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct logical_and : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct logical_or : binary_function<T, T, bool>
{
bool operator()(const T& x, const T& y) const;
};
-template <class T>
+template <class T> // <class T=void> in C++14
struct logical_not : unary_function<T, bool>
{
bool operator()(const T& x) const;
};
+template <class T> // <class T=void> in C++14
+struct bit_and : unary_function<T, bool>
+{
+ bool operator()(const T& x, const T& y) const;
+};
+
+template <class T> // <class T=void> in C++14
+struct bit_or : unary_function<T, bool>
+{
+ bool operator()(const T& x, const T& y) const;
+};
+
+template <class T> // <class T=void> in C++14
+struct bit_xor : unary_function<T, bool>
+{
+ bool operator()(const T& x, const T& y) const;
+};
+
+template <class T=void> // C++14
+struct bit_xor : unary_function<T, bool>
+{
+ bool operator()(const T& x) const;
+};
+
template <class Predicate>
class unary_negate
: public unary_function<typename Predicate::argument_type, bool>
@@ -473,127 +497,399 @@ POLICY: For non-variadic implementations, the number of arguments is limited
_LIBCPP_BEGIN_NAMESPACE_STD
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS plus : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x + __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS plus<void>
+{
+ template <class _T1, class _T2>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS minus : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x - __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS minus<void>
+{
+ template <class _T1, class _T2>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) - _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS multiplies : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x * __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS multiplies<void>
+{
+ template <class _T1, class _T2>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) * _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS divides : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x / __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS divides<void>
+{
+ template <class _T1, class _T2>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) / _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS modulus : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x % __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS modulus<void>
+{
+ template <class _T1, class _T2>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) % _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS negate : unary_function<_Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x) const
{return -__x;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS negate<void>
+{
+ template <class _Tp>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_Tp&& __x) const
+ { return -_VSTD::forward<_Tp>(__x); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS equal_to : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x == __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS equal_to<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) == _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS not_equal_to : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x != __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS not_equal_to<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) != _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS greater : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x > __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS greater<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) > _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
// less in <__functional_base>
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS greater_equal : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x >= __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS greater_equal<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) >= _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS less_equal : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x <= __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS less_equal<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) <= _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS logical_and : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x && __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS logical_and<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) && _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS logical_or : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x || __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS logical_or<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) || _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS logical_not : unary_function<_Tp, bool>
{
_LIBCPP_INLINE_VISIBILITY bool operator()(const _Tp& __x) const
{return !__x;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS logical_not<void>
+{
+ template <class _Tp>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_Tp&& __x) const
+ { return !_VSTD::forward<_Tp>(__x); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS bit_and : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x & __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS bit_and<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) & _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS bit_or : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x | __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS bit_or<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) | _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+#else
template <class _Tp>
+#endif
struct _LIBCPP_TYPE_VIS bit_xor : binary_function<_Tp, _Tp, _Tp>
{
_LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x, const _Tp& __y) const
{return __x ^ __y;}
};
+#if _LIBCPP_STD_VER > 11
+template <>
+struct _LIBCPP_TYPE_VIS bit_xor<void>
+{
+ template <class _T1, class _T2> _LIBCPP_INLINE_VISIBILITY
+ auto operator()(_T1&& __t, _T2&& __u) const
+ { return _VSTD::forward<_T1>(__t) ^ _VSTD::forward<_T2>(__u); }
+};
+#endif
+
+
+#if _LIBCPP_STD_VER > 11
+template <class _Tp = void>
+struct _LIBCPP_TYPE_VIS bit_not : unary_function<_Tp, _Tp>
+{
+ _LIBCPP_INLINE_VISIBILITY _Tp operator()(const _Tp& __x) const
+ {return ~__x;}
+};
+
+template <>
+struct _LIBCPP_TYPE_VIS bit_not<void>
+{
+ template <class _Tp>
+ _LIBCPP_INLINE_VISIBILITY auto operator()(_Tp&& __x) const
+ { return ~_VSTD::forward<_Tp>(__x); }
+};
+#endif
+
template <class _Predicate>
class _LIBCPP_TYPE_VIS unary_negate
: public unary_function<typename _Predicate::argument_type, bool>
@@ -1139,8 +1435,11 @@ public:
function(const function&);
function(function&&) _NOEXCEPT;
template<class _Fp>
- function(_Fp,
- typename enable_if<__callable<_Fp>::value>::type* = 0);
+ function(_Fp, typename enable_if
+ <
+ __callable<_Fp>::value &&
+ !is_same<_Fp, function>::value
+ >::type* = 0);
template<class _Alloc>
_LIBCPP_INLINE_VISIBILITY
@@ -1162,7 +1461,8 @@ public:
template<class _Fp>
typename enable_if
<
- __callable<typename decay<_Fp>::type>::value,
+ __callable<typename decay<_Fp>::type>::value &&
+ !is_same<typename remove_reference<_Fp>::type, function>::value,
function&
>::type
operator=(_Fp&&);
@@ -1266,7 +1566,11 @@ function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc&,
template<class _Rp, class ..._ArgTypes>
template <class _Fp>
function<_Rp(_ArgTypes...)>::function(_Fp __f,
- typename enable_if<__callable<_Fp>::value>::type*)
+ typename enable_if
+ <
+ __callable<_Fp>::value &&
+ !is_same<_Fp, function>::value
+ >::type*)
: __f_(0)
{
if (__not_null(__f))
@@ -1370,7 +1674,8 @@ template<class _Rp, class ..._ArgTypes>
template <class _Fp>
typename enable_if
<
- function<_Rp(_ArgTypes...)>::template __callable<typename decay<_Fp>::type>::value,
+ function<_Rp(_ArgTypes...)>::template __callable<typename decay<_Fp>::type>::value &&
+ !is_same<typename remove_reference<_Fp>::type, function<_Rp(_ArgTypes...)>>::value,
function<_Rp(_ArgTypes...)>&
>::type
function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f)
@@ -1594,12 +1899,24 @@ template <class _Ti, bool IsReferenceWrapper, bool IsBindEx, bool IsPh,
class _TupleUj>
struct ____mu_return;
+template <bool _Invokable, class _Ti, class ..._Uj>
+struct ____mu_return_invokable // false
+{
+ typedef __nat type;
+};
+
template <class _Ti, class ..._Uj>
-struct ____mu_return<_Ti, false, true, false, tuple<_Uj...> >
+struct ____mu_return_invokable<true, _Ti, _Uj...>
{
typedef typename __invoke_of<_Ti&, _Uj...>::type type;
};
+template <class _Ti, class ..._Uj>
+struct ____mu_return<_Ti, false, true, false, tuple<_Uj...> >
+ : public ____mu_return_invokable<__invokable<_Ti&, _Uj...>::value, _Ti, _Uj...>
+{
+};
+
template <class _Ti, class _TupleUj>
struct ____mu_return<_Ti, false, false, true, _TupleUj>
{
@@ -1737,7 +2054,9 @@ public:
template <class _Gp, class ..._BA,
class = typename enable_if
<
- is_constructible<_Fd, _Gp>::value
+ is_constructible<_Fd, _Gp>::value &&
+ !is_same<typename remove_reference<_Gp>::type,
+ __bind>::value
>::type>
_LIBCPP_INLINE_VISIBILITY
explicit __bind(_Gp&& __f, _BA&& ...__bound_args)
@@ -1802,7 +2121,13 @@ public:
#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
- template <class _Gp, class ..._BA>
+ template <class _Gp, class ..._BA,
+ class = typename enable_if
+ <
+ is_constructible<_Fd, _Gp>::value &&
+ !is_same<typename remove_reference<_Gp>::type,
+ __bind_r>::value
+ >::type>
_LIBCPP_INLINE_VISIBILITY
explicit __bind_r(_Gp&& __f, _BA&& ...__bound_args)
: base(_VSTD::forward<_Gp>(__f),
diff --git a/system/include/libcxx/future b/system/include/libcxx/future
index 3d7bb6c9..dae1a4b8 100644
--- a/system/include/libcxx/future
+++ b/system/include/libcxx/future
@@ -403,6 +403,72 @@ _LIBCPP_DECLARE_STRONG_ENUM(launch)
};
_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(launch)
+#ifndef _LIBCPP_HAS_NO_STRONG_ENUMS
+
+#ifdef _LIBCXX_UNDERLYING_TYPE
+typedef underlying_type<launch>::type __launch_underlying_type;
+#else
+typedef int __launch_underlying_type;
+#endif
+
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+launch
+operator&(launch __x, launch __y)
+{
+ return static_cast<launch>(static_cast<__launch_underlying_type>(__x) &
+ static_cast<__launch_underlying_type>(__y));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+launch
+operator|(launch __x, launch __y)
+{
+ return static_cast<launch>(static_cast<__launch_underlying_type>(__x) |
+ static_cast<__launch_underlying_type>(__y));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+launch
+operator^(launch __x, launch __y)
+{
+ return static_cast<launch>(static_cast<__launch_underlying_type>(__x) ^
+ static_cast<__launch_underlying_type>(__y));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR
+launch
+operator~(launch __x)
+{
+ return static_cast<launch>(~static_cast<__launch_underlying_type>(__x) & 3);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+launch&
+operator&=(launch& __x, launch __y)
+{
+ __x = __x & __y; return __x;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+launch&
+operator|=(launch& __x, launch __y)
+{
+ __x = __x | __y; return __x;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+launch&
+operator^=(launch& __x, launch __y)
+{
+ __x = __x ^ __y; return __x;
+}
+
+#endif // !_LIBCPP_HAS_NO_STRONG_ENUMS
+
//enum class future_status
_LIBCPP_DECLARE_STRONG_ENUM(future_status)
{
diff --git a/system/include/libcxx/ios b/system/include/libcxx/ios
index 25bbfc0b..c10003d0 100644
--- a/system/include/libcxx/ios
+++ b/system/include/libcxx/ios
@@ -983,6 +983,33 @@ defaultfloat(ios_base& __str)
return __str;
}
+template <class _CharT, class _Traits>
+class __save_flags
+{
+ typedef basic_ios<_CharT, _Traits> __stream_type;
+ typedef typename __stream_type::fmtflags fmtflags;
+
+ __stream_type& __stream_;
+ fmtflags __fmtflags_;
+ _CharT __fill_;
+
+ __save_flags(const __save_flags&);
+ __save_flags& operator=(const __save_flags&);
+public:
+ _LIBCPP_INLINE_VISIBILITY
+ explicit __save_flags(__stream_type& __stream)
+ : __stream_(__stream),
+ __fmtflags_(__stream.flags()),
+ __fill_(__stream.fill())
+ {}
+ _LIBCPP_INLINE_VISIBILITY
+ ~__save_flags()
+ {
+ __stream_.flags(__fmtflags_);
+ __stream_.fill(__fill_);
+ }
+};
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_IOS
diff --git a/system/include/libcxx/istream b/system/include/libcxx/istream
index 3f629f68..f3e74c38 100644
--- a/system/include/libcxx/istream
+++ b/system/include/libcxx/istream
@@ -1144,8 +1144,7 @@ basic_istream<_CharT, _Traits>::ignore(streamsize __n, int_type __dlm)
break;
}
++__gc_;
- char_type __ch = traits_type::to_char_type(__i);
- if (traits_type::eq(__ch, static_cast<char_type>(__dlm)))
+ if (traits_type::eq_int_type(__i, __dlm))
break;
}
}
@@ -1160,8 +1159,7 @@ basic_istream<_CharT, _Traits>::ignore(streamsize __n, int_type __dlm)
break;
}
++__gc_;
- char_type __ch = traits_type::to_char_type(__i);
- if (traits_type::eq(__ch, static_cast<char_type>(__dlm)))
+ if (traits_type::eq_int_type(__i, __dlm))
break;
}
}
diff --git a/system/include/libcxx/iterator b/system/include/libcxx/iterator
index 3b078a2a..858510d1 100644
--- a/system/include/libcxx/iterator
+++ b/system/include/libcxx/iterator
@@ -321,8 +321,10 @@ template <class T, size_t N> T* end(T (&array)[N]);
#include <Availability.h>
#endif
-#ifdef _LIBCPP_DEBUG
-#include <cassert>
+#ifdef _LIBCPP_DEBUG2
+# include <__debug>
+#else
+# define _LIBCPP_ASSERT(x, m) ((void)0)
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -1091,6 +1093,9 @@ private:
iterator_type __i;
public:
_LIBCPP_INLINE_VISIBILITY __wrap_iter() _NOEXCEPT
+#if _LIBCPP_STD_VER > 11
+ : __i{}
+#endif
{
#if _LIBCPP_DEBUG_LEVEL >= 2
__get_db()->__insert_i(this);
@@ -1135,7 +1140,14 @@ public:
#endif
return *__i;
}
- _LIBCPP_INLINE_VISIBILITY pointer operator->() const _NOEXCEPT {return &(operator*());}
+ _LIBCPP_INLINE_VISIBILITY pointer operator->() const _NOEXCEPT
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable iterator");
+#endif
+ return (pointer)&reinterpret_cast<const volatile char&>(*__i);
+ }
_LIBCPP_INLINE_VISIBILITY __wrap_iter& operator++() _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1257,10 +1269,6 @@ inline _LIBCPP_INLINE_VISIBILITY
bool
operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
-#if _LIBCPP_DEBUG_LEVEL >= 2
- _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y),
- "Attempted to compare incomparable iterators");
-#endif
return __x.base() == __y.base();
}
@@ -1270,7 +1278,7 @@ bool
operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
- _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y),
+ _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
"Attempted to compare incomparable iterators");
#endif
return __x.base() < __y.base();
@@ -1346,7 +1354,7 @@ typename __wrap_iter<_Iter1>::difference_type
operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
- _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y),
+ _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
"Attempted to subtract incompatible iterators");
#endif
return __x.base() - __y.base();
diff --git a/system/include/libcxx/limits b/system/include/libcxx/limits
index 9b9d7a6f..c995ef59 100644
--- a/system/include/libcxx/limits
+++ b/system/include/libcxx/limits
@@ -111,9 +111,9 @@ template<> class numeric_limits<cv long double>;
#include <__undef_min_max>
-#if defined(_MSC_VER)
+#if defined(_LIBCPP_MSVCRT)
#include "support/win32/limits_win32.h"
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
_LIBCPP_BEGIN_NAMESPACE_STD
diff --git a/system/include/libcxx/list b/system/include/libcxx/list
index 06904d96..4b1272a8 100644
--- a/system/include/libcxx/list
+++ b/system/include/libcxx/list
@@ -178,6 +178,12 @@ template <class T, class Alloc>
#include <__undef_min_max>
+#ifdef _LIBCPP_DEBUG2
+# include <__debug>
+#else
+# define _LIBCPP_ASSERT(x, m) ((void)0)
+#endif
+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
@@ -196,13 +202,20 @@ struct __list_node_base
rebind<__list_node<_Tp, _VoidPtr> >::other pointer;
#endif
+ typedef typename pointer_traits<_VoidPtr>::template
+#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
+ rebind<__list_node_base> __base_pointer;
+#else
+ rebind<__list_node_base>::other __base_pointer;
+#endif
+
pointer __prev_;
pointer __next_;
_LIBCPP_INLINE_VISIBILITY
__list_node_base()
- : __prev_(static_cast<pointer>(this)),
- __next_(static_cast<pointer>(this))
+ : __prev_(static_cast<pointer>(pointer_traits<__base_pointer>::pointer_to(*this))),
+ __next_(static_cast<pointer>(pointer_traits<__base_pointer>::pointer_to(*this)))
{}
};
@@ -260,7 +273,7 @@ public:
typedef typename pointer_traits<pointer>::difference_type difference_type;
_LIBCPP_INLINE_VISIBILITY
- __list_iterator() _NOEXCEPT
+ __list_iterator() _NOEXCEPT : __ptr_(nullptr)
{
#if _LIBCPP_DEBUG_LEVEL >= 2
__get_db()->__insert_i(this);
@@ -305,7 +318,14 @@ public:
return __ptr_->__value_;
}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return &(operator*());}
+ pointer operator->() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable list::iterator");
+#endif
+ return pointer_traits<pointer>::pointer_to(__ptr_->__value_);
+ }
_LIBCPP_INLINE_VISIBILITY
__list_iterator& operator++()
@@ -336,10 +356,6 @@ public:
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(const __list_iterator& __x, const __list_iterator& __y)
{
-#if _LIBCPP_DEBUG_LEVEL >= 2
- _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y),
- "Attempted to compare non-comparable list::iterator");
-#endif
return __x.__ptr_ == __y.__ptr_;
}
friend _LIBCPP_INLINE_VISIBILITY
@@ -352,9 +368,9 @@ class _LIBCPP_TYPE_VIS __list_const_iterator
{
typedef typename pointer_traits<_VoidPtr>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
- rebind<const __list_node<_Tp, _VoidPtr> > __node_pointer;
+ rebind<__list_node<_Tp, _VoidPtr> > __node_pointer;
#else
- rebind<const __list_node<_Tp, _VoidPtr> >::other __node_pointer;
+ rebind<__list_node<_Tp, _VoidPtr> >::other __node_pointer;
#endif
__node_pointer __ptr_;
@@ -387,14 +403,14 @@ public:
typedef typename pointer_traits<pointer>::difference_type difference_type;
_LIBCPP_INLINE_VISIBILITY
- __list_const_iterator() _NOEXCEPT
+ __list_const_iterator() _NOEXCEPT : __ptr_(nullptr)
{
#if _LIBCPP_DEBUG_LEVEL >= 2
__get_db()->__insert_i(this);
#endif
}
_LIBCPP_INLINE_VISIBILITY
- __list_const_iterator(__list_iterator<_Tp, _VoidPtr> __p) _NOEXCEPT
+ __list_const_iterator(const __list_iterator<_Tp, _VoidPtr>& __p) _NOEXCEPT
: __ptr_(__p.__ptr_)
{
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -439,7 +455,14 @@ public:
return __ptr_->__value_;
}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return &(operator*());}
+ pointer operator->() const
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
+ "Attempted to dereference a non-dereferenceable list::iterator");
+#endif
+ return pointer_traits<pointer>::pointer_to(__ptr_->__value_);
+ }
_LIBCPP_INLINE_VISIBILITY
__list_const_iterator& operator++()
@@ -470,10 +493,6 @@ public:
friend _LIBCPP_INLINE_VISIBILITY
bool operator==(const __list_const_iterator& __x, const __list_const_iterator& __y)
{
-#if _LIBCPP_DEBUG_LEVEL >= 2
- _LIBCPP_ASSERT(__get_const_db()->__comparable(&__x, &__y),
- "Attempted to compare non-comparable list::const_iterator");
-#endif
return __x.__ptr_ == __y.__ptr_;
}
friend _LIBCPP_INLINE_VISIBILITY
@@ -505,11 +524,20 @@ protected:
__node_allocator;
typedef allocator_traits<__node_allocator> __node_alloc_traits;
typedef typename __node_alloc_traits::pointer __node_pointer;
- typedef typename __node_alloc_traits::const_pointer __node_const_pointer;
+ typedef typename __node_alloc_traits::pointer __node_const_pointer;
typedef typename __alloc_traits::pointer pointer;
typedef typename __alloc_traits::const_pointer const_pointer;
typedef typename __alloc_traits::difference_type difference_type;
+ typedef typename __alloc_traits::template
+#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
+ rebind_alloc<__node_base>
+#else
+ rebind_alloc<__node_base>::other
+#endif
+ __node_base_allocator;
+ typedef typename allocator_traits<__node_base_allocator>::pointer __node_base_pointer;
+
__node_base __end_;
__compressed_pair<size_type, __node_allocator> __size_alloc_;
@@ -525,7 +553,7 @@ protected:
const __node_allocator& __node_alloc() const _NOEXCEPT
{return __size_alloc_.second();}
- static void __unlink_nodes(__node_base& __f, __node_base& __l) _NOEXCEPT;
+ static void __unlink_nodes(__node_pointer __f, __node_pointer __l) _NOEXCEPT;
__list_imp()
_NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value);
@@ -557,18 +585,22 @@ protected:
iterator end() _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
- return iterator(static_cast<__node_pointer>(&__end_), this);
+ return iterator(static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__end_)), this);
#else
- return iterator(static_cast<__node_pointer>(&__end_));
+ return iterator(static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__end_)));
#endif
}
_LIBCPP_INLINE_VISIBILITY
const_iterator end() const _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
- return const_iterator(static_cast<__node_const_pointer>(&__end_), this);
+ return const_iterator(static_cast<__node_const_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(__end_))), this);
#else
- return const_iterator(static_cast<__node_const_pointer>(&__end_));
+ return const_iterator(static_cast<__node_const_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(__end_))));
#endif
}
@@ -637,11 +669,11 @@ private:
template <class _Tp, class _Alloc>
inline _LIBCPP_INLINE_VISIBILITY
void
-__list_imp<_Tp, _Alloc>::__unlink_nodes(__node_base& __f, __node_base& __l)
+__list_imp<_Tp, _Alloc>::__unlink_nodes(__node_pointer __f, __node_pointer __l)
_NOEXCEPT
{
- __f.__prev_->__next_ = __l.__next_;
- __l.__next_->__prev_ = __f.__prev_;
+ __f->__prev_->__next_ = __l->__next_;
+ __l->__next_->__prev_ = __f->__prev_;
}
template <class _Tp, class _Alloc>
@@ -676,15 +708,16 @@ __list_imp<_Tp, _Alloc>::clear() _NOEXCEPT
{
__node_allocator& __na = __node_alloc();
__node_pointer __f = __end_.__next_;
- __node_pointer __l = static_cast<__node_pointer>(&__end_);
- __unlink_nodes(*__f, *__l->__prev_);
+ __node_pointer __l = static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__end_));
+ __unlink_nodes(__f, __l->__prev_);
__sz() = 0;
while (__f != __l)
{
- __node& __n = *__f;
+ __node_pointer __n = __f;
__f = __f->__next_;
- __node_alloc_traits::destroy(__na, _VSTD::addressof(__n.__value_));
- __node_alloc_traits::deallocate(__na, _VSTD::addressof(__n), 1);
+ __node_alloc_traits::destroy(__na, _VSTD::addressof(__n->__value_));
+ __node_alloc_traits::deallocate(__na, __n, 1);
}
#if _LIBCPP_DEBUG_LEVEL >= 2
__c_node* __c = __get_db()->__find_c_and_lock(this);
@@ -719,16 +752,20 @@ __list_imp<_Tp, _Alloc>::swap(__list_imp& __c)
swap(__sz(), __c.__sz());
swap(__end_, __c.__end_);
if (__sz() == 0)
- __end_.__next_ = __end_.__prev_ = &static_cast<__node&>(__end_);
+ __end_.__next_ = __end_.__prev_ = static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__end_));
else
__end_.__prev_->__next_ = __end_.__next_->__prev_
- = &static_cast<__node&>(__end_);
+ = static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__end_));
if (__c.__sz() == 0)
__c.__end_.__next_ = __c.__end_.__prev_
- = &static_cast<__node&>(__c.__end_);
+ = static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__c.__end_));
else
__c.__end_.__prev_->__next_ = __c.__end_.__next_->__prev_
- = &static_cast<__node&>(__c.__end_);
+ = static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__c.__end_));
#if _LIBCPP_DEBUG_LEVEL >= 2
__libcpp_db* __db = __get_db();
__c_node* __cn1 = __db->__find_c_and_lock(this);
@@ -740,7 +777,8 @@ __list_imp<_Tp, _Alloc>::swap(__list_imp& __c)
{
--__p;
const_iterator* __i = static_cast<const_iterator*>((*__p)->__i_);
- if (__i->__ptr_ == static_cast<__node_pointer>(&__c.__end_))
+ if (__i->__ptr_ == static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__c.__end_)))
{
__cn2->__add(*__p);
if (--__cn1->end_ != __p)
@@ -753,7 +791,8 @@ __list_imp<_Tp, _Alloc>::swap(__list_imp& __c)
{
--__p;
const_iterator* __i = static_cast<const_iterator*>((*__p)->__i_);
- if (__i->__ptr_ == static_cast<__node_pointer>(&__end_))
+ if (__i->__ptr_ == static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__end_)))
{
__cn1->__add(*__p);
if (--__cn2->end_ != __p)
@@ -775,6 +814,8 @@ class _LIBCPP_TYPE_VIS list
typedef typename base::__node_allocator __node_allocator;
typedef typename base::__node_pointer __node_pointer;
typedef typename base::__node_alloc_traits __node_alloc_traits;
+ typedef typename base::__node_base __node_base;
+ typedef typename base::__node_base_pointer __node_base_pointer;
public:
typedef _Tp value_type;
@@ -1014,7 +1055,7 @@ public:
#endif // _LIBCPP_DEBUG_LEVEL >= 2
private:
- static void __link_nodes(__node& __p, __node& __f, __node& __l);
+ static void __link_nodes(__node_pointer __p, __node_pointer __f, __node_pointer __l);
iterator __iterator(size_type __n);
template <class _Comp>
static iterator __sort(iterator __f1, iterator __e2, size_type __n, _Comp& __comp);
@@ -1028,12 +1069,12 @@ private:
template <class _Tp, class _Alloc>
inline _LIBCPP_INLINE_VISIBILITY
void
-list<_Tp, _Alloc>::__link_nodes(__node& __p, __node& __f, __node& __l)
+list<_Tp, _Alloc>::__link_nodes(__node_pointer __p, __node_pointer __f, __node_pointer __l)
{
- __p.__prev_->__next_ = &__f;
- __f.__prev_ = __p.__prev_;
- __p.__prev_ = &__l;
- __l.__next_ = &__p;
+ __p->__prev_->__next_ = __f;
+ __f->__prev_ = __p->__prev_;
+ __p->__prev_ = __l;
+ __l->__next_ = __p;
}
template <class _Tp, class _Alloc>
@@ -1290,9 +1331,13 @@ list<_Tp, _Alloc>::insert(const_iterator __p, const value_type& __x)
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__hold->__prev_ = 0;
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), __x);
- __link_nodes(const_cast<__node&>(*__p.__ptr_), *__hold, *__hold);
+ __link_nodes(__p.__ptr_, __hold.get(), __hold.get());
++base::__sz();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ return iterator(__hold.release(), this);
+#else
return iterator(__hold.release());
+#endif
}
template <class _Tp, class _Alloc>
@@ -1303,9 +1348,9 @@ list<_Tp, _Alloc>::insert(const_iterator __p, size_type __n, const value_type& _
_LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
"list::insert(iterator, n, x) called with an iterator not"
" referring to this list");
- iterator __r(const_cast<__node_pointer>(__p.__ptr_), this);
+ iterator __r(__p.__ptr_, this);
#else
- iterator __r(const_cast<__node_pointer>(__p.__ptr_));
+ iterator __r(__p.__ptr_);
#endif
if (__n > 0)
{
@@ -1355,7 +1400,7 @@ list<_Tp, _Alloc>::insert(const_iterator __p, size_type __n, const value_type& _
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
- __link_nodes(const_cast<__node&>(*__p.__ptr_), *__r.__ptr_, *__e.__ptr_);
+ __link_nodes(__p.__ptr_, __r.__ptr_, __e.__ptr_);
base::__sz() += __ds;
}
return __r;
@@ -1371,9 +1416,9 @@ list<_Tp, _Alloc>::insert(const_iterator __p, _InpIter __f, _InpIter __l,
_LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
"list::insert(iterator, range) called with an iterator not"
" referring to this list");
- iterator __r(const_cast<__node_pointer>(__p.__ptr_), this);
+ iterator __r(__p.__ptr_, this);
#else
- iterator __r(const_cast<__node_pointer>(__p.__ptr_));
+ iterator __r(__p.__ptr_);
#endif
if (__f != __l)
{
@@ -1423,7 +1468,7 @@ list<_Tp, _Alloc>::insert(const_iterator __p, _InpIter __f, _InpIter __l,
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
- __link_nodes(const_cast<__node&>(*__p.__ptr_), *__r.__ptr_, *__e.__ptr_);
+ __link_nodes(__p.__ptr_, __r.__ptr_, __e.__ptr_);
base::__sz() += __ds;
}
return __r;
@@ -1437,7 +1482,7 @@ list<_Tp, _Alloc>::push_front(const value_type& __x)
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), __x);
- __link_nodes(*base::__end_.__next_, *__hold, *__hold);
+ __link_nodes(base::__end_.__next_, __hold.get(), __hold.get());
++base::__sz();
__hold.release();
}
@@ -1450,7 +1495,8 @@ list<_Tp, _Alloc>::push_back(const value_type& __x)
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), __x);
- __link_nodes(static_cast<__node&>(base::__end_), *__hold, *__hold);
+ __link_nodes(static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::
+ pointer_to(base::__end_)), __hold.get(), __hold.get());
++base::__sz();
__hold.release();
}
@@ -1465,7 +1511,7 @@ list<_Tp, _Alloc>::push_front(value_type&& __x)
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), _VSTD::move(__x));
- __link_nodes(*base::__end_.__next_, *__hold, *__hold);
+ __link_nodes(base::__end_.__next_, __hold.get(), __hold.get());
++base::__sz();
__hold.release();
}
@@ -1478,7 +1524,8 @@ list<_Tp, _Alloc>::push_back(value_type&& __x)
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), _VSTD::move(__x));
- __link_nodes(static_cast<__node&>(base::__end_), *__hold, *__hold);
+ __link_nodes(static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::
+ pointer_to(base::__end_)), __hold.get(), __hold.get());
++base::__sz();
__hold.release();
}
@@ -1494,7 +1541,7 @@ list<_Tp, _Alloc>::emplace_front(_Args&&... __args)
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), _VSTD::forward<_Args>(__args)...);
- __link_nodes(*base::__end_.__next_, *__hold, *__hold);
+ __link_nodes(base::__end_.__next_, __hold.get(), __hold.get());
++base::__sz();
__hold.release();
}
@@ -1508,7 +1555,8 @@ list<_Tp, _Alloc>::emplace_back(_Args&&... __args)
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), _VSTD::forward<_Args>(__args)...);
- __link_nodes(static_cast<__node&>(base::__end_), *__hold, *__hold);
+ __link_nodes(static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::
+ pointer_to(base::__end_)), __hold.get(), __hold.get());
++base::__sz();
__hold.release();
}
@@ -1518,12 +1566,17 @@ template <class... _Args>
typename list<_Tp, _Alloc>::iterator
list<_Tp, _Alloc>::emplace(const_iterator __p, _Args&&... __args)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "list::emplace(iterator, args...) called with an iterator not"
+ " referring to this list");
+#endif
__node_allocator& __na = base::__node_alloc();
typedef __allocator_destructor<__node_allocator> _Dp;
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__hold->__prev_ = 0;
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), _VSTD::forward<_Args>(__args)...);
- __link_nodes(const_cast<__node&>(*__p.__ptr_), *__hold, *__hold);
+ __link_nodes(__p.__ptr_, __hold.get(), __hold.get());
++base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
return iterator(__hold.release(), this);
@@ -1548,7 +1601,7 @@ list<_Tp, _Alloc>::insert(const_iterator __p, value_type&& __x)
unique_ptr<__node, _Dp> __hold(__node_alloc_traits::allocate(__na, 1), _Dp(__na, 1));
__hold->__prev_ = 0;
__node_alloc_traits::construct(__na, _VSTD::addressof(__hold->__value_), _VSTD::move(__x));
- __link_nodes(const_cast<__node&>(*__p.__ptr_), *__hold, *__hold);
+ __link_nodes(__p.__ptr_, __hold.get(), __hold.get());
++base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
return iterator(__hold.release(), this);
@@ -1565,7 +1618,7 @@ list<_Tp, _Alloc>::pop_front()
{
_LIBCPP_ASSERT(!empty(), "list::pop_front() called with empty list");
__node_allocator& __na = base::__node_alloc();
- __node& __n = *base::__end_.__next_;
+ __node_pointer __n = base::__end_.__next_;
base::__unlink_nodes(__n, __n);
--base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1574,7 +1627,7 @@ list<_Tp, _Alloc>::pop_front()
{
--__p;
iterator* __i = static_cast<iterator*>((*__p)->__i_);
- if (__i->__ptr_ == &__n)
+ if (__i->__ptr_ == __n)
{
(*__p)->__c_ = nullptr;
if (--__c->end_ != __p)
@@ -1583,17 +1636,17 @@ list<_Tp, _Alloc>::pop_front()
}
__get_db()->unlock();
#endif
- __node_alloc_traits::destroy(__na, _VSTD::addressof(__n.__value_));
- __node_alloc_traits::deallocate(__na, _VSTD::addressof(__n), 1);
+ __node_alloc_traits::destroy(__na, _VSTD::addressof(__n->__value_));
+ __node_alloc_traits::deallocate(__na, __n, 1);
}
template <class _Tp, class _Alloc>
void
list<_Tp, _Alloc>::pop_back()
{
- _LIBCPP_ASSERT(!empty(), "list::pop_front() called with empty list");
+ _LIBCPP_ASSERT(!empty(), "list::pop_back() called with empty list");
__node_allocator& __na = base::__node_alloc();
- __node& __n = *base::__end_.__prev_;
+ __node_pointer __n = base::__end_.__prev_;
base::__unlink_nodes(__n, __n);
--base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1602,7 +1655,7 @@ list<_Tp, _Alloc>::pop_back()
{
--__p;
iterator* __i = static_cast<iterator*>((*__p)->__i_);
- if (__i->__ptr_ == &__n)
+ if (__i->__ptr_ == __n)
{
(*__p)->__c_ = nullptr;
if (--__c->end_ != __p)
@@ -1611,8 +1664,8 @@ list<_Tp, _Alloc>::pop_back()
}
__get_db()->unlock();
#endif
- __node_alloc_traits::destroy(__na, _VSTD::addressof(__n.__value_));
- __node_alloc_traits::deallocate(__na, _VSTD::addressof(__n), 1);
+ __node_alloc_traits::destroy(__na, _VSTD::addressof(__n->__value_));
+ __node_alloc_traits::deallocate(__na, __n, 1);
}
template <class _Tp, class _Alloc>
@@ -1624,9 +1677,11 @@ list<_Tp, _Alloc>::erase(const_iterator __p)
"list::erase(iterator) called with an iterator not"
" referring to this list");
#endif
+ _LIBCPP_ASSERT(__p != end(),
+ "list::erase(iterator) called with a non-dereferenceable iterator");
__node_allocator& __na = base::__node_alloc();
- __node& __n = const_cast<__node&>(*__p.__ptr_);
- __node_pointer __r = __n.__next_;
+ __node_pointer __n = __p.__ptr_;
+ __node_pointer __r = __n->__next_;
base::__unlink_nodes(__n, __n);
--base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1635,7 +1690,7 @@ list<_Tp, _Alloc>::erase(const_iterator __p)
{
--__p;
iterator* __i = static_cast<iterator*>((*__p)->__i_);
- if (__i->__ptr_ == &__n)
+ if (__i->__ptr_ == __n)
{
(*__p)->__c_ = nullptr;
if (--__c->end_ != __p)
@@ -1644,8 +1699,8 @@ list<_Tp, _Alloc>::erase(const_iterator __p)
}
__get_db()->unlock();
#endif
- __node_alloc_traits::destroy(__na, _VSTD::addressof(__n.__value_));
- __node_alloc_traits::deallocate(__na, _VSTD::addressof(__n), 1);
+ __node_alloc_traits::destroy(__na, _VSTD::addressof(__n->__value_));
+ __node_alloc_traits::deallocate(__na, __n, 1);
#if _LIBCPP_DEBUG_LEVEL >= 2
return iterator(__r, this);
#else
@@ -1665,10 +1720,10 @@ list<_Tp, _Alloc>::erase(const_iterator __f, const_iterator __l)
if (__f != __l)
{
__node_allocator& __na = base::__node_alloc();
- base::__unlink_nodes(const_cast<__node&>(*__f.__ptr_), *__l.__ptr_->__prev_);
+ base::__unlink_nodes(__f.__ptr_, __l.__ptr_->__prev_);
while (__f != __l)
{
- __node& __n = const_cast<__node&>(*__f.__ptr_);
+ __node_pointer __n = __f.__ptr_;
++__f;
--base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1677,7 +1732,7 @@ list<_Tp, _Alloc>::erase(const_iterator __f, const_iterator __l)
{
--__p;
iterator* __i = static_cast<iterator*>((*__p)->__i_);
- if (__i->__ptr_ == &__n)
+ if (__i->__ptr_ == __n)
{
(*__p)->__c_ = nullptr;
if (--__c->end_ != __p)
@@ -1686,14 +1741,14 @@ list<_Tp, _Alloc>::erase(const_iterator __f, const_iterator __l)
}
__get_db()->unlock();
#endif
- __node_alloc_traits::destroy(__na, _VSTD::addressof(__n.__value_));
- __node_alloc_traits::deallocate(__na, _VSTD::addressof(__n), 1);
+ __node_alloc_traits::destroy(__na, _VSTD::addressof(__n->__value_));
+ __node_alloc_traits::deallocate(__na, __n, 1);
}
}
#if _LIBCPP_DEBUG_LEVEL >= 2
- return iterator(const_cast<__node_pointer>(__l.__ptr_), this);
+ return iterator(__l.__ptr_, this);
#else
- return iterator(const_cast<__node_pointer>(__l.__ptr_));
+ return iterator(__l.__ptr_);
#endif
}
@@ -1751,7 +1806,8 @@ list<_Tp, _Alloc>::resize(size_type __n)
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
- __link_nodes(static_cast<__node&>(base::__end_), *__r.__ptr_, *__e.__ptr_);
+ __link_nodes(static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::
+ pointer_to(base::__end_)), __r.__ptr_, __e.__ptr_);
base::__sz() += __ds;
}
}
@@ -1810,7 +1866,8 @@ list<_Tp, _Alloc>::resize(size_type __n, const value_type& __x)
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
- __link_nodes(static_cast<__node&>(base::__end_), *__r.__ptr_, *__e.__ptr_);
+ __link_nodes(static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::
+ pointer_to(base::__end_)), __r.__ptr_, __e.__ptr_);
base::__sz() += __ds;
}
}
@@ -1828,10 +1885,10 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c)
#endif
if (!__c.empty())
{
- __node& __f = *__c.__end_.__next_;
- __node& __l = *__c.__end_.__prev_;
+ __node_pointer __f = __c.__end_.__next_;
+ __node_pointer __l = __c.__end_.__prev_;
base::__unlink_nodes(__f, __l);
- __link_nodes(const_cast<__node&>(*__p.__ptr_), __f, __l);
+ __link_nodes(__p.__ptr_, __f, __l);
base::__sz() += __c.__sz();
__c.__sz() = 0;
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1842,7 +1899,8 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c)
{
--__p;
iterator* __i = static_cast<iterator*>((*__p)->__i_);
- if (__i->__ptr_ != static_cast<__node_pointer>(&__c.__end_))
+ if (__i->__ptr_ != static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__c.__end_)))
{
__cn1->__add(*__p);
(*__p)->__c_ = __cn1;
@@ -1872,9 +1930,9 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c, const_iterator __i)
#endif
if (__p.__ptr_ != __i.__ptr_ && __p.__ptr_ != __i.__ptr_->__next_)
{
- __node& __f = const_cast<__node&>(*__i.__ptr_);
+ __node_pointer __f = __i.__ptr_;
base::__unlink_nodes(__f, __f);
- __link_nodes(const_cast<__node&>(*__p.__ptr_), __f, __f);
+ __link_nodes(__p.__ptr_, __f, __f);
--__c.__sz();
++base::__sz();
#if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1885,7 +1943,7 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c, const_iterator __i)
{
--__p;
iterator* __j = static_cast<iterator*>((*__p)->__i_);
- if (__j->__ptr_ == &__f)
+ if (__j->__ptr_ == __f)
{
__cn1->__add(*__p);
(*__p)->__c_ = __cn1;
@@ -1926,11 +1984,11 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c, const_iterator __f, con
__c.__sz() -= __s;
base::__sz() += __s;
}
- __node& __first = const_cast<__node&>(*__f.__ptr_);
+ __node_pointer __first = __f.__ptr_;
--__l;
- __node& __last = const_cast<__node&>(*__l.__ptr_);
+ __node_pointer __last = __l.__ptr_;
base::__unlink_nodes(__first, __last);
- __link_nodes(const_cast<__node&>(*__p.__ptr_), __first, __last);
+ __link_nodes(__p.__ptr_, __first, __last);
#if _LIBCPP_DEBUG_LEVEL >= 2
__libcpp_db* __db = __get_db();
__c_node* __cn1 = __db->__find_c_and_lock(this);
@@ -1939,7 +1997,7 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c, const_iterator __f, con
{
--__p;
iterator* __j = static_cast<iterator*>((*__p)->__i_);
- for (__node_pointer __k = const_cast<__node_pointer>(__f.__ptr_);
+ for (__node_pointer __k = __f.__ptr_;
__k != __l.__ptr_; __k = __k->__next_)
{
if (__j->__ptr_ == __k)
@@ -2045,12 +2103,12 @@ list<_Tp, _Alloc>::merge(list& __c, _Comp __comp)
;
base::__sz() += __ds;
__c.__sz() -= __ds;
- __node& __f = *__f2.__ptr_;
- __node& __l = *__m2.__ptr_->__prev_;
+ __node_pointer __f = __f2.__ptr_;
+ __node_pointer __l = __m2.__ptr_->__prev_;
__f2 = __m2;
base::__unlink_nodes(__f, __l);
__m2 = _VSTD::next(__f1);
- __link_nodes(*__f1.__ptr_, __f, __l);
+ __link_nodes(__f1.__ptr_, __f, __l);
__f1 = __m2;
}
else
@@ -2065,7 +2123,8 @@ list<_Tp, _Alloc>::merge(list& __c, _Comp __comp)
{
--__p;
iterator* __i = static_cast<iterator*>((*__p)->__i_);
- if (__i->__ptr_ != static_cast<__node_pointer>(&__c.__end_))
+ if (__i->__ptr_ != static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(__c.__end_)))
{
__cn1->__add(*__p);
(*__p)->__c_ = __cn1;
@@ -2108,9 +2167,9 @@ list<_Tp, _Alloc>::__sort(iterator __f1, iterator __e2, size_type __n, _Comp& __
case 2:
if (__comp(*--__e2, *__f1))
{
- __node& __f = *__e2.__ptr_;
+ __node_pointer __f = __e2.__ptr_;
base::__unlink_nodes(__f, __f);
- __link_nodes(*__f1.__ptr_, __f, __f);
+ __link_nodes(__f1.__ptr_, __f, __f);
return __e2;
}
return __f1;
@@ -2124,13 +2183,13 @@ list<_Tp, _Alloc>::__sort(iterator __f1, iterator __e2, size_type __n, _Comp& __
iterator __m2 = _VSTD::next(__f2);
for (; __m2 != __e2 && __comp(*__m2, *__f1); ++__m2)
;
- __node& __f = *__f2.__ptr_;
- __node& __l = *__m2.__ptr_->__prev_;
+ __node_pointer __f = __f2.__ptr_;
+ __node_pointer __l = __m2.__ptr_->__prev_;
__r = __f2;
__e1 = __f2 = __m2;
base::__unlink_nodes(__f, __l);
__m2 = _VSTD::next(__f1);
- __link_nodes(*__f1.__ptr_, __f, __l);
+ __link_nodes(__f1.__ptr_, __f, __l);
__f1 = __m2;
}
else
@@ -2142,14 +2201,14 @@ list<_Tp, _Alloc>::__sort(iterator __f1, iterator __e2, size_type __n, _Comp& __
iterator __m2 = _VSTD::next(__f2);
for (; __m2 != __e2 && __comp(*__m2, *__f1); ++__m2)
;
- __node& __f = *__f2.__ptr_;
- __node& __l = *__m2.__ptr_->__prev_;
+ __node_pointer __f = __f2.__ptr_;
+ __node_pointer __l = __m2.__ptr_->__prev_;
if (__e1 == __f2)
__e1 = __m2;
__f2 = __m2;
base::__unlink_nodes(__f, __l);
__m2 = _VSTD::next(__f1);
- __link_nodes(*__f1.__ptr_, __f, __l);
+ __link_nodes(__f1.__ptr_, __f, __l);
__f1 = __m2;
}
else
@@ -2187,7 +2246,8 @@ template <class _Tp, class _Alloc>
bool
list<_Tp, _Alloc>::__dereferenceable(const const_iterator* __i) const
{
- return __i->__ptr_ != &this->__end_;
+ return __i->__ptr_ != static_cast<__node_pointer>(
+ pointer_traits<__node_base_pointer>::pointer_to(const_cast<__node_base&>(this->__end_)));
}
template <class _Tp, class _Alloc>
diff --git a/system/include/libcxx/locale b/system/include/libcxx/locale
index 05020e17..00a275f9 100644
--- a/system/include/libcxx/locale
+++ b/system/include/libcxx/locale
@@ -186,11 +186,11 @@ template <class charT> class messages_byname;
#endif
#include <cstdlib>
#include <ctime>
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
#include <support/win32/locale_win32.h>
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
#include <nl_types.h>
-#endif // !_WIN32
+#endif // !_LIBCPP_MSVCRT
#ifdef __APPLE__
#include <Availability.h>
@@ -206,6 +206,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if defined(__APPLE__) || defined(__FreeBSD__)
# define _LIBCPP_GET_C_LOCALE 0
+#elif defined(__NetBSD__)
+# define _LIBCPP_GET_C_LOCALE LC_C_LOCALE
#else
# define _LIBCPP_GET_C_LOCALE __cloc()
// Get the C locale object
@@ -355,20 +357,6 @@ size_t __mbsrtowcs_l(wchar_t *__dest, const char **__src, size_t __len,
}
inline
-int __sprintf_l(char *__s, locale_t __l, const char *__format, ...) {
- va_list __va;
- va_start(__va, __format);
-#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
- int __res = vsprintf_l(__s, __l, __format, __va);
-#else
- __locale_raii __current(uselocale(__l), uselocale);
- int __res = vsprintf(__s, __format, __va);
-#endif
- va_end(__va);
- return __res;
-}
-
-inline
int __snprintf_l(char *__s, size_t __n, locale_t __l, const char *__format, ...) {
va_list __va;
va_start(__va, __format);
@@ -634,8 +622,7 @@ __num_get<_CharT>::__stage2_int_loop(_CharT __ct, int __base, char* __a, char*&
}
return -1;
}
- if (__a_end-__a < __num_get_buf_sz - 1)
- *__a_end++ = __src[__f];
+ *__a_end++ = __src[__f];
++__dc;
return 0;
}
@@ -646,8 +633,6 @@ __num_get<_CharT>::__stage2_float_loop(_CharT __ct, bool& __in_units, char& __ex
_CharT __decimal_point, _CharT __thousands_sep, const string& __grouping,
unsigned* __g, unsigned*& __g_end, unsigned& __dc, _CharT* __atoms)
{
- if (__a_end-__a >= __num_get_buf_sz - 1)
- return -1;
if (__ct == __decimal_point)
{
if (!__in_units)
@@ -694,8 +679,7 @@ __num_get<_CharT>::__stage2_float_loop(_CharT __ct, bool& __in_units, char& __ex
*__g_end++ = __dc;
}
}
- if (__a_end-__a < __num_get_buf_sz - ((__exp & 0x80) ? 1 : 11))
- *__a_end++ = __x;
+ *__a_end++ = __x;
if (__f >= 22)
return 0;
++__dc;
@@ -906,13 +890,20 @@ __num_get_float(const char* __a, const char* __a_end, ios_base::iostate& __err)
{
if (__a != __a_end)
{
+ typename remove_reference<decltype(errno)>::type __save_errno = errno;
+ errno = 0;
char *__p2;
long double __ld = strtold_l(__a, &__p2, _LIBCPP_GET_C_LOCALE);
+ typename remove_reference<decltype(errno)>::type __current_errno = errno;
+ if (__current_errno == 0)
+ errno = __save_errno;
if (__p2 != __a_end)
{
__err = ios_base::failbit;
return 0;
}
+ else if (__current_errno == ERANGE)
+ __err = ios_base::failbit;
return static_cast<_Tp>(__ld);
}
__err = ios_base::failbit;
@@ -968,16 +959,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
char_type __atoms[26];
char_type __thousands_sep;
string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping, __g, __g_end,
__atoms))
break;
+ }
if (__grouping.size() != 0 && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1003,16 +1006,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
char_type __atoms[26];
char_type __thousands_sep;
string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping, __g, __g_end,
__atoms))
break;
+ }
if (__grouping.size() != 0 && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1038,16 +1053,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
char_type __atoms[26];
char_type __thousands_sep;
string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping, __g, __g_end,
__atoms))
break;
+ }
if (__grouping.size() != 0 && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1073,16 +1100,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
char_type __atoms[26];
char_type __thousands_sep;
string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping, __g, __g_end,
__atoms))
break;
+ }
if (__grouping.size() != 0 && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1108,16 +1147,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
char_type __atoms[26];
char_type __thousands_sep;
string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping, __g, __g_end,
__atoms))
break;
+ }
if (__grouping.size() != 0 && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1143,16 +1194,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
char_type __atoms[26];
char_type __thousands_sep;
string __grouping = this->__stage2_int_prep(__iob, __atoms, __thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping, __g, __g_end,
__atoms))
break;
+ }
if (__grouping.size() != 0 && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1180,7 +1243,9 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
string __grouping = this->__stage2_float_prep(__iob, __atoms,
__decimal_point,
__thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
@@ -1188,11 +1253,21 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
bool __in_units = true;
char __exp = 'E';
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_float_loop(*__b, __in_units, __exp, __a, __a_end,
__decimal_point, __thousands_sep,
__grouping, __g, __g_end,
__dc, __atoms))
break;
+ }
if (__grouping.size() != 0 && __in_units && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1220,7 +1295,9 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
string __grouping = this->__stage2_float_prep(__iob, __atoms,
__decimal_point,
__thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
@@ -1228,11 +1305,21 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
bool __in_units = true;
char __exp = 'E';
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_float_loop(*__b, __in_units, __exp, __a, __a_end,
__decimal_point, __thousands_sep,
__grouping, __g, __g_end,
__dc, __atoms))
break;
+ }
if (__grouping.size() != 0 && __in_units && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1260,7 +1347,9 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
string __grouping = this->__stage2_float_prep(__iob, __atoms,
__decimal_point,
__thousands_sep);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
@@ -1268,11 +1357,21 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
bool __in_units = true;
char __exp = 'E';
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_float_loop(*__b, __in_units, __exp, __a, __a_end,
__decimal_point, __thousands_sep,
__grouping, __g, __g_end,
__dc, __atoms))
break;
+ }
if (__grouping.size() != 0 && __in_units && __g_end-__g < __num_get_base::__num_get_buf_sz)
*__g_end++ = __dc;
// Stage 3
@@ -1300,16 +1399,28 @@ num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
string __grouping;
use_facet<ctype<_CharT> >(__iob.getloc()).widen(__num_get_base::__src,
__num_get_base::__src + 26, __atoms);
- char __a[__num_get_base::__num_get_buf_sz] = {0};
+ string __buf;
+ __buf.resize(__buf.capacity());
+ char* __a = &__buf[0];
char* __a_end = __a;
unsigned __g[__num_get_base::__num_get_buf_sz];
unsigned* __g_end = __g;
unsigned __dc = 0;
for (; __b != __e; ++__b)
+ {
+ if (__a_end - __a == __buf.size())
+ {
+ size_t __tmp = __buf.size();
+ __buf.resize(2*__buf.size());
+ __buf.resize(__buf.capacity());
+ __a = &__buf[0];
+ __a_end = __a + __tmp;
+ }
if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
__thousands_sep, __grouping,
__g, __g_end, __atoms))
break;
+ }
// Stage 3
__a[sizeof(__a)-1] = 0;
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
@@ -1678,9 +1789,9 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
+ 1;
char __nar[__nbuf];
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
- int __nc = sprintf_l(__nar, _LIBCPP_GET_C_LOCALE, __fmt, __v);
+ int __nc = snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
#else
- int __nc = __sprintf_l(__nar, __cloc(), __fmt, __v);
+ int __nc = __snprintf_l(__nar, sizeof(__nar), __cloc(), __fmt, __v);
#endif
char* __ne = __nar + __nc;
char* __np = this->__identify_padding(__nar, __ne, __iob);
@@ -1708,9 +1819,9 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
+ 1;
char __nar[__nbuf];
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
- int __nc = sprintf_l(__nar, _LIBCPP_GET_C_LOCALE, __fmt, __v);
+ int __nc = snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
#else
- int __nc = __sprintf_l(__nar, __cloc(), __fmt, __v);
+ int __nc = __snprintf_l(__nar, sizeof(__nar), __cloc(), __fmt, __v);
#endif
char* __ne = __nar + __nc;
char* __np = this->__identify_padding(__nar, __ne, __iob);
@@ -1738,9 +1849,9 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
+ 1;
char __nar[__nbuf];
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
- int __nc = sprintf_l(__nar, _LIBCPP_GET_C_LOCALE, __fmt, __v);
+ int __nc = snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
#else
- int __nc = __sprintf_l(__nar, __cloc(), __fmt, __v);
+ int __nc = __snprintf_l(__nar, sizeof(__nar), __cloc(), __fmt, __v);
#endif
char* __ne = __nar + __nc;
char* __np = this->__identify_padding(__nar, __ne, __iob);
@@ -1768,9 +1879,9 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
+ 1;
char __nar[__nbuf];
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
- int __nc = sprintf_l(__nar, _LIBCPP_GET_C_LOCALE, __fmt, __v);
+ int __nc = snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
#else
- int __nc = __sprintf_l(__nar, __cloc(), __fmt, __v);
+ int __nc = __snprintf_l(__nar, sizeof(__nar), __cloc(), __fmt, __v);
#endif
char* __ne = __nar + __nc;
char* __np = this->__identify_padding(__nar, __ne, __iob);
@@ -1932,9 +2043,9 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
const unsigned __nbuf = 20;
char __nar[__nbuf];
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
- int __nc = sprintf_l(__nar, _LIBCPP_GET_C_LOCALE, __fmt, __v);
+ int __nc = snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
#else
- int __nc = __sprintf_l(__nar, __cloc(), __fmt, __v);
+ int __nc = __snprintf_l(__nar, sizeof(__nar), __cloc(), __fmt, __v);
#endif
char* __ne = __nar + __nc;
char* __np = this->__identify_padding(__nar, __ne, __iob);
diff --git a/system/include/libcxx/map b/system/include/libcxx/map
index abc07a35..953743a6 100644
--- a/system/include/libcxx/map
+++ b/system/include/libcxx/map
@@ -381,7 +381,7 @@ swap(multimap<Key, T, Compare, Allocator>& x,
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Key, class _Tp, class _Compare, bool = is_empty<_Compare>::value
+template <class _Key, class _CP, class _Compare, bool = is_empty<_Compare>::value
#if __has_feature(is_final)
&& !__is_final(_Compare)
#endif
@@ -389,8 +389,6 @@ template <class _Key, class _Tp, class _Compare, bool = is_empty<_Compare>::valu
class __map_value_compare
: private _Compare
{
- typedef pair<typename std::remove_const<_Key>::type, _Tp> _Pp;
- typedef pair<const _Key, _Tp> _CP;
public:
_LIBCPP_INLINE_VISIBILITY
__map_value_compare()
@@ -404,41 +402,20 @@ public:
const _Compare& key_comp() const _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _CP& __x, const _CP& __y) const
- {return static_cast<const _Compare&>(*this)(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _CP& __x, const _Pp& __y) const
- {return static_cast<const _Compare&>(*this)(__x.first, __y.first);}
+ {return static_cast<const _Compare&>(*this)(__x.__cc.first, __y.__cc.first);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _CP& __x, const _Key& __y) const
- {return static_cast<const _Compare&>(*this)(__x.first, __y);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _CP& __y) const
- {return static_cast<const _Compare&>(*this)(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Pp& __y) const
- {return static_cast<const _Compare&>(*this)(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Key& __y) const
- {return static_cast<const _Compare&>(*this)(__x.first, __y);}
+ {return static_cast<const _Compare&>(*this)(__x.__cc.first, __y);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Key& __x, const _CP& __y) const
- {return static_cast<const _Compare&>(*this)(__x, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Pp& __y) const
- {return static_cast<const _Compare&>(*this)(__x, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Key& __y) const
- {return static_cast<const _Compare&>(*this)(__x, __y);}
+ {return static_cast<const _Compare&>(*this)(__x, __y.__cc.first);}
};
-template <class _Key, class _Tp, class _Compare>
-class __map_value_compare<_Key, _Tp, _Compare, false>
+template <class _Key, class _CP, class _Compare>
+class __map_value_compare<_Key, _CP, _Compare, false>
{
_Compare comp;
- typedef pair<typename std::remove_const<_Key>::type, _Tp> _Pp;
- typedef pair<const _Key, _Tp> _CP;
-
public:
_LIBCPP_INLINE_VISIBILITY
__map_value_compare()
@@ -453,31 +430,13 @@ public:
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _CP& __x, const _CP& __y) const
- {return comp(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _CP& __x, const _Pp& __y) const
- {return comp(__x.first, __y.first);}
+ {return comp(__x.__cc.first, __y.__cc.first);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _CP& __x, const _Key& __y) const
- {return comp(__x.first, __y);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _CP& __y) const
- {return comp(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Pp& __y) const
- {return comp(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Key& __y) const
- {return comp(__x.first, __y);}
+ {return comp(__x.__cc.first, __y);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Key& __x, const _CP& __y) const
- {return comp(__x, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Pp& __y) const
- {return comp(__x, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Key& __y) const
- {return comp(__x, __y);}
+ {return comp(__x, __y.__cc.first);}
};
template <class _Allocator>
@@ -489,8 +448,8 @@ class __map_node_destructor
public:
typedef typename __alloc_traits::pointer pointer;
private:
- typedef typename value_type::first_type first_type;
- typedef typename value_type::second_type second_type;
+ typedef typename value_type::value_type::first_type first_type;
+ typedef typename value_type::value_type::second_type second_type;
allocator_type& __na_;
@@ -522,9 +481,9 @@ public:
void operator()(pointer __p) _NOEXCEPT
{
if (__second_constructed)
- __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.second));
+ __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__cc.second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.first));
+ __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__cc.first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
@@ -542,8 +501,8 @@ class _LIBCPP_TYPE_VIS __map_iterator
_TreeIterator __i_;
typedef typename _TreeIterator::__pointer_traits __pointer_traits;
- typedef const typename _TreeIterator::value_type::first_type __key_type;
- typedef typename _TreeIterator::value_type::second_type __mapped_type;
+ typedef const typename _TreeIterator::value_type::value_type::first_type __key_type;
+ typedef typename _TreeIterator::value_type::value_type::second_type __mapped_type;
public:
typedef bidirectional_iterator_tag iterator_category;
typedef pair<__key_type, __mapped_type> value_type;
@@ -564,9 +523,9 @@ public:
__map_iterator(_TreeIterator __i) _NOEXCEPT : __i_(__i) {}
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return *operator->();}
+ reference operator*() const {return __i_->__cc;}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return (pointer)__i_.operator->();}
+ pointer operator->() const {return pointer_traits<pointer>::pointer_to(__i_->__cc);}
_LIBCPP_INLINE_VISIBILITY
__map_iterator& operator++() {++__i_; return *this;}
@@ -607,8 +566,8 @@ class _LIBCPP_TYPE_VIS __map_const_iterator
_TreeIterator __i_;
typedef typename _TreeIterator::__pointer_traits __pointer_traits;
- typedef const typename _TreeIterator::value_type::first_type __key_type;
- typedef typename _TreeIterator::value_type::second_type __mapped_type;
+ typedef const typename _TreeIterator::value_type::value_type::first_type __key_type;
+ typedef typename _TreeIterator::value_type::value_type::second_type __mapped_type;
public:
typedef bidirectional_iterator_tag iterator_category;
typedef pair<__key_type, __mapped_type> value_type;
@@ -634,9 +593,9 @@ public:
: __i_(__i.__i_) {}
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return *operator->();}
+ reference operator*() const {return __i_->__cc;}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return (pointer)__i_.operator->();}
+ pointer operator->() const {return pointer_traits<pointer>::pointer_to(__i_->__cc);}
_LIBCPP_INLINE_VISIBILITY
__map_const_iterator& operator++() {++__i_; return *this;}
@@ -679,6 +638,7 @@ public:
typedef _Key key_type;
typedef _Tp mapped_type;
typedef pair<const key_type, mapped_type> value_type;
+ typedef pair<key_type, mapped_type> __nc_value_type;
typedef _Compare key_compare;
typedef _Allocator allocator_type;
typedef value_type& reference;
@@ -699,8 +659,51 @@ public:
};
private:
- typedef pair<key_type, mapped_type> __value_type;
- typedef __map_value_compare<key_type, mapped_type, key_compare> __vc;
+
+#if __cplusplus >= 201103L
+ union __value_type
+ {
+ typedef typename map::value_type value_type;
+ typedef typename map::__nc_value_type __nc_value_type;
+ value_type __cc;
+ __nc_value_type __nc;
+
+ template <class ..._Args>
+ __value_type(_Args&& ...__args)
+ : __cc(std::forward<_Args>(__args)...) {}
+
+ __value_type(const __value_type& __v)
+ : __cc(std::move(__v.__cc)) {}
+
+ __value_type(__value_type&& __v)
+ : __nc(std::move(__v.__nc)) {}
+
+ __value_type& operator=(const __value_type& __v)
+ {__nc = __v.__cc; return *this;}
+
+ __value_type& operator=(__value_type&& __v)
+ {__nc = std::move(__v.__nc); return *this;}
+
+ ~__value_type() {__cc.~value_type();}
+ };
+#else
+ struct __value_type
+ {
+ typedef typename map::value_type value_type;
+ value_type __cc;
+
+ __value_type() {}
+
+ template <class _A0>
+ __value_type(const _A0& __a0)
+ : __cc(__a0) {}
+
+ template <class _A0, class _A1>
+ __value_type(const _A0& __a0, const _A1& __a1)
+ : __cc(__a0, __a1) {}
+ };
+#endif
+ typedef __map_value_compare<key_type, __value_type, key_compare> __vc;
typedef typename allocator_traits<allocator_type>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
rebind_alloc<__value_type>
@@ -764,7 +767,14 @@ public:
_LIBCPP_INLINE_VISIBILITY
map& operator=(const map& __m)
{
+#if __cplusplus >= 201103L
__tree_ = __m.__tree_;
+#else
+ __tree_.clear();
+ __tree_.value_comp() = __m.__tree_.value_comp();
+ __tree_.__copy_assign_alloc(__m.__tree_);
+ insert(__m.begin(), __m.end());
+#endif
return *this;
}
@@ -986,32 +996,17 @@ private:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
__node_holder __construct_node();
template <class _A0>
- typename enable_if
- <
- is_constructible<value_type, _A0>::value,
- __node_holder
- >::type
- __construct_node(_A0&& __a0);
- template <class _A0>
- typename enable_if
- <
- is_constructible<key_type, _A0>::value,
- __node_holder
- >::type
- __construct_node(_A0&& __a0);
+ __node_holder __construct_node(_A0&& __a0);
+ __node_holder __construct_node_with_key(key_type&& __k);
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _A0, class _A1, class ..._Args>
__node_holder __construct_node(_A0&& __a0, _A1&& __a1, _Args&& ...__args);
#endif // _LIBCPP_HAS_NO_VARIADICS
-#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
- __node_holder __construct_node(const key_type& __k);
#endif
+ __node_holder __construct_node_with_key(const key_type& __k);
__node_base_pointer&
__find_equal_key(__node_base_pointer& __parent, const key_type& __k);
- __node_base_pointer&
- __find_equal_key(const_iterator __hint,
- __node_base_pointer& __parent, const key_type& __k);
__node_base_const_pointer
__find_equal_key(__node_base_const_pointer& __parent, const key_type& __k) const;
};
@@ -1030,97 +1025,37 @@ map<_Key, _Tp, _Compare, _Allocator>::__find_equal_key(__node_base_pointer& __pa
{
while (true)
{
- if (__tree_.value_comp().key_comp()(__k, __nd->__value_.first))
+ if (__tree_.value_comp().key_comp()(__k, __nd->__value_.__cc.first))
{
if (__nd->__left_ != nullptr)
__nd = static_cast<__node_pointer>(__nd->__left_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__left_;
}
}
- else if (__tree_.value_comp().key_comp()(__nd->__value_.first, __k))
+ else if (__tree_.value_comp().key_comp()(__nd->__value_.__cc.first, __k))
{
if (__nd->__right_ != nullptr)
__nd = static_cast<__node_pointer>(__nd->__right_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent->__right_;
}
}
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent;
}
}
}
- __parent = __tree_.__end_node();
+ __parent = static_cast<__node_base_pointer>(__tree_.__end_node());
return __parent->__left_;
}
-// Find place to insert if __k doesn't exist
-// First check prior to __hint.
-// Next check after __hint.
-// Next do O(log N) search.
-// Set __parent to parent of null leaf
-// Return reference to null leaf
-// If __k exists, set parent to node of __k and return reference to node of __k
-template <class _Key, class _Tp, class _Compare, class _Allocator>
-typename map<_Key, _Tp, _Compare, _Allocator>::__node_base_pointer&
-map<_Key, _Tp, _Compare, _Allocator>::__find_equal_key(const_iterator __hint,
- __node_base_pointer& __parent,
- const key_type& __k)
-{
- if (__hint == end() || __tree_.value_comp().key_comp()(__k, __hint->first)) // check before
- {
- // __k < *__hint
- const_iterator __prior = __hint;
- if (__prior == begin() || __tree_.value_comp().key_comp()((--__prior)->first, __k))
- {
- // *prev(__hint) < __k < *__hint
- if (__hint.__ptr_->__left_ == nullptr)
- {
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
- return __parent->__left_;
- }
- else
- {
- __parent = const_cast<__node_pointer&>(__prior.__ptr_);
- return __parent->__right_;
- }
- }
- // __k <= *prev(__hint)
- return __find_equal_key(__parent, __k);
- }
- else if (__tree_.value_comp().key_comp()(__hint->first, __k)) // check after
- {
- // *__hint < __k
- const_iterator __next = _VSTD::next(__hint);
- if (__next == end() || __tree_.value_comp().key_comp()(__k, __next->first))
- {
- // *__hint < __k < *next(__hint)
- if (__hint.__ptr_->__right_ == nullptr)
- {
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
- return __parent->__right_;
- }
- else
- {
- __parent = const_cast<__node_pointer&>(__next.__ptr_);
- return __parent->__left_;
- }
- }
- // *next(__hint) <= __k
- return __find_equal_key(__parent, __k);
- }
- // else __k == *__hint
- __parent = const_cast<__node_pointer&>(__hint.__ptr_);
- return __parent;
-}
-
// Find __k
// Set __parent to parent of null leaf and
// return reference to null leaf iv __k does not exist.
@@ -1135,34 +1070,34 @@ map<_Key, _Tp, _Compare, _Allocator>::__find_equal_key(__node_base_const_pointer
{
while (true)
{
- if (__tree_.value_comp().key_comp()(__k, __nd->__value_.first))
+ if (__tree_.value_comp().key_comp()(__k, __nd->__value_.__cc.first))
{
if (__nd->__left_ != nullptr)
__nd = static_cast<__node_pointer>(__nd->__left_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return const_cast<const __node_base_const_pointer&>(__parent->__left_);
}
}
- else if (__tree_.value_comp().key_comp()(__nd->__value_.first, __k))
+ else if (__tree_.value_comp().key_comp()(__nd->__value_.__cc.first, __k))
{
if (__nd->__right_ != nullptr)
__nd = static_cast<__node_pointer>(__nd->__right_);
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return const_cast<const __node_base_const_pointer&>(__parent->__right_);
}
}
else
{
- __parent = __nd;
+ __parent = static_cast<__node_base_pointer>(__nd);
return __parent;
}
}
}
- __parent = __tree_.__end_node();
+ __parent = static_cast<__node_base_pointer>(__tree_.__end_node());
return const_cast<const __node_base_const_pointer&>(__parent->__left_);
}
@@ -1187,20 +1122,16 @@ map<_Key, _Tp, _Compare, _Allocator>::__construct_node()
{
__node_allocator& __na = __tree_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first));
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second));
__h.get_deleter().__second_constructed = true;
return __h;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
template <class _A0>
-typename enable_if
-<
- is_constructible<pair<const _Key, _Tp>, _A0>::value,
- typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
->::type
+typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
map<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0)
{
__node_allocator& __na = __tree_.__node_alloc();
@@ -1212,21 +1143,16 @@ map<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0)
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
-template <class _A0>
-typename enable_if
-<
- is_constructible<_Key, _A0>::value,
- typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
->::type
-map<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0)
+typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
+map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(key_type&& __k)
{
__node_allocator& __na = __tree_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first), _VSTD::forward<_A0>(__a0));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first), _VSTD::move(__k));
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second));
__h.get_deleter().__second_constructed = true;
- return __h;
+ return _VSTD::move(__h);
}
#ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -1248,23 +1174,21 @@ map<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0, _A1&& __a1, _
#endif // _LIBCPP_HAS_NO_VARIADICS
-#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Key, class _Tp, class _Compare, class _Allocator>
typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder
-map<_Key, _Tp, _Compare, _Allocator>::__construct_node(const key_type& __k)
+map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k)
{
__node_allocator& __na = __tree_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first), __k);
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first), __k);
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second));
__h.get_deleter().__second_constructed = true;
return _VSTD::move(__h);
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
template <class _Key, class _Tp, class _Compare, class _Allocator>
_Tp&
map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k)
@@ -1274,11 +1198,11 @@ map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k)
__node_pointer __r = static_cast<__node_pointer>(__child);
if (__child == nullptr)
{
- __node_holder __h = __construct_node(__k);
- __tree_.__insert_node_at(__parent, __child, __h.get());
+ __node_holder __h = __construct_node_with_key(__k);
+ __tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
}
- return __r->__value_.second;
+ return __r->__value_.__cc.second;
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1292,11 +1216,11 @@ map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k)
__node_pointer __r = static_cast<__node_pointer>(__child);
if (__child == nullptr)
{
- __node_holder __h = __construct_node(_VSTD::move(__k));
- __tree_.__insert_node_at(__parent, __child, __h.get());
+ __node_holder __h = __construct_node_with_key(_VSTD::move(__k));
+ __tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
}
- return __r->__value_.second;
+ return __r->__value_.__cc.second;
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1311,7 +1235,7 @@ map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k)
if (__child == nullptr)
throw out_of_range("map::at: key not found");
#endif // _LIBCPP_NO_EXCEPTIONS
- return static_cast<__node_pointer>(__child)->__value_.second;
+ return static_cast<__node_pointer>(__child)->__value_.__cc.second;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
@@ -1324,7 +1248,7 @@ map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const
if (__child == nullptr)
throw out_of_range("map::at: key not found");
#endif // _LIBCPP_NO_EXCEPTIONS
- return static_cast<__node_const_pointer>(__child)->__value_.second;
+ return static_cast<__node_const_pointer>(__child)->__value_.__cc.second;
}
#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
@@ -1429,6 +1353,7 @@ public:
typedef _Key key_type;
typedef _Tp mapped_type;
typedef pair<const key_type, mapped_type> value_type;
+ typedef pair<key_type, mapped_type> __nc_value_type;
typedef _Compare key_compare;
typedef _Allocator allocator_type;
typedef value_type& reference;
@@ -1450,8 +1375,50 @@ public:
};
private:
- typedef pair<key_type, mapped_type> __value_type;
- typedef __map_value_compare<key_type, mapped_type, key_compare> __vc;
+#if __cplusplus >= 201103L
+ union __value_type
+ {
+ typedef typename multimap::value_type value_type;
+ typedef typename multimap::__nc_value_type __nc_value_type;
+ value_type __cc;
+ __nc_value_type __nc;
+
+ template <class ..._Args>
+ __value_type(_Args&& ...__args)
+ : __cc(std::forward<_Args>(__args)...) {}
+
+ __value_type(const __value_type& __v)
+ : __cc(std::move(__v.__cc)) {}
+
+ __value_type(__value_type&& __v)
+ : __nc(std::move(__v.__nc)) {}
+
+ __value_type& operator=(const __value_type& __v)
+ {__nc = __v.__cc; return *this;}
+
+ __value_type& operator=(__value_type&& __v)
+ {__nc = std::move(__v.__nc); return *this;}
+
+ ~__value_type() {__cc.~value_type();}
+ };
+#else
+ struct __value_type
+ {
+ typedef typename multimap::value_type value_type;
+ value_type __cc;
+
+ __value_type() {}
+
+ template <class _A0>
+ __value_type(const _A0& __a0)
+ : __cc(__a0) {}
+
+ template <class _A0, class _A1>
+ __value_type(const _A0& __a0, const _A1& __a1)
+ : __cc(__a0, __a1) {}
+ };
+#endif
+ typedef __map_value_compare<key_type, __value_type, key_compare> __vc;
typedef typename allocator_traits<allocator_type>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
rebind_alloc<__value_type>
@@ -1516,7 +1483,14 @@ public:
_LIBCPP_INLINE_VISIBILITY
multimap& operator=(const multimap& __m)
{
+#if __cplusplus >= 201103L
__tree_ = __m.__tree_;
+#else
+ __tree_.clear();
+ __tree_.value_comp() = __m.__tree_.value_comp();
+ __tree_.__copy_assign_alloc(__m.__tree_);
+ insert(__m.begin(), __m.end());
+#endif
return *this;
}
@@ -1725,18 +1699,7 @@ private:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
__node_holder __construct_node();
template <class _A0>
- typename enable_if
- <
- is_constructible<value_type, _A0>::value,
- __node_holder
- >::type
- __construct_node(_A0&& __a0);
- template <class _A0>
- typename enable_if
- <
- is_constructible<key_type, _A0>::value,
- __node_holder
- >::type
+ __node_holder
__construct_node(_A0&& __a0);
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _A0, class _A1, class ..._Args>
@@ -1766,20 +1729,16 @@ multimap<_Key, _Tp, _Compare, _Allocator>::__construct_node()
{
__node_allocator& __na = __tree_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first));
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second));
__h.get_deleter().__second_constructed = true;
return __h;
}
template <class _Key, class _Tp, class _Compare, class _Allocator>
template <class _A0>
-typename enable_if
-<
- is_constructible<pair<const _Key, _Tp>, _A0>::value,
- typename multimap<_Key, _Tp, _Compare, _Allocator>::__node_holder
->::type
+typename multimap<_Key, _Tp, _Compare, _Allocator>::__node_holder
multimap<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0)
{
__node_allocator& __na = __tree_.__node_alloc();
@@ -1790,24 +1749,6 @@ multimap<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0)
return __h;
}
-template <class _Key, class _Tp, class _Compare, class _Allocator>
-template <class _A0>
-typename enable_if
-<
- is_constructible<_Key, _A0>::value,
- typename multimap<_Key, _Tp, _Compare, _Allocator>::__node_holder
->::type
-multimap<_Key, _Tp, _Compare, _Allocator>::__construct_node(_A0&& __a0)
-{
- __node_allocator& __na = __tree_.__node_alloc();
- __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first), _VSTD::forward<_A0>(__a0));
- __h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
- __h.get_deleter().__second_constructed = true;
- return __h;
-}
-
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _Key, class _Tp, class _Compare, class _Allocator>
diff --git a/system/include/libcxx/memory b/system/include/libcxx/memory
index fe352382..ffd0cd0c 100644
--- a/system/include/libcxx/memory
+++ b/system/include/libcxx/memory
@@ -350,6 +350,10 @@ class bad_weak_ptr
bad_weak_ptr() noexcept;
};
+template<class T, class... Args> unique_ptr<T> make_unique(Args&&... args); // C++14
+template<class T> unique_ptr<T> make_unique(size_t n); // C++14
+template<class T, class... Args> unspecified make_unique(Args&&...) = delete; // C++14, T == U[N]
+
template<class T>
class shared_ptr
{
@@ -621,7 +625,7 @@ inline _LIBCPP_INLINE_VISIBILITY
_Tp*
addressof(_Tp& __x) _NOEXCEPT
{
- return (_Tp*)&(char&)__x;
+ return (_Tp*)&reinterpret_cast<const volatile char&>(__x);
}
#if defined(_LIBCPP_HAS_OBJC_ARC) && !defined(_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF)
@@ -1750,7 +1754,7 @@ public:
typedef const _Tp* const_pointer;
typedef const _Tp& reference;
typedef const _Tp& const_reference;
- typedef _Tp value_type;
+ typedef const _Tp value_type;
typedef true_type propagate_on_container_move_assignment;
@@ -2036,6 +2040,10 @@ public:
return *this;
}
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2>
@@ -2051,10 +2059,6 @@ public:
#endif // _LIBCPP_HAS_NO_VARIADICS
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
-
_LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return __first_;}
_LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return __first_;}
@@ -2131,6 +2135,10 @@ public:
return *this;
}
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2>
@@ -2146,10 +2154,6 @@ public:
#endif // _LIBCPP_HAS_NO_VARIADICS
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
-
_LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return *this;}
@@ -2227,6 +2231,10 @@ public:
return *this;
}
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2>
@@ -2243,10 +2251,6 @@ public:
#endif // _LIBCPP_HAS_NO_VARIADICS
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
-
_LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return __first_;}
_LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return __first_;}
@@ -2321,6 +2325,10 @@ public:
return *this;
}
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class... _Args1, class... _Args2, size_t... _I1, size_t... _I2>
@@ -2336,10 +2344,6 @@ public:
#endif // _LIBCPP_HAS_NO_VARIADICS
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
-
_LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return *this;}
@@ -2409,6 +2413,10 @@ public:
return *this;
}
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class... _Args1, class... _Args2>
@@ -2422,10 +2430,6 @@ public:
#endif // _LIBCPP_HAS_NO_VARIADICS
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
-
_LIBCPP_INLINE_VISIBILITY _T1_reference first() _NOEXCEPT {return base::first();}
_LIBCPP_INLINE_VISIBILITY _T1_const_reference first() const _NOEXCEPT {return base::first();}
@@ -2485,6 +2489,7 @@ struct _LIBCPP_TYPE_VIS default_delete
_LIBCPP_INLINE_VISIBILITY void operator() (_Tp* __ptr) const _NOEXCEPT
{
static_assert(sizeof(_Tp) > 0, "default_delete can not delete incomplete type");
+ static_assert(!is_void<_Tp>::value, "default_delete can not delete incomplete type");
delete __ptr;
}
};
@@ -2507,6 +2512,7 @@ public:
typename enable_if<__same_or_less_cv_qualified<_Up*, _Tp*>::value>::type* = 0) const _NOEXCEPT
{
static_assert(sizeof(_Tp) > 0, "default_delete can not delete incomplete type");
+ static_assert(!is_void<_Tp>::value, "default_delete can not delete incomplete type");
delete [] __ptr;
}
};
@@ -3077,8 +3083,61 @@ move(unique_ptr<_Tp, _Dp>& __t)
#endif
+#if _LIBCPP_STD_VER > 11
+
+template<class _Tp>
+struct __unique_if
+{
+ typedef unique_ptr<_Tp> __unique_single;
+};
+
+template<class _Tp>
+struct __unique_if<_Tp[]>
+{
+ typedef unique_ptr<_Tp[]> __unique_array_unknown_bound;
+};
+
+template<class _Tp, size_t _Np>
+struct __unique_if<_Tp[_Np]>
+{
+ typedef void __unique_array_known_bound;
+};
+
+template<class _Tp, class... _Args>
+inline _LIBCPP_INLINE_VISIBILITY
+typename __unique_if<_Tp>::__unique_single
+make_unique(_Args&&... __args)
+{
+ return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));
+}
+
+template<class _Tp>
+inline _LIBCPP_INLINE_VISIBILITY
+typename __unique_if<_Tp>::__unique_array_unknown_bound
+make_unique(size_t __n)
+{
+ typedef typename remove_extent<_Tp>::type _Up;
+ return unique_ptr<_Tp>(new _Up[__n]());
+}
+
+template<class _Tp, class... _Args>
+ typename __unique_if<_Tp>::__unique_array_known_bound
+ make_unique(_Args&&...) = delete;
+
+#endif // _LIBCPP_STD_VER > 11
+
template <class _Tp> struct hash;
+template <class _Size>
+inline _LIBCPP_INLINE_VISIBILITY
+_Size
+__loadword(const void* __p)
+{
+ _Size __r;
+ std::memcpy(&__r, __p, sizeof(__r));
+ return __r;
+}
+
// We use murmur2 when size_t is 32 bits, and cityhash64 when size_t
// is 64 bits. This is because cityhash64 uses 64bit x 64bit
// multiplication, which can be very slow on 32-bit systems.
@@ -3102,7 +3161,7 @@ __murmur2_or_cityhash<_Size, 32>::operator()(const void* __key, _Size __len)
const unsigned char* __data = static_cast<const unsigned char*>(__key);
for (; __len >= 4; __data += 4, __len -= 4)
{
- _Size __k = *(const _Size*)__data;
+ _Size __k = __loadword<_Size>(__data);
__k *= __m;
__k ^= __k >> __r;
__k *= __m;
@@ -3161,13 +3220,13 @@ struct __murmur2_or_cityhash<_Size, 64>
static _Size __hash_len_0_to_16(const char* __s, _Size __len) {
if (__len > 8) {
- const _Size __a = *(const _Size*)__s;
- const _Size __b = *(const _Size*)(__s + __len - 8);
+ const _Size __a = __loadword<_Size>(__s);
+ const _Size __b = __loadword<_Size>(__s + __len - 8);
return __hash_len_16(__a, __rotate_by_at_least_1(__b + __len, __len)) ^ __b;
}
if (__len >= 4) {
- const uint32_t __a = *(const uint32_t*)(__s);
- const uint32_t __b = *(const uint32_t*)(__s + __len - 4);
+ const uint32_t __a = __loadword<uint32_t>(__s);
+ const uint32_t __b = __loadword<uint32_t>(__s + __len - 4);
return __hash_len_16(__len + (__a << 3), __b);
}
if (__len > 0) {
@@ -3183,10 +3242,10 @@ struct __murmur2_or_cityhash<_Size, 64>
}
static _Size __hash_len_17_to_32(const char *__s, _Size __len) {
- const _Size __a = *(const _Size*)(__s) * __k1;
- const _Size __b = *(const _Size*)(__s + 8);
- const _Size __c = *(const _Size*)(__s + __len - 8) * __k2;
- const _Size __d = *(const _Size*)(__s + __len - 16) * __k0;
+ const _Size __a = __loadword<_Size>(__s) * __k1;
+ const _Size __b = __loadword<_Size>(__s + 8);
+ const _Size __c = __loadword<_Size>(__s + __len - 8) * __k2;
+ const _Size __d = __loadword<_Size>(__s + __len - 16) * __k0;
return __hash_len_16(__rotate(__a - __b, 43) + __rotate(__c, 30) + __d,
__a + __rotate(__b ^ __k3, 20) - __c + __len);
}
@@ -3207,33 +3266,33 @@ struct __murmur2_or_cityhash<_Size, 64>
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
const char* __s, _Size __a, _Size __b) {
- return __weak_hash_len_32_with_seeds(*(const _Size*)(__s),
- *(const _Size*)(__s + 8),
- *(const _Size*)(__s + 16),
- *(const _Size*)(__s + 24),
+ return __weak_hash_len_32_with_seeds(__loadword<_Size>(__s),
+ __loadword<_Size>(__s + 8),
+ __loadword<_Size>(__s + 16),
+ __loadword<_Size>(__s + 24),
__a,
__b);
}
// Return an 8-byte hash for 33 to 64 bytes.
static _Size __hash_len_33_to_64(const char *__s, size_t __len) {
- _Size __z = *(const _Size*)(__s + 24);
- _Size __a = *(const _Size*)(__s) +
- (__len + *(const _Size*)(__s + __len - 16)) * __k0;
+ _Size __z = __loadword<_Size>(__s + 24);
+ _Size __a = __loadword<_Size>(__s) +
+ (__len + __loadword<_Size>(__s + __len - 16)) * __k0;
_Size __b = __rotate(__a + __z, 52);
_Size __c = __rotate(__a, 37);
- __a += *(const _Size*)(__s + 8);
+ __a += __loadword<_Size>(__s + 8);
__c += __rotate(__a, 7);
- __a += *(const _Size*)(__s + 16);
+ __a += __loadword<_Size>(__s + 16);
_Size __vf = __a + __z;
_Size __vs = __b + __rotate(__a, 31) + __c;
- __a = *(const _Size*)(__s + 16) + *(const _Size*)(__s + __len - 32);
- __z += *(const _Size*)(__s + __len - 8);
+ __a = __loadword<_Size>(__s + 16) + __loadword<_Size>(__s + __len - 32);
+ __z += __loadword<_Size>(__s + __len - 8);
__b = __rotate(__a + __z, 52);
__c = __rotate(__a, 37);
- __a += *(const _Size*)(__s + __len - 24);
+ __a += __loadword<_Size>(__s + __len - 24);
__c += __rotate(__a, 7);
- __a += *(const _Size*)(__s + __len - 16);
+ __a += __loadword<_Size>(__s + __len - 16);
_Size __wf = __a + __z;
_Size __ws = __b + __rotate(__a, 31) + __c;
_Size __r = __shift_mix((__vf + __ws) * __k2 + (__wf + __vs) * __k0);
@@ -3259,26 +3318,26 @@ __murmur2_or_cityhash<_Size, 64>::operator()(const void* __key, _Size __len)
// For strings over 64 bytes we hash the end first, and then as we
// loop we keep 56 bytes of state: v, w, x, y, and z.
- _Size __x = *(const _Size*)(__s + __len - 40);
- _Size __y = *(const _Size*)(__s + __len - 16) +
- *(const _Size*)(__s + __len - 56);
- _Size __z = __hash_len_16(*(const _Size*)(__s + __len - 48) + __len,
- *(const _Size*)(__s + __len - 24));
+ _Size __x = __loadword<_Size>(__s + __len - 40);
+ _Size __y = __loadword<_Size>(__s + __len - 16) +
+ __loadword<_Size>(__s + __len - 56);
+ _Size __z = __hash_len_16(__loadword<_Size>(__s + __len - 48) + __len,
+ __loadword<_Size>(__s + __len - 24));
pair<_Size, _Size> __v = __weak_hash_len_32_with_seeds(__s + __len - 64, __len, __z);
pair<_Size, _Size> __w = __weak_hash_len_32_with_seeds(__s + __len - 32, __y + __k1, __x);
- __x = __x * __k1 + *(const _Size*)(__s);
+ __x = __x * __k1 + __loadword<_Size>(__s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
__len = (__len - 1) & ~static_cast<_Size>(63);
do {
- __x = __rotate(__x + __y + __v.first + *(const _Size*)(__s + 8), 37) * __k1;
- __y = __rotate(__y + __v.second + *(const _Size*)(__s + 48), 42) * __k1;
+ __x = __rotate(__x + __y + __v.first + __loadword<_Size>(__s + 8), 37) * __k1;
+ __y = __rotate(__y + __v.second + __loadword<_Size>(__s + 48), 42) * __k1;
__x ^= __w.second;
- __y += __v.first + *(const _Size*)(__s + 40);
+ __y += __v.first + __loadword<_Size>(__s + 40);
__z = __rotate(__z + __w.first, 33) * __k1;
__v = __weak_hash_len_32_with_seeds(__s, __v.second * __k1, __x + __w.first);
__w = __weak_hash_len_32_with_seeds(__s + 32, __z + __w.second,
- __y + *(const _Size*)(__s + 16));
+ __y + __loadword<_Size>(__s + 16));
std::swap(__z, __x);
__s += 64;
__len -= 64;
diff --git a/system/include/libcxx/random b/system/include/libcxx/random
index 92722ea6..2e7a4854 100644
--- a/system/include/libcxx/random
+++ b/system/include/libcxx/random
@@ -1880,7 +1880,7 @@ public:
seed(_Sseq& __q)
{__seed(__q, integral_constant<unsigned,
1 + (__m == 0 ? (sizeof(result_type) * __CHAR_BIT__ - 1)/32
- : (__m-1) / 0x100000000ull)>());}
+ : (__m > 0x100000000ull))>());}
// generating functions
_LIBCPP_INLINE_VISIBILITY
@@ -1969,37 +1969,10 @@ linear_congruential_engine<_UIntType, __a, __c, __m>::__seed(_Sseq& __q,
uint32_t __ar[__k+3];
__q.generate(__ar, __ar + __k + 3);
result_type __s = static_cast<result_type>((__ar[3] +
- (uint64_t)__ar[4] << 32) % __m);
+ ((uint64_t)__ar[4] << 32)) % __m);
__x_ = __c == 0 && __s == 0 ? result_type(1) : __s;
}
-template <class _CharT, class _Traits>
-class __save_flags
-{
- typedef basic_ios<_CharT, _Traits> __stream_type;
- typedef typename __stream_type::fmtflags fmtflags;
-
- __stream_type& __stream_;
- fmtflags __fmtflags_;
- _CharT __fill_;
-
- __save_flags(const __save_flags&);
- __save_flags& operator=(const __save_flags&);
-public:
- _LIBCPP_INLINE_VISIBILITY
- explicit __save_flags(__stream_type& __stream)
- : __stream_(__stream),
- __fmtflags_(__stream.flags()),
- __fill_(__stream.fill())
- {}
- _LIBCPP_INLINE_VISIBILITY
- ~__save_flags()
- {
- __stream_.flags(__fmtflags_);
- __stream_.fill(__fill_);
- }
-};
-
template <class _CharT, class _Traits,
class _UIntType, _UIntType __a, _UIntType __c, _UIntType __m>
inline _LIBCPP_INLINE_VISIBILITY
diff --git a/system/include/libcxx/readme.txt b/system/include/libcxx/readme.txt
index 97d8db86..7687e5b2 100644
--- a/system/include/libcxx/readme.txt
+++ b/system/include/libcxx/readme.txt
@@ -1 +1 @@
-These files are from libc++, svn revision 178253, Mar 29 2013
+These files are from libc++, svn revision 187959, 2013-08-08.
diff --git a/system/include/libcxx/regex b/system/include/libcxx/regex
index d1afa54a..bde3af7e 100644
--- a/system/include/libcxx/regex
+++ b/system/include/libcxx/regex
@@ -2769,7 +2769,7 @@ private:
void __push_end_marked_subexpression(unsigned);
void __push_empty();
void __push_word_boundary(bool);
- void __push_lookahead(const basic_regex&, bool);
+ void __push_lookahead(const basic_regex&, bool, unsigned);
template <class _Allocator>
bool
@@ -2843,6 +2843,15 @@ private:
const basic_regex<_Cp, _Tp>& __e,
regex_constants::match_flag_type __flags);
+ template <class _Iter, class _Ap, class _Cp, class _Tp>
+ friend
+ bool
+ regex_search(__wrap_iter<_Iter> __first,
+ __wrap_iter<_Iter> __last,
+ match_results<__wrap_iter<_Iter>, _Ap>& __m,
+ const basic_regex<_Cp, _Tp>& __e,
+ regex_constants::match_flag_type __flags);
+
template <class, class> friend class __lookahead;
};
@@ -2898,6 +2907,7 @@ class __lookahead
typedef __owns_one_state<_CharT> base;
basic_regex<_CharT, _Traits> __exp_;
+ unsigned __mexp_;
bool __invert_;
__lookahead(const __lookahead&);
@@ -2906,8 +2916,8 @@ public:
typedef _VSTD::__state<_CharT> __state;
_LIBCPP_INLINE_VISIBILITY
- __lookahead(const basic_regex<_CharT, _Traits>& __exp, bool __invert, __node<_CharT>* __s)
- : base(__s), __exp_(__exp), __invert_(__invert) {}
+ __lookahead(const basic_regex<_CharT, _Traits>& __exp, bool __invert, __node<_CharT>* __s, unsigned __mexp)
+ : base(__s), __exp_(__exp), __invert_(__invert), __mexp_(__mexp) {}
virtual void __exec(__state&) const;
};
@@ -2921,11 +2931,14 @@ __lookahead<_CharT, _Traits>::__exec(__state& __s) const
bool __matched = __exp_.__match_at_start_ecma(__s.__current_, __s.__last_,
__m,
__s.__flags_ | regex_constants::match_continuous,
- true);
+ __s.__at_first_ && __s.__current_ == __s.__first_);
if (__matched != __invert_)
{
__s.__do_ = __state::__accept_but_not_consume;
__s.__node_ = this->first();
+ for (unsigned __i = 1; __i < __m.size(); ++__i) {
+ __s.__sub_matches_[__mexp_ + __i - 1] = __m.__matches_[__i];
+ }
}
else
{
@@ -3420,6 +3433,7 @@ basic_regex<_CharT, _Traits>::__parse_QUOTED_CHAR_ERE(_ForwardIterator __first,
case '+':
case '?':
case '{':
+ case '}':
__push_char(*__temp);
__first = ++__temp;
break;
@@ -3903,7 +3917,7 @@ basic_regex<_CharT, _Traits>::__parse_awk_escape(_ForwardIterator __first,
{
__val = 8 * __val + *__first - '0';
if (++__first != __last && ('0' <= *__first && *__first <= '7'))
- __val = 8 * __val + *__first - '0';
+ __val = 8 * __val + *__first++ - '0';
}
if (__str)
*__str = _CharT(__val);
@@ -4158,7 +4172,9 @@ basic_regex<_CharT, _Traits>::__parse_assertion(_ForwardIterator __first,
basic_regex __exp;
__exp.__flags_ = __flags_;
__temp = __exp.__parse(++__temp, __last);
- __push_lookahead(_VSTD::move(__exp), false);
+ unsigned __mexp = __exp.__marked_count_;
+ __push_lookahead(_VSTD::move(__exp), false, __marked_count_);
+ __marked_count_ += __mexp;
#ifndef _LIBCPP_NO_EXCEPTIONS
if (__temp == __last || *__temp != ')')
throw regex_error(regex_constants::error_paren);
@@ -4171,7 +4187,9 @@ basic_regex<_CharT, _Traits>::__parse_assertion(_ForwardIterator __first,
basic_regex __exp;
__exp.__flags_ = __flags_;
__temp = __exp.__parse(++__temp, __last);
- __push_lookahead(_VSTD::move(__exp), true);
+ unsigned __mexp = __exp.__marked_count_;
+ __push_lookahead(_VSTD::move(__exp), true, __marked_count_);
+ __marked_count_ += __mexp;
#ifndef _LIBCPP_NO_EXCEPTIONS
if (__temp == __last || *__temp != ')')
throw regex_error(regex_constants::error_paren);
@@ -4408,7 +4426,8 @@ basic_regex<_CharT, _Traits>::__parse_character_escape(_ForwardIterator __first,
case 'c':
if ((__t = _VSTD::next(__first)) != __last)
{
- if ('A' <= *__t <= 'Z' || 'a' <= *__t <= 'z')
+ if (('A' <= *__t && *__t <= 'Z') ||
+ ('a' <= *__t && *__t <= 'z'))
{
if (__str)
*__str = _CharT(*__t % 32);
@@ -4416,7 +4435,15 @@ basic_regex<_CharT, _Traits>::__parse_character_escape(_ForwardIterator __first,
__push_char(_CharT(*__t % 32));
__first = ++__t;
}
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ else
+ throw regex_error(regex_constants::error_escape);
+#endif // _LIBCPP_NO_EXCEPTIONS
}
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ else
+ throw regex_error(regex_constants::error_escape);
+#endif // _LIBCPP_NO_EXCEPTIONS
break;
case 'u':
++__first;
@@ -4481,7 +4508,7 @@ basic_regex<_CharT, _Traits>::__parse_character_escape(_ForwardIterator __first,
++__first;
}
#ifndef _LIBCPP_NO_EXCEPTIONS
- else if (__str)
+ else
throw regex_error(regex_constants::error_escape);
#endif // _LIBCPP_NO_EXCEPTIONS
break;
@@ -4740,10 +4767,11 @@ basic_regex<_CharT, _Traits>::__start_matching_list(bool __negate)
template <class _CharT, class _Traits>
void
basic_regex<_CharT, _Traits>::__push_lookahead(const basic_regex& __exp,
- bool __invert)
+ bool __invert,
+ unsigned __mexp)
{
__end_->first() = new __lookahead<_CharT, _Traits>(__exp, __invert,
- __end_->first());
+ __end_->first(), __mexp);
__end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
}
@@ -5763,7 +5791,8 @@ basic_regex<_CharT, _Traits>::__search(
{
__m.__init(1 + mark_count(), __first, __last,
__flags & regex_constants::__no_update_pos);
- if (__match_at_start(__first, __last, __m, __flags, true))
+ if (__match_at_start(__first, __last, __m, __flags,
+ !(__flags & regex_constants::__no_update_pos)))
{
__m.__prefix_.second = __m[0].first;
__m.__prefix_.matched = __m.__prefix_.first != __m.__prefix_.second;
@@ -5800,9 +5829,25 @@ regex_search(_BidirectionalIterator __first, _BidirectionalIterator __last,
const basic_regex<_CharT, _Traits>& __e,
regex_constants::match_flag_type __flags = regex_constants::match_default)
{
- basic_string<_CharT> __s(__first, __last);
+ int __offset = (__flags & regex_constants::match_prev_avail) ? 1 : 0;
+ basic_string<_CharT> __s(_VSTD::prev(__first, __offset), __last);
match_results<const _CharT*> __mc;
- bool __r = __e.__search(__s.data(), __s.data() + __s.size(), __mc, __flags);
+ bool __r = __e.__search(__s.data() + __offset, __s.data() + __s.size(), __mc, __flags);
+ __m.__assign(__first, __last, __mc, __flags & regex_constants::__no_update_pos);
+ return __r;
+}
+
+template <class _Iter, class _Allocator, class _CharT, class _Traits>
+inline _LIBCPP_INLINE_VISIBILITY
+bool
+regex_search(__wrap_iter<_Iter> __first,
+ __wrap_iter<_Iter> __last,
+ match_results<__wrap_iter<_Iter>, _Allocator>& __m,
+ const basic_regex<_CharT, _Traits>& __e,
+ regex_constants::match_flag_type __flags = regex_constants::match_default)
+{
+ match_results<const _CharT*> __mc;
+ bool __r = __e.__search(__first.base(), __last.base(), __mc, __flags);
__m.__assign(__first, __last, __mc, __flags & regex_constants::__no_update_pos);
return __r;
}
@@ -6044,7 +6089,7 @@ regex_iterator<_BidirectionalIterator, _CharT, _Traits>::operator++()
{
__flags_ |= regex_constants::__no_update_pos;
_BidirectionalIterator __start = __match_[0].second;
- if (__match_.length() == 0)
+ if (__match_.empty())
{
if (__start == __end_)
{
diff --git a/system/include/libcxx/sstream b/system/include/libcxx/sstream
index c431fec0..a8f8148a 100644
--- a/system/include/libcxx/sstream
+++ b/system/include/libcxx/sstream
@@ -260,17 +260,36 @@ template <class _CharT, class _Traits, class _Allocator>
basic_stringbuf<_CharT, _Traits, _Allocator>::basic_stringbuf(basic_stringbuf&& __rhs)
: __mode_(__rhs.__mode_)
{
- ptrdiff_t __ninp = __rhs.gptr() - __rhs.eback();
- ptrdiff_t __einp = __rhs.egptr() - __rhs.eback();
- ptrdiff_t __nout = __rhs.pptr() - __rhs.pbase();
- ptrdiff_t __eout = __rhs.epptr() - __rhs.pbase();
- ptrdiff_t __hm = __rhs.__hm_ - __rhs.pbase();
+ char_type* __p = const_cast<char_type*>(__rhs.__str_.data());
+ ptrdiff_t __binp = -1;
+ ptrdiff_t __ninp = -1;
+ ptrdiff_t __einp = -1;
+ if (__rhs.eback() != nullptr)
+ {
+ __binp = __rhs.eback() - __p;
+ __ninp = __rhs.gptr() - __p;
+ __einp = __rhs.egptr() - __p;
+ }
+ ptrdiff_t __bout = -1;
+ ptrdiff_t __nout = -1;
+ ptrdiff_t __eout = -1;
+ if (__rhs.pbase() != nullptr)
+ {
+ __bout = __rhs.pbase() - __p;
+ __nout = __rhs.pptr() - __p;
+ __eout = __rhs.epptr() - __p;
+ }
+ ptrdiff_t __hm = __rhs.__hm_ == nullptr ? -1 : __rhs.__hm_ - __p;
__str_ = _VSTD::move(__rhs.__str_);
- char_type* __p = const_cast<char_type*>(__str_.data());
- this->setg(__p, __p + __ninp, __p + __einp);
- this->setp(__p, __p + __eout);
- this->pbump(__nout);
- __hm_ = __p + __hm;
+ __p = const_cast<char_type*>(__str_.data());
+ if (__binp != -1)
+ this->setg(__p + __binp, __p + __ninp, __p + __einp);
+ if (__bout != -1)
+ {
+ this->setp(__p + __bout, __p + __eout);
+ this->pbump(__nout);
+ }
+ __hm_ = __hm == -1 ? nullptr : __p + __hm;
__p = const_cast<char_type*>(__rhs.__str_.data());
__rhs.setg(__p, __p, __p);
__rhs.setp(__p, __p);
@@ -282,18 +301,37 @@ template <class _CharT, class _Traits, class _Allocator>
basic_stringbuf<_CharT, _Traits, _Allocator>&
basic_stringbuf<_CharT, _Traits, _Allocator>::operator=(basic_stringbuf&& __rhs)
{
- ptrdiff_t __ninp = __rhs.gptr() - __rhs.eback();
- ptrdiff_t __einp = __rhs.egptr() - __rhs.eback();
- ptrdiff_t __nout = __rhs.pptr() - __rhs.pbase();
- ptrdiff_t __eout = __rhs.epptr() - __rhs.pbase();
- ptrdiff_t __hm = __rhs.__hm_ - __rhs.pbase();
- __mode_ = __rhs.__mode_;
+ char_type* __p = const_cast<char_type*>(__rhs.__str_.data());
+ ptrdiff_t __binp = -1;
+ ptrdiff_t __ninp = -1;
+ ptrdiff_t __einp = -1;
+ if (__rhs.eback() != nullptr)
+ {
+ __binp = __rhs.eback() - __p;
+ __ninp = __rhs.gptr() - __p;
+ __einp = __rhs.egptr() - __p;
+ }
+ ptrdiff_t __bout = -1;
+ ptrdiff_t __nout = -1;
+ ptrdiff_t __eout = -1;
+ if (__rhs.pbase() != nullptr)
+ {
+ __bout = __rhs.pbase() - __p;
+ __nout = __rhs.pptr() - __p;
+ __eout = __rhs.epptr() - __p;
+ }
+ ptrdiff_t __hm = __rhs.__hm_ == nullptr ? -1 : __rhs.__hm_ - __p;
__str_ = _VSTD::move(__rhs.__str_);
- char_type* __p = const_cast<char_type*>(__str_.data());
- this->setg(__p, __p + __ninp, __p + __einp);
- this->setp(__p, __p + __eout);
- this->pbump(__nout);
- __hm_ = __p + __hm;
+ __p = const_cast<char_type*>(__str_.data());
+ if (__binp != -1)
+ this->setg(__p + __binp, __p + __ninp, __p + __einp);
+ if (__bout != -1)
+ {
+ this->setp(__p + __bout, __p + __eout);
+ this->pbump(__nout);
+ }
+ __hm_ = __hm == -1 ? nullptr : __p + __hm;
+ __mode_ = __rhs.__mode_;
__p = const_cast<char_type*>(__rhs.__str_.data());
__rhs.setg(__p, __p, __p);
__rhs.setp(__p, __p);
@@ -308,28 +346,74 @@ template <class _CharT, class _Traits, class _Allocator>
void
basic_stringbuf<_CharT, _Traits, _Allocator>::swap(basic_stringbuf& __rhs)
{
- ptrdiff_t __rninp = __rhs.gptr() - __rhs.eback();
- ptrdiff_t __reinp = __rhs.egptr() - __rhs.eback();
- ptrdiff_t __rnout = __rhs.pptr() - __rhs.pbase();
- ptrdiff_t __reout = __rhs.epptr() - __rhs.pbase();
- ptrdiff_t __rhm = __rhs.__hm_ - __rhs.pbase();
- ptrdiff_t __lninp = this->gptr() - this->eback();
- ptrdiff_t __leinp = this->egptr() - this->eback();
- ptrdiff_t __lnout = this->pptr() - this->pbase();
- ptrdiff_t __leout = this->epptr() - this->pbase();
- ptrdiff_t __lhm = this->__hm_ - this->pbase();
+ char_type* __p = const_cast<char_type*>(__rhs.__str_.data());
+ ptrdiff_t __rbinp = -1;
+ ptrdiff_t __rninp = -1;
+ ptrdiff_t __reinp = -1;
+ if (__rhs.eback() != nullptr)
+ {
+ __rbinp = __rhs.eback() - __p;
+ __rninp = __rhs.gptr() - __p;
+ __reinp = __rhs.egptr() - __p;
+ }
+ ptrdiff_t __rbout = -1;
+ ptrdiff_t __rnout = -1;
+ ptrdiff_t __reout = -1;
+ if (__rhs.pbase() != nullptr)
+ {
+ __rbout = __rhs.pbase() - __p;
+ __rnout = __rhs.pptr() - __p;
+ __reout = __rhs.epptr() - __p;
+ }
+ ptrdiff_t __rhm = __rhs.__hm_ == nullptr ? -1 : __rhs.__hm_ - __p;
+ __p = const_cast<char_type*>(__str_.data());
+ ptrdiff_t __lbinp = -1;
+ ptrdiff_t __lninp = -1;
+ ptrdiff_t __leinp = -1;
+ if (this->eback() != nullptr)
+ {
+ __lbinp = this->eback() - __p;
+ __lninp = this->gptr() - __p;
+ __leinp = this->egptr() - __p;
+ }
+ ptrdiff_t __lbout = -1;
+ ptrdiff_t __lnout = -1;
+ ptrdiff_t __leout = -1;
+ if (this->pbase() != nullptr)
+ {
+ __lbout = this->pbase() - __p;
+ __lnout = this->pptr() - __p;
+ __leout = this->epptr() - __p;
+ }
+ ptrdiff_t __lhm = __hm_ == nullptr ? -1 : __hm_ - __p;
_VSTD::swap(__mode_, __rhs.__mode_);
__str_.swap(__rhs.__str_);
- char_type* __p = const_cast<char_type*>(__str_.data());
- this->setg(__p, __p + __rninp, __p + __reinp);
- this->setp(__p, __p + __reout);
- this->pbump(__rnout);
- __hm_ = __p + __rhm;
+ __p = const_cast<char_type*>(__str_.data());
+ if (__rbinp != -1)
+ this->setg(__p + __rbinp, __p + __rninp, __p + __reinp);
+ else
+ this->setg(nullptr, nullptr, nullptr);
+ if (__rbout != -1)
+ {
+ this->setp(__p + __rbout, __p + __reout);
+ this->pbump(__rnout);
+ }
+ else
+ this->setp(nullptr, nullptr);
+ __hm_ = __rhm == -1 ? nullptr : __p + __rhm;
__p = const_cast<char_type*>(__rhs.__str_.data());
- __rhs.setg(__p, __p + __lninp, __p + __leinp);
- __rhs.setp(__p, __p + __leout);
- __rhs.pbump(__lnout);
- __rhs.__hm_ = __p + __lhm;
+ if (__lbinp != -1)
+ __rhs.setg(__p + __lbinp, __p + __lninp, __p + __leinp);
+ else
+ __rhs.setg(nullptr, nullptr, nullptr);
+ if (__lbout != -1)
+ {
+ __rhs.setp(__p + __lbout, __p + __leout);
+ __rhs.pbump(__lnout);
+ }
+ else
+ __rhs.setp(nullptr, nullptr);
+ __rhs.__hm_ = __lhm == -1 ? nullptr : __p + __lhm;
locale __tl = __rhs.getloc();
__rhs.pubimbue(this->getloc());
this->pubimbue(__tl);
diff --git a/system/include/libcxx/string b/system/include/libcxx/string
index de668bba..83dc53a1 100644
--- a/system/include/libcxx/string
+++ b/system/include/libcxx/string
@@ -100,8 +100,8 @@ public:
noexcept(is_nothrow_move_constructible<allocator_type>::value);
basic_string(const basic_string& str, size_type pos, size_type n = npos,
const allocator_type& a = allocator_type());
- basic_string(const_pointer s, const allocator_type& a = allocator_type());
- basic_string(const_pointer s, size_type n, const allocator_type& a = allocator_type());
+ basic_string(const value_type* s, const allocator_type& a = allocator_type());
+ basic_string(const value_type* s, size_type n, const allocator_type& a = allocator_type());
basic_string(size_type n, value_type c, const allocator_type& a = allocator_type());
template<class InputIterator>
basic_string(InputIterator begin, InputIterator end,
@@ -117,7 +117,7 @@ public:
noexcept(
allocator_type::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value);
- basic_string& operator=(const_pointer s);
+ basic_string& operator=(const value_type* s);
basic_string& operator=(value_type c);
basic_string& operator=(initializer_list<value_type>);
@@ -156,14 +156,14 @@ public:
reference at(size_type n);
basic_string& operator+=(const basic_string& str);
- basic_string& operator+=(const_pointer s);
+ basic_string& operator+=(const value_type* s);
basic_string& operator+=(value_type c);
basic_string& operator+=(initializer_list<value_type>);
basic_string& append(const basic_string& str);
basic_string& append(const basic_string& str, size_type pos, size_type n);
- basic_string& append(const_pointer s, size_type n);
- basic_string& append(const_pointer s);
+ basic_string& append(const value_type* s, size_type n);
+ basic_string& append(const value_type* s);
basic_string& append(size_type n, value_type c);
template<class InputIterator>
basic_string& append(InputIterator first, InputIterator last);
@@ -179,8 +179,8 @@ public:
basic_string& assign(const basic_string& str);
basic_string& assign(basic_string&& str);
basic_string& assign(const basic_string& str, size_type pos, size_type n);
- basic_string& assign(const_pointer s, size_type n);
- basic_string& assign(const_pointer s);
+ basic_string& assign(const value_type* s, size_type n);
+ basic_string& assign(const value_type* s);
basic_string& assign(size_type n, value_type c);
template<class InputIterator>
basic_string& assign(InputIterator first, InputIterator last);
@@ -189,8 +189,8 @@ public:
basic_string& insert(size_type pos1, const basic_string& str);
basic_string& insert(size_type pos1, const basic_string& str,
size_type pos2, size_type n);
- basic_string& insert(size_type pos, const_pointer s, size_type n);
- basic_string& insert(size_type pos, const_pointer s);
+ basic_string& insert(size_type pos, const value_type* s, size_type n);
+ basic_string& insert(size_type pos, const value_type* s);
basic_string& insert(size_type pos, size_type n, value_type c);
iterator insert(const_iterator p, value_type c);
iterator insert(const_iterator p, size_type n, value_type c);
@@ -205,66 +205,66 @@ public:
basic_string& replace(size_type pos1, size_type n1, const basic_string& str);
basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
size_type pos2, size_type n2);
- basic_string& replace(size_type pos, size_type n1, const_pointer s, size_type n2);
- basic_string& replace(size_type pos, size_type n1, const_pointer s);
+ basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2);
+ basic_string& replace(size_type pos, size_type n1, const value_type* s);
basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c);
basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str);
- basic_string& replace(const_iterator i1, const_iterator i2, const_pointer s, size_type n);
- basic_string& replace(const_iterator i1, const_iterator i2, const_pointer s);
+ basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n);
+ basic_string& replace(const_iterator i1, const_iterator i2, const value_type* s);
basic_string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c);
template<class InputIterator>
basic_string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2);
basic_string& replace(const_iterator i1, const_iterator i2, initializer_list<value_type>);
- size_type copy(pointer s, size_type n, size_type pos = 0) const;
+ size_type copy(value_type* s, size_type n, size_type pos = 0) const;
basic_string substr(size_type pos = 0, size_type n = npos) const;
void swap(basic_string& str)
noexcept(!allocator_type::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value)
- const_pointer c_str() const noexcept;
- const_pointer data() const noexcept;
+ const value_type* c_str() const noexcept;
+ const value_type* data() const noexcept;
allocator_type get_allocator() const noexcept;
size_type find(const basic_string& str, size_type pos = 0) const noexcept;
- size_type find(const_pointer s, size_type pos, size_type n) const noexcept;
- size_type find(const_pointer s, size_type pos = 0) const noexcept;
+ size_type find(const value_type* s, size_type pos, size_type n) const noexcept;
+ size_type find(const value_type* s, size_type pos = 0) const noexcept;
size_type find(value_type c, size_type pos = 0) const noexcept;
size_type rfind(const basic_string& str, size_type pos = npos) const noexcept;
- size_type rfind(const_pointer s, size_type pos, size_type n) const noexcept;
- size_type rfind(const_pointer s, size_type pos = npos) const noexcept;
+ size_type rfind(const value_type* s, size_type pos, size_type n) const noexcept;
+ size_type rfind(const value_type* s, size_type pos = npos) const noexcept;
size_type rfind(value_type c, size_type pos = npos) const noexcept;
size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept;
- size_type find_first_of(const_pointer s, size_type pos, size_type n) const noexcept;
- size_type find_first_of(const_pointer s, size_type pos = 0) const noexcept;
+ size_type find_first_of(const value_type* s, size_type pos, size_type n) const noexcept;
+ size_type find_first_of(const value_type* s, size_type pos = 0) const noexcept;
size_type find_first_of(value_type c, size_type pos = 0) const noexcept;
size_type find_last_of(const basic_string& str, size_type pos = npos) const noexcept;
- size_type find_last_of(const_pointer s, size_type pos, size_type n) const noexcept;
- size_type find_last_of(const_pointer s, size_type pos = npos) const noexcept;
+ size_type find_last_of(const value_type* s, size_type pos, size_type n) const noexcept;
+ size_type find_last_of(const value_type* s, size_type pos = npos) const noexcept;
size_type find_last_of(value_type c, size_type pos = npos) const noexcept;
size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept;
- size_type find_first_not_of(const_pointer s, size_type pos, size_type n) const noexcept;
- size_type find_first_not_of(const_pointer s, size_type pos = 0) const noexcept;
+ size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const noexcept;
+ size_type find_first_not_of(const value_type* s, size_type pos = 0) const noexcept;
size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept;
size_type find_last_not_of(const basic_string& str, size_type pos = npos) const noexcept;
- size_type find_last_not_of(const_pointer s, size_type pos, size_type n) const noexcept;
- size_type find_last_not_of(const_pointer s, size_type pos = npos) const noexcept;
+ size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const noexcept;
+ size_type find_last_not_of(const value_type* s, size_type pos = npos) const noexcept;
size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept;
int compare(const basic_string& str) const noexcept;
int compare(size_type pos1, size_type n1, const basic_string& str) const;
int compare(size_type pos1, size_type n1, const basic_string& str,
size_type pos2, size_type n2) const;
- int compare(const_pointer s) const noexcept;
- int compare(size_type pos1, size_type n1, const_pointer s) const;
- int compare(size_type pos1, size_type n1, const_pointer s, size_type n2) const;
+ int compare(const value_type* s) const noexcept;
+ int compare(size_type pos1, size_type n1, const value_type* s) const;
+ int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const;
bool __invariants() const;
};
@@ -422,6 +422,11 @@ template <> struct hash<u16string>;
template <> struct hash<u32string>;
template <> struct hash<wstring>;
+basic_string<char> operator "" s( const char *str, size_t len ); // C++14
+basic_string<wchar_t> operator "" s( const wchar_t *str, size_t len ); // C++14
+basic_string<char16_t> operator "" s( const char16_t *str, size_t len ); // C++14
+basic_string<char32_t> operator "" s( const char32_t *str, size_t len ); // C++14
+
} // std
*/
@@ -1027,14 +1032,29 @@ __basic_string_common<__b>::__throw_out_of_range() const
#endif
}
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVC
#pragma warning( push )
#pragma warning( disable: 4231 )
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVC
_LIBCPP_EXTERN_TEMPLATE(class __basic_string_common<true>)
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVC
#pragma warning( pop )
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVC
+
+#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT
+
+template <class _CharT, size_t = sizeof(_CharT)>
+struct __padding
+{
+ unsigned char __xx[sizeof(_CharT)-1];
+};
+
+template <class _CharT>
+struct __padding<_CharT, 1>
+{
+};
+
+#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT
template<class _CharT, class _Traits, class _Allocator>
class _LIBCPP_TYPE_VIS basic_string
@@ -1069,6 +1089,39 @@ public:
typedef _VSTD::reverse_iterator<const_iterator> const_reverse_iterator;
private:
+
+#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT
+
+ struct __long
+ {
+ pointer __data_;
+ size_type __size_;
+ size_type __cap_;
+ };
+
+#if _LIBCPP_BIG_ENDIAN
+ enum {__short_mask = 0x01};
+ enum {__long_mask = 0x1ul};
+#else // _LIBCPP_BIG_ENDIAN
+ enum {__short_mask = 0x80};
+ enum {__long_mask = ~(size_type(~0) >> 1)};
+#endif // _LIBCPP_BIG_ENDIAN
+
+ enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?
+ (sizeof(__long) - 1)/sizeof(value_type) : 2};
+
+ struct __short
+ {
+ value_type __data_[__min_cap];
+ struct
+ : __padding<value_type>
+ {
+ unsigned char __size_;
+ };
+ };
+
+#else
+
struct __long
{
size_type __cap_;
@@ -1084,8 +1137,6 @@ private:
enum {__long_mask = 0x1ul};
#endif // _LIBCPP_BIG_ENDIAN
- enum {__mask = size_type(~0) >> 1};
-
enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?
(sizeof(__long) - 1)/sizeof(value_type) : 2};
@@ -1099,6 +1150,8 @@ private:
value_type __data_[__min_cap];
};
+#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT
+
union __lx{__long __lx; __short __lxx;};
enum {__n_words = sizeof(__lx) / sizeof(size_type)};
@@ -1144,13 +1197,13 @@ public:
_LIBCPP_INLINE_VISIBILITY
basic_string(basic_string&& __str, const allocator_type& __a);
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
- _LIBCPP_INLINE_VISIBILITY basic_string(const_pointer __s);
+ _LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s);
_LIBCPP_INLINE_VISIBILITY
- basic_string(const_pointer __s, const allocator_type& __a);
+ basic_string(const value_type* __s, const allocator_type& __a);
_LIBCPP_INLINE_VISIBILITY
- basic_string(const_pointer __s, size_type __n);
+ basic_string(const value_type* __s, size_type __n);
_LIBCPP_INLINE_VISIBILITY
- basic_string(const_pointer __s, size_type __n, const allocator_type& __a);
+ basic_string(const value_type* __s, size_type __n, const allocator_type& __a);
_LIBCPP_INLINE_VISIBILITY
basic_string(size_type __n, value_type __c);
_LIBCPP_INLINE_VISIBILITY
@@ -1179,7 +1232,7 @@ public:
_NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value);
#endif
- _LIBCPP_INLINE_VISIBILITY basic_string& operator=(const_pointer __s) {return assign(__s);}
+ _LIBCPP_INLINE_VISIBILITY basic_string& operator=(const value_type* __s) {return assign(__s);}
basic_string& operator=(value_type __c);
#ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
_LIBCPP_INLINE_VISIBILITY
@@ -1192,13 +1245,13 @@ public:
{return iterator(__get_pointer());}
_LIBCPP_INLINE_VISIBILITY
const_iterator begin() const _NOEXCEPT
- {return const_iterator(data());}
+ {return const_iterator(__get_pointer());}
_LIBCPP_INLINE_VISIBILITY
iterator end() _NOEXCEPT
{return iterator(__get_pointer() + size());}
_LIBCPP_INLINE_VISIBILITY
const_iterator end() const _NOEXCEPT
- {return const_iterator(data() + size());}
+ {return const_iterator(__get_pointer() + size());}
#else // _LIBCPP_DEBUG
_LIBCPP_INLINE_VISIBILITY iterator begin() {return iterator(this, __get_pointer());}
_LIBCPP_INLINE_VISIBILITY const_iterator begin() const {return const_iterator(this, data());}
@@ -1255,7 +1308,7 @@ public:
reference at(size_type __n);
_LIBCPP_INLINE_VISIBILITY basic_string& operator+=(const basic_string& __str) {return append(__str);}
- _LIBCPP_INLINE_VISIBILITY basic_string& operator+=(const_pointer __s) {return append(__s);}
+ _LIBCPP_INLINE_VISIBILITY basic_string& operator+=(const value_type* __s) {return append(__s);}
_LIBCPP_INLINE_VISIBILITY basic_string& operator+=(value_type __c) {push_back(__c); return *this;}
#ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
_LIBCPP_INLINE_VISIBILITY basic_string& operator+=(initializer_list<value_type> __il) {return append(__il);}
@@ -1264,8 +1317,8 @@ public:
_LIBCPP_INLINE_VISIBILITY
basic_string& append(const basic_string& __str);
basic_string& append(const basic_string& __str, size_type __pos, size_type __n);
- basic_string& append(const_pointer __s, size_type __n);
- basic_string& append(const_pointer __s);
+ basic_string& append(const value_type* __s, size_type __n);
+ basic_string& append(const value_type* __s);
basic_string& append(size_type __n, value_type __c);
template<class _InputIterator>
typename enable_if
@@ -1303,8 +1356,8 @@ public:
{*this = _VSTD::move(str); return *this;}
#endif
basic_string& assign(const basic_string& __str, size_type __pos, size_type __n);
- basic_string& assign(const_pointer __s, size_type __n);
- basic_string& assign(const_pointer __s);
+ basic_string& assign(const value_type* __s, size_type __n);
+ basic_string& assign(const value_type* __s);
basic_string& assign(size_type __n, value_type __c);
template<class _InputIterator>
typename enable_if
@@ -1329,8 +1382,8 @@ public:
_LIBCPP_INLINE_VISIBILITY
basic_string& insert(size_type __pos1, const basic_string& __str);
basic_string& insert(size_type __pos1, const basic_string& __str, size_type __pos2, size_type __n);
- basic_string& insert(size_type __pos, const_pointer __s, size_type __n);
- basic_string& insert(size_type __pos, const_pointer __s);
+ basic_string& insert(size_type __pos, const value_type* __s, size_type __n);
+ basic_string& insert(size_type __pos, const value_type* __s);
basic_string& insert(size_type __pos, size_type __n, value_type __c);
iterator insert(const_iterator __pos, value_type __c);
_LIBCPP_INLINE_VISIBILITY
@@ -1365,15 +1418,15 @@ public:
_LIBCPP_INLINE_VISIBILITY
basic_string& replace(size_type __pos1, size_type __n1, const basic_string& __str);
basic_string& replace(size_type __pos1, size_type __n1, const basic_string& __str, size_type __pos2, size_type __n2);
- basic_string& replace(size_type __pos, size_type __n1, const_pointer __s, size_type __n2);
- basic_string& replace(size_type __pos, size_type __n1, const_pointer __s);
+ basic_string& replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2);
+ basic_string& replace(size_type __pos, size_type __n1, const value_type* __s);
basic_string& replace(size_type __pos, size_type __n1, size_type __n2, value_type __c);
_LIBCPP_INLINE_VISIBILITY
basic_string& replace(const_iterator __i1, const_iterator __i2, const basic_string& __str);
_LIBCPP_INLINE_VISIBILITY
- basic_string& replace(const_iterator __i1, const_iterator __i2, const_pointer __s, size_type __n);
+ basic_string& replace(const_iterator __i1, const_iterator __i2, const value_type* __s, size_type __n);
_LIBCPP_INLINE_VISIBILITY
- basic_string& replace(const_iterator __i1, const_iterator __i2, const_pointer __s);
+ basic_string& replace(const_iterator __i1, const_iterator __i2, const value_type* __s);
_LIBCPP_INLINE_VISIBILITY
basic_string& replace(const_iterator __i1, const_iterator __i2, size_type __n, value_type __c);
template<class _InputIterator>
@@ -1389,7 +1442,7 @@ public:
{return replace(__i1, __i2, __il.begin(), __il.end());}
#endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
- size_type copy(pointer __s, size_type __n, size_type __pos = 0) const;
+ size_type copy(value_type* __s, size_type __n, size_type __pos = 0) const;
_LIBCPP_INLINE_VISIBILITY
basic_string substr(size_type __pos = 0, size_type __n = npos) const;
@@ -1399,56 +1452,56 @@ public:
__is_nothrow_swappable<allocator_type>::value);
_LIBCPP_INLINE_VISIBILITY
- const_pointer c_str() const _NOEXCEPT {return data();}
+ const value_type* c_str() const _NOEXCEPT {return data();}
_LIBCPP_INLINE_VISIBILITY
- const_pointer data() const _NOEXCEPT {return __get_pointer();}
+ const value_type* data() const _NOEXCEPT {return _VSTD::__to_raw_pointer(__get_pointer());}
_LIBCPP_INLINE_VISIBILITY
allocator_type get_allocator() const _NOEXCEPT {return __alloc();}
_LIBCPP_INLINE_VISIBILITY
size_type find(const basic_string& __str, size_type __pos = 0) const _NOEXCEPT;
- size_type find(const_pointer __s, size_type __pos, size_type __n) const _NOEXCEPT;
+ size_type find(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
- size_type find(const_pointer __s, size_type __pos = 0) const _NOEXCEPT;
+ size_type find(const value_type* __s, size_type __pos = 0) const _NOEXCEPT;
size_type find(value_type __c, size_type __pos = 0) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type rfind(const basic_string& __str, size_type __pos = npos) const _NOEXCEPT;
- size_type rfind(const_pointer __s, size_type __pos, size_type __n) const _NOEXCEPT;
+ size_type rfind(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
- size_type rfind(const_pointer __s, size_type __pos = npos) const _NOEXCEPT;
+ size_type rfind(const value_type* __s, size_type __pos = npos) const _NOEXCEPT;
size_type rfind(value_type __c, size_type __pos = npos) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_first_of(const basic_string& __str, size_type __pos = 0) const _NOEXCEPT;
- size_type find_first_of(const_pointer __s, size_type __pos, size_type __n) const _NOEXCEPT;
+ size_type find_first_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
- size_type find_first_of(const_pointer __s, size_type __pos = 0) const _NOEXCEPT;
+ size_type find_first_of(const value_type* __s, size_type __pos = 0) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_first_of(value_type __c, size_type __pos = 0) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_last_of(const basic_string& __str, size_type __pos = npos) const _NOEXCEPT;
- size_type find_last_of(const_pointer __s, size_type __pos, size_type __n) const _NOEXCEPT;
+ size_type find_last_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
- size_type find_last_of(const_pointer __s, size_type __pos = npos) const _NOEXCEPT;
+ size_type find_last_of(const value_type* __s, size_type __pos = npos) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_last_of(value_type __c, size_type __pos = npos) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_first_not_of(const basic_string& __str, size_type __pos = 0) const _NOEXCEPT;
- size_type find_first_not_of(const_pointer __s, size_type __pos, size_type __n) const _NOEXCEPT;
+ size_type find_first_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
- size_type find_first_not_of(const_pointer __s, size_type __pos = 0) const _NOEXCEPT;
+ size_type find_first_not_of(const value_type* __s, size_type __pos = 0) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_first_not_of(value_type __c, size_type __pos = 0) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_last_not_of(const basic_string& __str, size_type __pos = npos) const _NOEXCEPT;
- size_type find_last_not_of(const_pointer __s, size_type __pos, size_type __n) const _NOEXCEPT;
+ size_type find_last_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
- size_type find_last_not_of(const_pointer __s, size_type __pos = npos) const _NOEXCEPT;
+ size_type find_last_not_of(const value_type* __s, size_type __pos = npos) const _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
size_type find_last_not_of(value_type __c, size_type __pos = npos) const _NOEXCEPT;
@@ -1457,11 +1510,16 @@ public:
_LIBCPP_INLINE_VISIBILITY
int compare(size_type __pos1, size_type __n1, const basic_string& __str) const;
int compare(size_type __pos1, size_type __n1, const basic_string& __str, size_type __pos2, size_type __n2) const;
- int compare(const_pointer __s) const _NOEXCEPT;
- int compare(size_type __pos1, size_type __n1, const_pointer __s) const;
- int compare(size_type __pos1, size_type __n1, const_pointer __s, size_type __n2) const;
+ int compare(const value_type* __s) const _NOEXCEPT;
+ int compare(size_type __pos1, size_type __n1, const value_type* __s) const;
+ int compare(size_type __pos1, size_type __n1, const value_type* __s, size_type __n2) const;
_LIBCPP_INLINE_VISIBILITY bool __invariants() const;
+
+ _LIBCPP_INLINE_VISIBILITY
+ bool __is_long() const _NOEXCEPT
+ {return bool(__r_.first().__s.__size_ & __short_mask);}
+
private:
_LIBCPP_INLINE_VISIBILITY
allocator_type& __alloc() _NOEXCEPT
@@ -1470,24 +1528,44 @@ private:
const allocator_type& __alloc() const _NOEXCEPT
{return __r_.second();}
+#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT
+
_LIBCPP_INLINE_VISIBILITY
- bool __is_long() const _NOEXCEPT
- {return bool(__r_.first().__s.__size_ & __short_mask);}
+ void __set_short_size(size_type __s) _NOEXCEPT
+# if _LIBCPP_BIG_ENDIAN
+ {__r_.first().__s.__size_ = (unsigned char)(__s << 1);}
+# else
+ {__r_.first().__s.__size_ = (unsigned char)(__s);}
+# endif
+
+ _LIBCPP_INLINE_VISIBILITY
+ size_type __get_short_size() const _NOEXCEPT
+# if _LIBCPP_BIG_ENDIAN
+ {return __r_.first().__s.__size_ >> 1;}
+# else
+ {return __r_.first().__s.__size_;}
+# endif
+
+#else // _LIBCPP_ALTERNATE_STRING_LAYOUT
_LIBCPP_INLINE_VISIBILITY
void __set_short_size(size_type __s) _NOEXCEPT
-#if _LIBCPP_BIG_ENDIAN
+# if _LIBCPP_BIG_ENDIAN
{__r_.first().__s.__size_ = (unsigned char)(__s);}
-#else
+# else
{__r_.first().__s.__size_ = (unsigned char)(__s << 1);}
-#endif
+# endif
+
_LIBCPP_INLINE_VISIBILITY
size_type __get_short_size() const _NOEXCEPT
-#if _LIBCPP_BIG_ENDIAN
+# if _LIBCPP_BIG_ENDIAN
{return __r_.first().__s.__size_;}
-#else
+# else
{return __r_.first().__s.__size_ >> 1;}
-#endif
+# endif
+
+#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT
+
_LIBCPP_INLINE_VISIBILITY
void __set_long_size(size_type __s) _NOEXCEPT
{__r_.first().__l.__size_ = __s;}
@@ -1516,10 +1594,10 @@ private:
{return __r_.first().__l.__data_;}
_LIBCPP_INLINE_VISIBILITY
pointer __get_short_pointer() _NOEXCEPT
- {return __r_.first().__s.__data_;}
+ {return pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]);}
_LIBCPP_INLINE_VISIBILITY
const_pointer __get_short_pointer() const _NOEXCEPT
- {return __r_.first().__s.__data_;}
+ {return pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]);}
_LIBCPP_INLINE_VISIBILITY
pointer __get_pointer() _NOEXCEPT
{return __is_long() ? __get_long_pointer() : __get_short_pointer();}
@@ -1546,8 +1624,8 @@ private:
__align<sizeof(value_type) < __alignment ?
__alignment/sizeof(value_type) : 1 > (__s+1)) - 1;}
- void __init(const_pointer __s, size_type __sz, size_type __reserve);
- void __init(const_pointer __s, size_type __sz);
+ void __init(const value_type* __s, size_type __sz, size_type __reserve);
+ void __init(const value_type* __s, size_type __sz);
void __init(size_type __n, value_type __c);
template <class _InputIterator>
@@ -1571,7 +1649,7 @@ private:
size_type __n_copy, size_type __n_del, size_type __n_add = 0);
void __grow_by_and_replace(size_type __old_cap, size_type __delta_cap, size_type __old_sz,
size_type __n_copy, size_type __n_del,
- size_type __n_add, const_pointer __p_new_stuff);
+ size_type __n_add, const value_type* __p_new_stuff);
_LIBCPP_INLINE_VISIBILITY
void __erase_to_end(size_type __pos);
@@ -1728,7 +1806,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __
template <class _CharT, class _Traits, class _Allocator>
void
-basic_string<_CharT, _Traits, _Allocator>::__init(const_pointer __s, size_type __sz, size_type __reserve)
+basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve)
{
if (__reserve > max_size())
this->__throw_length_error();
@@ -1746,13 +1824,13 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const_pointer __s, size_type _
__set_long_cap(__cap+1);
__set_long_size(__sz);
}
- traits_type::copy(__p, __s, __sz);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz);
traits_type::assign(__p[__sz], value_type());
}
template <class _CharT, class _Traits, class _Allocator>
void
-basic_string<_CharT, _Traits, _Allocator>::__init(const_pointer __s, size_type __sz)
+basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz)
{
if (__sz > max_size())
this->__throw_length_error();
@@ -1770,13 +1848,13 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const_pointer __s, size_type _
__set_long_cap(__cap+1);
__set_long_size(__sz);
}
- traits_type::copy(__p, __s, __sz);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz);
traits_type::assign(__p[__sz], value_type());
}
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
-basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s)
+basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -1786,7 +1864,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s)
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
-basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s, const allocator_type& __a)
+basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, const allocator_type& __a)
: __r_(__a)
{
#ifdef _LIBCPP_DEBUG
@@ -1797,7 +1875,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s, const
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
-basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s, size_type __n)
+basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -1807,7 +1885,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s, size_
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
-basic_string<_CharT, _Traits, _Allocator>::basic_string(const_pointer __s, size_type __n, const allocator_type& __a)
+basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n, const allocator_type& __a)
: __r_(__a)
{
#ifdef _LIBCPP_DEBUG
@@ -1823,7 +1901,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const basic_string& __st
if (!__str.__is_long())
__r_.first().__r = __str.__r_.first().__r;
else
- __init(__str.__get_long_pointer(), __str.__get_long_size());
+ __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
}
template <class _CharT, class _Traits, class _Allocator>
@@ -1833,7 +1911,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const basic_string& __st
if (!__str.__is_long())
__r_.first().__r = __str.__r_.first().__r;
else
- __init(__str.__get_long_pointer(), __str.__get_long_size());
+ __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1858,7 +1936,7 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(basic_string&& __str, co
if (__a == __str.__alloc() || !__str.__is_long())
__r_.first().__r = __str.__r_.first().__r;
else
- __init(__str.__get_long_pointer(), __str.__get_long_size());
+ __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
__str.__zero();
#ifdef _LIBCPP_DEBUG
__str.__invalidate_all_iterators();
@@ -1887,7 +1965,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c)
__set_long_cap(__cap+1);
__set_long_size(__n);
}
- traits_type::assign(__p, __n, __c);
+ traits_type::assign(_VSTD::__to_raw_pointer(__p), __n, __c);
traits_type::assign(__p[__n], value_type());
}
@@ -2025,7 +2103,7 @@ template <class _CharT, class _Traits, class _Allocator>
void
basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
(size_type __old_cap, size_type __delta_cap, size_type __old_sz,
- size_type __n_copy, size_type __n_del, size_type __n_add, const_pointer __p_new_stuff)
+ size_type __n_copy, size_type __n_del, size_type __n_add, const value_type* __p_new_stuff)
{
size_type __ms = max_size();
if (__delta_cap > __ms - __old_cap - 1)
@@ -2037,12 +2115,14 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
__invalidate_all_iterators();
if (__n_copy != 0)
- traits_type::copy(__p, __old_p, __n_copy);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p),
+ _VSTD::__to_raw_pointer(__old_p), __n_copy);
if (__n_add != 0)
- traits_type::copy(__p + __n_copy, __p_new_stuff, __n_add);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p) + __n_copy, __p_new_stuff, __n_add);
size_type __sec_cp_sz = __old_sz - __n_del - __n_copy;
if (__sec_cp_sz != 0)
- traits_type::copy(__p + __n_copy + __n_add, __old_p + __n_copy + __n_del, __sec_cp_sz);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p) + __n_copy + __n_add,
+ _VSTD::__to_raw_pointer(__old_p) + __n_copy + __n_del, __sec_cp_sz);
if (__old_cap+1 != __min_cap)
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
__set_long_pointer(__p);
@@ -2067,10 +2147,13 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
__invalidate_all_iterators();
if (__n_copy != 0)
- traits_type::copy(__p, __old_p, __n_copy);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p),
+ _VSTD::__to_raw_pointer(__old_p), __n_copy);
size_type __sec_cp_sz = __old_sz - __n_del - __n_copy;
if (__sec_cp_sz != 0)
- traits_type::copy(__p + __n_copy + __n_add, __old_p + __n_copy + __n_del, __sec_cp_sz);
+ traits_type::copy(_VSTD::__to_raw_pointer(__p) + __n_copy + __n_add,
+ _VSTD::__to_raw_pointer(__old_p) + __n_copy + __n_del,
+ __sec_cp_sz);
if (__old_cap+1 != __min_cap)
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
__set_long_pointer(__p);
@@ -2081,7 +2164,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::assign(const_pointer __s, size_type __n)
+basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2089,7 +2172,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const_pointer __s, size_type _
size_type __cap = capacity();
if (__cap >= __n)
{
- pointer __p = __get_pointer();
+ value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
traits_type::move(__p, __s, __n);
traits_type::assign(__p[__n], value_type());
__set_size(__n);
@@ -2115,7 +2198,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c)
}
else
__invalidate_iterators_past(__n);
- pointer __p = __get_pointer();
+ value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
traits_type::assign(__p, __n, __c);
traits_type::assign(__p[__n], value_type());
__set_size(__n);
@@ -2257,7 +2340,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const basic_string& __str, siz
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::assign(const_pointer __s)
+basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2269,7 +2352,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const_pointer __s)
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::append(const_pointer __s, size_type __n)
+basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2280,7 +2363,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const_pointer __s, size_type _
{
if (__n)
{
- pointer __p = __get_pointer();
+ value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
traits_type::copy(__p + __sz, __s, __n);
__sz += __n;
__set_size(__sz);
@@ -2303,7 +2386,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c)
if (__cap - __sz < __n)
__grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0);
pointer __p = __get_pointer();
- traits_type::assign(__p + __sz, __n, __c);
+ traits_type::assign(_VSTD::__to_raw_pointer(__p) + __sz, __n, __c);
__sz += __n;
__set_size(__sz);
traits_type::assign(__p[__sz], value_type());
@@ -2315,14 +2398,37 @@ template <class _CharT, class _Traits, class _Allocator>
void
basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c)
{
- size_type __cap = capacity();
- size_type __sz = size();
+ bool __is_short = !__is_long();
+ size_type __cap;
+ size_type __sz;
+ if (__is_short)
+ {
+ __cap = __min_cap - 1;
+ __sz = __get_short_size();
+ }
+ else
+ {
+ __cap = __get_long_cap() - 1;
+ __sz = __get_long_size();
+ }
if (__sz == __cap)
+ {
__grow_by(__cap, 1, __sz, __sz, 0);
- pointer __p = __get_pointer() + __sz;
+ __is_short = !__is_long();
+ }
+ pointer __p;
+ if (__is_short)
+ {
+ __p = __get_short_pointer() + __sz;
+ __set_short_size(__sz+1);
+ }
+ else
+ {
+ __p = __get_long_pointer() + __sz;
+ __set_long_size(__sz+1);
+ }
traits_type::assign(*__p, __c);
traits_type::assign(*++__p, value_type());
- __set_size(__sz+1);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2385,7 +2491,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const basic_string& __str, siz
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::append(const_pointer __s)
+basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2397,7 +2503,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const_pointer __s)
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const_pointer __s, size_type __n)
+basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s, size_type __n)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2410,7 +2516,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const_pointer
{
if (__n)
{
- pointer __p = __get_pointer();
+ value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
size_type __n_move = __sz - __pos;
if (__n_move != 0)
{
@@ -2439,10 +2545,10 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n
if (__n)
{
size_type __cap = capacity();
- pointer __p;
+ value_type* __p;
if (__cap - __sz >= __n)
{
- __p = __get_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_pointer());
size_type __n_move = __sz - __pos;
if (__n_move != 0)
traits_type::move(__p + __pos + __n, __p + __pos, __n_move);
@@ -2450,7 +2556,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n
else
{
__grow_by(__cap, __sz + __n - __cap, __sz, __pos, 0, __n);
- __p = __get_long_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_long_pointer());
}
traits_type::assign(__p + __pos, __n, __c);
__sz += __n;
@@ -2494,10 +2600,10 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _Forward
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
if (__n)
{
- pointer __p;
+ value_type* __p;
if (__cap - __sz >= __n)
{
- __p = __get_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_pointer());
size_type __n_move = __sz - __ip;
if (__n_move != 0)
traits_type::move(__p + __ip + __n, __p + __ip, __n_move);
@@ -2505,7 +2611,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _Forward
else
{
__grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n);
- __p = __get_long_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_long_pointer());
}
__sz += __n;
__set_size(__sz);
@@ -2537,7 +2643,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos1, const basic_
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const_pointer __s)
+basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2552,15 +2658,15 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, value_ty
size_type __ip = static_cast<size_type>(__pos - begin());
size_type __sz = size();
size_type __cap = capacity();
- pointer __p;
+ value_type* __p;
if (__cap == __sz)
{
__grow_by(__cap, 1, __sz, __ip, 0, 1);
- __p = __get_long_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_long_pointer());
}
else
{
- __p = __get_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_pointer());
size_type __n_move = __sz - __ip;
if (__n_move != 0)
traits_type::move(__p + __ip + 1, __p + __ip, __n_move);
@@ -2585,7 +2691,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, size_typ
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const_pointer __s, size_type __n2)
+basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2597,7 +2703,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
size_type __cap = capacity();
if (__cap - __sz + __n1 >= __n2)
{
- pointer __p = __get_pointer();
+ value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
if (__n1 != __n2)
{
size_type __n_move = __sz - __pos - __n1;
@@ -2646,10 +2752,10 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
this->__throw_out_of_range();
__n1 = _VSTD::min(__n1, __sz - __pos);
size_type __cap = capacity();
- pointer __p;
+ value_type* __p;
if (__cap - __sz + __n1 >= __n2)
{
- __p = __get_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_pointer());
if (__n1 != __n2)
{
size_type __n_move = __sz - __pos - __n1;
@@ -2660,7 +2766,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
else
{
__grow_by(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2);
- __p = __get_long_pointer();
+ __p = _VSTD::__to_raw_pointer(__get_long_pointer());
}
traits_type::assign(__p + __pos, __n2, __c);
__sz += __n2 - __n1;
@@ -2719,7 +2825,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos1, size_type _
template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const_pointer __s)
+basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s)
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -2739,7 +2845,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_it
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_iterator __i2, const_pointer __s, size_type __n)
+basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_iterator __i2, const value_type* __s, size_type __n)
{
return replace(static_cast<size_type>(__i1 - begin()), static_cast<size_type>(__i2 - __i1), __s, __n);
}
@@ -2747,7 +2853,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_it
template <class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_iterator __i2, const_pointer __s)
+basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_iterator __i2, const value_type* __s)
{
return replace(static_cast<size_type>(__i1 - begin()), static_cast<size_type>(__i2 - __i1), __s);
}
@@ -2771,7 +2877,7 @@ basic_string<_CharT, _Traits, _Allocator>::erase(size_type __pos, size_type __n)
this->__throw_out_of_range();
if (__n)
{
- pointer __p = __get_pointer();
+ value_type* __p = _VSTD::__to_raw_pointer(__get_pointer());
__n = _VSTD::min(__n, __sz - __pos);
size_type __n_move = __sz - __pos - __n;
if (__n_move != 0)
@@ -2929,7 +3035,7 @@ basic_string<_CharT, _Traits, _Allocator>::reserve(size_type __res_arg)
return;
}
#else // _LIBCPP_NO_EXCEPTIONS
- if (__new_data == 0)
+ if (__new_data == nullptr)
return;
#endif // _LIBCPP_NO_EXCEPTIONS
}
@@ -2937,7 +3043,8 @@ basic_string<_CharT, _Traits, _Allocator>::reserve(size_type __res_arg)
__was_long = __is_long();
__p = __get_pointer();
}
- traits_type::copy(__new_data, __p, size()+1);
+ traits_type::copy(_VSTD::__to_raw_pointer(__new_data),
+ _VSTD::__to_raw_pointer(__p), size()+1);
if (__was_long)
__alloc_traits::deallocate(__alloc(), __p, __cap+1);
if (__now_long)
@@ -3038,7 +3145,7 @@ basic_string<_CharT, _Traits, _Allocator>::back() const
template <class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::copy(pointer __s, size_type __n, size_type __pos) const
+basic_string<_CharT, _Traits, _Allocator>::copy(value_type* __s, size_type __n, size_type __pos) const
{
size_type __sz = size();
if (__pos > __sz)
@@ -3084,7 +3191,7 @@ struct _LIBCPP_HIDDEN __traits_eq
template<class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s,
size_type __pos,
size_type __n) const _NOEXCEPT
{
@@ -3096,8 +3203,8 @@ basic_string<_CharT, _Traits, _Allocator>::find(const_pointer __s,
return npos;
if (__n == 0)
return __pos;
- const_pointer __p = data();
- const_pointer __r = _VSTD::search(__p + __pos, __p + __sz, __s, __s + __n,
+ const value_type* __p = data();
+ const value_type* __r = _VSTD::search(__p + __pos, __p + __sz, __s, __s + __n,
__traits_eq<traits_type>());
if (__r == __p + __sz)
return npos;
@@ -3116,7 +3223,7 @@ basic_string<_CharT, _Traits, _Allocator>::find(const basic_string& __str,
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
@@ -3133,8 +3240,8 @@ basic_string<_CharT, _Traits, _Allocator>::find(value_type __c,
size_type __sz = size();
if (__pos >= __sz)
return npos;
- const_pointer __p = data();
- const_pointer __r = traits_type::find(__p + __pos, __sz - __pos, __c);
+ const value_type* __p = data();
+ const value_type* __r = traits_type::find(__p + __pos, __sz - __pos, __c);
if (__r == 0)
return npos;
return static_cast<size_type>(__r - __p);
@@ -3144,7 +3251,7 @@ basic_string<_CharT, _Traits, _Allocator>::find(value_type __c,
template<class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::rfind(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s,
size_type __pos,
size_type __n) const _NOEXCEPT
{
@@ -3157,8 +3264,8 @@ basic_string<_CharT, _Traits, _Allocator>::rfind(const_pointer __s,
__pos += __n;
else
__pos = __sz;
- const_pointer __p = data();
- const_pointer __r = _VSTD::find_end(__p, __p + __pos, __s, __s + __n,
+ const value_type* __p = data();
+ const value_type* __r = _VSTD::find_end(__p, __p + __pos, __s, __s + __n,
__traits_eq<traits_type>());
if (__n > 0 && __r == __p + __pos)
return npos;
@@ -3177,7 +3284,7 @@ basic_string<_CharT, _Traits, _Allocator>::rfind(const basic_string& __str,
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::rfind(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
@@ -3198,8 +3305,8 @@ basic_string<_CharT, _Traits, _Allocator>::rfind(value_type __c,
++__pos;
else
__pos = __sz;
- const_pointer __p = data();
- for (const_pointer __ps = __p + __pos; __ps != __p;)
+ const value_type* __p = data();
+ for (const value_type* __ps = __p + __pos; __ps != __p;)
{
if (traits_type::eq(*--__ps, __c))
return static_cast<size_type>(__ps - __p);
@@ -3212,7 +3319,7 @@ basic_string<_CharT, _Traits, _Allocator>::rfind(value_type __c,
template<class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_first_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s,
size_type __pos,
size_type __n) const _NOEXCEPT
{
@@ -3222,8 +3329,8 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_of(const_pointer __s,
size_type __sz = size();
if (__pos >= __sz || __n == 0)
return npos;
- const_pointer __p = data();
- const_pointer __r = _VSTD::find_first_of(__p + __pos, __p + __sz, __s,
+ const value_type* __p = data();
+ const value_type* __r = _VSTD::find_first_of(__p + __pos, __p + __sz, __s,
__s + __n, __traits_eq<traits_type>());
if (__r == __p + __sz)
return npos;
@@ -3242,7 +3349,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_of(const basic_string& __s
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_first_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
@@ -3264,7 +3371,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_of(value_type __c,
template<class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_last_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s,
size_type __pos,
size_type __n) const _NOEXCEPT
{
@@ -3278,10 +3385,10 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_of(const_pointer __s,
++__pos;
else
__pos = __sz;
- const_pointer __p = data();
- for (const_pointer __ps = __p + __pos; __ps != __p;)
+ const value_type* __p = data();
+ for (const value_type* __ps = __p + __pos; __ps != __p;)
{
- const_pointer __r = traits_type::find(__s, __n, *--__ps);
+ const value_type* __r = traits_type::find(__s, __n, *--__ps);
if (__r)
return static_cast<size_type>(__ps - __p);
}
@@ -3301,7 +3408,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_of(const basic_string& __st
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_last_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
@@ -3323,7 +3430,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_of(value_type __c,
template<class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s,
size_type __pos,
size_type __n) const _NOEXCEPT
{
@@ -3333,9 +3440,9 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const_pointer __s,
size_type __sz = size();
if (__pos < __sz)
{
- const_pointer __p = data();
- const_pointer __pe = __p + __sz;
- for (const_pointer __ps = __p + __pos; __ps != __pe; ++__ps)
+ const value_type* __p = data();
+ const value_type* __pe = __p + __sz;
+ for (const value_type* __ps = __p + __pos; __ps != __pe; ++__ps)
if (traits_type::find(__s, __n, *__ps) == 0)
return static_cast<size_type>(__ps - __p);
}
@@ -3354,7 +3461,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const basic_string&
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
@@ -3372,9 +3479,9 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(value_type __c,
size_type __sz = size();
if (__pos < __sz)
{
- const_pointer __p = data();
- const_pointer __pe = __p + __sz;
- for (const_pointer __ps = __p + __pos; __ps != __pe; ++__ps)
+ const value_type* __p = data();
+ const value_type* __pe = __p + __sz;
+ for (const value_type* __ps = __p + __pos; __ps != __pe; ++__ps)
if (!traits_type::eq(*__ps, __c))
return static_cast<size_type>(__ps - __p);
}
@@ -3385,7 +3492,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(value_type __c,
template<class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s,
size_type __pos,
size_type __n) const _NOEXCEPT
{
@@ -3397,8 +3504,8 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const_pointer __s,
++__pos;
else
__pos = __sz;
- const_pointer __p = data();
- for (const_pointer __ps = __p + __pos; __ps != __p;)
+ const value_type* __p = data();
+ for (const value_type* __ps = __p + __pos; __ps != __p;)
if (traits_type::find(__s, __n, *--__ps) == 0)
return static_cast<size_type>(__ps - __p);
return npos;
@@ -3416,7 +3523,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const basic_string&
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
typename basic_string<_CharT, _Traits, _Allocator>::size_type
-basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const_pointer __s,
+basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s,
size_type __pos) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
@@ -3436,8 +3543,8 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(value_type __c,
++__pos;
else
__pos = __sz;
- const_pointer __p = data();
- for (const_pointer __ps = __p + __pos; __ps != __p;)
+ const value_type* __p = data();
+ for (const value_type* __ps = __p + __pos; __ps != __p;)
if (!traits_type::eq(*--__ps, __c))
return static_cast<size_type>(__ps - __p);
return npos;
@@ -3490,7 +3597,7 @@ basic_string<_CharT, _Traits, _Allocator>::compare(size_type __pos1,
template <class _CharT, class _Traits, class _Allocator>
int
-basic_string<_CharT, _Traits, _Allocator>::compare(const_pointer __s) const _NOEXCEPT
+basic_string<_CharT, _Traits, _Allocator>::compare(const value_type* __s) const _NOEXCEPT
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -3502,7 +3609,7 @@ template <class _CharT, class _Traits, class _Allocator>
int
basic_string<_CharT, _Traits, _Allocator>::compare(size_type __pos1,
size_type __n1,
- const_pointer __s) const
+ const value_type* __s) const
{
#ifdef _LIBCPP_DEBUG
assert(__s != 0);
@@ -3514,7 +3621,7 @@ template <class _CharT, class _Traits, class _Allocator>
int
basic_string<_CharT, _Traits, _Allocator>::compare(size_type __pos1,
size_type __n1,
- const_pointer __s,
+ const value_type* __s,
size_type __n2) const
{
#ifdef _LIBCPP_DEBUG
@@ -3561,9 +3668,29 @@ bool
operator==(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT
{
- return __lhs.size() == __rhs.size() && _Traits::compare(__lhs.data(),
- __rhs.data(),
- __lhs.size()) == 0;
+ size_t __lhs_sz = __lhs.size();
+ return __lhs_sz == __rhs.size() && _Traits::compare(__lhs.data(),
+ __rhs.data(),
+ __lhs_sz) == 0;
+}
+
+template<class _Allocator>
+_LIBCPP_INLINE_VISIBILITY inline
+bool
+operator==(const basic_string<char, char_traits<char>, _Allocator>& __lhs,
+ const basic_string<char, char_traits<char>, _Allocator>& __rhs) _NOEXCEPT
+{
+ size_t __lhs_sz = __lhs.size();
+ if (__lhs_sz != __rhs.size())
+ return false;
+ const char* __lp = __lhs.data();
+ const char* __rp = __rhs.data();
+ if (__lhs.__is_long())
+ return char_traits<char>::compare(__lp, __rp, __lhs_sz) == 0;
+ for (; __lhs_sz != 0; --__lhs_sz, ++__lp, ++__rp)
+ if (*__lp != *__rp)
+ return false;
+ return true;
}
template<class _CharT, class _Traits, class _Allocator>
@@ -3975,6 +4102,42 @@ getline(basic_istream<_CharT, _Traits>&& __is,
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#if _LIBCPP_STD_VER > 11
+// Literal suffixes for basic_string [basic.string.literals]
+// inline // Deviation from N3690.
+// We believe the inline to be a defect and have submitted an LWG issue.
+// An LWG issue number has not yet been assigned.
+namespace literals
+{
+ inline namespace string_literals
+ {
+ inline _LIBCPP_INLINE_VISIBILITY
+ basic_string<char> operator "" s( const char *__str, size_t __len )
+ {
+ return basic_string<char> (__str, __len);
+ }
+
+ inline _LIBCPP_INLINE_VISIBILITY
+ basic_string<wchar_t> operator "" s( const wchar_t *__str, size_t __len )
+ {
+ return basic_string<wchar_t> (__str, __len);
+ }
+
+ inline _LIBCPP_INLINE_VISIBILITY
+ basic_string<char16_t> operator "" s( const char16_t *__str, size_t __len )
+ {
+ return basic_string<char16_t> (__str, __len);
+ }
+
+ inline _LIBCPP_INLINE_VISIBILITY
+ basic_string<char32_t> operator "" s( const char32_t *__str, size_t __len )
+ {
+ return basic_string<char32_t> (__str, __len);
+ }
+ }
+}
+#endif
+
_LIBCPP_EXTERN_TEMPLATE(class basic_string<char>)
_LIBCPP_EXTERN_TEMPLATE(class basic_string<wchar_t>)
diff --git a/system/include/libcxx/support/win32/limits_win32.h b/system/include/libcxx/support/win32/limits_win32.h
index 671631df..52229c4d 100644
--- a/system/include/libcxx/support/win32/limits_win32.h
+++ b/system/include/libcxx/support/win32/limits_win32.h
@@ -11,8 +11,8 @@
#ifndef _LIBCPP_SUPPORT_WIN32_LIMITS_WIN32_H
#define _LIBCPP_SUPPORT_WIN32_LIMITS_WIN32_H
-#if !defined(_MSC_VER)
-#error "This header is MSVC specific, Clang and GCC should not include it"
+#if !defined(_LIBCPP_MSVCRT)
+#error "This header complements Microsoft's C Runtime library, and should not be included otherwise."
#else
#ifndef NOMINMAX
@@ -74,6 +74,6 @@
#define __builtin_nansf(__dummy) _FSnan._Float
#define __builtin_nansl(__dummy) _LSnan._Long_double
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
#endif // _LIBCPP_SUPPORT_WIN32_LIMITS_WIN32_H
diff --git a/system/include/libcxx/support/win32/locale_win32.h b/system/include/libcxx/support/win32/locale_win32.h
index e035420f..019586c0 100644
--- a/system/include/libcxx/support/win32/locale_win32.h
+++ b/system/include/libcxx/support/win32/locale_win32.h
@@ -65,8 +65,21 @@ decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )
#define strtoull_l _strtoui64_l
// FIXME: current msvcrt does not know about long double
#define strtold_l _strtod_l
-#define islower_l _islower_l
-#define isupper_l _isupper_l
+
+inline _LIBCPP_INLINE_VISIBILITY
+int
+islower_l(int c, _locale_t loc)
+{
+ return _islower_l((int)c, loc);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+int
+isupper_l(int c, _locale_t loc)
+{
+ return _isupper_l((int)c, loc);
+}
+
#define isdigit_l _isdigit_l
#define isxdigit_l _isxdigit_l
#define strcoll_l _strcoll_l
diff --git a/system/include/libcxx/support/win32/math_win32.h b/system/include/libcxx/support/win32/math_win32.h
index 41c50d62..22400c0d 100644
--- a/system/include/libcxx/support/win32/math_win32.h
+++ b/system/include/libcxx/support/win32/math_win32.h
@@ -11,8 +11,8 @@
#ifndef _LIBCPP_SUPPORT_WIN32_MATH_WIN32_H
#define _LIBCPP_SUPPORT_WIN32_MATH_WIN32_H
-#if !defined(_MSC_VER)
-#error "This header is MSVC specific, Clang and GCC should not include it"
+#if !defined(_LIBCPP_MSVCRT)
+#error "This header complements Microsoft's C Runtime library, and should not be included otherwise."
#else
#include <math.h>
@@ -108,6 +108,6 @@ _LIBCPP_ALWAYS_INLINE int fpclassify( double num )
return _fpclass(num);
}
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
#endif // _LIBCPP_SUPPORT_WIN32_MATH_WIN32_H
diff --git a/system/include/libcxx/support/win32/support.h b/system/include/libcxx/support/win32/support.h
index 0b8a912a..17abb915 100644
--- a/system/include/libcxx/support/win32/support.h
+++ b/system/include/libcxx/support/win32/support.h
@@ -15,26 +15,23 @@
Functions and constants used in libc++ that are missing from the Windows C library.
*/
-#include <__config>
-#include <wchar.h> // mbstate_t
-#include <stdio.h> // _snwprintf
+#include <cwchar> // mbstate_t
+#include <cstdarg> // va_ macros
#define swprintf _snwprintf
#define vswprintf _vsnwprintf
-#define vfscnaf fscanf
-int vasprintf( char **sptr, const char *__restrict fmt , va_list ap );
-int asprintf( char **sptr, const char *__restrict fmt, ...);
-//int vfscanf( FILE *__restrict stream, const char *__restrict format,
-// va_list arg);
+extern "C" {
+int vasprintf( char **sptr, const char *__restrict fmt, va_list ap );
+int asprintf( char **sptr, const char *__restrict fmt, ...);
size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
size_t nmc, size_t len, mbstate_t *__restrict ps );
size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
size_t nwc, size_t len, mbstate_t *__restrict ps );
+}
-#if defined(_MSC_VER)
+#if defined(_LIBCPP_MSVCRT)
#define snprintf _snprintf
-
#include <xlocinfo.h>
#define atoll _atoi64
#define strtoll _strtoi64
@@ -85,9 +82,11 @@ _LIBCPP_ALWAYS_INLINE int __builtin_ctz( unsigned int x )
_BitScanReverse(&r, x);
return static_cast<int>(r);
}
+
// sizeof(long) == sizeof(int) on Windows
_LIBCPP_ALWAYS_INLINE int __builtin_ctzl( unsigned long x )
{ return __builtin_ctz( static_cast<int>(x) ); }
+
_LIBCPP_ALWAYS_INLINE int __builtin_ctzll( unsigned long long x )
{
DWORD r = 0;
@@ -110,6 +109,6 @@ _LIBCPP_ALWAYS_INLINE int __builtin_clzll( unsigned long long x )
return static_cast<int>(r);
}
#endif // !__clang__
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVCRT
#endif // _LIBCPP_SUPPORT_WIN32_SUPPORT_H
diff --git a/system/include/libcxx/thread b/system/include/libcxx/thread
index 8d3aab2a..f41ea290 100644
--- a/system/include/libcxx/thread
+++ b/system/include/libcxx/thread
@@ -328,7 +328,7 @@ __thread_specific_ptr<__thread_struct>& __thread_local_data();
template <class _Fp, class ..._Args, size_t ..._Indices>
inline _LIBCPP_INLINE_VISIBILITY
void
-__threaad_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>)
+__thread_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>)
{
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
}
@@ -340,7 +340,7 @@ __thread_proxy(void* __vp)
__thread_local_data().reset(new __thread_struct);
std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
- __threaad_execute(*__p, _Index());
+ __thread_execute(*__p, _Index());
return nullptr;
}
diff --git a/system/include/libcxx/tuple b/system/include/libcxx/tuple
index 7f299e9d..94876c91 100644
--- a/system/include/libcxx/tuple
+++ b/system/include/libcxx/tuple
@@ -21,19 +21,19 @@ template <class... T>
class tuple {
public:
constexpr tuple();
- explicit tuple(const T&...);
+ explicit tuple(const T&...); // constexpr in C++14
template <class... U>
- explicit tuple(U&&...);
+ explicit tuple(U&&...); // constexpr in C++14
tuple(const tuple&) = default;
tuple(tuple&&) = default;
template <class... U>
- tuple(const tuple<U...>&);
+ tuple(const tuple<U...>&); // constexpr in C++14
template <class... U>
- tuple(tuple<U...>&&);
+ tuple(tuple<U...>&&); // constexpr in C++14
template <class U1, class U2>
- tuple(const pair<U1, U2>&); // iff sizeof...(T) == 2
+ tuple(const pair<U1, U2>&); // iff sizeof...(T) == 2 // constexpr in C++14
template <class U1, class U2>
- tuple(pair<U1, U2>&&); // iff sizeof...(T) == 2
+ tuple(pair<U1, U2>&&); // iff sizeof...(T) == 2 // constexpr in C++14
// allocator-extended constructors
template <class Alloc>
@@ -72,10 +72,10 @@ public:
const unspecified ignore;
-template <class... T> tuple<V...> make_tuple(T&&...);
+template <class... T> tuple<V...> make_tuple(T&&...); // constexpr in C++14
template <class... T> tuple<ATypes...> forward_as_tuple(T&&...) noexcept;
template <class... T> tuple<T&...> tie(T&...) noexcept;
-template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls);
+template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls); // constexpr in C++14
// 20.4.1.4, tuple helper classes:
template <class T> class tuple_size; // undefined
@@ -86,21 +86,28 @@ template <intsize_t I, class... T> class tuple_element<I, tuple<T...>>;
// 20.4.1.5, element access:
template <intsize_t I, class... T>
typename tuple_element<I, tuple<T...>>::type&
- get(tuple<T...>&) noexcept;
+ get(tuple<T...>&) noexcept; // constexpr in C++14
template <intsize_t I, class... T>
typename tuple_element<I, tuple<T...>>::type const&
- get(const tuple<T...>&) noexcept;
+ get(const tuple<T...>&) noexcept; // constexpr in C++14
template <intsize_t I, class... T>
typename tuple_element<I, tuple<T...>>::type&&
- get(tuple<T...>&&) noexcept;
+ get(tuple<T...>&&) noexcept; // constexpr in C++14
+
+template <class T1, class... T>
+ constexpr T1& get(tuple<T...>&) noexcept; // C++14
+template <class T1, class... T>
+ constexpr T1 const& get(const tuple<T...>&) noexcept; // C++14
+template <class T1, class... T>
+ constexpr T1&& get(tuple<T...>&&) noexcept; // C++14
// 20.4.1.6, relational operators:
-template<class... T, class... U> bool operator==(const tuple<T...>&, const tuple<U...>&);
-template<class... T, class... U> bool operator<(const tuple<T...>&, const tuple<U...>&);
-template<class... T, class... U> bool operator!=(const tuple<T...>&, const tuple<U...>&);
-template<class... T, class... U> bool operator>(const tuple<T...>&, const tuple<U...>&);
-template<class... T, class... U> bool operator<=(const tuple<T...>&, const tuple<U...>&);
-template<class... T, class... U> bool operator>=(const tuple<T...>&, const tuple<U...>&);
+template<class... T, class... U> bool operator==(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14
+template<class... T, class... U> bool operator<(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14
+template<class... T, class... U> bool operator!=(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14
+template<class... T, class... U> bool operator>(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14
+template<class... T, class... U> bool operator<=(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14
+template<class... T, class... U> bool operator>=(const tuple<T...>&, const tuple<U...>&); // constexpr in C++14
template <class... Types, class Alloc>
struct uses_allocator<tuple<Types...>, Alloc>;
@@ -259,7 +266,7 @@ public:
template <class _Tp,
class = typename enable_if<is_constructible<_Hp, _Tp>::value>::type>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
: value(_VSTD::forward<_Tp>(__t))
{static_assert(!is_reference<_Hp>::value ||
@@ -316,15 +323,17 @@ public:
>::value)),
"Attempted to construct a reference element in a tuple with an rvalue");}
+ _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_CONSTEXPR_AFTER_CXX11
__tuple_leaf(const __tuple_leaf& __t) _NOEXCEPT_(is_nothrow_copy_constructible<_Hp>::value)
: value(__t.get())
{static_assert(!is_rvalue_reference<_Hp>::value, "Can not copy a tuple with rvalue reference member");}
- template <class _Tp>
- _LIBCPP_INLINE_VISIBILITY
- explicit __tuple_leaf(const __tuple_leaf<_Ip, _Tp>& __t)
- _NOEXCEPT_((is_nothrow_constructible<_Hp, const _Tp&>::value))
- : value(__t.get()) {}
+ _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_CONSTEXPR_AFTER_CXX11
+ __tuple_leaf(__tuple_leaf&& __t) _NOEXCEPT_(is_nothrow_move_constructible<_Hp>::value)
+ : value(_VSTD::move(__t.get()))
+ {}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
@@ -342,8 +351,8 @@ public:
return 0;
}
- _LIBCPP_INLINE_VISIBILITY _Hp& get() _NOEXCEPT {return value;}
- _LIBCPP_INLINE_VISIBILITY const _Hp& get() const _NOEXCEPT {return value;}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return value;}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return value;}
};
template <size_t _Ip, class _Hp>
@@ -372,7 +381,7 @@ public:
template <class _Tp,
class = typename enable_if<is_constructible<_Hp, _Tp>::value>::type>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
: _Hp(_VSTD::forward<_Tp>(__t)) {}
@@ -393,12 +402,6 @@ public:
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY
- explicit __tuple_leaf(const __tuple_leaf<_Ip, _Tp>& __t)
- _NOEXCEPT_((is_nothrow_constructible<_Hp, const _Tp&>::value))
- : _Hp(__t.get()) {}
-
- template <class _Tp>
- _LIBCPP_INLINE_VISIBILITY
__tuple_leaf&
operator=(_Tp&& __t) _NOEXCEPT_((is_nothrow_assignable<_Hp&, _Tp>::value))
{
@@ -414,8 +417,8 @@ public:
return 0;
}
- _LIBCPP_INLINE_VISIBILITY _Hp& get() _NOEXCEPT {return static_cast<_Hp&>(*this);}
- _LIBCPP_INLINE_VISIBILITY const _Hp& get() const _NOEXCEPT {return static_cast<const _Hp&>(*this);}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return static_cast<_Hp&>(*this);}
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return static_cast<const _Hp&>(*this);}
};
template <class ..._Tp>
@@ -450,7 +453,7 @@ struct __tuple_impl<__tuple_indices<_Indx...>, _Tp...>
template <size_t ..._Uf, class ..._Tf,
size_t ..._Ul, class ..._Tl, class ..._Up>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit
__tuple_impl(__tuple_indices<_Uf...>, __tuple_types<_Tf...>,
__tuple_indices<_Ul...>, __tuple_types<_Tl...>,
@@ -477,10 +480,10 @@ struct __tuple_impl<__tuple_indices<_Indx...>, _Tp...>
template <class _Tuple,
class = typename enable_if
<
- __tuple_convertible<_Tuple, tuple<_Tp...> >::value
+ __tuple_constructible<_Tuple, tuple<_Tp...> >::value
>::type
>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
__tuple_impl(_Tuple&& __t) _NOEXCEPT_((__all<is_nothrow_constructible<_Tp, typename tuple_element<_Indx,
typename __make_tuple_types<_Tuple>::type>::type>::value...>::value))
: __tuple_leaf<_Indx, _Tp>(_VSTD::forward<typename tuple_element<_Indx,
@@ -539,11 +542,11 @@ class _LIBCPP_TYPE_VIS tuple
base base_;
- template <size_t _Jp, class ..._Up> friend
+ template <size_t _Jp, class ..._Up> friend _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Jp, tuple<_Up...> >::type& get(tuple<_Up...>&) _NOEXCEPT;
- template <size_t _Jp, class ..._Up> friend
+ template <size_t _Jp, class ..._Up> friend _LIBCPP_CONSTEXPR_AFTER_CXX11
const typename tuple_element<_Jp, tuple<_Up...> >::type& get(const tuple<_Up...>&) _NOEXCEPT;
- template <size_t _Jp, class ..._Up> friend
+ template <size_t _Jp, class ..._Up> friend _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Jp, tuple<_Up...> >::type&& get(tuple<_Up...>&&) _NOEXCEPT;
public:
@@ -551,7 +554,7 @@ public:
_LIBCPP_CONSTEXPR tuple()
_NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
: base_(typename __make_tuple_indices<sizeof...(_Tp)>::type(),
typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
@@ -586,7 +589,7 @@ public:
bool
>::type = false
>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
tuple(_Up&&... __u)
_NOEXCEPT_((
is_nothrow_constructible<
@@ -626,7 +629,7 @@ public:
bool
>::type =false
>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit
tuple(_Up&&... __u)
_NOEXCEPT_((
@@ -674,7 +677,7 @@ public:
bool
>::type = false
>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<base, _Tuple>::value))
: base_(_VSTD::forward<_Tuple>(__t)) {}
@@ -686,7 +689,7 @@ public:
bool
>::type = false
>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit
tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<base, _Tuple>::value))
: base_(_VSTD::forward<_Tuple>(__t)) {}
@@ -756,7 +759,7 @@ swap(tuple<_Tp...>& __t, tuple<_Tp...>& __u)
// get
template <size_t _Ip, class ..._Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, tuple<_Tp...> >::type&
get(tuple<_Tp...>& __t) _NOEXCEPT
{
@@ -765,7 +768,7 @@ get(tuple<_Tp...>& __t) _NOEXCEPT
}
template <size_t _Ip, class ..._Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const typename tuple_element<_Ip, tuple<_Tp...> >::type&
get(const tuple<_Tp...>& __t) _NOEXCEPT
{
@@ -774,7 +777,7 @@ get(const tuple<_Tp...>& __t) _NOEXCEPT
}
template <size_t _Ip, class ..._Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, tuple<_Tp...> >::type&&
get(tuple<_Tp...>&& __t) _NOEXCEPT
{
@@ -783,6 +786,64 @@ get(tuple<_Tp...>&& __t) _NOEXCEPT
static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get());
}
+#if _LIBCPP_STD_VER > 11
+// get by type
+template <typename _T1, size_t _Idx, typename... _Args>
+struct __find_exactly_one_t_helper;
+
+// -- find exactly one
+template <typename _T1, size_t _Idx, typename... _Args>
+struct __find_exactly_one_t_checker {
+ static constexpr size_t value = _Idx;
+// Check the rest of the list to make sure there's only one
+ static_assert ( __find_exactly_one_t_helper<_T1, 0, _Args...>::value == -1, "type can only occur once in type list" );
+ };
+
+
+template <typename _T1, size_t _Idx>
+struct __find_exactly_one_t_helper <_T1, _Idx> {
+ static constexpr size_t value = -1;
+ };
+
+template <typename _T1, size_t _Idx, typename _Head, typename... _Args>
+struct __find_exactly_one_t_helper <_T1, _Idx, _Head, _Args...> {
+ static constexpr size_t value =
+ std::conditional<
+ std::is_same<_T1, _Head>::value,
+ __find_exactly_one_t_checker<_T1, _Idx,   _Args...>,
+ __find_exactly_one_t_helper <_T1, _Idx+1, _Args...>
+ >::type::value;
+ };
+
+template <typename _T1, typename... _Args>
+struct __find_exactly_one_t {
+ static constexpr size_t value = __find_exactly_one_t_helper<_T1, 0, _Args...>::value;
+ static_assert ( value != -1, "type not found in type list" );
+ };
+
+template <class _T1, class... _Args>
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr _T1& get(tuple<_Args...>& __tup) noexcept
+{
+ return _VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup);
+}
+
+template <class _T1, class... _Args>
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr _T1 const& get(tuple<_Args...> const& __tup) noexcept
+{
+ return _VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup);
+}
+
+template <class _T1, class... _Args>
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr _T1&& get(tuple<_Args...>&& __tup) noexcept
+{
+ return _VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(_VSTD::move(__tup));
+}
+
+#endif
+
// tie
template <class ..._Tp>
@@ -824,7 +885,7 @@ struct __make_tuple_return
};
template <class... _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
tuple<typename __make_tuple_return<_Tp>::type...>
make_tuple(_Tp&&... __t)
{
@@ -832,6 +893,14 @@ make_tuple(_Tp&&... __t)
}
template <class... _Tp>
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+tuple<_Tp&&...>
+__forward_as_tuple(_Tp&&... __t) _NOEXCEPT
+{
+ return tuple<_Tp&&...>(_VSTD::forward<_Tp>(__t)...);
+}
+
+template <class... _Tp>
inline _LIBCPP_INLINE_VISIBILITY
tuple<_Tp&&...>
forward_as_tuple(_Tp&&... __t) _NOEXCEPT
@@ -843,7 +912,7 @@ template <size_t _Ip>
struct __tuple_equal
{
template <class _Tp, class _Up>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool operator()(const _Tp& __x, const _Up& __y)
{
return __tuple_equal<_Ip - 1>()(__x, __y) && get<_Ip-1>(__x) == get<_Ip-1>(__y);
@@ -854,7 +923,7 @@ template <>
struct __tuple_equal<0>
{
template <class _Tp, class _Up>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool operator()(const _Tp&, const _Up&)
{
return true;
@@ -862,7 +931,7 @@ struct __tuple_equal<0>
};
template <class ..._Tp, class ..._Up>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
{
@@ -870,7 +939,7 @@ operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
}
template <class ..._Tp, class ..._Up>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator!=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
{
@@ -881,7 +950,7 @@ template <size_t _Ip>
struct __tuple_less
{
template <class _Tp, class _Up>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool operator()(const _Tp& __x, const _Up& __y)
{
return __tuple_less<_Ip-1>()(__x, __y) ||
@@ -893,7 +962,7 @@ template <>
struct __tuple_less<0>
{
template <class _Tp, class _Up>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool operator()(const _Tp&, const _Up&)
{
return false;
@@ -901,7 +970,7 @@ struct __tuple_less<0>
};
template <class ..._Tp, class ..._Up>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator<(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
{
@@ -909,7 +978,7 @@ operator<(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
}
template <class ..._Tp, class ..._Up>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator>(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
{
@@ -917,7 +986,7 @@ operator>(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
}
template <class ..._Tp, class ..._Up>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator>=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
{
@@ -925,7 +994,7 @@ operator>=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
}
template <class ..._Tp, class ..._Up>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator<=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y)
{
@@ -983,7 +1052,7 @@ struct __tuple_cat_return<>
typedef tuple<> type;
};
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
tuple<>
tuple_cat()
{
@@ -1030,16 +1099,16 @@ template <class ..._Types, size_t ..._I0, size_t ..._J0>
struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J0...> >
{
template <class _Tuple0>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename __tuple_cat_return_ref<tuple<_Types...>&&, _Tuple0&&>::type
operator()(tuple<_Types...> __t, _Tuple0&& __t0)
{
- return _VSTD::forward_as_tuple(_VSTD::forward<_Types>(get<_I0>(__t))...,
+ return __forward_as_tuple(_VSTD::forward<_Types>(get<_I0>(__t))...,
get<_J0>(_VSTD::forward<_Tuple0>(__t0))...);
}
template <class _Tuple0, class _Tuple1, class ..._Tuples>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename __tuple_cat_return_ref<tuple<_Types...>&&, _Tuple0&&, _Tuple1&&, _Tuples&&...>::type
operator()(tuple<_Types...> __t, _Tuple0&& __t0, _Tuple1&& __t1, _Tuples&& ...__tpls)
{
@@ -1049,7 +1118,7 @@ struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J
tuple<_Types..., typename __apply_cv<_Tuple0, typename tuple_element<_J0, _T0>::type>::type&&...>,
typename __make_tuple_indices<sizeof ...(_Types) + tuple_size<_T0>::value>::type,
typename __make_tuple_indices<tuple_size<_T1>::value>::type>()
- (_VSTD::forward_as_tuple(
+ (__forward_as_tuple(
_VSTD::forward<_Types>(get<_I0>(__t))...,
get<_J0>(_VSTD::forward<_Tuple0>(__t0))...
),
@@ -1059,7 +1128,7 @@ struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J
};
template <class _Tuple0, class... _Tuples>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename __tuple_cat_return<_Tuple0, _Tuples...>::type
tuple_cat(_Tuple0&& __t0, _Tuples&&... __tpls)
{
diff --git a/system/include/libcxx/type_traits b/system/include/libcxx/type_traits
index f60f71b5..99e34d13 100644
--- a/system/include/libcxx/type_traits
+++ b/system/include/libcxx/type_traits
@@ -129,6 +129,7 @@ namespace std
template <class T> struct alignment_of;
template <size_t Len, size_t Align = most_stringent_alignment_requirement>
struct aligned_storage;
+ template <size_t Len, class... Types> struct aligned_union;
template <class T> struct decay;
template <class... T> struct common_type;
@@ -136,6 +137,64 @@ namespace std
template <class> class result_of; // undefined
template <class Fn, class... ArgTypes> class result_of<Fn(ArgTypes...)>;
+ // const-volatile modifications:
+ template <class T>
+ using remove_const_t = typename remove_const<T>::type; // C++14
+ template <class T>
+ using remove_volatile_t = typename remove_volatile<T>::type; // C++14
+ template <class T>
+ using remove_cv_t = typename remove_cv<T>::type; // C++14
+ template <class T>
+ using add_const_t = typename add_const<T>::type; // C++14
+ template <class T>
+ using add_volatile_t = typename add_volatile<T>::type; // C++14
+ template <class T>
+ using add_cv_t = typename add_cv<T>::type; // C++14
+
+ // reference modifications:
+ template <class T>
+ using remove_reference_t = typename remove_reference<T>::type; // C++14
+ template <class T>
+ using add_lvalue_reference_t = typename add_lvalue_reference<T>::type; // C++14
+ template <class T>
+ using add_rvalue_reference_t = typename add_rvalue_reference<T>::type; // C++14
+
+ // sign modifications:
+ template <class T>
+ using make_signed_t = typename make_signed<T>::type; // C++14
+ template <class T>
+ using make_unsigned_t = typename make_unsigned<T>::type; // C++14
+
+ // array modifications:
+ template <class T>
+ using remove_extent_t = typename remove_extent<T>::type; // C++14
+ template <class T>
+ using remove_all_extents_t = typename remove_all_extents<T>::type; // C++14
+
+ // pointer modifications:
+ template <class T>
+ using remove_pointer_t = typename remove_pointer<T>::type; // C++14
+ template <class T>
+ using add_pointer_t = typename add_pointer<T>::type; // C++14
+
+ // other transformations:
+ template <size_t Len, std::size_t Align=default-alignment>
+ using aligned_storage_t = typename aligned_storage<Len,Align>::type; // C++14
+ template <std::size_t Len, class... Types>
+ using aligned_union_t = typename aligned_union<Len,Types...>::type; // C++14
+ template <class T>
+ using decay_t = typename decay<T>::type; // C++14
+ template <bool b, class T=void>
+ using enable_if_t = typename enable_if<b,T>::type; // C++14
+ template <bool b, class T, class F>
+ using conditional_t = typename conditional<b,T,F>::type; // C++14
+ template <class... T>
+ using common_type_t = typename common_type<T...>::type; // C++14
+ template <class T>
+ using underlying_type_t = typename underlying_type<T>::type; // C++14
+ template <class F, class... ArgTypes>
+ using result_of_t = typename result_of<F(ArgTypes...)>::type; // C++14
+
} // std
*/
@@ -153,9 +212,18 @@ template <bool _Bp, class _If, class _Then>
template <class _If, class _Then>
struct _LIBCPP_TYPE_VIS conditional<false, _If, _Then> {typedef _Then type;};
+#if _LIBCPP_STD_VER > 11
+template <bool _Bp, class _If, class _Then> using conditional_t = typename conditional<_Bp, _If, _Then>::type;
+#endif
+
template <bool, class _Tp = void> struct _LIBCPP_TYPE_VIS enable_if {};
template <class _Tp> struct _LIBCPP_TYPE_VIS enable_if<true, _Tp> {typedef _Tp type;};
+#if _LIBCPP_STD_VER > 11
+template <bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type;
+#endif
+
+
struct __two {char __lx[2];};
// helper class:
@@ -168,6 +236,10 @@ struct _LIBCPP_TYPE_VIS integral_constant
typedef integral_constant type;
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR operator value_type() const {return value;}
+#if _LIBCPP_STD_VER > 11
+ _LIBCPP_INLINE_VISIBILITY
+ constexpr value_type operator ()() const {return value;}
+#endif
};
template <class _Tp, _Tp __v>
@@ -190,16 +262,25 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS is_volatile<_Tp volatile> : public
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_const {typedef _Tp type;};
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_const<const _Tp> {typedef _Tp type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_const_t = typename remove_const<_Tp>::type;
+#endif
// remove_volatile
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_volatile {typedef _Tp type;};
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_volatile<volatile _Tp> {typedef _Tp type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_volatile_t = typename remove_volatile<_Tp>::type;
+#endif
// remove_cv
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_cv
{typedef typename remove_volatile<typename remove_const<_Tp>::type>::type type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_cv_t = typename remove_cv<_Tp>::type;
+#endif
// is_void
@@ -445,6 +526,10 @@ struct __add_const<_Tp, false> {typedef const _Tp type;};
template <class _Tp> struct _LIBCPP_TYPE_VIS add_const
{typedef typename __add_const<_Tp>::type type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using add_const_t = typename add_const<_Tp>::type;
+#endif
+
// add_volatile
template <class _Tp, bool = is_reference<_Tp>::value ||
@@ -458,11 +543,19 @@ struct __add_volatile<_Tp, false> {typedef volatile _Tp type;};
template <class _Tp> struct _LIBCPP_TYPE_VIS add_volatile
{typedef typename __add_volatile<_Tp>::type type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using add_volatile_t = typename add_volatile<_Tp>::type;
+#endif
+
// add_cv
template <class _Tp> struct _LIBCPP_TYPE_VIS add_cv
{typedef typename add_const<typename add_volatile<_Tp>::type>::type type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using add_cv_t = typename add_cv<_Tp>::type;
+#endif
+
// remove_reference
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_reference {typedef _Tp type;};
@@ -471,6 +564,10 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS remove_reference<_Tp&> {typedef _T
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_reference<_Tp&&> {typedef _Tp type;};
#endif
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_reference_t = typename remove_reference<_Tp>::type;
+#endif
+
// add_lvalue_reference
template <class _Tp> struct _LIBCPP_TYPE_VIS add_lvalue_reference {typedef _Tp& type;};
@@ -480,6 +577,10 @@ template <> struct _LIBCPP_TYPE_VIS add_lvalue_reference<const void>
template <> struct _LIBCPP_TYPE_VIS add_lvalue_reference<volatile void> {typedef volatile void type;};
template <> struct _LIBCPP_TYPE_VIS add_lvalue_reference<const volatile void> {typedef const volatile void type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type;
+#endif
+
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Tp> struct _LIBCPP_TYPE_VIS add_rvalue_reference {typedef _Tp&& type;};
@@ -488,6 +589,10 @@ template <> struct _LIBCPP_TYPE_VIS add_rvalue_reference<const void>
template <> struct _LIBCPP_TYPE_VIS add_rvalue_reference<volatile void> {typedef volatile void type;};
template <> struct _LIBCPP_TYPE_VIS add_rvalue_reference<const volatile void> {typedef const volatile void type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type;
+#endif
+
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -517,11 +622,19 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS remove_pointer<_Tp* const>
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_pointer<_Tp* volatile> {typedef _Tp type;};
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_pointer<_Tp* const volatile> {typedef _Tp type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_pointer_t = typename remove_pointer<_Tp>::type;
+#endif
+
// add_pointer
template <class _Tp> struct _LIBCPP_TYPE_VIS add_pointer
{typedef typename remove_reference<_Tp>::type* type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using add_pointer_t = typename add_pointer<_Tp>::type;
+#endif
+
// is_signed
template <class _Tp, bool = is_integral<_Tp>::value>
@@ -583,6 +696,10 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS remove_extent<_Tp[]>
template <class _Tp, size_t _Np> struct _LIBCPP_TYPE_VIS remove_extent<_Tp[_Np]>
{typedef _Tp type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_extent_t = typename remove_extent<_Tp>::type;
+#endif
+
// remove_all_extents
template <class _Tp> struct _LIBCPP_TYPE_VIS remove_all_extents
@@ -592,6 +709,10 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS remove_all_extents<_Tp[]>
template <class _Tp, size_t _Np> struct _LIBCPP_TYPE_VIS remove_all_extents<_Tp[_Np]>
{typedef typename remove_all_extents<_Tp>::type type;};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using remove_all_extents_t = typename remove_all_extents<_Tp>::type;
+#endif
+
// is_abstract
namespace __is_abstract_imp
@@ -609,7 +730,7 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS is_abstract : public __libcpp_abstr
// is_base_of
-#ifdef _LIBCP_HAS_IS_BASE_OF
+#ifdef _LIBCPP_HAS_IS_BASE_OF
template <class _Bp, class _Dp>
struct _LIBCPP_TYPE_VIS is_base_of
@@ -802,17 +923,13 @@ struct _LIBCPP_TYPE_VIS is_polymorphic
#else
-template <class _Tp> struct __is_polymorphic1 : public _Tp {};
-template <class _Tp> struct __is_polymorphic2 : public _Tp {virtual ~__is_polymorphic2() throw();};
-
-template <class _Tp, bool = is_class<_Tp>::value>
-struct __libcpp_polymorphic
- : public integral_constant<bool, sizeof(__is_polymorphic1<_Tp>) == sizeof(__is_polymorphic2<_Tp>)> {};
-
-template <class _Tp> struct __libcpp_polymorphic<_Tp, false> : public false_type {};
+template<typename _Tp> char &__is_polymorphic_impl(
+ typename enable_if<sizeof((_Tp*)dynamic_cast<const volatile void*>(declval<_Tp*>())) != 0,
+ int>::type);
+template<typename _Tp> __two &__is_polymorphic_impl(...);
template <class _Tp> struct _LIBCPP_TYPE_VIS is_polymorphic
- : public __libcpp_polymorphic<_Tp> {};
+ : public integral_constant<bool, sizeof(__is_polymorphic_impl<_Tp>(0)) == 1> {};
#endif // __has_feature(is_polymorphic)
@@ -832,10 +949,8 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS has_virtual_destructor
// alignment_of
-template <class _Tp> struct __alignment_of {_Tp __lx;};
-
template <class _Tp> struct _LIBCPP_TYPE_VIS alignment_of
- : public integral_constant<size_t, __alignof__(__alignment_of<typename remove_all_extents<_Tp>::type>)> {};
+ : public integral_constant<size_t, __alignof__(_Tp)> {};
// aligned_storage
@@ -921,7 +1036,7 @@ template <class _Hp, class _Tp, size_t _Len>
struct __find_max_align<__type_list<_Hp, _Tp>, _Len>
: public integral_constant<size_t, __select_align<_Len, _Hp::value, __find_max_align<_Tp, _Len>::value>::value> {};
-template <size_t _Len, const size_t _Align = __find_max_align<__all_types, _Len>::value>
+template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
struct _LIBCPP_TYPE_VIS aligned_storage
{
typedef typename __find_pod<__all_types, _Align>::type _Aligner;
@@ -933,6 +1048,11 @@ struct _LIBCPP_TYPE_VIS aligned_storage
};
};
+#if _LIBCPP_STD_VER > 11
+template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value>
+ using aligned_storage_t = typename aligned_storage<_Len, _Align>::type;
+#endif
+
#define _CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \
template <size_t _Len>\
struct _LIBCPP_TYPE_VIS aligned_storage<_Len, n>\
@@ -958,12 +1078,48 @@ _CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800);
_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000);
_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000);
// MSDN says that MSVC does not support alignment beyond 8192 (=0x2000)
-#if !defined(_MSC_VER)
+#if !defined(_LIBCPP_MSVC)
_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000);
-#endif // !_MSC_VER
+#endif // !_LIBCPP_MSVC
#undef _CREATE_ALIGNED_STORAGE_SPECIALIZATION
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+
+// aligned_union
+
+template <size_t _I0, size_t ..._In>
+struct __static_max;
+
+template <size_t _I0>
+struct __static_max<_I0>
+{
+ static const size_t value = _I0;
+};
+
+template <size_t _I0, size_t _I1, size_t ..._In>
+struct __static_max<_I0, _I1, _In...>
+{
+ static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value :
+ __static_max<_I1, _In...>::value;
+};
+
+template <size_t _Len, class _Type0, class ..._Types>
+struct aligned_union
+{
+ static const size_t alignment_value = __static_max<__alignof__(_Type0),
+ __alignof__(_Types)...>::value;
+ static const size_t __len = __static_max<_Len, sizeof(_Type0),
+ sizeof(_Types)...>::value;
+ typedef typename aligned_storage<__len, alignment_value>::type type;
+};
+
+#if _LIBCPP_STD_VER > 11
+template <size_t _Len, class ..._Types> using aligned_union_t = typename aligned_union<_Len, _Types...>::type;
+#endif
+
+#endif // _LIBCPP_HAS_NO_VARIADICS
+
// __promote
template <class _A1, class _A2 = void, class _A3 = void,
@@ -1123,6 +1279,10 @@ struct _LIBCPP_TYPE_VIS make_signed
typedef typename __apply_cv<_Tp, typename __make_signed<typename remove_cv<_Tp>::type>::type>::type type;
};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using make_signed_t = typename make_signed<_Tp>::type;
+#endif
+
template <class _Tp, bool = is_integral<_Tp>::value || is_enum<_Tp>::value>
struct __make_unsigned {};
@@ -1148,6 +1308,10 @@ struct _LIBCPP_TYPE_VIS make_unsigned
typedef typename __apply_cv<_Tp, typename __make_unsigned<typename remove_cv<_Tp>::type>::type>::type type;
};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using make_unsigned_t = typename make_unsigned<_Tp>::type;
+#endif
+
#ifdef _LIBCPP_HAS_NO_VARIADICS
template <class _Tp, class _Up = void, class V = void>
@@ -1206,6 +1370,10 @@ struct _LIBCPP_TYPE_VIS common_type<_Tp, _Up, _Vp...>
typedef typename common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type;
};
+#if _LIBCPP_STD_VER > 11
+template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type;
+#endif
+
#endif // _LIBCPP_HAS_NO_VARIADICS
// is_assignable
@@ -1298,7 +1466,7 @@ struct is_destructible
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename remove_reference<_Tp>::type&&
move(_Tp&& __t) _NOEXCEPT
{
@@ -1307,7 +1475,7 @@ move(_Tp&& __t) _NOEXCEPT
}
template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) _NOEXCEPT
{
@@ -1315,7 +1483,7 @@ forward(typename std::remove_reference<_Tp>::type& __t) _NOEXCEPT
}
template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp&&
forward(typename std::remove_reference<_Tp>::type&& __t) _NOEXCEPT
{
@@ -1384,6 +1552,10 @@ public:
>::type type;
};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using decay_t = typename decay<_Tp>::type;
+#endif
+
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Tp>
@@ -1626,7 +1798,7 @@ struct __member_pointer_traits_imp<_Rp _Class::*, false, true>
template <class _MP>
struct __member_pointer_traits
- : public __member_pointer_traits_imp<_MP,
+ : public __member_pointer_traits_imp<typename remove_cv<_MP>::type,
is_member_function_pointer<_MP>::value,
is_member_object_pointer<_MP>::value>
{
@@ -2851,13 +3023,27 @@ __invoke(__any, _Args&& ...__args)
// bullets 1 and 2
-template <class _Fp, class _A0, class ..._Args>
+template <class _Fp, class _A0, class ..._Args,
+ class = typename enable_if
+ <
+ is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
+ is_base_of<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType,
+ typename remove_reference<_A0>::type>::value
+ >::type
+ >
_LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
-> decltype((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...));
-template <class _Fp, class _A0, class ..._Args>
+template <class _Fp, class _A0, class ..._Args,
+ class = typename enable_if
+ <
+ is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
+ !is_base_of<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType,
+ typename remove_reference<_A0>::type>::value
+ >::type
+ >
_LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
@@ -2865,13 +3051,27 @@ __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
// bullets 3 and 4
-template <class _Fp, class _A0>
+template <class _Fp, class _A0,
+ class = typename enable_if
+ <
+ is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
+ is_base_of<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType,
+ typename remove_reference<_A0>::type>::value
+ >::type
+ >
_LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0)
-> decltype(_VSTD::forward<_A0>(__a0).*__f);
-template <class _Fp, class _A0>
+template <class _Fp, class _A0,
+ class = typename enable_if
+ <
+ is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
+ !is_base_of<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType,
+ typename remove_reference<_A0>::type>::value
+ >::type
+ >
_LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0)
@@ -2929,6 +3129,10 @@ class _LIBCPP_TYPE_VIS result_of<_Fp(_Args...)>
{
};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using result_of_t = typename result_of<_Tp>::type;
+#endif
+
#endif // _LIBCPP_HAS_NO_VARIADICS
template <class _Tp>
@@ -3023,6 +3227,10 @@ struct underlying_type
typedef _LIBCXX_UNDERLYING_TYPE(_Tp) type;
};
+#if _LIBCPP_STD_VER > 11
+template <class _Tp> using underlying_type_t = typename underlying_type<_Tp>::type;
+#endif
+
#else // _LIBCXX_UNDERLYING_TYPE
template <class _Tp, bool _Support = false>
diff --git a/system/include/libcxx/unordered_map b/system/include/libcxx/unordered_map
index 235b2eab..eebf2f5e 100644
--- a/system/include/libcxx/unordered_map
+++ b/system/include/libcxx/unordered_map
@@ -325,7 +325,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Key, class _Tp, class _Hash, bool = is_empty<_Hash>::value
+template <class _Key, class _Cp, class _Hash, bool = is_empty<_Hash>::value
#if __has_feature(is_final)
&& !__is_final(_Hash)
#endif
@@ -333,8 +333,6 @@ template <class _Key, class _Tp, class _Hash, bool = is_empty<_Hash>::value
class __unordered_map_hasher
: private _Hash
{
- typedef pair<typename remove_const<_Key>::type, _Tp> _Pp;
- typedef pair<const _Key, _Tp> _Cp;
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_hasher()
@@ -347,23 +345,18 @@ public:
_LIBCPP_INLINE_VISIBILITY
const _Hash& hash_function() const _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY
- size_t operator()(const _Pp& __x) const
- {return static_cast<const _Hash&>(*this)(__x.first);}
- _LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Cp& __x) const
- {return static_cast<const _Hash&>(*this)(__x.first);}
+ {return static_cast<const _Hash&>(*this)(__x.__cc.first);}
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Key& __x) const
{return static_cast<const _Hash&>(*this)(__x);}
};
-template <class _Key, class _Tp, class _Hash>
-class __unordered_map_hasher<_Key, _Tp, _Hash, false>
+template <class _Key, class _Cp, class _Hash>
+class __unordered_map_hasher<_Key, _Cp, _Hash, false>
{
_Hash __hash_;
- typedef pair<typename remove_const<_Key>::type, _Tp> _Pp;
- typedef pair<const _Key, _Tp> _Cp;
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_hasher()
@@ -376,17 +369,14 @@ public:
_LIBCPP_INLINE_VISIBILITY
const _Hash& hash_function() const _NOEXCEPT {return __hash_;}
_LIBCPP_INLINE_VISIBILITY
- size_t operator()(const _Pp& __x) const
- {return __hash_(__x.first);}
- _LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Cp& __x) const
- {return __hash_(__x.first);}
+ {return __hash_(__x.__cc.first);}
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Key& __x) const
{return __hash_(__x);}
};
-template <class _Key, class _Tp, class _Pred, bool = is_empty<_Pred>::value
+template <class _Key, class _Cp, class _Pred, bool = is_empty<_Pred>::value
#if __has_feature(is_final)
&& !__is_final(_Pred)
#endif
@@ -394,8 +384,6 @@ template <class _Key, class _Tp, class _Pred, bool = is_empty<_Pred>::value
class __unordered_map_equal
: private _Pred
{
- typedef pair<typename remove_const<_Key>::type, _Tp> _Pp;
- typedef pair<const _Key, _Tp> _Cp;
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_equal()
@@ -408,41 +396,21 @@ public:
_LIBCPP_INLINE_VISIBILITY
const _Pred& key_eq() const _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Pp& __y) const
- {return static_cast<const _Pred&>(*this)(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Cp& __y) const
- {return static_cast<const _Pred&>(*this)(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Key& __y) const
- {return static_cast<const _Pred&>(*this)(__x.first, __y);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Cp& __x, const _Pp& __y) const
- {return static_cast<const _Pred&>(*this)(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _Cp& __y) const
- {return static_cast<const _Pred&>(*this)(__x.first, __y.first);}
+ {return static_cast<const _Pred&>(*this)(__x.__cc.first, __y.__cc.first);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _Key& __y) const
- {return static_cast<const _Pred&>(*this)(__x.first, __y);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Pp& __y) const
- {return static_cast<const _Pred&>(*this)(__x, __y.first);}
+ {return static_cast<const _Pred&>(*this)(__x.__cc.first, __y);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Key& __x, const _Cp& __y) const
- {return static_cast<const _Pred&>(*this)(__x, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Key& __y) const
- {return static_cast<const _Pred&>(*this)(__x, __y);}
+ {return static_cast<const _Pred&>(*this)(__x, __y.__cc.first);}
};
-template <class _Key, class _Tp, class _Pred>
-class __unordered_map_equal<_Key, _Tp, _Pred, false>
+template <class _Key, class _Cp, class _Pred>
+class __unordered_map_equal<_Key, _Cp, _Pred, false>
{
_Pred __pred_;
- typedef pair<typename remove_const<_Key>::type, _Tp> _Pp;
- typedef pair<const _Key, _Tp> _Cp;
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_equal()
@@ -455,32 +423,14 @@ public:
_LIBCPP_INLINE_VISIBILITY
const _Pred& key_eq() const _NOEXCEPT {return __pred_;}
_LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Pp& __y) const
- {return __pred_(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Cp& __y) const
- {return __pred_(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Pp& __x, const _Key& __y) const
- {return __pred_(__x.first, __y);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Cp& __x, const _Pp& __y) const
- {return __pred_(__x.first, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _Cp& __y) const
- {return __pred_(__x.first, __y.first);}
+ {return __pred_(__x.__cc.first, __y.__cc.first);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _Key& __y) const
- {return __pred_(__x.first, __y);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Pp& __y) const
- {return __pred_(__x, __y.first);}
+ {return __pred_(__x.__cc.first, __y);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Key& __x, const _Cp& __y) const
- {return __pred_(__x, __y.first);}
- _LIBCPP_INLINE_VISIBILITY
- bool operator()(const _Key& __x, const _Key& __y) const
- {return __pred_(__x, __y);}
+ {return __pred_(__x, __y.__cc.first);}
};
template <class _Alloc>
@@ -492,8 +442,8 @@ class __hash_map_node_destructor
public:
typedef typename __alloc_traits::pointer pointer;
private:
- typedef typename value_type::first_type first_type;
- typedef typename value_type::second_type second_type;
+ typedef typename value_type::value_type::first_type first_type;
+ typedef typename value_type::value_type::second_type second_type;
allocator_type& __na_;
@@ -535,9 +485,9 @@ public:
void operator()(pointer __p) _NOEXCEPT
{
if (__second_constructed)
- __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.second));
+ __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__cc.second));
if (__first_constructed)
- __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.first));
+ __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__cc.first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
@@ -549,8 +499,8 @@ class _LIBCPP_TYPE_VIS __hash_map_iterator
_HashIterator __i_;
typedef pointer_traits<typename _HashIterator::pointer> __pointer_traits;
- typedef const typename _HashIterator::value_type::first_type key_type;
- typedef typename _HashIterator::value_type::second_type mapped_type;
+ typedef const typename _HashIterator::value_type::value_type::first_type key_type;
+ typedef typename _HashIterator::value_type::value_type::second_type mapped_type;
public:
typedef forward_iterator_tag iterator_category;
typedef pair<key_type, mapped_type> value_type;
@@ -571,9 +521,9 @@ public:
__hash_map_iterator(_HashIterator __i) _NOEXCEPT : __i_(__i) {}
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return *operator->();}
+ reference operator*() const {return __i_->__cc;}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return (pointer)__i_.operator->();}
+ pointer operator->() const {return pointer_traits<pointer>::pointer_to(__i_->__cc);}
_LIBCPP_INLINE_VISIBILITY
__hash_map_iterator& operator++() {++__i_; return *this;}
@@ -605,8 +555,8 @@ class _LIBCPP_TYPE_VIS __hash_map_const_iterator
_HashIterator __i_;
typedef pointer_traits<typename _HashIterator::pointer> __pointer_traits;
- typedef const typename _HashIterator::value_type::first_type key_type;
- typedef typename _HashIterator::value_type::second_type mapped_type;
+ typedef const typename _HashIterator::value_type::value_type::first_type key_type;
+ typedef typename _HashIterator::value_type::value_type::second_type mapped_type;
public:
typedef forward_iterator_tag iterator_category;
typedef pair<key_type, mapped_type> value_type;
@@ -632,9 +582,9 @@ public:
: __i_(__i.__i_) {}
_LIBCPP_INLINE_VISIBILITY
- reference operator*() const {return *operator->();}
+ reference operator*() const {return __i_->__cc;}
_LIBCPP_INLINE_VISIBILITY
- pointer operator->() const {return (pointer)__i_.operator->();}
+ pointer operator->() const {return pointer_traits<pointer>::pointer_to(__i_->__cc);}
_LIBCPP_INLINE_VISIBILITY
__hash_map_const_iterator& operator++() {++__i_; return *this;}
@@ -671,13 +621,58 @@ public:
typedef _Pred key_equal;
typedef _Alloc allocator_type;
typedef pair<const key_type, mapped_type> value_type;
+ typedef pair<key_type, mapped_type> __nc_value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
+ static_assert((is_same<value_type, typename allocator_type::value_type>::value),
+ "Invalid allocator::value_type");
private:
- typedef pair<key_type, mapped_type> __value_type;
- typedef __unordered_map_hasher<key_type, mapped_type, hasher> __hasher;
- typedef __unordered_map_equal<key_type, mapped_type, key_equal> __key_equal;
+#if __cplusplus >= 201103L
+ union __value_type
+ {
+ typedef typename unordered_map::value_type value_type;
+ typedef typename unordered_map::__nc_value_type __nc_value_type;
+ value_type __cc;
+ __nc_value_type __nc;
+
+ template <class ..._Args>
+ __value_type(_Args&& ...__args)
+ : __cc(std::forward<_Args>(__args)...) {}
+
+ __value_type(const __value_type& __v)
+ : __cc(std::move(__v.__cc)) {}
+
+ __value_type(__value_type&& __v)
+ : __nc(std::move(__v.__nc)) {}
+
+ __value_type& operator=(const __value_type& __v)
+ {__nc = __v.__cc; return *this;}
+
+ __value_type& operator=(__value_type&& __v)
+ {__nc = std::move(__v.__nc); return *this;}
+
+ ~__value_type() {__cc.~value_type();}
+ };
+#else
+ struct __value_type
+ {
+ typedef typename unordered_map::value_type value_type;
+ value_type __cc;
+
+ __value_type() {}
+
+ template <class _A0>
+ __value_type(const _A0& __a0)
+ : __cc(__a0) {}
+
+ template <class _A0, class _A1>
+ __value_type(const _A0& __a0, const _A1& __a1)
+ : __cc(__a0, __a1) {}
+ };
+#endif
+ typedef __unordered_map_hasher<key_type, __value_type, hasher> __hasher;
+ typedef __unordered_map_equal<key_type, __value_type, key_equal> __key_equal;
typedef typename allocator_traits<allocator_type>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
rebind_alloc<__value_type>
@@ -713,7 +708,11 @@ public:
_LIBCPP_INLINE_VISIBILITY
unordered_map()
_NOEXCEPT_(is_nothrow_default_constructible<__table>::value)
- {} // = default;
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
+ }
explicit unordered_map(size_type __n, const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
unordered_map(size_type __n, const hasher& __hf,
@@ -750,7 +749,16 @@ public:
_LIBCPP_INLINE_VISIBILITY
unordered_map& operator=(const unordered_map& __u)
{
+#if __cplusplus >= 201103L
__table_ = __u.__table_;
+#else
+ __table_.clear();
+ __table_.hash_function() = __u.__table_.hash_function();
+ __table_.key_eq() = __u.__table_.key_eq();
+ __table_.max_load_factor() = __u.__table_.max_load_factor();
+ __table_.__copy_assign_alloc(__u.__table_);
+ insert(__u.begin(), __u.end());
+#endif
return *this;
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -793,8 +801,18 @@ public:
template <class... _Args>
_LIBCPP_INLINE_VISIBILITY
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ iterator emplace_hint(const_iterator __p, _Args&&... __args)
+ {
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered_map::emplace_hint(const_iterator, args...) called with an iterator not"
+ " referring to this unordered_map");
+ return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first;
+ }
+#else
iterator emplace_hint(const_iterator, _Args&&... __args)
{return emplace(_VSTD::forward<_Args>(__args)...).first;}
+#endif
#endif // _LIBCPP_HAS_NO_VARIADICS
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
@@ -808,14 +826,34 @@ public:
{return __table_.__insert_unique(_VSTD::forward<_Pp>(__x));}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ iterator insert(const_iterator __p, const value_type& __x)
+ {
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered_map::insert(const_iterator, const value_type&) called with an iterator not"
+ " referring to this unordered_map");
+ return insert(__x).first;
+ }
+#else
iterator insert(const_iterator, const value_type& __x)
{return insert(__x).first;}
+#endif
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Pp,
class = typename enable_if<is_constructible<value_type, _Pp>::value>::type>
_LIBCPP_INLINE_VISIBILITY
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ iterator insert(const_iterator __p, _Pp&& __x)
+ {
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered_map::insert(const_iterator, value_type&&) called with an iterator not"
+ " referring to this unordered_map");
+ return insert(_VSTD::forward<_Pp>(__x)).first;
+ }
+#else
iterator insert(const_iterator, _Pp&& __x)
{return insert(_VSTD::forward<_Pp>(__x)).first;}
+#endif
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _InputIterator>
void insert(_InputIterator __first, _InputIterator __last);
@@ -903,30 +941,32 @@ public:
_LIBCPP_INLINE_VISIBILITY
void reserve(size_type __n) {__table_.reserve(__n);}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ bool __dereferenceable(const const_iterator* __i) const
+ {return __table_.__dereferenceable(&__i->__i_);}
+ bool __decrementable(const const_iterator* __i) const
+ {return __table_.__decrementable(&__i->__i_);}
+ bool __addable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(&__i->__i_, __n);}
+ bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(&__i->__i_, __n);}
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
private:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
__node_holder __construct_node();
template <class _A0>
- typename enable_if
- <
- is_constructible<value_type, _A0>::value,
- __node_holder
- >::type
- __construct_node(_A0&& __a0);
- template <class _A0>
- typename enable_if
- <
- is_constructible<key_type, _A0>::value,
- __node_holder
- >::type
+ __node_holder
__construct_node(_A0&& __a0);
+ __node_holder __construct_node_with_key(key_type&& __k);
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _A0, class _A1, class ..._Args>
__node_holder __construct_node(_A0&& __a0, _A1&& __a1, _Args&& ...__args);
#endif // _LIBCPP_HAS_NO_VARIADICS
-#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
- __node_holder __construct_node(const key_type& __k);
-#endif
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+ __node_holder __construct_node_with_key(const key_type& __k);
};
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -934,6 +974,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
size_type __n, const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -943,6 +986,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -952,6 +998,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const allocator_type& __a)
: __table_(__a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -959,6 +1008,9 @@ template <class _InputIterator>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
_InputIterator __first, _InputIterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__first, __last);
}
@@ -969,6 +1021,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -980,6 +1035,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -989,6 +1047,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const unordered_map& __u)
: __table_(__u.__table_)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -998,6 +1059,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const unordered_map& __u, const allocator_type& __a)
: __table_(__u.__table_, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -1011,6 +1075,10 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
: __table_(_VSTD::move(__u.__table_))
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+ __get_db()->swap(this, &__u);
+#endif
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -1018,6 +1086,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
unordered_map&& __u, const allocator_type& __a)
: __table_(_VSTD::move(__u.__table_), __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
if (__a != __u.get_allocator())
{
iterator __i = __u.begin();
@@ -1026,6 +1097,10 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
_VSTD::move(__u.__table_.remove((__i++).__i_)->__value_)
);
}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ else
+ __get_db()->swap(this, &__u);
+#endif
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1036,6 +1111,9 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
initializer_list<value_type> __il)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__il.begin(), __il.end());
}
@@ -1045,6 +1123,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -1055,6 +1136,9 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -1105,11 +1189,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node()
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _A0>
-typename enable_if
-<
- is_constructible<pair<const _Key, _Tp>, _A0>::value,
- typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
->::type
+typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
{
__node_allocator& __na = __table_.__node_alloc();
@@ -1122,22 +1202,16 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class _A0>
-typename enable_if
-<
- is_constructible<_Key, _A0>::value,
- typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
->::type
-unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
+typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
+unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(key_type&& __k)
{
__node_allocator& __na = __table_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first),
- _VSTD::forward<_A0>(__a0));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first), _VSTD::move(__k));
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second));
__h.get_deleter().__second_constructed = true;
- return __h;
+ return _VSTD::move(__h);
}
#ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -1172,23 +1246,21 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::emplace(_Args&&... __args)
}
#endif // _LIBCPP_HAS_NO_VARIADICS
-#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(const key_type& __k)
+unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(const key_type& __k)
{
__node_allocator& __na = __table_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first), __k);
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.first), __k);
__h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
+ __node_traits::construct(__na, _VSTD::addressof(__h->__value_.__cc.second));
__h.get_deleter().__second_constructed = true;
return _VSTD::move(__h);
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _InputIterator>
inline _LIBCPP_INLINE_VISIBILITY
@@ -1207,7 +1279,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k)
iterator __i = find(__k);
if (__i != end())
return __i->second;
- __node_holder __h = __construct_node(__k);
+ __node_holder __h = __construct_node_with_key(__k);
pair<iterator, bool> __r = __table_.__node_insert_unique(__h.get());
__h.release();
return __r.first->second;
@@ -1222,7 +1294,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k)
iterator __i = find(__k);
if (__i != end())
return __i->second;
- __node_holder __h = __construct_node(_VSTD::move(__k));
+ __node_holder __h = __construct_node_with_key(_VSTD::move(__k));
pair<iterator, bool> __r = __table_.__node_insert_unique(__h.get());
__h.release();
return __r.first->second;
@@ -1304,13 +1376,58 @@ public:
typedef _Pred key_equal;
typedef _Alloc allocator_type;
typedef pair<const key_type, mapped_type> value_type;
+ typedef pair<key_type, mapped_type> __nc_value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
+ static_assert((is_same<value_type, typename allocator_type::value_type>::value),
+ "Invalid allocator::value_type");
private:
- typedef pair<key_type, mapped_type> __value_type;
- typedef __unordered_map_hasher<key_type, mapped_type, hasher> __hasher;
- typedef __unordered_map_equal<key_type, mapped_type, key_equal> __key_equal;
+#if __cplusplus >= 201103L
+ union __value_type
+ {
+ typedef typename unordered_multimap::value_type value_type;
+ typedef typename unordered_multimap::__nc_value_type __nc_value_type;
+ value_type __cc;
+ __nc_value_type __nc;
+
+ template <class ..._Args>
+ __value_type(_Args&& ...__args)
+ : __cc(std::forward<_Args>(__args)...) {}
+
+ __value_type(const __value_type& __v)
+ : __cc(std::move(__v.__cc)) {}
+
+ __value_type(__value_type&& __v)
+ : __nc(std::move(__v.__nc)) {}
+
+ __value_type& operator=(const __value_type& __v)
+ {__nc = __v.__cc; return *this;}
+
+ __value_type& operator=(__value_type&& __v)
+ {__nc = std::move(__v.__nc); return *this;}
+
+ ~__value_type() {__cc.~value_type();}
+ };
+#else
+ struct __value_type
+ {
+ typedef typename unordered_multimap::value_type value_type;
+ value_type __cc;
+
+ __value_type() {}
+
+ template <class _A0>
+ __value_type(const _A0& __a0)
+ : __cc(__a0) {}
+
+ template <class _A0, class _A1>
+ __value_type(const _A0& __a0, const _A1& __a1)
+ : __cc(__a0, __a1) {}
+ };
+#endif
+ typedef __unordered_map_hasher<key_type, __value_type, hasher> __hasher;
+ typedef __unordered_map_equal<key_type, __value_type, key_equal> __key_equal;
typedef typename allocator_traits<allocator_type>::template
#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
rebind_alloc<__value_type>
@@ -1344,7 +1461,11 @@ public:
_LIBCPP_INLINE_VISIBILITY
unordered_multimap()
_NOEXCEPT_(is_nothrow_default_constructible<__table>::value)
- {} // = default;
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
+ }
explicit unordered_multimap(size_type __n, const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
unordered_multimap(size_type __n, const hasher& __hf,
@@ -1382,7 +1503,16 @@ public:
_LIBCPP_INLINE_VISIBILITY
unordered_multimap& operator=(const unordered_multimap& __u)
{
+#if __cplusplus >= 201103L
__table_ = __u.__table_;
+#else
+ __table_.clear();
+ __table_.hash_function() = __u.__table_.hash_function();
+ __table_.key_eq() = __u.__table_.key_eq();
+ __table_.max_load_factor() = __u.__table_.max_load_factor();
+ __table_.__copy_assign_alloc(__u.__table_);
+ insert(__u.begin(), __u.end());
+#endif
return *this;
}
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1525,22 +1655,24 @@ public:
_LIBCPP_INLINE_VISIBILITY
void reserve(size_type __n) {__table_.reserve(__n);}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ bool __dereferenceable(const const_iterator* __i) const
+ {return __table_.__dereferenceable(&__i->__i_);}
+ bool __decrementable(const const_iterator* __i) const
+ {return __table_.__decrementable(&__i->__i_);}
+ bool __addable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(&__i->__i_, __n);}
+ bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(&__i->__i_, __n);}
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
private:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
__node_holder __construct_node();
template <class _A0>
- typename enable_if
- <
- is_constructible<value_type, _A0>::value,
- __node_holder
- >::type
- __construct_node(_A0&& __a0);
- template <class _A0>
- typename enable_if
- <
- is_constructible<key_type, _A0>::value,
- __node_holder
- >::type
+ __node_holder
__construct_node(_A0&& __a0);
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _A0, class _A1, class ..._Args>
@@ -1554,6 +1686,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
size_type __n, const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -1563,6 +1698,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -1571,6 +1709,9 @@ template <class _InputIterator>
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
_InputIterator __first, _InputIterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__first, __last);
}
@@ -1581,6 +1722,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -1592,6 +1736,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -1602,6 +1749,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const allocator_type& __a)
: __table_(__a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -1609,6 +1759,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const unordered_multimap& __u)
: __table_(__u.__table_)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -1618,6 +1771,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const unordered_multimap& __u, const allocator_type& __a)
: __table_(__u.__table_, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -1631,6 +1787,10 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
: __table_(_VSTD::move(__u.__table_))
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+ __get_db()->swap(this, &__u);
+#endif
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -1638,16 +1798,23 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
unordered_multimap&& __u, const allocator_type& __a)
: __table_(_VSTD::move(__u.__table_), __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
if (__a != __u.get_allocator())
{
iterator __i = __u.begin();
while (__u.size() != 0)
-{
+ {
__table_.__insert_multi(
_VSTD::move(__u.__table_.remove((__i++).__i_)->__value_)
);
-}
+ }
}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ else
+ __get_db()->swap(this, &__u);
+#endif
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1658,6 +1825,9 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
initializer_list<value_type> __il)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__il.begin(), __il.end());
}
@@ -1667,6 +1837,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -1677,6 +1850,9 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -1727,11 +1903,7 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node()
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _A0>
-typename enable_if
-<
- is_constructible<pair<const _Key, _Tp>, _A0>::value,
- typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
->::type
+typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
{
__node_allocator& __na = __table_.__node_alloc();
@@ -1743,25 +1915,6 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0
return __h;
}
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class _A0>
-typename enable_if
-<
- is_constructible<_Key, _A0>::value,
- typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
->::type
-unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
-{
- __node_allocator& __na = __table_.__node_alloc();
- __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.first),
- _VSTD::forward<_A0>(__a0));
- __h.get_deleter().__first_constructed = true;
- __node_traits::construct(__na, _VSTD::addressof(__h->__value_.second));
- __h.get_deleter().__second_constructed = true;
- return __h;
-}
-
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
diff --git a/system/include/libcxx/unordered_set b/system/include/libcxx/unordered_set
index 119251dc..8be36df6 100644
--- a/system/include/libcxx/unordered_set
+++ b/system/include/libcxx/unordered_set
@@ -324,6 +324,8 @@ public:
typedef _Alloc allocator_type;
typedef value_type& reference;
typedef const value_type& const_reference;
+ static_assert((is_same<value_type, typename allocator_type::value_type>::value),
+ "Invalid allocator::value_type");
private:
typedef __hash_table<value_type, hasher, key_equal, allocator_type> __table;
@@ -344,7 +346,11 @@ public:
_LIBCPP_INLINE_VISIBILITY
unordered_set()
_NOEXCEPT_(is_nothrow_default_constructible<__table>::value)
- {} // = default;
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
+ }
explicit unordered_set(size_type __n, const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
unordered_set(size_type __n, const hasher& __hf, const key_equal& __eql,
@@ -422,8 +428,18 @@ public:
{return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...);}
template <class... _Args>
_LIBCPP_INLINE_VISIBILITY
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ iterator emplace_hint(const_iterator __p, _Args&&... __args)
+ {
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered_set::emplace_hint(const_iterator, args...) called with an iterator not"
+ " referring to this unordered_set");
+ return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first;
+ }
+#else
iterator emplace_hint(const_iterator, _Args&&... __args)
{return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first;}
+#endif
#endif // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
_LIBCPP_INLINE_VISIBILITY
pair<iterator, bool> insert(const value_type& __x)
@@ -434,12 +450,32 @@ public:
{return __table_.__insert_unique(_VSTD::move(__x));}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ iterator insert(const_iterator __p, const value_type& __x)
+ {
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered_set::insert(const_iterator, const value_type&) called with an iterator not"
+ " referring to this unordered_set");
+ return insert(__x).first;
+ }
+#else
iterator insert(const_iterator, const value_type& __x)
{return insert(__x).first;}
+#endif
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ iterator insert(const_iterator __p, value_type&& __x)
+ {
+ _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+ "unordered_set::insert(const_iterator, value_type&&) called with an iterator not"
+ " referring to this unordered_set");
+ return insert(_VSTD::move(__x)).first;
+ }
+#else
iterator insert(const_iterator, value_type&& __x)
{return insert(_VSTD::move(__x)).first;}
+#endif
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _InputIterator>
void insert(_InputIterator __first, _InputIterator __last);
@@ -515,6 +551,20 @@ public:
void rehash(size_type __n) {__table_.rehash(__n);}
_LIBCPP_INLINE_VISIBILITY
void reserve(size_type __n) {__table_.reserve(__n);}
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ bool __dereferenceable(const const_iterator* __i) const
+ {return __table_.__dereferenceable(__i);}
+ bool __decrementable(const const_iterator* __i) const
+ {return __table_.__decrementable(__i);}
+ bool __addable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(__i, __n);}
+ bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(__i, __n);}
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
};
template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -522,6 +572,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(size_type __n,
const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -530,6 +583,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(size_type __n,
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -538,6 +594,9 @@ template <class _InputIterator>
unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
_InputIterator __first, _InputIterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__first, __last);
}
@@ -548,6 +607,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -559,6 +621,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -569,6 +634,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const allocator_type& __a)
: __table_(__a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -576,6 +644,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const unordered_set& __u)
: __table_(__u.__table_)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -585,6 +656,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const unordered_set& __u, const allocator_type& __a)
: __table_(__u.__table_, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -598,6 +672,10 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
: __table_(_VSTD::move(__u.__table_))
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+ __get_db()->swap(this, &__u);
+#endif
}
template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -605,12 +683,19 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
unordered_set&& __u, const allocator_type& __a)
: __table_(_VSTD::move(__u.__table_), __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
if (__a != __u.get_allocator())
{
iterator __i = __u.begin();
while (__u.size() != 0)
__table_.__insert_unique(_VSTD::move(__u.__table_.remove(__i++)->__value_));
}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ else
+ __get_db()->swap(this, &__u);
+#endif
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -621,6 +706,9 @@ template <class _Value, class _Hash, class _Pred, class _Alloc>
unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
initializer_list<value_type> __il)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__il.begin(), __il.end());
}
@@ -630,6 +718,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -640,6 +731,9 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -736,6 +830,8 @@ public:
typedef _Alloc allocator_type;
typedef value_type& reference;
typedef const value_type& const_reference;
+ static_assert((is_same<value_type, typename allocator_type::value_type>::value),
+ "Invalid allocator::value_type");
private:
typedef __hash_table<value_type, hasher, key_equal, allocator_type> __table;
@@ -756,7 +852,11 @@ public:
_LIBCPP_INLINE_VISIBILITY
unordered_multiset()
_NOEXCEPT_(is_nothrow_default_constructible<__table>::value)
- {} // = default
+ {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
+ }
explicit unordered_multiset(size_type __n, const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
unordered_multiset(size_type __n, const hasher& __hf,
@@ -925,6 +1025,20 @@ public:
void rehash(size_type __n) {__table_.rehash(__n);}
_LIBCPP_INLINE_VISIBILITY
void reserve(size_type __n) {__table_.reserve(__n);}
+
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+ bool __dereferenceable(const const_iterator* __i) const
+ {return __table_.__dereferenceable(__i);}
+ bool __decrementable(const const_iterator* __i) const
+ {return __table_.__decrementable(__i);}
+ bool __addable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(__i, __n);}
+ bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const
+ {return __table_.__addable(__i, __n);}
+
+#endif // _LIBCPP_DEBUG_LEVEL >= 2
+
};
template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -932,6 +1046,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
size_type __n, const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -941,6 +1058,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
}
@@ -949,6 +1069,9 @@ template <class _InputIterator>
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
_InputIterator __first, _InputIterator __last)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__first, __last);
}
@@ -959,6 +1082,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -970,6 +1096,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__first, __last);
}
@@ -980,6 +1109,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const allocator_type& __a)
: __table_(__a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
}
template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -987,6 +1119,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const unordered_multiset& __u)
: __table_(__u.__table_)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -996,6 +1131,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const unordered_multiset& __u, const allocator_type& __a)
: __table_(__u.__table_, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__u.bucket_count());
insert(__u.begin(), __u.end());
}
@@ -1009,6 +1147,10 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
: __table_(_VSTD::move(__u.__table_))
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+ __get_db()->swap(this, &__u);
+#endif
}
template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -1016,12 +1158,19 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
unordered_multiset&& __u, const allocator_type& __a)
: __table_(_VSTD::move(__u.__table_), __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
if (__a != __u.get_allocator())
{
iterator __i = __u.begin();
while (__u.size() != 0)
__table_.__insert_multi(_VSTD::move(__u.__table_.remove(__i++)->__value_));
}
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ else
+ __get_db()->swap(this, &__u);
+#endif
}
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1032,6 +1181,9 @@ template <class _Value, class _Hash, class _Pred, class _Alloc>
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
initializer_list<value_type> __il)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
insert(__il.begin(), __il.end());
}
@@ -1041,6 +1193,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const key_equal& __eql)
: __table_(__hf, __eql)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
@@ -1051,6 +1206,9 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, __a)
{
+#if _LIBCPP_DEBUG_LEVEL >= 2
+ __get_db()->__insert_c(this);
+#endif
__table_.rehash(__n);
insert(__il.begin(), __il.end());
}
diff --git a/system/include/libcxx/utility b/system/include/libcxx/utility
index 2df4b361..d36cf9dd 100644
--- a/system/include/libcxx/utility
+++ b/system/include/libcxx/utility
@@ -38,10 +38,10 @@ template <class T, size_t N>
void
swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));
-template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
-template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
+template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept; // constexpr in C++14
+template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept; // constexpr in C++14
-template <class T> typename remove_reference<T>::type&& move(T&&) noexcept;
+template <class T> typename remove_reference<T>::type&& move(T&&) noexcept; // constexpr in C++14
template <class T>
typename conditional
@@ -50,7 +50,7 @@ template <class T>
const T&,
T&&
>::type
- move_if_noexcept(T& x) noexcept;
+ move_if_noexcept(T& x) noexcept; // constexpr in C++14
template <class T> typename add_rvalue_reference<T>::type declval() noexcept;
@@ -66,10 +66,10 @@ struct pair
pair(const pair&) = default;
pair(pair&&) = default;
constexpr pair();
- pair(const T1& x, const T2& y);
- template <class U, class V> pair(U&& x, V&& y);
- template <class U, class V> pair(const pair<U, V>& p);
- template <class U, class V> pair(pair<U, V>&& p);
+ pair(const T1& x, const T2& y); // constexpr in C++14
+ template <class U, class V> pair(U&& x, V&& y); // constexpr in C++14
+ template <class U, class V> pair(const pair<U, V>& p); // constexpr in C++14
+ template <class U, class V> pair(pair<U, V>&& p); // constexpr in C++14
template <class... Args1, class... Args2>
pair(piecewise_construct_t, tuple<Args1...> first_args,
tuple<Args2...> second_args);
@@ -83,14 +83,14 @@ struct pair
noexcept(swap(second, p.second)));
};
-template <class T1, class T2> bool operator==(const pair<T1,T2>&, const pair<T1,T2>&);
-template <class T1, class T2> bool operator!=(const pair<T1,T2>&, const pair<T1,T2>&);
-template <class T1, class T2> bool operator< (const pair<T1,T2>&, const pair<T1,T2>&);
-template <class T1, class T2> bool operator> (const pair<T1,T2>&, const pair<T1,T2>&);
-template <class T1, class T2> bool operator>=(const pair<T1,T2>&, const pair<T1,T2>&);
-template <class T1, class T2> bool operator<=(const pair<T1,T2>&, const pair<T1,T2>&);
+template <class T1, class T2> bool operator==(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
+template <class T1, class T2> bool operator!=(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
+template <class T1, class T2> bool operator< (const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
+template <class T1, class T2> bool operator> (const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
+template <class T1, class T2> bool operator>=(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
+template <class T1, class T2> bool operator<=(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14
-template <class T1, class T2> pair<V1, V2> make_pair(T1&&, T2&&);
+template <class T1, class T2> pair<V1, V2> make_pair(T1&&, T2&&); // constexpr in C++14
template <class T1, class T2>
void
swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));
@@ -107,16 +107,48 @@ template <class T1, class T2> struct tuple_element<1, std::pair<T1, T2> >;
template<size_t I, class T1, class T2>
typename tuple_element<I, std::pair<T1, T2> >::type&
- get(std::pair<T1, T2>&) noexcept;
+ get(std::pair<T1, T2>&) noexcept; // constexpr in C++14
template<size_t I, class T1, class T2>
const typename const tuple_element<I, std::pair<T1, T2> >::type&
- get(const std::pair<T1, T2>&) noexcept;
+ get(const std::pair<T1, T2>&) noexcept; // constexpr in C++14
template<size_t I, class T1, class T2>
typename tuple_element<I, std::pair<T1, T2> >::type&&
- get(std::pair<T1, T2>&&) noexcept;
+ get(std::pair<T1, T2>&&) noexcept; // constexpr in C++14
+template<class T1, class T2>
+ constexpr T1& get(std::pair<T1, T2>&) noexcept; // C++14
+
+template<size_t I, class T1, class T2>
+ constexpr T1 const& get(std::pair<T1, T2> const &) noexcept; // C++14
+
+template<size_t I, class T1, class T2>
+ constexpr T1&& get(std::pair<T1, T2>&&) noexcept; // C++14
+
+// C++14
+
+template<class T, T... I>
+struct integer_sequence
+{
+ typedef T value_type;
+
+ static constexpr size_t size() noexcept;
+};
+
+template<size_t... I>
+ using index_sequence = integer_sequence<size_t, I...>;
+
+template<class T, T N>
+ using make_integer_sequence = integer_sequence<T, 0, 1, ..., N-1>;
+template<size_t N>
+ using make_index_sequence = make_integer_sequence<size_t, N>;
+
+template<class... T>
+ using index_sequence_for = make_index_sequence<sizeof...(T)>;
+
+template<class T, class U=T>
+ T exchange(T& obj, U&& new_value);
} // std
*/
@@ -189,7 +221,7 @@ swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::v
}
template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
typename conditional
<
@@ -226,11 +258,12 @@ struct _LIBCPP_TYPE_VIS pair
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR pair() : first(), second() {}
- _LIBCPP_INLINE_VISIBILITY pair(const _T1& __x, const _T2& __y)
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+ pair(const _T1& __x, const _T2& __y)
: first(__x), second(__y) {}
template<class _U1, class _U2>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
pair(const pair<_U1, _U2>& __p
#ifndef _LIBCPP_HAS_NO_ADVANCED_SFINAE
,typename enable_if<is_convertible<const _U1&, _T1>::value &&
@@ -239,6 +272,10 @@ struct _LIBCPP_TYPE_VIS pair
)
: first(__p.first), second(__p.second) {}
+#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+ _LIBCPP_INLINE_VISIBILITY
+ pair(const pair& __p) = default;
+#else
_LIBCPP_INLINE_VISIBILITY
pair(const pair& __p)
_NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value &&
@@ -247,6 +284,7 @@ struct _LIBCPP_TYPE_VIS pair
second(__p.second)
{
}
+#endif
_LIBCPP_INLINE_VISIBILITY
pair& operator=(const pair& __p)
@@ -263,20 +301,24 @@ struct _LIBCPP_TYPE_VIS pair
template <class _U1, class _U2,
class = typename enable_if<is_convertible<_U1, first_type>::value &&
is_convertible<_U2, second_type>::value>::type>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
pair(_U1&& __u1, _U2&& __u2)
: first(_VSTD::forward<_U1>(__u1)),
second(_VSTD::forward<_U2>(__u2))
{}
template<class _U1, class _U2>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
pair(pair<_U1, _U2>&& __p,
typename enable_if<is_convertible<_U1, _T1>::value &&
is_convertible<_U2, _T2>::value>::type* = 0)
: first(_VSTD::forward<_U1>(__p.first)),
second(_VSTD::forward<_U2>(__p.second)) {}
+#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+ _LIBCPP_INLINE_VISIBILITY
+ pair(pair&& __p) = default;
+#else
_LIBCPP_INLINE_VISIBILITY
pair(pair&& __p) _NOEXCEPT_(is_nothrow_move_constructible<first_type>::value &&
is_nothrow_move_constructible<second_type>::value)
@@ -284,6 +326,7 @@ struct _LIBCPP_TYPE_VIS pair
second(_VSTD::forward<second_type>(__p.second))
{
}
+#endif
_LIBCPP_INLINE_VISIBILITY
pair&
@@ -299,7 +342,7 @@ struct _LIBCPP_TYPE_VIS pair
template<class _Tuple,
class = typename enable_if<__tuple_convertible<_Tuple, pair>::value>::type>
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
pair(_Tuple&& __p)
: first(_VSTD::forward<typename tuple_element<0,
typename __make_tuple_types<_Tuple>::type>::type>(get<0>(__p))),
@@ -355,7 +398,7 @@ private:
};
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator==(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
{
@@ -363,7 +406,7 @@ operator==(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
}
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator!=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
{
@@ -371,7 +414,7 @@ operator!=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
}
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator< (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
{
@@ -379,7 +422,7 @@ operator< (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
}
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator> (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
{
@@ -387,7 +430,7 @@ operator> (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
}
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator>=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
{
@@ -395,7 +438,7 @@ operator>=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
}
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
bool
operator<=(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
{
@@ -440,7 +483,7 @@ struct __make_pair_return
};
template <class _T1, class _T2>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
make_pair(_T1&& __t1, _T2&& __t2)
{
@@ -503,13 +546,13 @@ struct __get_pair<0>
{
template <class _T1, class _T2>
static
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_T1&
get(pair<_T1, _T2>& __p) _NOEXCEPT {return __p.first;}
template <class _T1, class _T2>
static
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const _T1&
get(const pair<_T1, _T2>& __p) _NOEXCEPT {return __p.first;}
@@ -517,7 +560,7 @@ struct __get_pair<0>
template <class _T1, class _T2>
static
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_T1&&
get(pair<_T1, _T2>&& __p) _NOEXCEPT {return _VSTD::forward<_T1>(__p.first);}
@@ -529,13 +572,13 @@ struct __get_pair<1>
{
template <class _T1, class _T2>
static
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_T2&
get(pair<_T1, _T2>& __p) _NOEXCEPT {return __p.second;}
template <class _T1, class _T2>
static
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const _T2&
get(const pair<_T1, _T2>& __p) _NOEXCEPT {return __p.second;}
@@ -543,7 +586,7 @@ struct __get_pair<1>
template <class _T1, class _T2>
static
- _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_T2&&
get(pair<_T1, _T2>&& __p) _NOEXCEPT {return _VSTD::forward<_T2>(__p.second);}
@@ -551,7 +594,7 @@ struct __get_pair<1>
};
template <size_t _Ip, class _T1, class _T2>
-_LIBCPP_INLINE_VISIBILITY inline
+_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, pair<_T1, _T2> >::type&
get(pair<_T1, _T2>& __p) _NOEXCEPT
{
@@ -559,7 +602,7 @@ get(pair<_T1, _T2>& __p) _NOEXCEPT
}
template <size_t _Ip, class _T1, class _T2>
-_LIBCPP_INLINE_VISIBILITY inline
+_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR_AFTER_CXX11
const typename tuple_element<_Ip, pair<_T1, _T2> >::type&
get(const pair<_T1, _T2>& __p) _NOEXCEPT
{
@@ -569,7 +612,7 @@ get(const pair<_T1, _T2>& __p) _NOEXCEPT
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
template <size_t _Ip, class _T1, class _T2>
-_LIBCPP_INLINE_VISIBILITY inline
+_LIBCPP_INLINE_VISIBILITY inline _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Ip, pair<_T1, _T2> >::type&&
get(pair<_T1, _T2>&& __p) _NOEXCEPT
{
@@ -578,6 +621,148 @@ get(pair<_T1, _T2>&& __p) _NOEXCEPT
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#if _LIBCPP_STD_VER > 11
+template <class _T1, class _T2>
+_LIBCPP_INLINE_VISIBILITY inline
+constexpr _T1 & get(pair<_T1, _T2>& __p) _NOEXCEPT
+{
+ return __get_pair<0>::get(__p);
+}
+
+template <class _T1, class _T2>
+_LIBCPP_INLINE_VISIBILITY inline
+constexpr _T1 const & get(pair<_T1, _T2> const& __p) _NOEXCEPT
+{
+ return __get_pair<0>::get(__p);
+}
+
+template <class _T1, class _T2>
+_LIBCPP_INLINE_VISIBILITY inline
+constexpr _T1 && get(pair<_T1, _T2>&& __p) _NOEXCEPT
+{
+ return __get_pair<0>::get(_VSTD::move(__p));
+}
+
+template <class _T1, class _T2>
+_LIBCPP_INLINE_VISIBILITY inline
+constexpr _T1 & get(pair<_T2, _T1>& __p) _NOEXCEPT
+{
+ return __get_pair<1>::get(__p);
+}
+
+template <class _T1, class _T2>
+_LIBCPP_INLINE_VISIBILITY inline
+constexpr _T1 const & get(pair<_T2, _T1> const& __p) _NOEXCEPT
+{
+ return __get_pair<1>::get(__p);
+}
+
+template <class _T1, class _T2>
+_LIBCPP_INLINE_VISIBILITY inline
+constexpr _T1 && get(pair<_T2, _T1>&& __p) _NOEXCEPT
+{
+ return __get_pair<1>::get(_VSTD::move(__p));
+}
+
+#endif
+
+#if _LIBCPP_STD_VER > 11
+
+template<class _Tp, _Tp... _Ip>
+struct _LIBCPP_TYPE_VIS integer_sequence
+{
+ typedef _Tp value_type;
+ static_assert( is_integral<_Tp>::value,
+ "std::integer_sequence can only be instantiated with an integral type" );
+ static
+ _LIBCPP_INLINE_VISIBILITY
+ constexpr
+ size_t
+ size() noexcept { return sizeof...(_Ip); }
+};
+
+template<size_t... _Ip>
+ using index_sequence = integer_sequence<size_t, _Ip...>;
+
+namespace __detail {
+
+template<typename _Tp, size_t ..._Extra> struct __repeat;
+template<typename _Tp, _Tp ..._Np, size_t ..._Extra> struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...> {
+ typedef integer_sequence<_Tp,
+ _Np...,
+ sizeof...(_Np) + _Np...,
+ 2 * sizeof...(_Np) + _Np...,
+ 3 * sizeof...(_Np) + _Np...,
+ 4 * sizeof...(_Np) + _Np...,
+ 5 * sizeof...(_Np) + _Np...,
+ 6 * sizeof...(_Np) + _Np...,
+ 7 * sizeof...(_Np) + _Np...,
+ _Extra...> type;
+};
+
+template<size_t _Np> struct __parity;
+template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
+
+template<> struct __make<0> { typedef integer_sequence<size_t> type; };
+template<> struct __make<1> { typedef integer_sequence<size_t, 0> type; };
+template<> struct __make<2> { typedef integer_sequence<size_t, 0, 1> type; };
+template<> struct __make<3> { typedef integer_sequence<size_t, 0, 1, 2> type; };
+template<> struct __make<4> { typedef integer_sequence<size_t, 0, 1, 2, 3> type; };
+template<> struct __make<5> { typedef integer_sequence<size_t, 0, 1, 2, 3, 4> type; };
+template<> struct __make<6> { typedef integer_sequence<size_t, 0, 1, 2, 3, 4, 5> type; };
+template<> struct __make<7> { typedef integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6> type; };
+
+template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
+template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
+template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
+template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
+template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
+template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
+template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
+template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
+
+template<typename _Tp, typename _Up> struct __convert {
+ template<typename> struct __result;
+ template<_Tp ..._Np> struct __result<integer_sequence<_Tp, _Np...> > { typedef integer_sequence<_Up, _Np...> type; };
+};
+template<typename _Tp> struct __convert<_Tp, _Tp> { template<typename _Up> struct __result { typedef _Up type; }; };
+
+}
+
+template<typename _Tp, _Tp _Np> using __make_integer_sequence_unchecked =
+ typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type;
+
+template <class _Tp, _Tp _Ep>
+struct __make_integer_sequence
+{
+ static_assert(is_integral<_Tp>::value,
+ "std::make_integer_sequence can only be instantiated with an integral type" );
+ static_assert(0 <= _Ep, "std::make_integer_sequence input shall not be negative");
+ typedef __make_integer_sequence_unchecked<_Tp, _Ep> type;
+};
+
+template<class _Tp, _Tp _Np>
+ using make_integer_sequence = typename __make_integer_sequence<_Tp, _Np>::type;
+
+template<size_t _Np>
+ using make_index_sequence = make_integer_sequence<size_t, _Np>;
+
+template<class... _Tp>
+ using index_sequence_for = make_index_sequence<sizeof...(_Tp)>;
+
+#endif // _LIBCPP_STD_VER > 11
+
+#if _LIBCPP_STD_VER > 11
+template<class _T1, class _T2 = _T1>
+_LIBCPP_INLINE_VISIBILITY inline
+_T1 exchange(_T1& __obj, _T2 && __new_value)
+{
+ _T1 __old_value = _VSTD::move(__obj);
+ __obj = _VSTD::forward<_T2>(__new_value);
+ return __old_value;
+}
+#endif // _LIBCPP_STD_VER > 11
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_UTILITY
diff --git a/system/include/libcxx/vector b/system/include/libcxx/vector
index d1bc23e6..0758f75b 100644
--- a/system/include/libcxx/vector
+++ b/system/include/libcxx/vector
@@ -272,6 +272,12 @@ void swap(vector<T,Allocator>& x, vector<T,Allocator>& y)
#include <__undef_min_max>
+#ifdef _LIBCPP_DEBUG2
+# include <__debug>
+#else
+# define _LIBCPP_ASSERT(x, m) ((void)0)
+#endif
+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
@@ -309,14 +315,14 @@ __vector_base_common<__b>::__throw_out_of_range() const
#endif
}
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVC
#pragma warning( push )
#pragma warning( disable: 4231 )
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVC
_LIBCPP_EXTERN_TEMPLATE(class __vector_base_common<true>)
-#ifdef _MSC_VER
+#ifdef _LIBCPP_MSVC
#pragma warning( pop )
-#endif // _MSC_VER
+#endif // _LIBCPP_MSVC
template <class _Tp, class _Allocator>
class __vector_base
@@ -365,12 +371,7 @@ protected:
{return static_cast<size_type>(__end_cap() - __begin_);}
_LIBCPP_INLINE_VISIBILITY
- void __destruct_at_end(const_pointer __new_last) _NOEXCEPT
- {__destruct_at_end(__new_last, false_type());}
- _LIBCPP_INLINE_VISIBILITY
- void __destruct_at_end(const_pointer __new_last, false_type) _NOEXCEPT;
- _LIBCPP_INLINE_VISIBILITY
- void __destruct_at_end(const_pointer __new_last, true_type) _NOEXCEPT;
+ void __destruct_at_end(pointer __new_last) _NOEXCEPT;
_LIBCPP_INLINE_VISIBILITY
void __copy_assign_alloc(const __vector_base& __c)
@@ -437,43 +438,35 @@ private:
template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
void
-__vector_base<_Tp, _Allocator>::__destruct_at_end(const_pointer __new_last, false_type) _NOEXCEPT
+__vector_base<_Tp, _Allocator>::__destruct_at_end(pointer __new_last) _NOEXCEPT
{
while (__new_last != __end_)
- __alloc_traits::destroy(__alloc(), const_cast<pointer>(--__end_));
-}
-
-template <class _Tp, class _Allocator>
-_LIBCPP_INLINE_VISIBILITY inline
-void
-__vector_base<_Tp, _Allocator>::__destruct_at_end(const_pointer __new_last, true_type) _NOEXCEPT
-{
- __end_ = const_cast<pointer>(__new_last);
+ __alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));
}
template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
__vector_base<_Tp, _Allocator>::__vector_base()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __begin_(0),
- __end_(0),
- __end_cap_(0)
+ : __begin_(nullptr),
+ __end_(nullptr),
+ __end_cap_(nullptr)
{
}
template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
__vector_base<_Tp, _Allocator>::__vector_base(const allocator_type& __a)
- : __begin_(0),
- __end_(0),
- __end_cap_(0, __a)
+ : __begin_(nullptr),
+ __end_(nullptr),
+ __end_cap_(nullptr, __a)
{
}
template <class _Tp, class _Allocator>
__vector_base<_Tp, _Allocator>::~__vector_base()
{
- if (__begin_ != 0)
+ if (__begin_ != nullptr)
{
clear();
__alloc_traits::deallocate(__alloc(), __begin_, capacity());
@@ -797,7 +790,7 @@ private:
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value);
void __move_assign(vector& __c, false_type);
_LIBCPP_INLINE_VISIBILITY
- void __destruct_at_end(const_pointer __new_last) _NOEXCEPT
+ void __destruct_at_end(pointer __new_last) _NOEXCEPT
{
#if _LIBCPP_DEBUG_LEVEL >= 2
__c_node* __c = __get_db()->__find_c_and_lock(this);
@@ -878,11 +871,11 @@ template <class _Tp, class _Allocator>
void
vector<_Tp, _Allocator>::deallocate() _NOEXCEPT
{
- if (this->__begin_ != 0)
+ if (this->__begin_ != nullptr)
{
clear();
__alloc_traits::deallocate(this->__alloc(), this->__begin_, capacity());
- this->__begin_ = this->__end_ = this->__end_cap() = 0;
+ this->__begin_ = this->__end_ = this->__end_cap() = nullptr;
}
}
@@ -1171,7 +1164,7 @@ vector<_Tp, _Allocator>::vector(vector&& __x)
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
this->__end_cap() = __x.__end_cap();
- __x.__begin_ = __x.__end_ = __x.__end_cap() = 0;
+ __x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr;
}
template <class _Tp, class _Allocator>
@@ -1597,7 +1590,8 @@ vector<_Tp, _Allocator>::erase(const_iterator __position)
#endif
_LIBCPP_ASSERT(__position != end(),
"vector::erase(iterator) called with a non-dereferenceable iterator");
- pointer __p = const_cast<pointer>(&*__position);
+ difference_type __ps = __position - cbegin();
+ pointer __p = this->__begin_ + __ps;
iterator __r = __make_iter(__p);
this->__destruct_at_end(_VSTD::move(__p + 1, this->__end_, __p));
return __r;
@@ -1615,7 +1609,8 @@ vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last)
_LIBCPP_ASSERT(__first <= __last, "vector::erase(first, last) called with invalid range");
pointer __p = this->__begin_ + (__first - begin());
iterator __r = __make_iter(__p);
- this->__destruct_at_end(_VSTD::move(__p + (__last - __first), this->__end_, __p));
+ if (__first != __last)
+ this->__destruct_at_end(_VSTD::move(__p + (__last - __first), this->__end_, __p));
return __r;
}
@@ -1942,9 +1937,9 @@ template <class _Tp, class _Allocator>
bool
vector<_Tp, _Allocator>::__invariants() const
{
- if (this->__begin_ == 0)
+ if (this->__begin_ == nullptr)
{
- if (this->__end_ != 0 || this->__end_cap() != 0)
+ if (this->__end_ != nullptr || this->__end_cap() != nullptr)
return false;
}
else
@@ -2306,7 +2301,7 @@ private:
{return const_iterator(__begin_ + __pos / __bits_per_word, static_cast<unsigned>(__pos % __bits_per_word));}
_LIBCPP_INLINE_VISIBILITY
iterator __const_iterator_cast(const_iterator __p) _NOEXCEPT
- {return iterator(const_cast<__storage_pointer>(__p.__seg_), __p.__ctz_);}
+ {return begin() + (__p - cbegin());}
#endif // _LIBCPP_DEBUG
_LIBCPP_INLINE_VISIBILITY
@@ -2413,11 +2408,11 @@ template <class _Allocator>
void
vector<bool, _Allocator>::deallocate() _NOEXCEPT
{
- if (this->__begin_ != 0)
+ if (this->__begin_ != nullptr)
{
__storage_traits::deallocate(this->__alloc(), this->__begin_, __cap());
__invalidate_all_iterators();
- this->__begin_ = 0;
+ this->__begin_ = nullptr;
this->__size_ = this->__cap() = 0;
}
}
@@ -2480,7 +2475,7 @@ template <class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
vector<bool, _Allocator>::vector()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0)
{
@@ -2489,7 +2484,7 @@ vector<bool, _Allocator>::vector()
template <class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
vector<bool, _Allocator>::vector(const allocator_type& __a)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
@@ -2497,7 +2492,7 @@ vector<bool, _Allocator>::vector(const allocator_type& __a)
template <class _Allocator>
vector<bool, _Allocator>::vector(size_type __n)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0)
{
@@ -2510,7 +2505,7 @@ vector<bool, _Allocator>::vector(size_type __n)
template <class _Allocator>
vector<bool, _Allocator>::vector(size_type __n, const value_type& __x)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0)
{
@@ -2523,7 +2518,7 @@ vector<bool, _Allocator>::vector(size_type __n, const value_type& __x)
template <class _Allocator>
vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const allocator_type& __a)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
@@ -2539,7 +2534,7 @@ template <class _InputIterator>
vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last,
typename enable_if<__is_input_iterator <_InputIterator>::value &&
!__is_forward_iterator<_InputIterator>::value>::type*)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0)
{
@@ -2553,7 +2548,7 @@ vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last,
}
catch (...)
{
- if (__begin_ != 0)
+ if (__begin_ != nullptr)
__storage_traits::deallocate(__alloc(), __begin_, __cap());
__invalidate_all_iterators();
throw;
@@ -2566,7 +2561,7 @@ template <class _InputIterator>
vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a,
typename enable_if<__is_input_iterator <_InputIterator>::value &&
!__is_forward_iterator<_InputIterator>::value>::type*)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
@@ -2580,7 +2575,7 @@ vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last,
}
catch (...)
{
- if (__begin_ != 0)
+ if (__begin_ != nullptr)
__storage_traits::deallocate(__alloc(), __begin_, __cap());
__invalidate_all_iterators();
throw;
@@ -2592,7 +2587,7 @@ template <class _Allocator>
template <class _ForwardIterator>
vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last,
typename enable_if<__is_forward_iterator<_ForwardIterator>::value>::type*)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0)
{
@@ -2608,7 +2603,7 @@ template <class _Allocator>
template <class _ForwardIterator>
vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a,
typename enable_if<__is_forward_iterator<_ForwardIterator>::value>::type*)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
@@ -2624,7 +2619,7 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
template <class _Allocator>
vector<bool, _Allocator>::vector(initializer_list<value_type> __il)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0)
{
@@ -2638,7 +2633,7 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il)
template <class _Allocator>
vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
@@ -2655,7 +2650,7 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const alloca
template <class _Allocator>
vector<bool, _Allocator>::~vector()
{
- if (__begin_ != 0)
+ if (__begin_ != nullptr)
__storage_traits::deallocate(__alloc(), __begin_, __cap());
#ifdef _LIBCPP_DEBUG
__invalidate_all_iterators();
@@ -2664,7 +2659,7 @@ vector<bool, _Allocator>::~vector()
template <class _Allocator>
vector<bool, _Allocator>::vector(const vector& __v)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, __storage_traits::select_on_container_copy_construction(__v.__alloc()))
{
@@ -2677,7 +2672,7 @@ vector<bool, _Allocator>::vector(const vector& __v)
template <class _Allocator>
vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, __a)
{
@@ -2719,14 +2714,14 @@ vector<bool, _Allocator>::vector(vector&& __v)
__size_(__v.__size_),
__cap_alloc_(__v.__cap_alloc_)
{
- __v.__begin_ = 0;
+ __v.__begin_ = nullptr;
__v.__size_ = 0;
__v.__cap() = 0;
}
template <class _Allocator>
vector<bool, _Allocator>::vector(vector&& __v, const allocator_type& __a)
- : __begin_(0),
+ : __begin_(nullptr),
__size_(0),
__cap_alloc_(0, __a)
{
@@ -3122,7 +3117,7 @@ template <class _Allocator>
bool
vector<bool, _Allocator>::__invariants() const
{
- if (this->__begin_ == 0)
+ if (this->__begin_ == nullptr)
{
if (this->__size_ != 0 || this->__cap() != 0)
return false;
diff --git a/system/include/net/if.h b/system/include/net/if.h
index dd7884aa..0ef18520 100644
--- a/system/include/net/if.h
+++ b/system/include/net/if.h
@@ -77,7 +77,26 @@ char *if_indextoname(unsigned int a, char *b);
struct if_nameindex *if_nameindex();
void if_freenameindex(struct if_nameindex *a);
-
+#define IFF_UP 0x1
+#define IFF_BROADCAST 0x2
+#define IFF_DEBUG 0x4
+#define IFF_LOOPBACK 0x8
+#define IFF_POINTOPOINT 0x10
+#define IFF_NOTRAILERS 0x20
+#define IFF_RUNNING 0x40
+#define IFF_NOARP 0x80
+#define IFF_PROMISC 0x100
+#define IFF_ALLMULTI 0x200
+#define IFF_MASTER 0x400
+#define IFF_SLAVE 0x800
+#define IFF_MULTICAST 0x1000
+#define IFF_PORTSEL 0x2000
+#define IFF_AUTOMEDIA 0x4000
+#define IFF_DYNAMIC 0x8000
+#define IFF_LOWER_UP 0x10000
+#define IFF_DORMANT 0x20000
+#define IFF_ECHO 0x40000
+#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
#ifdef __cplusplus
}
diff --git a/system/include/net/netinet/in.h b/system/include/net/netinet/in.h
index fba1a7b3..1d3952f5 100644
--- a/system/include/net/netinet/in.h
+++ b/system/include/net/netinet/in.h
@@ -11,11 +11,63 @@ extern "C" {
enum {
IPPROTO_IP = 0,
-#define IPPROTO_IP IPPROTO_IP
- IPPROTO_TCP = 1,
-#define IPPROTO_TCP IPPROTO_TCP
- IPPROTO_UDP = 2,
-#define IPPROTO_UDP IPPROTO_UDP
+#define IPPROTO_IP IPPROTO_IP
+ IPPROTO_HOPOPTS = 0,
+#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
+ IPPROTO_ICMP = 1,
+#define IPPROTO_ICMP IPPROTO_ICMP
+ IPPROTO_IGMP = 2,
+#define IPPROTO_IGMP IPPROTO_IGMP
+ IPPROTO_IPIP = 4,
+#define IPPROTO_IPIP IPPROTO_IPIP
+ IPPROTO_TCP = 6,
+#define IPPROTO_TCP IPPROTO_TCP
+ IPPROTO_EGP = 8,
+#define IPPROTO_EGP IPPROTO_EGP
+ IPPROTO_PUP = 12,
+#define IPPROTO_PUP IPPROTO_PUP
+ IPPROTO_UDP = 17,
+#define IPPROTO_UDP IPPROTO_UDP
+ IPPROTO_IDP = 22,
+#define IPPROTO_IDP IPPROTO_IDP
+ IPPROTO_TP = 29,
+#define IPPROTO_TP IPPROTO_TP
+ IPPROTO_DCCP = 33,
+#define IPPROTO_DCCP IPPROTO_DCCP
+ IPPROTO_IPV6 = 41,
+#define IPPROTO_IPV6 IPPROTO_IPV6
+ IPPROTO_ROUTING = 43,
+#define IPPROTO_ROUTING IPPROTO_ROUTING
+ IPPROTO_FRAGMENT = 44,
+#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
+ IPPROTO_RSVP = 46,
+#define IPPROTO_RSVP IPPROTO_RSVP
+ IPPROTO_GRE = 47,
+#define IPPROTO_GRE IPPROTO_GRE
+ IPPROTO_ESP = 50,
+#define IPPROTO_ESP IPPROTO_ESP
+ IPPROTO_AH = 51,
+#define IPPROTO_AH IPPROTO_AH
+ IPPROTO_ICMPV6 = 58,
+#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
+ IPPROTO_NONE = 59,
+#define IPPROTO_NONE IPPROTO_NONE
+ IPPROTO_DSTOPTS = 60,
+#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
+ IPPROTO_MTP = 92,
+#define IPPROTO_MTP IPPROTO_MTP
+ IPPROTO_ENCAP = 98,
+#define IPPROTO_ENCAP IPPROTO_ENCAP
+ IPPROTO_PIM = 103,
+#define IPPROTO_PIM IPPROTO_PIM
+ IPPROTO_COMP = 108,
+#define IPPROTO_COMP IPPROTO_COMP
+ IPPROTO_SCTP = 132,
+#define IPPROTO_SCTP IPPROTO_SCTP
+ IPPROTO_UDPLITE = 136,
+#define IPPROTO_UDPLITE IPPROTO_UDPLITE
+ IPPROTO_RAW = 255,
+#define IPPROTO_RAW IPPROTO_RAW
IPPROTO_MAX
};
@@ -75,6 +127,11 @@ struct ip_mreq {
struct in_addr imr_interface;
};
+#define IP_PMTUDISC_DONT 0
+#define IP_PMTUDISC_WANT 1
+#define IP_PMTUDISC_DO 2
+#define IP_PMTUDISC_PROBE 3
+
#define IP_MULTICAST_IF 32
#define IP_MULTICAST_TTL 33
#define IP_MULTICAST_LOOP 34
diff --git a/system/include/netdb.h b/system/include/netdb.h
index 48acdcc4..df74a117 100644
--- a/system/include/netdb.h
+++ b/system/include/netdb.h
@@ -11,6 +11,20 @@ extern "C" {
#define NO_DATA 4
#define NO_ADDRESS 5
+#define AI_PASSIVE 0x0001
+#define AI_CANONNAME 0x0002
+#define AI_NUMERICHOST 0x0004
+#define AI_V4MAPPED 0x0008
+#define AI_ALL 0x0010
+#define AI_ADDRCONFIG 0x0020
+#ifdef __USE_GNU
+# define AI_IDN 0x0040
+# define AI_CANONIDN 0x0080
+# define AI_IDN_ALLOW_UNASSIGNED 0x0100
+# define AI_IDN_USE_STD3_ASCII_RULES 0x0200
+#endif
+#define AI_NUMERICSERV 0x0400
+
#define EAI_ADDRFAMILY 1
#define EAI_AGAIN 2
#define EAI_BADFLAGS 3
@@ -47,6 +61,15 @@ extern "C" {
#define IP_PASSSEC 18
#define IP_TRANSPARENT 19
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+
typedef int socklen_t;
struct addrinfo
@@ -85,6 +108,19 @@ const char* hstrerror(int err);
extern int h_errno;
+struct servent {
+ char *s_name;
+ char **s_aliases;
+ int s_port;
+ char *s_proto;
+};
+
+struct servent *getservent(void);
+struct servent *getservbyname(const char *name, const char *proto);
+struct servent *getservbyport(int port, const char *proto);
+void setservent(int stayopen);
+void endservent(void);
+
#include <netinet/in.h>
#ifdef __cplusplus
diff --git a/system/include/sys/ioctl.h b/system/include/sys/ioctl.h
index c54d4ccc..047329cb 100644
--- a/system/include/sys/ioctl.h
+++ b/system/include/sys/ioctl.h
@@ -5,9 +5,6 @@
extern "C" {
#endif
-#define SIOCGIFCONF 1 // bogus value
-#define SIOCGIFNETMASK 2 // bogus value
-
#define TIOCGSIZE 80 // bogus
#define TIOCGWINSZ 80 // bogus
@@ -19,6 +16,61 @@ int ioctl(int d, int request, ...);
#define SO_RCVTIMEO 1000
#define SO_SNDTIMEO 2000
+#define SIOCADDRT 0x890B
+#define SIOCDELRT 0x890C
+#define SIOCRTMSG 0x890D
+#define SIOCGIFNAME 0x8910
+#define SIOCSIFLINK 0x8911
+#define SIOCGIFCONF 0x8912
+#define SIOCGIFFLAGS 0x8913
+#define SIOCSIFFLAGS 0x8914
+#define SIOCGIFADDR 0x8915
+#define SIOCSIFADDR 0x8916
+#define SIOCGIFDSTADDR 0x8917
+#define SIOCSIFDSTADDR 0x8918
+#define SIOCGIFBRDADDR 0x8919
+#define SIOCSIFBRDADDR 0x891a
+#define SIOCGIFNETMASK 0x891b
+#define SIOCSIFNETMASK 0x891c
+#define SIOCGIFMETRIC 0x891d
+#define SIOCSIFMETRIC 0x891e
+#define SIOCGIFMEM 0x891f
+#define SIOCSIFMEM 0x8920
+#define SIOCGIFMTU 0x8921
+#define SIOCSIFMTU 0x8922
+#define SIOCSIFNAME 0x8923
+#define SIOCSIFHWADDR 0x8924
+#define SIOCGIFENCAP 0x8925
+#define SIOCSIFENCAP 0x8926
+#define SIOCGIFHWADDR 0x8927
+#define SIOCGIFSLAVE 0x8929
+#define SIOCSIFSLAVE 0x8930
+#define SIOCADDMULTI 0x8931
+#define SIOCDELMULTI 0x8932
+#define SIOCGIFINDEX 0x8933
+#define SIOGIFINDEX SIOCGIFINDEX
+#define SIOCSIFPFLAGS 0x8934
+#define SIOCGIFPFLAGS 0x8935
+#define SIOCDIFADDR 0x8936
+#define SIOCSIFHWBROADCAST 0x8937
+#define SIOCGIFCOUNT 0x8938
+#define SIOCGIFBR 0x8940
+#define SIOCSIFBR 0x8941
+#define SIOCGIFTXQLEN 0x8942
+#define SIOCSIFTXQLEN 0x8943
+#define SIOCDARP 0x8953
+#define SIOCGARP 0x8954
+#define SIOCSARP 0x8955
+#define SIOCDRARP 0x8960
+#define SIOCGRARP 0x8961
+#define SIOCSRARP 0x8962
+#define SIOCGIFMAP 0x8970
+#define SIOCSIFMAP 0x8971
+#define SIOCADDDLCI 0x8980
+#define SIOCDELDLCI 0x8981
+#define SIOCDEVPRIVATE 0x89F0
+#define SIOCPROTOPRIVATE 0x89E0
+
#ifdef __cplusplus
}
#endif
diff --git a/system/include/sys/select.h b/system/include/sys/select.h
index a5c73147..d6957fea 100644
--- a/system/include/sys/select.h
+++ b/system/include/sys/select.h
@@ -1,6 +1,8 @@
#ifndef _SELECT_H
#define _SELECT_H
+#include <unistd.h>
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/system/include/sys/socket.h b/system/include/sys/socket.h
index 9650bb9a..abc0aa62 100644
--- a/system/include/sys/socket.h
+++ b/system/include/sys/socket.h
@@ -4,44 +4,196 @@
#include <netdb.h>
#include <sys/select.h>
#include <sys/uio.h>
+#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
-// Note that the values of these constants are mostly arbitrary numbers.
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define SOCK_RAW 3
+#define SOCK_RDM 4
+#define SOCK_SEQPACKET 5
+#define SOCK_DCCP 6
+#define SOCK_PACKET 10
+#define SOCK_CLOEXEC 02000000
+#define SOCK_NONBLOCK 04000
+
+#define PF_UNSPEC 0
+#define PF_LOCAL 1
+#define PF_UNIX PF_LOCAL
+#define PF_FILE PF_LOCAL
+#define PF_INET 2
+#define PF_AX25 3
+#define PF_IPX 4
+#define PF_APPLETALK 5
+#define PF_NETROM 6
+#define PF_BRIDGE 7
+#define PF_ATMPVC 8
+#define PF_X25 9
+#define PF_INET6 10
+#define PF_ROSE 11
+#define PF_DECnet 12
+#define PF_NETBEUI 13
+#define PF_SECURITY 14
+#define PF_KEY 15
+#define PF_NETLINK 16
+#define PF_ROUTE PF_NETLINK
+#define PF_PACKET 17
+#define PF_ASH 18
+#define PF_ECONET 19
+#define PF_ATMSVC 20
+#define PF_RDS 21
+#define PF_SNA 22
+#define PF_IRDA 23
+#define PF_PPPOX 24
+#define PF_WANPIPE 25
+#define PF_LLC 26
+#define PF_CAN 29
+#define PF_TIPC 30
+#define PF_BLUETOOTH 31
+#define PF_IUCV 32
+#define PF_RXRPC 33
+#define PF_ISDN 34
+#define PF_PHONET 35
+#define PF_IEEE802154 36
+#define PF_CAIF 37
+#define PF_ALG 38
+#define PF_NFC 39
+#define PF_MAX 40
+
+#define AF_UNSPEC PF_UNSPEC
+#define AF_LOCAL PF_LOCAL
+#define AF_UNIX PF_UNIX
+#define AF_FILE PF_FILE
+#define AF_INET PF_INET
+#define AF_AX25 PF_AX25
+#define AF_IPX PF_IPX
+#define AF_APPLETALK PF_APPLETALK
+#define AF_NETROM PF_NETROM
+#define AF_BRIDGE PF_BRIDGE
+#define AF_ATMPVC PF_ATMPVC
+#define AF_X25 PF_X25
+#define AF_INET6 PF_INET6
+#define AF_ROSE PF_ROSE
+#define AF_DECnet PF_DECnet
+#define AF_NETBEUI PF_NETBEUI
+#define AF_SECURITY PF_SECURITY
+#define AF_KEY PF_KEY
+#define AF_NETLINK PF_NETLINK
+#define AF_ROUTE PF_ROUTE
+#define AF_PACKET PF_PACKET
+#define AF_ASH PF_ASH
+#define AF_ECONET PF_ECONET
+#define AF_ATMSVC PF_ATMSVC
+#define AF_RDS PF_RDS
+#define AF_SNA PF_SNA
+#define AF_IRDA PF_IRDA
+#define AF_PPPOX PF_PPPOX
+#define AF_WANPIPE PF_WANPIPE
+#define AF_LLC PF_LLC
+#define AF_CAN PF_CAN
+#define AF_TIPC PF_TIPC
+#define AF_BLUETOOTH PF_BLUETOOTH
+#define AF_IUCV PF_IUCV
+#define AF_RXRPC PF_RXRPC
+#define AF_ISDN PF_ISDN
+#define AF_PHONET PF_PHONET
+#define AF_IEEE802154 PF_IEEE802154
+#define AF_CAIF PF_CAIF
+#define AF_ALG PF_ALG
+#define AF_NFC PF_NFC
+#define AF_MAX PF_MAX
+
#define SOMAXCONN 128
-#define PF_LOCAL 1
-#define PF_UNIX PF_LOCAL
-#define PF_INET 2
-#define SO_BROADCAST 6
-#define AF_UNIX PF_UNIX
-
-#define AF_UNSPEC 0
-#define SOCK_STREAM 200
-#define SOL_SOCKET 50
-#define SO_ERROR 10
-#define SOCK_DGRAM 20
-#define SO_REUSEADDR 30
-#define SO_SNDBUF 40
-#define SO_RCVBUF 60
-#define SO_LINGER 70
-#define SO_NOSIGPIPE 80
-#define SO_KEEPALIVE 90
-#define SO_OOBINLINE 100
-#define SO_NO_CHECK 110
-#define SO_PRIORITY 120
-#define SO_LINGER 130
-#define SO_BSDCOMPAT 140
+
+#define SOL_SOCKET 1
+
+#define SO_DEBUG 1
+#define SO_REUSEADDR 2
+#define SO_TYPE 3
+#define SO_ERROR 4
+#define SO_DONTROUTE 5
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
+#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_LINGER 13
+#define SO_BSDCOMPAT 14
+#ifndef SO_PASSCRED
+#define SO_PASSCRED 16
+#define SO_PEERCRED 17
+#define SO_RCVLOWAT 18
+#define SO_SNDLOWAT 19
+#define SO_RCVTIMEO 20
+#define SO_SNDTIMEO 21
+#endif
+#define SO_SECURITY_AUTHENTICATION 22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
+#define SO_SECURITY_ENCRYPTION_NETWORK 24
+#define SO_BINDTODEVICE 25
+#define SO_ATTACH_FILTER 26
+#define SO_DETACH_FILTER 27
+#define SO_PEERNAME 28
+#define SO_TIMESTAMP 29
+#define SCM_TIMESTAMP SO_TIMESTAMP
+#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+#define SO_PASSSEC 34
+#define SO_TIMESTAMPNS 35
+#define SCM_TIMESTAMPNS SO_TIMESTAMPNS
+#define SO_MARK 36
+#define SO_TIMESTAMPING 37
+#define SCM_TIMESTAMPING SO_TIMESTAMPING
+#define SO_PROTOCOL 38
+#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
+#if __BSD_VISIBLE
+#define SO_NOSIGPIPE 0x0800
+#endif
+
+#define MSG_OOB 0x01
+#define MSG_PEEK 0x02
+#define MSG_DONTROUTE 0x04
+#ifdef __USE_GNU
+# define MSG_TRYHARD MSG_DONTROUTE
+#endif
+#define MSG_CTRUNC 0x08
+#define MSG_PROXY 0x10
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40
+#define MSG_EOR 0x80
+#define MSG_WAITALL 0x100
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_CONFIRM 0x800
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000
+#define MSG_NOSIGNAL 0x4000
+#define MSG_MORE 0x8000
+#define MSG_WAITFORONE 0x10000
+#define MSG_CMSG_CLOEXEC 0x40000000
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
+#define FIOSETOWN 0x8901
+#define SIOCSPGRP 0x8902
+#define FIOGETOWN 0x8903
+#define SIOCGPGRP 0x8904
+#define SIOCATMARK 0x8905
+#define SIOCGSTAMP 0x8906
+#define SIOCGSTAMPNS 0x8907
+
typedef unsigned int sa_family_t;
-#define AF_INET PF_INET
-#define AF_INET6 6
-#define PF_INET6 AF_INET6
struct sockaddr {
sa_family_t sa_family;
@@ -87,13 +239,6 @@ struct linger {
int l_linger;
};
-#define SIOCATMARK 0x8905
-
-#define SOCK_RAW 111
-#define SOCK_SEQPACKET 555
-
-#define PF_APPLETALK 5
-
#ifdef __cplusplus
}
#endif
diff --git a/system/include/xlocale.h b/system/include/xlocale.h
index bb3b50e5..6867d25f 100644
--- a/system/include/xlocale.h
+++ b/system/include/xlocale.h
@@ -1,4 +1,3 @@
-
#ifndef _XLOCALE_H_
#define _XLOCALE_H_
@@ -9,10 +8,6 @@
extern "C" {
#endif
-long long strtoll_l(const char *start, char **end, int base, locale_t loc);
-unsigned long long strtoull_l(const char *start, char **end, int base, locale_t loc);
-double strtold_l(const char *start, char **end, locale_t loc);
-
int strcoll_l(const char *s1, const char *s2, locale_t locale);
int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale);
@@ -43,5 +38,5 @@ size_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm *
}
#endif
-#endif /* _LOCALE_H_ */
+#endif /* _XLOCALE_H_ */
diff --git a/system/lib/dlmalloc.c b/system/lib/dlmalloc.c
index e833ae42..ce2c25f1 100644
--- a/system/lib/dlmalloc.c
+++ b/system/lib/dlmalloc.c
@@ -1,4 +1,14 @@
+/* XXX Emscripten XXX */
+#if EMSCRIPTEN
+#define DLMALLOC_EXPORT __attribute__((__weak__, __visibility__("default")))
+/* mmap uses malloc, so malloc can't use mmap */
+#define HAVE_MMAP 0
+/* we can only grow the heap up anyhow, so don't try to trim */
+#define MORECORE_CANNOT_TRIM 1
+#endif
+
+
#define __THROW
#define __attribute_malloc__
#define __wur
@@ -532,10 +542,6 @@
#define DLMALLOC_VERSION 20806
#endif /* DLMALLOC_VERSION */
-#if EMSCRIPTEN
-#define DLMALLOC_EXPORT __attribute__((__weak__, __visibility__("default")))
-#endif
-
#ifndef DLMALLOC_EXPORT
#define DLMALLOC_EXPORT extern
#endif
@@ -647,15 +653,7 @@ defined(__i386__) || defined(__x86_64__))) || \
#define MALLOC_INSPECT_ALL 0
#endif /* MALLOC_INSPECT_ALL */
#ifndef HAVE_MMAP
-/* XXX Emscripten
- * mmap uses malloc, so malloc can't use mmap
- */
-#ifdef EMSCRIPTEN
-#define HAVE_MMAP 0
-#else
#define HAVE_MMAP 1
-#endif
-
#endif /* HAVE_MMAP */
#ifndef MMAP_CLEARS
#define MMAP_CLEARS 1
diff --git a/system/lib/libc/musl/src/stdlib/ecvt.c b/system/lib/libc/musl/src/stdlib/ecvt.c
new file mode 100644
index 00000000..79c3de63
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/ecvt.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+char *ecvt(double x, int n, int *dp, int *sign)
+{
+ static char buf[16];
+ char tmp[32];
+ int i, j;
+
+ if (n-1U > 15) n = 15;
+ sprintf(tmp, "%.*e", n-1, x);
+ i = *sign = (tmp[0]=='-');
+ for (j=0; tmp[i]!='e'; j+=(tmp[i++]!='.'))
+ buf[j] = tmp[i];
+ buf[j] = 0;
+ *dp = atoi(tmp+i+1)+1;
+
+ return buf;
+}
diff --git a/system/lib/libc/musl/src/stdlib/fcvt.c b/system/lib/libc/musl/src/stdlib/fcvt.c
new file mode 100644
index 00000000..f90928fe
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/fcvt.c
@@ -0,0 +1,25 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+char *fcvt(double x, int n, int *dp, int *sign)
+{
+ char tmp[1500];
+ int i, lz;
+
+ if (n > 1400U) n = 1400;
+ sprintf(tmp, "%.*f", n, x);
+ i = (tmp[0] == '-');
+ if (tmp[i] == '0') lz = strspn(tmp+i+2, "0");
+ else lz = -(int)strcspn(tmp+i, ".");
+
+ if (n<=lz) {
+ *sign = i;
+ *dp = 1;
+ if (n>14U) n = 14;
+ return "000000000000000"+14-n;
+ }
+
+ return ecvt(x, n-lz, dp, sign);
+}
diff --git a/system/lib/libc/musl/src/stdlib/gcvt.c b/system/lib/libc/musl/src/stdlib/gcvt.c
new file mode 100644
index 00000000..6c075e25
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/gcvt.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+char *gcvt(double x, int n, char *b)
+{
+ sprintf(b, "%.*g", n, x);
+ return b;
+}
diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols
index 42e66b51..a365271d 100644
--- a/system/lib/libcextra.symbols
+++ b/system/lib/libcextra.symbols
@@ -1,4 +1,7 @@
T btowc
+ T ecvt
+ T fcvt
+ T gcvt
T iswalnum
T iswalpha
T iswblank
diff --git a/system/lib/libcxx/CREDITS.TXT b/system/lib/libcxx/CREDITS.TXT
index 52948510..5e4d14ec 100644
--- a/system/lib/libcxx/CREDITS.TXT
+++ b/system/lib/libcxx/CREDITS.TXT
@@ -33,6 +33,14 @@ E: mclow.lists@gmail.com
E: marshall@idio.com
D: Minor patches and bug fixes.
+N: Bill Fisher
+E: william.w.fisher@gmail.com
+D: Regex bug fixes.
+
+N: Matthew Dempsky
+E: matthew@dempsky.org
+D: Minor patches and bug fixes.
+
N: Google Inc.
D: Copyright owner and contributor of the CityHash algorithm
@@ -48,6 +56,10 @@ N: Argyrios Kyrtzidis
E: kyrtzidis@apple.com
D: Bug fixes.
+N: Bruce Mitchener, Jr.
+E: bruce.mitchener@gmail.com
+D: Emscripten-related changes.
+
N: Michel Morin
E: mimomorin@gmail.com
D: Minor patches to is_convertible.
@@ -74,6 +86,14 @@ D: Implemented Cityhash as the string hash function on 64-bit machines
N: Richard Smith
D: Minor patches.
+N: Joerg Sonnenberger
+E: joerg@NetBSD.org
+D: NetBSD port.
+
+N: Stephan Tolksdorf
+E: st@quanttec.com
+D: Minor <atomic> fix
+
N: Michael van der Westhuizen
E: r1mikey at gmail dot com
@@ -85,6 +105,10 @@ N: Zhang Xiongpang
E: zhangxiongpang@gmail.com
D: Minor patches and bug fixes.
+N: Zhihao Yuan
+E: lichray@gmail.com
+D: Standard compatibility fixes.
+
N: Jeffrey Yasskin
E: jyasskin@gmail.com
E: jyasskin@google.com
diff --git a/system/lib/libcxx/debug.cpp b/system/lib/libcxx/debug.cpp
index 2d4b094b..c9b09b7a 100644
--- a/system/lib/libcxx/debug.cpp
+++ b/system/lib/libcxx/debug.cpp
@@ -110,8 +110,7 @@ __libcpp_db::__find_c_from_i(void* __i) const
{
RLock _(mut());
__i_node* i = __find_iterator(__i);
- _LIBCPP_ASSERT(i != nullptr, "iterator constructed in translation unit with debug mode not enabled."
- " #define _LIBCPP_DEBUG2 1 for that translation unit.");
+ _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database.");
return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
}
@@ -144,7 +143,7 @@ __libcpp_db::__insert_c(void* __c)
if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
{
size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
- __c_node** cbeg = (__c_node**)calloc(nc, sizeof(void*));
+ __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(void*)));
if (cbeg == nullptr)
#ifndef _LIBCPP_NO_EXCEPTIONS
throw bad_alloc();
@@ -169,7 +168,8 @@ __libcpp_db::__insert_c(void* __c)
}
size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
__c_node* p = __cbeg_[hc];
- __c_node* r = __cbeg_[hc] = (__c_node*)malloc(sizeof(__c_node));
+ __c_node* r = __cbeg_[hc] =
+ static_cast<__c_node*>(malloc(sizeof(__c_node)));
if (__cbeg_[hc] == nullptr)
#ifndef _LIBCPP_NO_EXCEPTIONS
throw bad_alloc();
@@ -302,7 +302,7 @@ __libcpp_db::__iterator_copy(void* __i, const void* __i0)
__i_node* i = __find_iterator(__i);
__i_node* i0 = __find_iterator(__i0);
__c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
- if (i == nullptr && c0 != nullptr)
+ if (i == nullptr && i0 != nullptr)
i = __insert_iterator(__i);
__c_node* c = i != nullptr ? i->__c_ : nullptr;
if (c != c0)
@@ -354,7 +354,7 @@ __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
}
bool
-__libcpp_db::__comparable(const void* __i, const void* __j) const
+__libcpp_db::__less_than_comparable(const void* __i, const void* __j) const
{
RLock _(mut());
__i_node* i = __find_iterator(__i);
@@ -408,7 +408,8 @@ __c_node::__add(__i_node* i)
size_t nc = 2*static_cast<size_t>(cap_ - beg_);
if (nc == 0)
nc = 1;
- __i_node** beg = (__i_node**)malloc(nc * sizeof(__i_node*));
+ __i_node** beg =
+ static_cast<__i_node**>(malloc(nc * sizeof(__i_node*)));
if (beg == nullptr)
#ifndef _LIBCPP_NO_EXCEPTIONS
throw bad_alloc();
@@ -434,7 +435,7 @@ __libcpp_db::__insert_iterator(void* __i)
if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
{
size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
- __i_node** ibeg = (__i_node**)calloc(nc, sizeof(void*));
+ __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(void*)));
if (ibeg == nullptr)
#ifndef _LIBCPP_NO_EXCEPTIONS
throw bad_alloc();
@@ -459,7 +460,8 @@ __libcpp_db::__insert_iterator(void* __i)
}
size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
__i_node* p = __ibeg_[hi];
- __i_node* r = __ibeg_[hi] = (__i_node*)malloc(sizeof(__i_node));
+ __i_node* r = __ibeg_[hi] =
+ static_cast<__i_node*>(malloc(sizeof(__i_node)));
if (r == nullptr)
#ifndef _LIBCPP_NO_EXCEPTIONS
throw bad_alloc();
diff --git a/system/lib/libcxx/exception.cpp b/system/lib/libcxx/exception.cpp
index 1d2f6b25..d3e1b292 100644
--- a/system/lib/libcxx/exception.cpp
+++ b/system/lib/libcxx/exception.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
+#include <stdio.h>
#include "exception"
@@ -88,12 +89,14 @@ terminate() _NOEXCEPT
#endif // _LIBCPP_NO_EXCEPTIONS
(*get_terminate())();
// handler should not return
+ printf("terminate_handler unexpectedly returned\n");
::abort ();
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
// handler should not throw exception
+ printf("terminate_handler unexpectedly threw an exception\n");
::abort ();
}
#endif // _LIBCPP_NO_EXCEPTIONS
@@ -109,6 +112,7 @@ bool uncaught_exception() _NOEXCEPT
return __cxa_uncaught_exception();
#else // __APPLE__
#warning uncaught_exception not yet implemented
+ printf("uncaught_exception not yet implemented\n");
::abort();
#endif // __APPLE__
}
@@ -146,6 +150,7 @@ exception_ptr::~exception_ptr() _NOEXCEPT
__cxa_decrement_exception_refcount(__ptr_);
#else
#warning exception_ptr not yet implemented
+ printf("exception_ptr not yet implemented\n");
::abort();
#endif // __APPLE__
}
@@ -157,6 +162,7 @@ exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
__cxa_increment_exception_refcount(__ptr_);
#else
#warning exception_ptr not yet implemented
+ printf("exception_ptr not yet implemented\n");
::abort();
#endif // __APPLE__
}
@@ -173,6 +179,7 @@ exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
return *this;
#else // __APPLE__
#warning exception_ptr not yet implemented
+ printf("exception_ptr not yet implemented\n");
::abort();
#endif // __APPLE__
}
@@ -207,6 +214,7 @@ exception_ptr current_exception() _NOEXCEPT
return ptr;
#else // __APPLE__
#warning exception_ptr not yet implemented
+ printf("exception_ptr not yet implemented\n");
::abort();
#endif // __APPLE__
}
@@ -220,6 +228,7 @@ void rethrow_exception(exception_ptr p)
terminate();
#else // __APPLE__
#warning exception_ptr not yet implemented
+ printf("exception_ptr not yet implemented\n");
::abort();
#endif // __APPLE__
}
diff --git a/system/lib/libcxx/hash.cpp b/system/lib/libcxx/hash.cpp
index a0135002..388ab2eb 100644
--- a/system/lib/libcxx/hash.cpp
+++ b/system/lib/libcxx/hash.cpp
@@ -12,7 +12,9 @@
#include "stdexcept"
#include "type_traits"
+#ifdef __clang__
#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
+#endif
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -155,6 +157,8 @@ __check_for_overflow(size_t N)
#ifndef _LIBCPP_NO_EXCEPTIONS
if (N > 0xFFFFFFFB)
throw overflow_error("__next_prime overflow");
+#else
+ (void)N;
#endif
}
@@ -166,6 +170,8 @@ __check_for_overflow(size_t N)
#ifndef _LIBCPP_NO_EXCEPTIONS
if (N > 0xFFFFFFFFFFFFFFC5ull)
throw overflow_error("__next_prime overflow");
+#else
+ (void)N;
#endif
}
diff --git a/system/lib/libcxx/iostream.cpp b/system/lib/libcxx/iostream.cpp
index 7fc71df4..f413681f 100644
--- a/system/lib/libcxx/iostream.cpp
+++ b/system/lib/libcxx/iostream.cpp
@@ -54,13 +54,13 @@ ios_base::Init::Init()
ios_base::Init::~Init()
{
- ostream* cout_ptr = (ostream*)cout;
- ostream* clog_ptr = (ostream*)clog;
+ ostream* cout_ptr = reinterpret_cast<ostream*>(cout);
+ ostream* clog_ptr = reinterpret_cast<ostream*>(clog);
cout_ptr->flush();
clog_ptr->flush();
- wostream* wcout_ptr = (wostream*)wcout;
- wostream* wclog_ptr = (wostream*)wclog;
+ wostream* wcout_ptr = reinterpret_cast<wostream*>(wcout);
+ wostream* wclog_ptr = reinterpret_cast<wostream*>(wclog);
wcout_ptr->flush();
wclog_ptr->flush();
}
diff --git a/system/lib/libcxx/locale.cpp b/system/lib/libcxx/locale.cpp
index d9bc6f9a..d95d0c9c 100644
--- a/system/lib/libcxx/locale.cpp
+++ b/system/lib/libcxx/locale.cpp
@@ -18,19 +18,21 @@
#include "codecvt"
#include "vector"
#include "algorithm"
-#include "algorithm"
#include "typeinfo"
-#include "type_traits"
+#ifndef _LIBCPP_NO_EXCEPTIONS
+# include "type_traits"
+#endif
#include "clocale"
#include "cstring"
#include "cwctype"
#include "__sso_allocator"
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
#include <support/win32/locale_win32.h>
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
#include <langinfo.h>
-#endif // _!WIN32
+#endif // !_LIBCPP_MSVCRT
#include <stdlib.h>
+#include <stdio.h>
// On Linux, wint_t and wchar_t have different signed-ness, and this causes
// lots of noise in the build log, but no bugs that I know of.
@@ -230,8 +232,10 @@ locale::__imp::__imp(const string& name, size_t refs)
// NOTE avoid the `base class should be explicitly initialized in the
// copy constructor` warning emitted by GCC
+#if defined(__clang__) || _GNUC_VER >= 406
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wextra"
+#endif
locale::__imp::__imp(const __imp& other)
: facets_(max<size_t>(N, other.facets_.size())),
@@ -243,7 +247,9 @@ locale::__imp::__imp(const __imp& other)
facets_[i]->__add_shared();
}
+#if defined(__clang__) || _GNUC_VER >= 406
#pragma GCC diagnostic pop
+#endif
locale::__imp::__imp(const __imp& other, const string& name, locale::category c)
: facets_(N),
@@ -786,7 +792,7 @@ ctype<wchar_t>::do_toupper(char_type c) const
{
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
-#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
+#elif defined(__GLIBC__) || defined(EMSCRIPTEN) || defined(__NetBSD__)
return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
#else
return (isascii(c) && iswlower_l(c, __cloc())) ? c-L'a'+L'A' : c;
@@ -799,7 +805,7 @@ ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
for (; low != high; ++low)
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
-#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
+#elif defined(__GLIBC__) || defined(EMSCRIPTEN) || defined(__NetBSD__)
*low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
: *low;
#else
@@ -813,7 +819,7 @@ ctype<wchar_t>::do_tolower(char_type c) const
{
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
-#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
+#elif defined(__GLIBC__) || defined(EMSCRIPTEN) || defined(__NetBSD__)
return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
#else
return (isascii(c) && isupper_l(c, __cloc())) ? c-L'A'+'a' : c;
@@ -826,7 +832,7 @@ ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
for (; low != high; ++low)
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
-#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
+#elif defined(__GLIBC__) || defined(EMSCRIPTEN) || defined(__NetBSD__)
*low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
: *low;
#else
@@ -893,9 +899,11 @@ ctype<char>::do_toupper(char_type c) const
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return isascii(c) ?
static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
+#elif defined(__NetBSD__)
+ return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
return isascii(c) ?
- static_cast<char>(__classic_upper_table()[static_cast<size_t>(c)]) : c;
+ static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
#else
return (isascii(c) && islower_l(c, __cloc())) ? c-'a'+'A' : c;
#endif
@@ -908,6 +916,8 @@ ctype<char>::do_toupper(char_type* low, const char_type* high) const
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = isascii(*low) ?
static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
+#elif defined(__NetBSD__)
+ *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
*low = isascii(*low) ?
static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
@@ -923,7 +933,9 @@ ctype<char>::do_tolower(char_type c) const
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
return isascii(c) ?
static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
-#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
+#elif defined(__NetBSD__)
+ return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
+#elif defined(__GLIBC__) || defined(EMSCRIPTEN) || defined(__NetBSD__)
return isascii(c) ?
static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
#else
@@ -937,6 +949,8 @@ ctype<char>::do_tolower(char_type* low, const char_type* high) const
for (; low != high; ++low)
#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
*low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
+#elif defined(__NetBSD__)
+ *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
#elif defined(__GLIBC__) || defined(EMSCRIPTEN)
*low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
#else
@@ -989,11 +1003,13 @@ ctype<char>::classic_table() _NOEXCEPT
{
#if defined(__APPLE__) || defined(__FreeBSD__)
return _DefaultRuneLocale.__runetype;
+#elif defined(__NetBSD__)
+ return _C_ctype_tab_ + 1;
#elif defined(__GLIBC__)
return __cloc()->__ctype_b;
#elif __sun__
return __ctype_mask;
-#elif defined(_WIN32)
+#elif defined(_LIBCPP_MSVCRT)
return _ctype+1; // internal ctype mask table defined in msvcrt.dll
// This is assumed to be safe, which is a nonsense assumption because we're
// going to end up dereferencing it later...
@@ -1003,6 +1019,7 @@ ctype<char>::classic_table() _NOEXCEPT
// Platform not supported: abort so the person doing the port knows what to
// fix
# warning ctype<char>::classic_table() is not implemented
+ printf("ctype<char>::classic_table() is not implemented\n");
abort();
return NULL;
#endif
@@ -1020,9 +1037,20 @@ ctype<char>::__classic_upper_table() _NOEXCEPT
{
return __cloc()->__ctype_toupper;
}
-#endif // __GLIBC__
+#elif __NetBSD__
+const short*
+ctype<char>::__classic_lower_table() _NOEXCEPT
+{
+ return _C_tolower_tab_ + 1;
+}
-#if defined(EMSCRIPTEN)
+const short*
+ctype<char>::__classic_upper_table() _NOEXCEPT
+{
+ return _C_toupper_tab_ + 1;
+}
+
+#elif defined(EMSCRIPTEN)
const int*
ctype<char>::__classic_lower_table() _NOEXCEPT
{
@@ -1034,7 +1062,7 @@ ctype<char>::__classic_upper_table() _NOEXCEPT
{
return *__ctype_toupper_loc();
}
-#endif // EMSCRIPTEN
+#endif // __GLIBC__ || EMSCRIPTEN || __NETBSD__
// template <> class ctype_byname<char>
@@ -1068,28 +1096,28 @@ ctype_byname<char>::~ctype_byname()
char
ctype_byname<char>::do_toupper(char_type c) const
{
- return static_cast<char>(toupper_l(c, __l));
+ return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l));
}
const char*
ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
{
for (; low != high; ++low)
- *low = static_cast<char>(toupper_l(*low, __l));
+ *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l));
return low;
}
char
ctype_byname<char>::do_tolower(char_type c) const
{
- return static_cast<char>(tolower_l(c, __l));
+ return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l));
}
const char*
ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
{
for (; low != high; ++low)
- *low = static_cast<char>(tolower_l(*low, __l));
+ *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l));
return low;
}
@@ -1372,7 +1400,7 @@ locale::id codecvt<wchar_t, char, mbstate_t>::id;
codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
: locale::facet(refs),
- __l(0)
+ __l(_LIBCPP_GET_C_LOCALE)
{
}
@@ -1389,7 +1417,7 @@ codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
codecvt<wchar_t, char, mbstate_t>::~codecvt()
{
- if (__l != 0)
+ if (__l != _LIBCPP_GET_C_LOCALE)
freelocale(__l);
}
@@ -1407,7 +1435,7 @@ codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st,
to_nxt = to;
for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
{
- // save state in case needed to reover to_nxt on error
+ // save state in case it is needed to recover to_nxt on error
mbstate_t save_state = st;
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
size_t n = wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
@@ -1476,7 +1504,7 @@ codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st,
to_nxt = to;
for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
{
- // save state in case needed to reover to_nxt on error
+ // save state in case it is needed to recover to_nxt on error
mbstate_t save_state = st;
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
size_t n = mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
@@ -3176,14 +3204,25 @@ __codecvt_utf8<wchar_t>::do_out(state_type&,
const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
{
+#if _WIN32
+ const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
+ const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
+ const uint16_t* _frm_nxt = _frm;
+#else
const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
const uint32_t* _frm_nxt = _frm;
+#endif
uint8_t* _to = reinterpret_cast<uint8_t*>(to);
uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
uint8_t* _to_nxt = _to;
+#if _WIN32
+ result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
+ _Maxcode_, _Mode_);
+#else
result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
_Maxcode_, _Mode_);
+#endif
frm_nxt = frm + (_frm_nxt - _frm);
to_nxt = to + (_to_nxt - _to);
return r;
@@ -3197,11 +3236,19 @@ __codecvt_utf8<wchar_t>::do_in(state_type&,
const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
const uint8_t* _frm_nxt = _frm;
+#if _WIN32
+ uint16_t* _to = reinterpret_cast<uint16_t*>(to);
+ uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
+ uint16_t* _to_nxt = _to;
+ result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
+ _Maxcode_, _Mode_);
+#else
uint32_t* _to = reinterpret_cast<uint32_t*>(to);
uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
uint32_t* _to_nxt = _to;
result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
_Maxcode_, _Mode_);
+#endif
frm_nxt = frm + (_frm_nxt - _frm);
to_nxt = to + (_to_nxt - _to);
return r;
@@ -5315,7 +5362,7 @@ __time_put::__time_put(const string& nm)
__time_put::~__time_put()
{
- if (__loc_)
+ if (__loc_ != _LIBCPP_GET_C_LOCALE)
freelocale(__loc_);
}
@@ -5801,19 +5848,19 @@ moneypunct_byname<char, true>::init(const char* nm)
__frac_digits_ = lc->int_frac_digits;
else
__frac_digits_ = base::do_frac_digits();
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
if (lc->p_sign_posn == 0)
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
if (lc->int_p_sign_posn == 0)
-#endif //_WIN32
+#endif // !_LIBCPP_MSVCRT
__positive_sign_ = "()";
else
__positive_sign_ = lc->positive_sign;
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
if(lc->n_sign_posn == 0)
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
if (lc->int_n_sign_posn == 0)
-#endif // _WIN32
+#endif // !_LIBCPP_MSVCRT
__negative_sign_ = "()";
else
__negative_sign_ = lc->negative_sign;
@@ -5821,19 +5868,19 @@ moneypunct_byname<char, true>::init(const char* nm)
// the same places in curr_symbol since there's no way to
// represent anything else.
string_type __dummy_curr_symbol = __curr_symbol_;
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
__init_pat(__pos_format_, __dummy_curr_symbol, true,
lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
__init_pat(__neg_format_, __curr_symbol_, true,
lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
-#else
+#else // _LIBCPP_MSVCRT
__init_pat(__pos_format_, __dummy_curr_symbol, true,
lc->int_p_cs_precedes, lc->int_p_sep_by_space,
lc->int_p_sign_posn, ' ');
__init_pat(__neg_format_, __curr_symbol_, true,
lc->int_n_cs_precedes, lc->int_n_sep_by_space,
lc->int_n_sign_posn, ' ');
-#endif // _WIN32
+#endif // !_LIBCPP_MSVCRT
}
template<>
@@ -5960,11 +6007,11 @@ moneypunct_byname<wchar_t, true>::init(const char* nm)
__frac_digits_ = lc->int_frac_digits;
else
__frac_digits_ = base::do_frac_digits();
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
if (lc->p_sign_posn == 0)
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
if (lc->int_p_sign_posn == 0)
-#endif // _WIN32
+#endif // !_LIBCPP_MSVCRT
__positive_sign_ = L"()";
else
{
@@ -5980,11 +6027,11 @@ moneypunct_byname<wchar_t, true>::init(const char* nm)
wbe = wbuf + j;
__positive_sign_.assign(wbuf, wbe);
}
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
if (lc->n_sign_posn == 0)
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
if (lc->int_n_sign_posn == 0)
-#endif // _WIN32
+#endif // !_LIBCPP_MSVCRT
__negative_sign_ = L"()";
else
{
@@ -6004,19 +6051,19 @@ moneypunct_byname<wchar_t, true>::init(const char* nm)
// the same places in curr_symbol since there's no way to
// represent anything else.
string_type __dummy_curr_symbol = __curr_symbol_;
-#ifdef _WIN32
+#ifdef _LIBCPP_MSVCRT
__init_pat(__pos_format_, __dummy_curr_symbol, true,
lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
__init_pat(__neg_format_, __curr_symbol_, true,
lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
-#else // _WIN32
+#else // _LIBCPP_MSVCRT
__init_pat(__pos_format_, __dummy_curr_symbol, true,
lc->int_p_cs_precedes, lc->int_p_sep_by_space,
lc->int_p_sign_posn, L' ');
__init_pat(__neg_format_, __curr_symbol_, true,
lc->int_n_cs_precedes, lc->int_n_sep_by_space,
lc->int_n_sign_posn, L' ');
-#endif // _WIN32
+#endif // !_LIBCPP_MSVCRT
}
void __do_nothing(void*) {}
@@ -6025,6 +6072,8 @@ void __throw_runtime_error(const char* msg)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
throw runtime_error(msg);
+#else
+ (void)msg;
#endif
}
diff --git a/system/lib/libcxx/readme.txt b/system/lib/libcxx/readme.txt
index 97d8db86..7687e5b2 100644
--- a/system/lib/libcxx/readme.txt
+++ b/system/lib/libcxx/readme.txt
@@ -1 +1 @@
-These files are from libc++, svn revision 178253, Mar 29 2013
+These files are from libc++, svn revision 187959, 2013-08-08.
diff --git a/system/lib/libcxx/stdexcept.cpp b/system/lib/libcxx/stdexcept.cpp
index 0c4e8323..8d25f3ee 100644
--- a/system/lib/libcxx/stdexcept.cpp
+++ b/system/lib/libcxx/stdexcept.cpp
@@ -61,7 +61,7 @@ __libcpp_nmstr::__libcpp_nmstr(const char* msg)
c[0] = c[1] = len;
str_ += offset;
count() = 0;
- std::strcpy(const_cast<char*>(c_str()), msg);
+ std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
}
inline
diff --git a/system/lib/libcxx/string.cpp b/system/lib/libcxx/string.cpp
index c71af4fe..5a869116 100644
--- a/system/lib/libcxx/string.cpp
+++ b/system/lib/libcxx/string.cpp
@@ -11,9 +11,12 @@
#include "cstdlib"
#include "cwchar"
#include "cerrno"
-#ifdef _WIN32
+#include "limits"
+#include "stdexcept"
+#ifdef _LIBCPP_MSVCRT
#include "support/win32/support.h"
-#endif // _WIN32
+#endif // _LIBCPP_MSVCRT
+#include <stdio.h>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -26,662 +29,500 @@ template
string
operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
-int
-stoi(const string& str, size_t* idx, int base)
+namespace
+{
+
+template<typename T>
+inline
+void throw_helper( const string& msg )
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ throw T( msg );
+#else
+ printf("%s\n", msg.c_str());
+ abort();
+#endif
+}
+
+inline
+void throw_from_string_out_of_range( const string& func )
+{
+ throw_helper<out_of_range>(func + ": out of range");
+}
+
+inline
+void throw_from_string_invalid_arg( const string& func )
+{
+ throw_helper<invalid_argument>(func + ": no conversion");
+}
+
+// as_integer
+
+template<typename V, typename S, typename F>
+inline
+V
+as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
{
- char* ptr;
- const char* const p = str.c_str();
+ typename S::value_type* ptr;
+ const typename S::value_type* const p = str.c_str();
typename remove_reference<decltype(errno)>::type errno_save = errno;
errno = 0;
- long r = strtol(p, &ptr, base);
+ V r = f(p, &ptr, base);
swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE || r < numeric_limits<int>::min() ||
- numeric_limits<int>::max() < r)
- throw out_of_range("stoi: out of range");
+ if (errno_save == ERANGE)
+ throw_from_string_out_of_range(func);
if (ptr == p)
- throw invalid_argument("stoi: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
+ throw_from_string_invalid_arg(func);
if (idx)
*idx = static_cast<size_t>(ptr - p);
+ return r;
+}
+
+template<typename V, typename S>
+inline
+V
+as_integer(const string& func, const S& s, size_t* idx, int base);
+
+// string
+template<>
+inline
+int
+as_integer(const string& func, const string& s, size_t* idx, int base )
+{
+ // Use long as no Stantard string to integer exists.
+ long r = as_integer_helper<long>( func, s, idx, base, strtol );
+ if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
+ throw_from_string_out_of_range(func);
return static_cast<int>(r);
}
+template<>
+inline
+long
+as_integer(const string& func, const string& s, size_t* idx, int base )
+{
+ return as_integer_helper<long>( func, s, idx, base, strtol );
+}
+
+template<>
+inline
+unsigned long
+as_integer( const string& func, const string& s, size_t* idx, int base )
+{
+ return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
+}
+
+template<>
+inline
+long long
+as_integer( const string& func, const string& s, size_t* idx, int base )
+{
+ return as_integer_helper<long long>( func, s, idx, base, strtoll );
+}
+
+template<>
+inline
+unsigned long long
+as_integer( const string& func, const string& s, size_t* idx, int base )
+{
+ return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
+}
+
+// wstring
+template<>
+inline
int
-stoi(const wstring& str, size_t* idx, int base)
+as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- long r = wcstol(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE || r < numeric_limits<int>::min() ||
- numeric_limits<int>::max() < r)
- throw out_of_range("stoi: out of range");
- if (ptr == p)
- throw invalid_argument("stoi: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
+ // Use long as no Stantard string to integer exists.
+ long r = as_integer_helper<long>( func, s, idx, base, wcstol );
+ if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
+ throw_from_string_out_of_range(func);
return static_cast<int>(r);
}
+template<>
+inline
long
-stol(const string& str, size_t* idx, int base)
+as_integer( const string& func, const wstring& s, size_t* idx, int base )
+{
+ return as_integer_helper<long>( func, s, idx, base, wcstol );
+}
+
+template<>
+inline
+unsigned long
+as_integer( const string& func, const wstring& s, size_t* idx, int base )
+{
+ return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
+}
+
+template<>
+inline
+long long
+as_integer( const string& func, const wstring& s, size_t* idx, int base )
+{
+ return as_integer_helper<long long>( func, s, idx, base, wcstoll );
+}
+
+template<>
+inline
+unsigned long long
+as_integer( const string& func, const wstring& s, size_t* idx, int base )
+{
+ return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
+}
+
+// as_float
+
+template<typename V, typename S, typename F>
+inline
+V
+as_float_helper(const string& func, const S& str, size_t* idx, F f )
{
- char* ptr;
- const char* const p = str.c_str();
+ typename S::value_type* ptr;
+ const typename S::value_type* const p = str.c_str();
typename remove_reference<decltype(errno)>::type errno_save = errno;
errno = 0;
- long r = strtol(p, &ptr, base);
+ V r = f(p, &ptr);
swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
if (errno_save == ERANGE)
- throw out_of_range("stol: out of range");
+ throw_from_string_out_of_range(func);
if (ptr == p)
- throw invalid_argument("stol: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
+ throw_from_string_invalid_arg(func);
if (idx)
*idx = static_cast<size_t>(ptr - p);
return r;
}
+template<typename V, typename S>
+inline
+V as_float( const string& func, const S& s, size_t* idx = nullptr );
+
+template<>
+inline
+float
+as_float( const string& func, const string& s, size_t* idx )
+{
+ return as_float_helper<float>( func, s, idx, strtof );
+}
+
+template<>
+inline
+double
+as_float(const string& func, const string& s, size_t* idx )
+{
+ return as_float_helper<double>( func, s, idx, strtod );
+}
+
+template<>
+inline
+long double
+as_float( const string& func, const string& s, size_t* idx )
+{
+ return as_float_helper<long double>( func, s, idx, strtold );
+}
+
+template<>
+inline
+float
+as_float( const string& func, const wstring& s, size_t* idx )
+{
+ return as_float_helper<float>( func, s, idx, wcstof );
+}
+
+template<>
+inline
+double
+as_float( const string& func, const wstring& s, size_t* idx )
+{
+ return as_float_helper<double>( func, s, idx, wcstod );
+}
+
+template<>
+inline
+long double
+as_float( const string& func, const wstring& s, size_t* idx )
+{
+ return as_float_helper<long double>( func, s, idx, wcstold );
+}
+
+} // unnamed namespace
+
+int
+stoi(const string& str, size_t* idx, int base)
+{
+ return as_integer<int>( "stoi", str, idx, base );
+}
+
+int
+stoi(const wstring& str, size_t* idx, int base)
+{
+ return as_integer<int>( "stoi", str, idx, base );
+}
+
+long
+stol(const string& str, size_t* idx, int base)
+{
+ return as_integer<long>( "stol", str, idx, base );
+}
+
long
stol(const wstring& str, size_t* idx, int base)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- long r = wcstol(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stol: out of range");
- if (ptr == p)
- throw invalid_argument("stol: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<long>( "stol", str, idx, base );
}
unsigned long
stoul(const string& str, size_t* idx, int base)
{
- char* ptr;
- const char* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- unsigned long r = strtoul(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stoul: out of range");
- if (ptr == p)
- throw invalid_argument("stoul: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<unsigned long>( "stoul", str, idx, base );
}
unsigned long
stoul(const wstring& str, size_t* idx, int base)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- unsigned long r = wcstoul(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stoul: out of range");
- if (ptr == p)
- throw invalid_argument("stoul: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<unsigned long>( "stoul", str, idx, base );
}
long long
stoll(const string& str, size_t* idx, int base)
{
- char* ptr;
- const char* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- long long r = strtoll(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stoll: out of range");
- if (ptr == p)
- throw invalid_argument("stoll: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<long long>( "stoll", str, idx, base );
}
long long
stoll(const wstring& str, size_t* idx, int base)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- long long r = wcstoll(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stoll: out of range");
- if (ptr == p)
- throw invalid_argument("stoll: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<long long>( "stoll", str, idx, base );
}
unsigned long long
stoull(const string& str, size_t* idx, int base)
{
- char* ptr;
- const char* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- unsigned long long r = strtoull(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stoull: out of range");
- if (ptr == p)
- throw invalid_argument("stoull: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<unsigned long long>( "stoull", str, idx, base );
}
unsigned long long
stoull(const wstring& str, size_t* idx, int base)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- unsigned long long r = wcstoull(p, &ptr, base);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stoull: out of range");
- if (ptr == p)
- throw invalid_argument("stoull: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_integer<unsigned long long>( "stoull", str, idx, base );
}
float
stof(const string& str, size_t* idx)
{
- char* ptr;
- const char* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- float r = strtof(p, &ptr);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stof: out of range");
- if (ptr == p)
- throw invalid_argument("stof: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_float<float>( "stof", str, idx );
}
float
stof(const wstring& str, size_t* idx)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- float r = wcstof(p, &ptr);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stof: out of range");
- if (ptr == p)
- throw invalid_argument("stof: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_float<float>( "stof", str, idx );
}
double
stod(const string& str, size_t* idx)
{
- char* ptr;
- const char* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- double r = strtod(p, &ptr);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stod: out of range");
- if (ptr == p)
- throw invalid_argument("stod: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_float<double>( "stod", str, idx );
}
double
stod(const wstring& str, size_t* idx)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- double r = wcstod(p, &ptr);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stod: out of range");
- if (ptr == p)
- throw invalid_argument("stod: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_float<double>( "stod", str, idx );
}
long double
stold(const string& str, size_t* idx)
{
- char* ptr;
- const char* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- long double r = strtold(p, &ptr);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stold: out of range");
- if (ptr == p)
- throw invalid_argument("stold: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_float<long double>( "stold", str, idx );
}
long double
stold(const wstring& str, size_t* idx)
{
- wchar_t* ptr;
- const wchar_t* const p = str.c_str();
- typename remove_reference<decltype(errno)>::type errno_save = errno;
- errno = 0;
- long double r = wcstold(p, &ptr);
- swap(errno, errno_save);
-#ifndef _LIBCPP_NO_EXCEPTIONS
- if (errno_save == ERANGE)
- throw out_of_range("stold: out of range");
- if (ptr == p)
- throw invalid_argument("stold: no conversion");
-#endif // _LIBCPP_NO_EXCEPTIONS
- if (idx)
- *idx = static_cast<size_t>(ptr - p);
- return r;
+ return as_float<long double>( "stold", str, idx );
}
-string to_string(int val)
+// to_string
+
+namespace
+{
+
+// as_string
+
+template<typename S, typename P, typename V >
+inline
+S
+as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
{
- string s;
- s.resize(s.capacity());
+ typedef typename S::size_type size_type;
+ size_type available = s.size();
while (true)
{
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%d", val));
- if (n2 <= s.size())
+ int status = sprintf_like(&s[0], available + 1, fmt, a);
+ if ( status >= 0 )
{
- s.resize(n2);
- break;
+ size_type used = static_cast<size_type>(status);
+ if ( used <= available )
+ {
+ s.resize( used );
+ break;
+ }
+ available = used; // Assume this is advice of how much space we need.
}
- s.resize(n2);
+ else
+ available = available * 2 + 1;
+ s.resize(available);
}
return s;
}
-string to_string(unsigned val)
+template <class S, class V, bool = is_floating_point<V>::value>
+struct initial_string;
+
+template <class V, bool b>
+struct initial_string<string, V, b>
{
- string s;
- s.resize(s.capacity());
- while (true)
+ string
+ operator()() const
{
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%u", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
+ string s;
+ s.resize(s.capacity());
+ return s;
}
- return s;
-}
+};
-string to_string(long val)
+template <class V>
+struct initial_string<wstring, V, false>
{
- string s;
- s.resize(s.capacity());
- while (true)
+ wstring
+ operator()() const
{
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%ld", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
+ const size_t n = (numeric_limits<unsigned long long>::digits / 3)
+ + ((numeric_limits<unsigned long long>::digits % 3) != 0)
+ + 1;
+ wstring s(n, wchar_t());
+ s.resize(s.capacity());
+ return s;
}
- return s;
-}
+};
-string to_string(unsigned long val)
+template <class V>
+struct initial_string<wstring, V, true>
{
- string s;
- s.resize(s.capacity());
- while (true)
+ wstring
+ operator()() const
{
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%lu", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
+ wstring s(20, wchar_t());
+ s.resize(s.capacity());
+ return s;
}
- return s;
+};
+
+typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
+
+inline
+wide_printf
+get_swprintf()
+{
+#ifndef _LIBCPP_MSVCRT
+ return swprintf;
+#else
+ return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(swprintf);
+#endif
+}
+
+} // unnamed namespace
+
+string to_string(int val)
+{
+ return as_string(snprintf, initial_string<string, int>()(), "%d", val);
+}
+
+string to_string(unsigned val)
+{
+ return as_string(snprintf, initial_string<string, unsigned>()(), "%u", val);
+}
+
+string to_string(long val)
+{
+ return as_string(snprintf, initial_string<string, long>()(), "%ld", val);
+}
+
+string to_string(unsigned long val)
+{
+ return as_string(snprintf, initial_string<string, unsigned long>()(), "%lu", val);
}
string to_string(long long val)
{
- string s;
- s.resize(s.capacity());
- while (true)
- {
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%lld", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
- }
- return s;
+ return as_string(snprintf, initial_string<string, long long>()(), "%lld", val);
}
string to_string(unsigned long long val)
{
- string s;
- s.resize(s.capacity());
- while (true)
- {
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%llu", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
- }
- return s;
+ return as_string(snprintf, initial_string<string, unsigned long long>()(), "%llu", val);
}
string to_string(float val)
{
- string s;
- s.resize(s.capacity());
- while (true)
- {
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%f", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
- }
- return s;
+ return as_string(snprintf, initial_string<string, float>()(), "%f", val);
}
string to_string(double val)
{
- string s;
- s.resize(s.capacity());
- while (true)
- {
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%f", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
- }
- return s;
+ return as_string(snprintf, initial_string<string, double>()(), "%f", val);
}
string to_string(long double val)
{
- string s;
- s.resize(s.capacity());
- while (true)
- {
- size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%Lf", val));
- if (n2 <= s.size())
- {
- s.resize(n2);
- break;
- }
- s.resize(n2);
- }
- return s;
+ return as_string(snprintf, initial_string<string, long double>()(), "%Lf", val);
}
wstring to_wstring(int val)
{
- const size_t n = (numeric_limits<int>::digits / 3)
- + ((numeric_limits<int>::digits % 3) != 0)
- + 1;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%d", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, int>()(), L"%d", val);
}
wstring to_wstring(unsigned val)
{
- const size_t n = (numeric_limits<unsigned>::digits / 3)
- + ((numeric_limits<unsigned>::digits % 3) != 0)
- + 1;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%u", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, unsigned>()(), L"%u", val);
}
wstring to_wstring(long val)
{
- const size_t n = (numeric_limits<long>::digits / 3)
- + ((numeric_limits<long>::digits % 3) != 0)
- + 1;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%ld", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, long>()(), L"%ld", val);
}
wstring to_wstring(unsigned long val)
{
- const size_t n = (numeric_limits<unsigned long>::digits / 3)
- + ((numeric_limits<unsigned long>::digits % 3) != 0)
- + 1;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%lu", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, unsigned long>()(), L"%lu", val);
}
wstring to_wstring(long long val)
{
- const size_t n = (numeric_limits<long long>::digits / 3)
- + ((numeric_limits<long long>::digits % 3) != 0)
- + 1;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%lld", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, long long>()(), L"%lld", val);
}
wstring to_wstring(unsigned long long val)
{
- const size_t n = (numeric_limits<unsigned long long>::digits / 3)
- + ((numeric_limits<unsigned long long>::digits % 3) != 0)
- + 1;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%llu", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, unsigned long long>()(), L"%llu", val);
}
wstring to_wstring(float val)
{
- const size_t n = 20;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%f", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, float>()(), L"%f", val);
}
wstring to_wstring(double val)
{
- const size_t n = 20;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%f", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, double>()(), L"%f", val);
}
wstring to_wstring(long double val)
{
- const size_t n = 20;
- wstring s(n, wchar_t());
- s.resize(s.capacity());
- while (true)
- {
- int n2 = swprintf(&s[0], s.size()+1, L"%Lf", val);
- if (n2 > 0)
- {
- s.resize(static_cast<size_t>(n2));
- break;
- }
- s.resize(2*s.size());
- s.resize(s.capacity());
- }
- return s;
+ return as_string(get_swprintf(), initial_string<wstring, long double>()(), L"%Lf", val);
}
-
_LIBCPP_END_NAMESPACE_STD
diff --git a/system/lib/libcxx/support/win32/locale_win32.cpp b/system/lib/libcxx/support/win32/locale_win32.cpp
index 02b5874e..a639ade4 100644
--- a/system/lib/libcxx/support/win32/locale_win32.cpp
+++ b/system/lib/libcxx/support/win32/locale_win32.cpp
@@ -9,8 +9,8 @@
//===----------------------------------------------------------------------===//
#include "support/win32/locale_win32.h"
-
-#include <stdarg.h> // va_start, va_end
+#include <cstdarg> // va_start, va_end
+#include <cwchar> // mbstate_t
// FIXME: base currently unused. Needs manual work to construct the new locale
locale_t newlocale( int mask, const char * locale, locale_t /*base*/ )
@@ -20,6 +20,8 @@ locale_t newlocale( int mask, const char * locale, locale_t /*base*/ )
locale_t uselocale( locale_t newloc )
{
locale_t old_locale = _get_current_locale();
+ if ( newloc == NULL )
+ return old_locale;
// uselocale sets the thread's locale by definition, so unconditionally use thread-local locale
_configthreadlocale( _ENABLE_PER_THREAD_LOCALE );
// uselocale sets all categories
diff --git a/system/lib/libcxx/support/win32/support.cpp b/system/lib/libcxx/support/win32/support.cpp
index 9e85077a..4215a700 100644
--- a/system/lib/libcxx/support/win32/support.cpp
+++ b/system/lib/libcxx/support/win32/support.cpp
@@ -8,63 +8,162 @@
//
//===----------------------------------------------------------------------===//
-#include <support/win32/support.h>
-#include <stdarg.h> // va_start, va_end
-#include <stddef.h> // size_t
-#include <stdlib.h> // malloc
-#include <stdio.h> // vsprintf, vsnprintf
-#include <string.h> // strcpy, wcsncpy
+#include <cstdarg> // va_start, va_end
+#include <cstddef> // size_t
+#include <cstdlib> // malloc
+#include <cstdio> // vsprintf, vsnprintf
+#include <cstring> // strcpy, wcsncpy
+#include <cwchar> // mbstate_t
+#include <memory> // unique_ptr
-int asprintf(char **sptr, const char *__restrict fmt, ...)
+namespace { // Private
+
+ struct free_deleter {
+ inline void operator()(char* p) { free(p); }
+ };
+}
+// Some of these functions aren't standard or if they conform, the name does not.
+
+int asprintf(char **sptr, const char *__restrict format, ...)
{
va_list ap;
- va_start(ap, fmt);
- int result = vasprintf(sptr, fmt, ap);
+ va_start(ap, format);
+ int result;
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ try {
+#endif
+ result = vasprintf(sptr, format, ap);
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ } catch( ... ) {
+ va_end(ap);
+ throw;
+ }
+#endif
va_end(ap);
return result;
}
-int vasprintf( char **sptr, const char *__restrict fmt, va_list ap )
+
+// Like sprintf, but when return value >= 0 it returns a pointer to a malloc'd string in *sptr.
+// If return >= 0, use free to delete *sptr.
+int vasprintf( char **sptr, const char *__restrict format, va_list ap )
{
*sptr = NULL;
- int count = vsnprintf( *sptr, 0, fmt, ap );
- if( (count >= 0) && ((*sptr = (char*)malloc(count+1)) != NULL) )
- {
- vsprintf( *sptr, fmt, ap );
- sptr[count] = '\0';
+ int count = _vsnprintf( NULL, 0, format, ap ); // Query the buffer size required.
+ if( count >= 0 ) {
+ std::unique_ptr<char, free_deleter> p( static_cast<char*>(malloc(count+1)) );
+ if ( ! p )
+ return -1;
+ if ( vsnprintf( p.get(), count+1, format, ap ) == count ) // We should have used exactly what was required.
+ *sptr = p.release();
+ else // Otherwise something is wrong, likely a bug in vsnprintf. If so free the memory and report the error.
+ return -1; // Pointer will get automaticlaly deleted.
}
return count;
}
-// FIXME: use wcrtomb and avoid copy
-// use mbsrtowcs which is available, first copy first nwc elements of src
+// Returns >= 0: the number of wide characters found in the multi byte sequence src (of src_size_bytes),
+// that fit in the buffer dst (of max_dest_chars elements size). The count returned excludes the null terminator.
+// When dst is NULL, no characters are copied and no "out" parameters are updated.
+// Returns (size_t) -1: an incomplete sequence encountered.
+// Leaves *src pointing the next character to convert or NULL if a null character was converted from *src.
size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
- size_t nmc, size_t len, mbstate_t *__restrict ps )
+ size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps )
{
- char* local_src = new char[nmc+1];
- char* nmcsrc = local_src;
- strncpy( nmcsrc, *src, nmc );
- nmcsrc[nmc] = '\0';
- const size_t result = mbsrtowcs( dst, const_cast<const char **>(&nmcsrc), len, ps );
- // propagate error
- if( nmcsrc == NULL )
- *src = NULL;
- delete[] local_src;
- return result;
+ const size_t terminated_sequence = static_cast<size_t>(0);
+ //const size_t invalid_sequence = static_cast<size_t>(-1);
+ const size_t incomplete_sequence = static_cast< size_t>(-2);
+
+ size_t dest_converted = 0;
+ size_t source_converted = 0;
+ size_t source_remaining = src_size_bytes;
+ size_t result = 0;
+ bool have_result = false;
+
+ while ( source_remaining ) {
+ if ( dst && dest_converted >= max_dest_chars )
+ break;
+ // Converts one multi byte character.
+ // if result > 0, it's the size in bytes of that character.
+ // othewise if result is zero it indicates the null character has been found.
+ // otherwise it's an error and errno may be set.
+ size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps );
+ // Don't do anything to change errno from here on.
+ if ( char_size > 0 ) {
+ source_remaining -= char_size;
+ source_converted += char_size;
+ ++dest_converted;
+ continue;
+ }
+ result = char_size;
+ have_result = true;
+ break;
+ }
+ if ( dst ) {
+ if ( have_result && result == terminated_sequence )
+ *src = NULL;
+ else
+ *src += source_converted;
+ }
+ if ( have_result && result != terminated_sequence && result != incomplete_sequence )
+ return static_cast<size_t>(-1);
+
+ return dest_converted;
}
-// FIXME: use wcrtomb and avoid copy
-// use wcsrtombs which is available, first copy first nwc elements of src
+
+// Converts max_source_chars from the wide character buffer pointer to by *src,
+// into the multi byte character sequence buffer stored at dst which must be dst_size_bytes bytes in size.
+// Returns >= 0: the number of bytes in the sequence sequence converted frome *src, excluding the null terminator.
+// Returns size_t(-1) if an error occurs, also sets errno.
+// If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst and no "out" parameters are updated.
size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
- size_t nwc, size_t len, mbstate_t *__restrict ps )
+ size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps )
{
- wchar_t* local_src = new wchar_t[nwc];
- wchar_t* nwcsrc = local_src;
- wcsncpy(nwcsrc, *src, nwc);
- nwcsrc[nwc] = '\0';
- const size_t result = wcsrtombs( dst, const_cast<const wchar_t **>(&nwcsrc), len, ps );
- // propogate error
- if( nwcsrc == NULL )
- *src = NULL;
- delete[] nwcsrc;
- return result;
+ //const size_t invalid_sequence = static_cast<size_t>(-1);
+
+ size_t source_converted = 0;
+ size_t dest_converted = 0;
+ size_t dest_remaining = dst_size_bytes;
+ size_t char_size = 0;
+ const errno_t no_error = ( errno_t) 0;
+ errno_t result = ( errno_t ) 0;
+ bool have_result = false;
+ bool terminator_found = false;
+
+ while ( source_converted != max_source_chars ) {
+ if ( ! dest_remaining )
+ break;
+ wchar_t c = (*src)[source_converted];
+ if ( dst )
+ result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps);
+ else
+ result = wcrtomb_s( &char_size, NULL, 0, c, ps);
+ // If result is zero there is no error and char_size contains the size of the multi-byte-sequence converted.
+ // Otherwise result indicates an errno type error.
+ if ( result == no_error ) {
+ if ( c == L'\0' ) {
+ terminator_found = true;
+ break;
+ }
+ ++source_converted;
+ if ( dst )
+ dest_remaining -= char_size;
+ dest_converted += char_size;
+ continue;
+ }
+ have_result = true;
+ break;
+ }
+ if ( dst ) {
+ if ( terminator_found )
+ *src = NULL;
+ else
+ *src = *src + source_converted;
+ }
+ if ( have_result && result != no_error ) {
+ errno = result;
+ return static_cast<size_t>(-1);
+ }
+
+ return dest_converted;
}
diff --git a/system/lib/libcxx/symbols b/system/lib/libcxx/symbols
index 84f4ddc9..92a665d8 100644
--- a/system/lib/libcxx/symbols
+++ b/system/lib/libcxx/symbols
@@ -77,13 +77,13 @@
W _ZNKSt3__110moneypunctIwLb1EE16do_positive_signEv
W _ZNKSt3__110moneypunctIwLb1EE16do_thousands_sepEv
W _ZNKSt3__110moneypunctIwLb1EE8groupingEv
- T _ZNKSt3__111__libcpp_db12__comparableEPKvS2_
T _ZNKSt3__111__libcpp_db15__decrementableEPKv
T _ZNKSt3__111__libcpp_db15__find_c_from_iEPv
T _ZNKSt3__111__libcpp_db15__find_iteratorEPKv
T _ZNKSt3__111__libcpp_db15__subscriptableEPKvi
T _ZNKSt3__111__libcpp_db17__dereferenceableEPKv
T _ZNKSt3__111__libcpp_db17__find_c_and_lockEPv
+ T _ZNKSt3__111__libcpp_db22__less_than_comparableEPKvS2_
T _ZNKSt3__111__libcpp_db6unlockEv
T _ZNKSt3__111__libcpp_db8__find_cEPv
T _ZNKSt3__111__libcpp_db9__addableEPKvi
@@ -372,8 +372,6 @@
W _ZNKSt3__117moneypunct_bynameIwLb1EE16do_negative_signEv
W _ZNKSt3__117moneypunct_bynameIwLb1EE16do_positive_signEv
W _ZNKSt3__117moneypunct_bynameIwLb1EE16do_thousands_sepEv
- C _ZNKSt3__118__hidden_allocatorINS_4pairIPNS_18condition_variableEPNS_5mutexEEEE8max_sizeEv
- C _ZNKSt3__118__hidden_allocatorIPNS_17__assoc_sub_stateEE8max_sizeEv
T _ZNKSt3__118__time_get_storageIcE15__do_date_orderEv
T _ZNKSt3__118__time_get_storageIwE15__do_date_orderEv
T _ZNKSt3__119__iostream_category4nameEv
@@ -448,15 +446,10 @@
T _ZNKSt3__15ctypeIwE9do_narrowEPKwS3_cPc
T _ZNKSt3__15ctypeIwE9do_narrowEwc
T _ZNKSt3__16locale4nameEv
- C _ZNKSt3__16locale5__imp4nameEv
- C _ZNKSt3__16locale5__imp9has_facetEl
T _ZNKSt3__16locale5__imp9use_facetEl
T _ZNKSt3__16locale9has_facetERNS0_2idE
T _ZNKSt3__16locale9use_facetERNS0_2idE
T _ZNKSt3__16localeeqERKS0_
- C _ZNKSt3__16vectorINS_4pairIPNS_18condition_variableEPNS_5mutexEEENS_18__hidden_allocatorIS6_EEE8max_sizeEv
- C _ZNKSt3__16vectorIPNS_17__assoc_sub_stateENS_18__hidden_allocatorIS2_EEE8max_sizeEv
- C _ZNKSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE8max_sizeEv
T _ZNKSt3__17codecvtIDic10_mbstate_tE10do_unshiftERS1_PcS4_RS4_
T _ZNKSt3__17codecvtIDic10_mbstate_tE11do_encodingEv
T _ZNKSt3__17codecvtIDic10_mbstate_tE13do_max_lengthEv
@@ -758,29 +751,23 @@
T _ZNSt16nested_exceptionD0Ev
T _ZNSt16nested_exceptionD1Ev
T _ZNSt16nested_exceptionD2Ev
- C _ZNSt3__110__find_endIRNS_11__traits_eqINS_11char_traitsIcEEEEPKcS7_EET0_S8_S8_T1_S9_T_NS_26random_access_iterator_tagESB_
- C _ZNSt3__110__find_endIRNS_11__traits_eqINS_11char_traitsIwEEEEPKwS7_EET0_S8_S8_T1_S9_T_NS_26random_access_iterator_tagESB_
C _ZNSt3__110__sscanf_lEPKcPvS1_z
C _ZNSt3__110__stdinbufIcE5imbueERKNS_6localeE
C _ZNSt3__110__stdinbufIcE5uflowEv
C _ZNSt3__110__stdinbufIcE9__getcharEb
C _ZNSt3__110__stdinbufIcE9pbackfailEi
C _ZNSt3__110__stdinbufIcE9underflowEv
- C _ZNSt3__110__stdinbufIcEC1EP7__sFILEP10_mbstate_t
C _ZNSt3__110__stdinbufIcEC2EP7__sFILEP10_mbstate_t
C _ZNSt3__110__stdinbufIcED0Ev
C _ZNSt3__110__stdinbufIcED1Ev
- C _ZNSt3__110__stdinbufIcED2Ev
C _ZNSt3__110__stdinbufIwE5imbueERKNS_6localeE
C _ZNSt3__110__stdinbufIwE5uflowEv
C _ZNSt3__110__stdinbufIwE9__getcharEb
- C _ZNSt3__110__stdinbufIwE9pbackfailEj
+ C _ZNSt3__110__stdinbufIwE9pbackfailEi
C _ZNSt3__110__stdinbufIwE9underflowEv
- C _ZNSt3__110__stdinbufIwEC1EP7__sFILEP10_mbstate_t
C _ZNSt3__110__stdinbufIwEC2EP7__sFILEP10_mbstate_t
C _ZNSt3__110__stdinbufIwED0Ev
C _ZNSt3__110__stdinbufIwED1Ev
- C _ZNSt3__110__stdinbufIwED2Ev
T _ZNSt3__110__time_getC1EPKc
T _ZNSt3__110__time_getC1ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
T _ZNSt3__110__time_getC2EPKc
@@ -878,23 +865,16 @@
W _ZNSt3__111__money_putIwE8__formatEPwRS2_S3_jPKwS5_RKNS_5ctypeIwEEbRKNS_10money_base7patternEwwRKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEERKNSE_IwNSF_IwEENSH_IwEEEESQ_i
W _ZNSt3__111__money_putIwEC1Ev
W _ZNSt3__111__money_putIwEC2Ev
- C _ZNSt3__111__sprintf_lEPcPvPKcz
C _ZNSt3__111__stdoutbufIcE4syncEv
C _ZNSt3__111__stdoutbufIcE5imbueERKNS_6localeE
C _ZNSt3__111__stdoutbufIcE8overflowEi
- C _ZNSt3__111__stdoutbufIcEC1EP7__sFILEP10_mbstate_t
- C _ZNSt3__111__stdoutbufIcEC2EP7__sFILEP10_mbstate_t
C _ZNSt3__111__stdoutbufIcED0Ev
C _ZNSt3__111__stdoutbufIcED1Ev
- C _ZNSt3__111__stdoutbufIcED2Ev
C _ZNSt3__111__stdoutbufIwE4syncEv
C _ZNSt3__111__stdoutbufIwE5imbueERKNS_6localeE
- C _ZNSt3__111__stdoutbufIwE8overflowEj
- C _ZNSt3__111__stdoutbufIwEC1EP7__sFILEP10_mbstate_t
- C _ZNSt3__111__stdoutbufIwEC2EP7__sFILEP10_mbstate_t
+ C _ZNSt3__111__stdoutbufIwE8overflowEi
C _ZNSt3__111__stdoutbufIwED0Ev
C _ZNSt3__111__stdoutbufIwED1Ev
- C _ZNSt3__111__stdoutbufIwED2Ev
T _ZNSt3__111regex_errorC1ENS_15regex_constants10error_typeE
T _ZNSt3__111regex_errorC2ENS_15regex_constants10error_typeE
T _ZNSt3__111regex_errorD0Ev
@@ -909,17 +889,12 @@
T _ZNSt3__111timed_mutexD1Ev
T _ZNSt3__111timed_mutexD2Ev
D _ZNSt3__111try_to_lockE
- C _ZNSt3__111unique_lockINS_5mutexEE6unlockEv
C _ZNSt3__112__asprintf_lEPPcPvPKcz
- C _ZNSt3__112__do_messageC2Ev
C _ZNSt3__112__do_messageD0Ev
C _ZNSt3__112__do_messageD1Ev
- C _ZNSt3__112__do_messageD2Ev
T _ZNSt3__112__do_nothingEPv
T _ZNSt3__112__get_sp_mutEPKv
T _ZNSt3__112__next_primeEj
- C _ZNSt3__112__rotate_gcdINS_11__wrap_iterIPcEEEET_S4_S4_S4_
- C _ZNSt3__112__rotate_gcdINS_11__wrap_iterIPwEEEET_S4_S4_S4_
D _ZNSt3__112__rs_default4__c_E
T _ZNSt3__112__rs_defaultC1ERKS0_
T _ZNSt3__112__rs_defaultC1Ev
@@ -972,7 +947,6 @@
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcj
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcjj
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEjc
- C _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initIPKcEENS_9enable_ifIXsr21__is_forward_iteratorIT_EE5valueEvE4typeESA_SA_
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__zeroEv
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcj
@@ -1011,7 +985,6 @@
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7replaceEjjRKS5_
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7replaceEjjRKS5_jj
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7replaceEjjjc
- C _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7replaceIPKcEENS_9enable_ifIXsr19__is_input_iteratorIT_EE5valueERS5_E4typeENS_11__wrap_iterIS8_EESF_SA_SA_
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7reserveEj
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE8pop_backEv
W _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__grow_byEjjjjjj
@@ -1098,7 +1071,6 @@
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initEPKwj
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initEPKwjj
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initEjw
- C _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__initIPKwEENS_9enable_ifIXsr21__is_forward_iteratorIT_EE5valueEvE4typeESA_SA_
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6__zeroEv
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6appendEPKw
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6appendEPKwj
@@ -1138,7 +1110,6 @@
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE7replaceEjjRKS5_
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE7replaceEjjRKS5_jj
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE7replaceEjjjw
- C _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE7replaceIPKwEENS_9enable_ifIXsr19__is_input_iteratorIT_EE5valueERS5_E4typeENS_11__wrap_iterIS8_EESF_SA_SA_
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE7reserveEj
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE8pop_backEv
W _ZNSt3__112basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE9__grow_byEjjjjjj
@@ -1200,9 +1171,7 @@
T _ZNSt3__112ctype_bynameIwED1Ev
T _ZNSt3__112ctype_bynameIwED2Ev
T _ZNSt3__112future_errorC1ENS_10error_codeE
- C _ZNSt3__112future_errorC1ERKS0_
T _ZNSt3__112future_errorC2ENS_10error_codeE
- C _ZNSt3__112future_errorC2ERKS0_
T _ZNSt3__112future_errorD0Ev
T _ZNSt3__112future_errorD1Ev
T _ZNSt3__112future_errorD2Ev
@@ -1260,12 +1229,6 @@
T _ZNSt3__112system_errorD0Ev
T _ZNSt3__112system_errorD1Ev
T _ZNSt3__112system_errorD2Ev
- C _ZNSt3__113__lower_boundIRNS_6__lessIjjEEPKjjEET0_S6_S6_RKT1_T_
- C _ZNSt3__113__rotate_leftINS_11__wrap_iterIPcEEEET_S4_S4_
- C _ZNSt3__113__rotate_leftINS_11__wrap_iterIPwEEEET_S4_S4_
- C _ZNSt3__113__vector_baseINS_4pairIPNS_18condition_variableEPNS_5mutexEEENS_18__hidden_allocatorIS6_EEED2Ev
- C _ZNSt3__113__vector_baseIPNS_17__assoc_sub_stateENS_18__hidden_allocatorIS2_EEED2Ev
- C _ZNSt3__113__vector_baseIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEED2Ev
D _ZNSt3__113allocator_argE
W _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE3getEPci
W _ZNSt3__113basic_istreamIcNS_11char_traitsIcEEE3getEPcic
@@ -1327,7 +1290,7 @@
W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE5seekgExNS_8ios_base7seekdirE
W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE5tellgEv
W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE5ungetEv
- W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE6ignoreEij
+ W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE6ignoreEii
W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE6sentryC1ERS3_b
W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE6sentryC2ERS3_b
W _ZNSt3__113basic_istreamIwNS_11char_traitsIwEEE7getlineEPwi
@@ -1435,8 +1398,6 @@
W _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEElsEt
W _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEElsEx
W _ZNSt3__113basic_ostreamIwNS_11char_traitsIwEEElsEy
- C _ZNSt3__113find_first_ofIPKcS2_NS_11__traits_eqINS_11char_traitsIcEEEEEET_S7_S7_T0_S8_T1_
- C _ZNSt3__113find_first_ofIPKwS2_NS_11__traits_eqINS_11char_traitsIwEEEEEET_S7_S7_T0_S8_T1_
T _ZNSt3__113random_deviceC1ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
T _ZNSt3__113random_deviceC2ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
T _ZNSt3__113random_deviceD1Ev
@@ -1447,21 +1408,16 @@
T _ZNSt3__113shared_futureIvEaSERKS1_
C _ZNSt3__114__codecvt_utf8IDiED0Ev
C _ZNSt3__114__codecvt_utf8IDiED1Ev
- C _ZNSt3__114__codecvt_utf8IDiED2Ev
C _ZNSt3__114__codecvt_utf8IDsED0Ev
C _ZNSt3__114__codecvt_utf8IDsED1Ev
- C _ZNSt3__114__codecvt_utf8IDsED2Ev
C _ZNSt3__114__codecvt_utf8IwED0Ev
C _ZNSt3__114__codecvt_utf8IwED1Ev
- C _ZNSt3__114__codecvt_utf8IwED2Ev
T _ZNSt3__114__get_const_dbEv
T _ZNSt3__114__num_get_base10__get_baseERNS_8ios_baseE
D _ZNSt3__114__num_get_base5__srcE
T _ZNSt3__114__num_put_base12__format_intEPcPKcbj
T _ZNSt3__114__num_put_base14__format_floatEPcPKcj
T _ZNSt3__114__num_put_base18__identify_paddingEPcS1_RKNS_8ios_baseE
- C _ZNSt3__114__rotate_rightINS_11__wrap_iterIPcEEEET_S4_S4_
- C _ZNSt3__114__rotate_rightINS_11__wrap_iterIPwEEEET_S4_S4_
C _ZNSt3__114__scan_keywordINS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEPKNS_12basic_stringIcS3_NS_9allocatorIcEEEENS_5ctypeIcEEEET0_RT_SE_SD_SD_RKT1_Rjb
C _ZNSt3__114__scan_keywordINS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEPKNS_12basic_stringIwS3_NS_9allocatorIwEEEENS_5ctypeIwEEEET0_RT_SE_SD_SD_RKT1_Rjb
C _ZNSt3__114__scan_keywordIPcPNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_5ctypeIcEEEET0_RT_SC_SB_SB_RKT1_Rjb
@@ -1471,19 +1427,6 @@
T _ZNSt3__114__shared_countD0Ev
T _ZNSt3__114__shared_countD1Ev
T _ZNSt3__114__shared_countD2Ev
- C _ZNSt3__114__split_bufferINS_4pairIPNS_18condition_variableEPNS_5mutexEEERNS_18__hidden_allocatorIS6_EEEC1EjjS9_
- C _ZNSt3__114__split_bufferINS_4pairIPNS_18condition_variableEPNS_5mutexEEERNS_18__hidden_allocatorIS6_EEEC2EjjS9_
- C _ZNSt3__114__split_bufferINS_4pairIPNS_18condition_variableEPNS_5mutexEEERNS_18__hidden_allocatorIS6_EEED1Ev
- C _ZNSt3__114__split_bufferINS_4pairIPNS_18condition_variableEPNS_5mutexEEERNS_18__hidden_allocatorIS6_EEED2Ev
- C _ZNSt3__114__split_bufferIPNS_17__assoc_sub_stateERNS_18__hidden_allocatorIS2_EEEC1EjjS5_
- C _ZNSt3__114__split_bufferIPNS_17__assoc_sub_stateERNS_18__hidden_allocatorIS2_EEEC2EjjS5_
- C _ZNSt3__114__split_bufferIPNS_17__assoc_sub_stateERNS_18__hidden_allocatorIS2_EEED1Ev
- C _ZNSt3__114__split_bufferIPNS_17__assoc_sub_stateERNS_18__hidden_allocatorIS2_EEED2Ev
- C _ZNSt3__114__split_bufferIPNS_6locale5facetERNS_15__sso_allocatorIS3_Lj28EEEE18__construct_at_endEj
- C _ZNSt3__114__split_bufferIPNS_6locale5facetERNS_15__sso_allocatorIS3_Lj28EEEEC1EjjS6_
- C _ZNSt3__114__split_bufferIPNS_6locale5facetERNS_15__sso_allocatorIS3_Lj28EEEEC2EjjS6_
- C _ZNSt3__114__split_bufferIPNS_6locale5facetERNS_15__sso_allocatorIS3_Lj28EEEED1Ev
- C _ZNSt3__114__split_bufferIPNS_6locale5facetERNS_15__sso_allocatorIS3_Lj28EEEED2Ev
W _ZNSt3__114basic_iostreamIcNS_11char_traitsIcEEE4swapERS3_
W _ZNSt3__114basic_iostreamIcNS_11char_traitsIcEEEC1EOS3_
W _ZNSt3__114basic_iostreamIcNS_11char_traitsIcEEEC1EPNS_15basic_streambufIcS2_EE
@@ -1541,22 +1484,16 @@
T _ZNSt3__114error_categoryD2Ev
C _ZNSt3__115__codecvt_utf16IDiLb0EED0Ev
C _ZNSt3__115__codecvt_utf16IDiLb0EED1Ev
- C _ZNSt3__115__codecvt_utf16IDiLb0EED2Ev
C _ZNSt3__115__codecvt_utf16IDiLb1EED0Ev
C _ZNSt3__115__codecvt_utf16IDiLb1EED1Ev
- C _ZNSt3__115__codecvt_utf16IDiLb1EED2Ev
C _ZNSt3__115__codecvt_utf16IDsLb0EED0Ev
C _ZNSt3__115__codecvt_utf16IDsLb0EED1Ev
- C _ZNSt3__115__codecvt_utf16IDsLb0EED2Ev
C _ZNSt3__115__codecvt_utf16IDsLb1EED0Ev
C _ZNSt3__115__codecvt_utf16IDsLb1EED1Ev
- C _ZNSt3__115__codecvt_utf16IDsLb1EED2Ev
C _ZNSt3__115__codecvt_utf16IwLb0EED0Ev
C _ZNSt3__115__codecvt_utf16IwLb0EED1Ev
- C _ZNSt3__115__codecvt_utf16IwLb0EED2Ev
C _ZNSt3__115__codecvt_utf16IwLb1EED0Ev
C _ZNSt3__115__codecvt_utf16IwLb1EED1Ev
- C _ZNSt3__115__codecvt_utf16IwLb1EED2Ev
T _ZNSt3__115__get_classnameEPKcb
C _ZNSt3__115__num_get_floatIdEET_PKcS3_Rj
C _ZNSt3__115__num_get_floatIeEET_PKcS3_Rj
@@ -1567,20 +1504,10 @@
T _ZNSt3__115__thread_structC2Ev
T _ZNSt3__115__thread_structD1Ev
T _ZNSt3__115__thread_structD2Ev
- C _ZNSt3__115__time_get_tempIcEC1EPKc
- C _ZNSt3__115__time_get_tempIcEC1ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
- C _ZNSt3__115__time_get_tempIcEC2EPKc
- C _ZNSt3__115__time_get_tempIcEC2ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
C _ZNSt3__115__time_get_tempIcED0Ev
C _ZNSt3__115__time_get_tempIcED1Ev
- C _ZNSt3__115__time_get_tempIcED2Ev
- C _ZNSt3__115__time_get_tempIwEC1EPKc
- C _ZNSt3__115__time_get_tempIwEC1ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
- C _ZNSt3__115__time_get_tempIwEC2EPKc
- C _ZNSt3__115__time_get_tempIwEC2ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
C _ZNSt3__115__time_get_tempIwED0Ev
C _ZNSt3__115__time_get_tempIwED1Ev
- C _ZNSt3__115__time_get_tempIwED2Ev
W _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE10pubseekoffExNS_8ios_base7seekdirEj
W _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE10pubseekposENS_4fposI10_mbstate_tEEj
W _ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE4setgEPcS4_S4_
@@ -1644,9 +1571,9 @@
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE7seekposENS_4fposI10_mbstate_tEEj
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE7sungetcEv
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE8in_availEv
- W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE8overflowEj
+ W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE8overflowEi
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE8pubimbueERKNS_6localeE
- W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9pbackfailEj
+ W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9pbackfailEi
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9pubsetbufEPwi
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9showmanycEv
W _ZNSt3__115basic_streambufIwNS_11char_traitsIwEEE9sputbackcEw
@@ -1748,7 +1675,6 @@
T _ZNSt3__117__assoc_sub_state9set_valueEv
C _ZNSt3__117__assoc_sub_stateD0Ev
C _ZNSt3__117__assoc_sub_stateD1Ev
- C _ZNSt3__117__assoc_sub_stateD2Ev
T _ZNSt3__117__widen_from_utf8ILj16EED0Ev
T _ZNSt3__117__widen_from_utf8ILj16EED1Ev
T _ZNSt3__117__widen_from_utf8ILj16EED2Ev
@@ -1789,25 +1715,6 @@
W _ZNSt3__117moneypunct_bynameIwLb1EED0Ev
W _ZNSt3__117moneypunct_bynameIwLb1EED1Ev
W _ZNSt3__117moneypunct_bynameIwLb1EED2Ev
- C _ZNSt3__118__hidden_allocatorINS_4pairIPNS_18condition_variableEPNS_5mutexEEEE10deallocateEPS6_j
- C _ZNSt3__118__hidden_allocatorINS_4pairIPNS_18condition_variableEPNS_5mutexEEEE8allocateEj
- C _ZNSt3__118__hidden_allocatorIPNS_17__assoc_sub_stateEE10deallocateEPS2_j
- C _ZNSt3__118__hidden_allocatorIPNS_17__assoc_sub_stateEE8allocateEj
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIaaEEPaEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIccEEPcEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIddEEPdEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIeeEEPeEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIffEEPfEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIhhEEPhEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIiiEEPiEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIjjEEPjEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIllEEPlEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessImmEEPmEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIssEEPsEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIttEEPtEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIwwEEPwEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIxxEEPxEEvT0_S5_T_
- C _ZNSt3__118__insertion_sort_3IRNS_6__lessIyyEEPyEEvT0_S5_T_
T _ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE
T _ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE
T _ZNSt3__118__time_get_storageIcEC1EPKc
@@ -1827,14 +1734,9 @@
T _ZNSt3__118condition_variableD1Ev
T _ZNSt3__118condition_variableD2Ev
T _ZNSt3__118get_pointer_safetyEv
- C _ZNSt3__119__double_or_nothingIcEEvRNS_10unique_ptrIT_PFvPvEEERPS2_S9_
- C _ZNSt3__119__double_or_nothingIjEEvRNS_10unique_ptrIT_PFvPvEEERPS2_S9_
C _ZNSt3__119__double_or_nothingIwEEvRNS_10unique_ptrIT_PFvPvEEERPS2_S9_
- C _ZNSt3__119__iostream_categoryC1Ev
- C _ZNSt3__119__iostream_categoryC2Ev
C _ZNSt3__119__iostream_categoryD0Ev
C _ZNSt3__119__iostream_categoryD1Ev
- C _ZNSt3__119__iostream_categoryD2Ev
T _ZNSt3__119__shared_weak_count10__add_weakEv
T _ZNSt3__119__shared_weak_count12__add_sharedEv
T _ZNSt3__119__shared_weak_count14__release_weakEv
@@ -1847,37 +1749,25 @@
T _ZNSt3__119__thread_local_dataEv
T _ZNSt3__119__thread_struct_imp25notify_all_at_thread_exitEPNS_18condition_variableEPNS_5mutexE
T _ZNSt3__119__thread_struct_imp27__make_ready_at_thread_exitEPNS_17__assoc_sub_stateE
- C _ZNSt3__119__thread_struct_impC1Ev
- C _ZNSt3__119__thread_struct_impC2Ev
T _ZNSt3__119__thread_struct_impD1Ev
T _ZNSt3__119__thread_struct_impD2Ev
T _ZNSt3__119declare_no_pointersEPcj
D _ZNSt3__119piecewise_constructE
C _ZNSt3__120__codecvt_utf8_utf16IDiED0Ev
C _ZNSt3__120__codecvt_utf8_utf16IDiED1Ev
- C _ZNSt3__120__codecvt_utf8_utf16IDiED2Ev
C _ZNSt3__120__codecvt_utf8_utf16IDsED0Ev
C _ZNSt3__120__codecvt_utf8_utf16IDsED1Ev
- C _ZNSt3__120__codecvt_utf8_utf16IDsED2Ev
C _ZNSt3__120__codecvt_utf8_utf16IwED0Ev
C _ZNSt3__120__codecvt_utf8_utf16IwED1Ev
- C _ZNSt3__120__codecvt_utf8_utf16IwED2Ev
T _ZNSt3__120__get_collation_nameEPKc
C _ZNSt3__120__get_up_to_n_digitsIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEiRT0_S5_RjRKNS_5ctypeIT_EEi
C _ZNSt3__120__get_up_to_n_digitsIcPcEEiRT0_S2_RjRKNS_5ctypeIT_EEi
C _ZNSt3__120__get_up_to_n_digitsIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEiRT0_S5_RjRKNS_5ctypeIT_EEi
- C _ZNSt3__120__get_up_to_n_digitsIwPwEEiRT0_S2_RjRKNS_5ctypeIT_EEi
T _ZNSt3__120__throw_system_errorEiPKc
- C _ZNSt3__120__time_get_c_storageIcEC2Ev
- C _ZNSt3__120__time_get_c_storageIwEC2Ev
W _ZNSt3__120__vector_base_commonILb1EEC1Ev
W _ZNSt3__120__vector_base_commonILb1EEC2Ev
- C _ZNSt3__121__murmur2_or_cityhashIjLj32EEclEPKvj
C _ZNSt3__121__thread_specific_ptrINS_15__thread_structEE16__at_thread_exitEPv
- C _ZNSt3__121__thread_specific_ptrINS_15__thread_structEEC1Ev
- C _ZNSt3__121__thread_specific_ptrINS_15__thread_structEEC2Ev
C _ZNSt3__121__thread_specific_ptrINS_15__thread_structEED1Ev
- C _ZNSt3__121__thread_specific_ptrINS_15__thread_structEED2Ev
T _ZNSt3__121__throw_runtime_errorEPKc
T _ZNSt3__121__undeclare_reachableEPv
T _ZNSt3__121recursive_timed_mutex4lockEv
@@ -1888,24 +1778,12 @@
T _ZNSt3__121recursive_timed_mutexD1Ev
T _ZNSt3__121recursive_timed_mutexD2Ev
T _ZNSt3__121undeclare_no_pointersEPcj
- C _ZNSt3__122__release_shared_countclEPNS_14__shared_countE
- C _ZNSt3__123__future_error_categoryC1Ev
- C _ZNSt3__123__future_error_categoryC2Ev
C _ZNSt3__123__future_error_categoryD0Ev
C _ZNSt3__123__future_error_categoryD1Ev
- C _ZNSt3__123__future_error_categoryD2Ev
- C _ZNSt3__123__system_error_categoryC1Ev
- C _ZNSt3__123__system_error_categoryC2Ev
C _ZNSt3__123__system_error_categoryD0Ev
C _ZNSt3__123__system_error_categoryD1Ev
- C _ZNSt3__123__system_error_categoryD2Ev
- C _ZNSt3__123mersenne_twister_engineIjLj32ELj624ELj397ELj31ELj2567483615ELj11ELj4294967295ELj7ELj2636928640ELj15ELj4022730752ELj18ELj1812433253EE4seedEj
- C _ZNSt3__123mersenne_twister_engineIjLj32ELj624ELj397ELj31ELj2567483615ELj11ELj4294967295ELj7ELj2636928640ELj15ELj4022730752ELj18ELj1812433253EEclEv
- C _ZNSt3__124__generic_error_categoryC1Ev
- C _ZNSt3__124__generic_error_categoryC2Ev
C _ZNSt3__124__generic_error_categoryD0Ev
C _ZNSt3__124__generic_error_categoryD1Ev
- C _ZNSt3__124__generic_error_categoryD2Ev
C _ZNSt3__125__num_get_signed_integralIlEET_PKcS3_Rji
C _ZNSt3__125__num_get_signed_integralIxEET_PKcS3_Rji
T _ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE
@@ -2005,84 +1883,8 @@
D _ZNSt3__16locale4noneE
D _ZNSt3__16locale4timeE
T _ZNSt3__16locale5__imp11make_globalEv
- C _ZNSt3__16locale5__imp12install_fromINS_10moneypunctIcLb0EEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_10moneypunctIcLb1EEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_10moneypunctIwLb0EEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_10moneypunctIwLb1EEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_5ctypeIcEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_5ctypeIwEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7codecvtIDic10_mbstate_tEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7codecvtIDsc10_mbstate_tEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7codecvtIcc10_mbstate_tEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7codecvtIwc10_mbstate_tEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7collateIcEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7collateIwEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7num_getIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7num_getIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7num_putIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_7num_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8messagesIcEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8messagesIwEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8numpunctIcEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8numpunctIwEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8time_getIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8time_getIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8time_putIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_8time_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_9money_getIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_9money_getIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_9money_putIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvRKS1_
- C _ZNSt3__16locale5__imp12install_fromINS_9money_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvRKS1_
T _ZNSt3__16locale5__imp12make_classicEv
T _ZNSt3__16locale5__imp7installEPNS0_5facetEl
- C _ZNSt3__16locale5__imp7installINS_10moneypunctIcLb0EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_10moneypunctIcLb1EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_10moneypunctIwLb0EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_10moneypunctIwLb1EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_12ctype_bynameIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_12ctype_bynameIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_14codecvt_bynameIDic10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_14codecvt_bynameIDsc10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_14codecvt_bynameIcc10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_14codecvt_bynameIwc10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_14collate_bynameIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_14collate_bynameIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15messages_bynameIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15messages_bynameIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15numpunct_bynameIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15numpunct_bynameIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15time_get_bynameIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15time_get_bynameIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15time_put_bynameIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_15time_put_bynameIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_17moneypunct_bynameIcLb0EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_17moneypunct_bynameIcLb1EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_17moneypunct_bynameIwLb0EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_17moneypunct_bynameIwLb1EEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_5ctypeIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_5ctypeIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7codecvtIDic10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7codecvtIDsc10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7codecvtIcc10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7codecvtIwc10_mbstate_tEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7collateIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7collateIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7num_getIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7num_getIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7num_putIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_7num_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8messagesIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8messagesIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8numpunctIcEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8numpunctIwEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8time_getIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8time_getIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8time_putIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_8time_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_9money_getIcNS_19istreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_9money_getIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_9money_putIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEEEEvPT_
- C _ZNSt3__16locale5__imp7installINS_9money_putIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEEEEvPT_
T _ZNSt3__16locale5__impC1ERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEj
T _ZNSt3__16locale5__impC1ERKS1_
T _ZNSt3__16locale5__impC1ERKS1_PNS0_5facetEl
@@ -2135,55 +1937,10 @@
T _ZNSt3__16threadD1Ev
T _ZNSt3__16threadD2Ev
C _ZNSt3__16vectorINS_4pairIPNS_18condition_variableEPNS_5mutexEEENS_18__hidden_allocatorIS6_EEE21__push_back_slow_pathIS6_EEvOT_
- C _ZNSt3__16vectorINS_4pairIPNS_18condition_variableEPNS_5mutexEEENS_18__hidden_allocatorIS6_EEE26__swap_out_circular_bufferERNS_14__split_bufferIS6_RS8_EE
- C _ZNSt3__16vectorINS_4pairIPNS_18condition_variableEPNS_5mutexEEENS_18__hidden_allocatorIS6_EEED1Ev
- C _ZNSt3__16vectorINS_4pairIPNS_18condition_variableEPNS_5mutexEEENS_18__hidden_allocatorIS6_EEED2Ev
C _ZNSt3__16vectorIPNS_17__assoc_sub_stateENS_18__hidden_allocatorIS2_EEE21__push_back_slow_pathIRKS2_EEvOT_
- C _ZNSt3__16vectorIPNS_17__assoc_sub_stateENS_18__hidden_allocatorIS2_EEE26__swap_out_circular_bufferERNS_14__split_bufferIS2_RS4_EE
- C _ZNSt3__16vectorIPNS_17__assoc_sub_stateENS_18__hidden_allocatorIS2_EEED1Ev
- C _ZNSt3__16vectorIPNS_17__assoc_sub_stateENS_18__hidden_allocatorIS2_EEED2Ev
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE10deallocateEv
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE18__construct_at_endEj
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE18__construct_at_endIPS3_EENS_9enable_ifIXsr21__is_forward_iteratorIT_EE5valueEvE4typeESA_SA_
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE26__swap_out_circular_bufferERNS_14__split_bufferIS3_RS5_EE
C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE6assignIPS3_EENS_9enable_ifIXaasr21__is_forward_iteratorIT_EE5valuesr16is_constructibleIS3_NS_15iterator_traitsISA_E9referenceEEE5valueEvE4typeESA_SA_
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE6resizeEj
C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE8__appendEj
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEE8allocateEj
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEEC1Ej
C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEEC2Ej
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEED1Ev
- C _ZNSt3__16vectorIPNS_6locale5facetENS_15__sso_allocatorIS3_Lj28EEEED2Ev
- C _ZNSt3__17__sort3IRNS_6__lessIaaEEPaEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIccEEPcEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIddEEPdEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIeeEEPeEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIffEEPfEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIhhEEPhEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIiiEEPiEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIjjEEPjEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIllEEPlEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessImmEEPmEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIssEEPsEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIttEEPtEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIwwEEPwEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIxxEEPxEEjT0_S5_S5_T_
- C _ZNSt3__17__sort3IRNS_6__lessIyyEEPyEEjT0_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIaaEEPaEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIccEEPcEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIddEEPdEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIeeEEPeEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIffEEPfEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIhhEEPhEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIiiEEPiEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIjjEEPjEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIllEEPlEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessImmEEPmEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIssEEPsEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIttEEPtEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIwwEEPwEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIxxEEPxEEjT0_S5_S5_S5_T_
- C _ZNSt3__17__sort4IRNS_6__lessIyyEEPyEEjT0_S5_S5_S5_T_
C _ZNSt3__17__sort5IRNS_6__lessIaaEEPaEEjT0_S5_S5_S5_S5_T_
C _ZNSt3__17__sort5IRNS_6__lessIccEEPcEEjT0_S5_S5_S5_S5_T_
C _ZNSt3__17__sort5IRNS_6__lessIddEEPdEEjT0_S5_S5_S5_S5_T_
@@ -2273,12 +2030,8 @@
T _ZNSt3__18__i_nodeD1Ev
T _ZNSt3__18__i_nodeD2Ev
T _ZNSt3__18__rs_getEv
- C _ZNSt3__18__searchIRNS_11__traits_eqINS_11char_traitsIcEEEEPKcS7_EET0_S8_S8_T1_S9_T_NS_26random_access_iterator_tagESB_
- C _ZNSt3__18__searchIRNS_11__traits_eqINS_11char_traitsIwEEEEPKwS7_EET0_S8_S8_T1_S9_T_NS_26random_access_iterator_tagESB_
T _ZNSt3__18__sp_mut4lockEv
T _ZNSt3__18__sp_mut6unlockEv
- C _ZNSt3__18__sp_mutC1EPv
- C _ZNSt3__18__sp_mutC2EPv
D _ZNSt3__18ios_base10floatfieldE
D _ZNSt3__18ios_base10scientificE
D _ZNSt3__18ios_base11adjustfieldE
@@ -2488,6 +2241,7 @@
T _ZNSt3__19to_stringEx
T _ZNSt3__19to_stringEy
W _ZNSt3__1plIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_12basic_stringIT_T0_T1_EEPKS6_RKS9_
+ C _ZNSt3__1plIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_12basic_stringIT_T0_T1_EERKS9_PKS6_
T _ZSt10unexpectedv
T _ZSt13get_terminatev
T _ZSt13set_terminatePFvvE
@@ -2495,7 +2249,6 @@
T _ZSt14set_unexpectedPFvvE
T _ZSt17current_exceptionv
T _ZSt17rethrow_exceptionSt13exception_ptr
- C _ZSt18make_exception_ptrINSt3__112future_errorEESt13exception_ptrT_
D _ZTCNSt3__110istrstreamE0_NS_13basic_istreamIcNS_11char_traitsIcEEEE
D _ZTCNSt3__110ostrstreamE0_NS_13basic_ostreamIcNS_11char_traitsIcEEEE
W _ZTCNSt3__114basic_iostreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE
@@ -2636,6 +2389,7 @@
D _ZTISt15underflow_error
D _ZTISt16invalid_argument
D _ZTISt16nested_exception
+ C _ZTISt9exception
C _ZTSNSt3__110__stdinbufIcEE
C _ZTSNSt3__110__stdinbufIwEE
C _ZTSNSt3__110__time_getE
@@ -2769,6 +2523,7 @@
D _ZTSSt15underflow_error
D _ZTSSt16invalid_argument
D _ZTSSt16nested_exception
+ C _ZTSSt9exception
D _ZTTNSt3__110istrstreamE
D _ZTTNSt3__110ostrstreamE
W _ZTTNSt3__113basic_istreamIcNS_11char_traitsIcEEEE
@@ -2843,8 +2598,6 @@
D _ZTVNSt3__120__codecvt_utf8_utf16IDiEE
D _ZTVNSt3__120__codecvt_utf8_utf16IDsEE
D _ZTVNSt3__120__codecvt_utf8_utf16IwEE
- C _ZTVNSt3__120__time_get_c_storageIcEE
- C _ZTVNSt3__120__time_get_c_storageIwEE
D _ZTVNSt3__123__future_error_categoryE
D _ZTVNSt3__123__system_error_categoryE
D _ZTVNSt3__124__generic_error_categoryE
diff --git a/system/lib/libcxx/system_error.cpp b/system/lib/libcxx/system_error.cpp
index 763d62c2..7376b770 100644
--- a/system/lib/libcxx/system_error.cpp
+++ b/system/lib/libcxx/system_error.cpp
@@ -195,6 +195,9 @@ __throw_system_error(int ev, const char* what_arg)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
throw system_error(error_code(ev, system_category()), what_arg);
+#else
+ (void)ev;
+ (void)what_arg;
#endif
}
diff --git a/system/lib/libcxx/thread.cpp b/system/lib/libcxx/thread.cpp
index 76af3d0c..1fd8bb04 100644
--- a/system/lib/libcxx/thread.cpp
+++ b/system/lib/libcxx/thread.cpp
@@ -16,11 +16,17 @@
#if !defined(_WIN32)
#if !defined(__sun__) && !defined(__linux__)
#include <sys/sysctl.h>
-#else
-#include <unistd.h>
#endif // !__sun__ && !__linux__
+#include <unistd.h>
#endif // !_WIN32
+#if defined(__NetBSD__)
+#pragma weak pthread_create // Do not create libpthread dependency
+#endif
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
_LIBCPP_BEGIN_NAMESPACE_STD
thread::~thread()
@@ -36,6 +42,8 @@ thread::join()
#ifndef _LIBCPP_NO_EXCEPTIONS
if (ec)
throw system_error(error_code(ec, system_category()), "thread::join failed");
+#else
+ (void)ec;
#endif // _LIBCPP_NO_EXCEPTIONS
__t_ = 0;
}
@@ -65,7 +73,7 @@ thread::hardware_concurrency() _NOEXCEPT
std::size_t s = sizeof(n);
sysctl(mib, 2, &n, &s, 0, 0);
return n;
-#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) && defined(_SC_NPROCESSORS_ONLN)) || defined(EMSCRIPTEN)
+#elif defined(_SC_NPROCESSORS_ONLN)
long result = sysconf(_SC_NPROCESSORS_ONLN);
// sysconf returns -1 if the name is invalid, the option does not exist or
// does not have a definite limit.
@@ -74,9 +82,14 @@ thread::hardware_concurrency() _NOEXCEPT
if (result < 0)
return 0;
return static_cast<unsigned>(result);
+#elif defined(_WIN32)
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
#else // defined(CTL_HW) && defined(HW_NCPU)
// TODO: grovel through /proc or check cpuid on x86 and similar
// instructions on other architectures.
+#warning hardware_concurrency not yet implemented
return 0; // Means not computable [thread.thread.static]
#endif // defined(CTL_HW) && defined(HW_NCPU)
}
diff --git a/system/lib/libcxx/typeinfo.cpp b/system/lib/libcxx/typeinfo.cpp
index 7b47d741..60828944 100644
--- a/system/lib/libcxx/typeinfo.cpp
+++ b/system/lib/libcxx/typeinfo.cpp
@@ -53,8 +53,18 @@ std::bad_typeid::what() const _NOEXCEPT
#ifdef __APPLE__
// On Darwin, the cxa_bad_* functions cannot be in the lower level library
// because bad_cast and bad_typeid are defined in his higher level library
- void __cxxabiv1::__cxa_bad_typeid() { throw std::bad_typeid(); }
- void __cxxabiv1::__cxa_bad_cast() { throw std::bad_cast(); }
+ void __cxxabiv1::__cxa_bad_typeid()
+ {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ throw std::bad_typeid();
+#endif
+ }
+ void __cxxabiv1::__cxa_bad_cast()
+ {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ throw std::bad_cast();
+#endif
+ }
#endif
#endif // _LIBCPPABI_VERSION
diff --git a/tests/aniso.c b/tests/aniso.c
index 1126265e..f210e5a5 100644
--- a/tests/aniso.c
+++ b/tests/aniso.c
@@ -161,7 +161,7 @@ int main(int argc, char *argv[])
for (int x = 0; x < n; x++) {
int start = x*w*2;
glBegin( GL_TRIANGLES );
- glTexCoord2i( 1, 0 ); glVertex3f( start , 0, 0 );
+ glTexCoord2i( 1, 0 ); glVertex2i( start , 0 );
glTexCoord2i( 0, 0 ); glVertex3f( start+w, 300, 0 );
glTexCoord2i( 1, 1 ); glVertex3f( start-w, 300, 0 );
glEnd();
@@ -209,5 +209,11 @@ int main(int argc, char *argv[])
SDL_Quit();
- return 0;
+ // check for asm compilation bug with aliased functions with different sigs
+ void (*f)(int, int) = glVertex2i;
+ if ((int)f % 16 == 4) f(5, 7);
+ void (*g)(int, int) = glVertex3f;
+ if ((int)g % 16 == 4) g(5, 7);
+ return (int)f + (int)g;
}
+
diff --git a/tests/cases/phi24_ta2.ll b/tests/cases/phi24_ta2.ll
index b5b0664b..2d9b6646 100644
--- a/tests/cases/phi24_ta2.ll
+++ b/tests/cases/phi24_ta2.ll
@@ -252,6 +252,7 @@ target triple = "i386-pc-linux-gnu"
@g_287 = internal constant i32 -1, align 4
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
+ %msgdummy = alloca { i8*, { i64, i8* } (i8*)* } ; test for parsing of this kind of stuff, compilation-only test
%p_6.i.i = alloca %union.U3, align 8
%1 = icmp eq i32 %argc, 2
br i1 %1, label %2, label %7
@@ -549,7 +550,8 @@ safe_mod_func_uint32_t_u_u.exit.i.i: ; preds = %189, %.preheader..p
%p_5.sroa.0.0.extract.trunc2674116.i.i = phi i8 [ %p_5.sroa.0.0.extract.trunc2670.i.i, %189 ], [ -1, %.preheader..preheader.split_crit_edge.i.i ]
%p_5.sroa.1.sroa.0.0.load6982115.i.i = phi i24 [ %p_5.sroa.1.sroa.0.0.load6978.i.i, %189 ], [ -1, %.preheader..preheader.split_crit_edge.i.i ]
store i16 0, i16* @g_84, align 2
- %p_5.sroa.1.1.insert.ext36.i.i = trunc i24 %p_5.sroa.1.sroa.0.0.load6982115.i.i to i16
+ %adddd = add i24 %p_5.sroa.1.sroa.0.0.load6982115.i.i, 1 ; test i24 add
+ %p_5.sroa.1.1.insert.ext36.i.i = trunc i24 %adddd to i16
%p_5.sroa.1.1.insert.shift37.i.i = shl i16 %p_5.sroa.1.1.insert.ext36.i.i, 8
%p_5.sroa.0.0.insert.ext10.i.i = zext i8 %p_5.sroa.0.0.extract.trunc2674116.i.i to i16
%p_5.sroa.0.0.insert.insert12.i.i = or i16 %p_5.sroa.1.1.insert.shift37.i.i, %p_5.sroa.0.0.insert.ext10.i.i
diff --git a/tests/runner.py b/tests/runner.py
index b9807209..ed68463c 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -16,44 +16,7 @@ so you may prefer to use fewer cores here.
'''
from subprocess import Popen, PIPE, STDOUT
-import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools, stat
-
-if len(sys.argv) == 1:
- print '''
-==============================================================================
-Running the main part of the test suite. Don't forget to run the other parts!
-
- sanity - tests for first run, etc., modifies ~/.emscripten
- benchmark - run before and after each set of changes before pushing to
- master, verify no regressions
- browser - runs pages in a web browser
- browser audio - runs audio tests in a web browser (requires human verification)
-
-To run one of those parts, do something like
-
- python tests/runner.py sanity
-
-To run a specific set of tests, you can do things like
-
- python tests/runner.py o1
-
-(that runs the o1 (-O1) tests). You can run individual tests with
-
- python tests/runner.py test_hello_world
-
-Combinations work too, for example
-
- python tests/runner.py browser.test_sdl_image
-
-In the main test suite, you can run all variations (O0, O1, O2, etc.) of
-an individual test with
-
- python tests/runner.py ALL.test_hello_world
-
-==============================================================================
-
-'''
- time.sleep(2)
+import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools, stat, string
# Setup
@@ -72,10 +35,12 @@ except:
raise Exception('Cannot find "COMPILER_OPTS" definition. Is %s set up properly? You may need to copy the template settings file into it.' % EM_CONFIG)
# Core test runner class, shared between normal tests and benchmarks
-
checked_sanity = False
+test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1', 'other']
+test_index = 0
class RunnerCore(unittest.TestCase):
+ emcc_args = None
save_dir = os.environ.get('EM_SAVE_DIR')
save_JS = 0
stderr_redirect = STDOUT # This avoids cluttering the test runner output, which is stderr too, with compiler warnings etc.
@@ -87,9 +52,7 @@ class RunnerCore(unittest.TestCase):
return self.skip('requested to be skipped')
def setUp(self):
- global Settings
Settings.reset()
- Settings = tools.shared.Settings
self.banned_js_engines = []
if not self.save_dir:
dirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
@@ -271,7 +234,7 @@ process(sys.argv[1])
print >> sys.stderr, "[was asm.js'ified]"
elif 'asm.js' in err: # if no asm.js error, then not an odin build
raise Exception("did NOT asm.js'ify")
- err = '\n'.join(filter(lambda line: 'successfully compiled asm.js code' not in line, err.split('\n')))
+ err = '\n'.join(filter(lambda line: 'uccessfully compiled asm.js code' not in line, err.split('\n')))
return err
def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None):
@@ -312,6 +275,18 @@ process(sys.argv[1])
print "Output: " + output[0]
return output[0]
+ # Tests that the given two paths are identical, modulo path delimiters. E.g. "C:/foo" is equal to "C:\foo".
+ def assertPathsIdentical(self, path1, path2):
+ path1 = path1.replace('\\', '/')
+ path2 = path2.replace('\\', '/')
+ return self.assertIdentical(path1, path2)
+
+ # Tests that the given two multiline text content are identical, modulo line ending differences (\r\n on Windows, \n on Unix).
+ def assertTextDataIdentical(self, text1, text2):
+ text1 = text1.replace('\r\n', '\n')
+ text2 = text2.replace('\r\n', '\n')
+ return self.assertIdentical(text1, text2)
+
def assertIdentical(self, values, y):
if type(values) not in [list, tuple]: values = [values]
for x in values:
@@ -355,6 +330,9 @@ process(sys.argv[1])
cache_name = name + str(Building.COMPILER_TEST_OPTS) + cache_name_extra + (self.env.get('EMCC_LLVM_TARGET') or '')
+ valid_chars = "_%s%s" % (string.ascii_letters, string.digits)
+ cache_name = ''.join([(c if c in valid_chars else '_') for c in cache_name])
+
if self.library_cache is not None:
if cache and self.library_cache.get(cache_name):
print >> sys.stderr, '<load %s from cache> ' % cache_name,
@@ -434,14745 +412,383 @@ process(sys.argv[1])
return 0;
}
'''
-
return (main, supp)
-###################################################################################################
-
-sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv)
-
-test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2g', 'asm2x86', 's_0_0', 's_0_1']
-
-test_index = 0
-
-if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'browser' not in str(sys.argv):
- # Tests
-
- print "Running Emscripten tests..."
-
- if len(sys.argv) == 2 and sys.argv[1].startswith('ALL.'):
- ignore, test = sys.argv[1].split('.')
- print 'Running all test modes on test "%s"' % test
- sys.argv = [sys.argv[0]] + map(lambda mode: mode+'.'+test, test_modes)
-
- class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
- ## Does a complete test - builds, runs, checks output, etc.
- def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
- if force_c or (main_file is not None and main_file[-2:]) == '.c':
- basename = 'src.c'
- Building.COMPILER = to_cc(Building.COMPILER)
-
- dirname = self.get_dir()
- filename = os.path.join(dirname, basename)
- if not no_build:
- self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
- build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
-
- # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
- if js_engines is None:
- js_engines = JS_ENGINES
- if Settings.USE_TYPED_ARRAYS:
- js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822
- js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
- if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
- for engine in js_engines:
- js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
- self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
- self.assertNotContained('ERROR', js_output)
-
- #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
-
- if self.save_JS:
- global test_index
- self.hardcode_arguments(filename + '.o.js', args)
- shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js'))
- test_index += 1
-
- # No building - just process an existing .ll file (or .bc, which we turn into .ll)
- def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]):
- filename = os.path.join(self.get_dir(), 'src.cpp')
-
- self.prep_ll_run(filename, ll_file, force_recompile, build_ll_hook)
-
- self.ll_to_js(filename, extra_emscripten_args, post_build)
-
- self.do_run(None,
- expected_output,
- args,
- no_build=True,
- js_engines=js_engines,
- output_nicerizer=output_nicerizer,
- post_build=None) # post_build was already done in ll_to_js, this do_run call is just to test the output
-
- def is_le32(self):
- return not ('i386-pc-linux-gnu' in COMPILER_OPTS or self.env.get('EMCC_LLVM_TARGET') == 'i386-pc-linux-gnu')
-
- def test_hello_world(self):
- src = '''
- #include <stdio.h>
- int main()
- {
- printf("hello, world!\\n");
- return 0;
- }
- '''
- self.do_run(src, 'hello, world!')
-
- assert 'EMSCRIPTEN_GENERATED_FUNCTIONS' not in open(self.in_dir('src.cpp.o.js')).read(), 'must not emit this unneeded internal thing'
-
- def test_intvars(self):
- if self.emcc_args == None: return self.skip('needs ta2')
-
- src = '''
- #include <stdio.h>
- int global = 20;
- int *far;
- int main()
- {
- int x = 5;
- int y = x+17;
- int z = (y-1)/2; // Should stay an integer after division!
- y += 1;
- int w = x*3+4;
- int k = w < 15 ? 99 : 101;
- far = &k;
- *far += global;
- int i = k > 100; // Should be an int, not a bool!
- int j = i << 6;
- j >>= 1;
- j = j ^ 5;
- int h = 1;
- h |= 0;
- int p = h;
- p &= 0;
- printf("*%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n", x, y, z, w, k, i, j, h, p);
-
- long hash = -1;
- size_t perturb;
- int ii = 0;
- for (perturb = hash; ; perturb >>= 5) {
- printf("%d:%d", ii, perturb);
- ii++;
- if (ii == 9) break;
- printf(",");
- }
- printf("*\\n");
- printf("*%.1d,%.2d*\\n", 56, 9);
-
- // Fixed-point math on 64-bit ints. Tricky to support since we have no 64-bit shifts in JS
- {
- struct Fixed {
- static int Mult(int a, int b) {
- return ((long long)a * (long long)b) >> 16;
- }
- };
- printf("fixed:%d\\n", Fixed::Mult(150000, 140000));
- }
-
- printf("*%ld*%p\\n", (long)21, &hash); // The %p should not enter an infinite loop!
- return 0;
- }
- '''
- self.do_run(src, '*5,23,10,19,121,1,37,1,0*\n0:-1,1:134217727,2:4194303,3:131071,4:4095,5:127,6:3,7:0,8:0*\n*56,09*\nfixed:320434\n*21*')
-
- def test_sintvars(self):
- Settings.CORRECT_SIGNS = 1 # Relevant to this test
- src = '''
- #include <stdio.h>
- struct S {
- char *match_start;
- char *strstart;
- };
- int main()
- {
- struct S _s;
- struct S *s = &_s;
- unsigned short int sh;
-
- s->match_start = (char*)32522;
- s->strstart = (char*)(32780);
- printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start));
- sh = s->strstart - s->match_start;
- printf("*%d,%d*\\n", sh, sh>>7);
-
- s->match_start = (char*)32999;
- s->strstart = (char*)(32780);
- printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start));
- sh = s->strstart - s->match_start;
- printf("*%d,%d*\\n", sh, sh>>7);
- }
- '''
- output = '*32780,32522,258*\n*258,2*\n*32780,32999,-219*\n*65317,510*'
- Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right
- self.do_run(src, output, force_c=True)
-
- def test_i64(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
-
- src = '''
- #include <stdio.h>
- int main()
- {
- long long a = 0x2b00505c10;
- long long b = a >> 29;
- long long c = a >> 32;
- long long d = a >> 34;
- printf("*%Ld,%Ld,%Ld,%Ld*\\n", a, b, c, d);
- unsigned long long ua = 0x2b00505c10;
- unsigned long long ub = ua >> 29;
- unsigned long long uc = ua >> 32;
- unsigned long long ud = ua >> 34;
- printf("*%Ld,%Ld,%Ld,%Ld*\\n", ua, ub, uc, ud);
-
- long long x = 0x0000def123450789ULL; // any bigger than this, and we
- long long y = 0x00020ef123456089ULL; // start to run into the double precision limit!
- printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2);
-
- printf("*");
- long long z = 13;
- int n = 0;
- while (z > 1) {
- printf("%.2f,", (float)z); // these must be integers!
- z = z >> 1;
- n++;
- }
- printf("*%d*\\n", n);
- return 0;
- }
- '''
- self.do_run(src, '*184688860176,344,43,10*\n*184688860176,344,43,10*\n*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*')
-
- src = r'''
- #include <time.h>
- #include <stdio.h>
- #include <stdint.h>
-
- int64_t returner1() { return 0x0000def123450789ULL; }
- int64_t returner2(int test) {
- while (test > 10) test /= 2; // confuse the compiler so it doesn't eliminate this function
- return test > 5 ? 0x0000def123450123ULL : 0ULL;
- }
-
- void modifier1(int64_t t) {
- t |= 12;
- printf("m1: %Ld\n", t);
- }
- void modifier2(int64_t &t) {
- t |= 12;
- }
-
- int truthy() {
- int x = time(0);
- while (x > 10) {
- x |= 7;
- x /= 2;
- }
- return x < 3;
- }
-
- struct IUB {
- int c;
- long long d;
- };
-
- IUB iub[] = {
- { 55, 17179869201 },
- { 122, 25769803837 },
- };
-
- int main(int argc, char **argv)
- {
- int64_t x1 = 0x1234def123450789ULL;
- int64_t x2 = 0x1234def123450788ULL;
- int64_t x3 = 0x1234def123450789ULL;
- printf("*%Ld\n%d,%d,%d,%d,%d\n%d,%d,%d,%d,%d*\n", x1, x1==x2, x1<x2, x1<=x2, x1>x2, x1>=x2, // note: some rounding in the printing!
- x1==x3, x1<x3, x1<=x3, x1>x3, x1>=x3);
- printf("*%Ld*\n", returner1());
- printf("*%Ld*\n", returner2(30));
-
- uint64_t maxx = -1ULL;
- printf("*%Lu*\n*%Lu*\n", maxx, maxx >> 5);
-
- // Make sure params are not modified if they shouldn't be
- int64_t t = 123;
- modifier1(t);
- printf("*%Ld*\n", t);
- modifier2(t);
- printf("*%Ld*\n", t);
-
- // global structs with i64s
- printf("*%d,%Ld*\n*%d,%Ld*\n", iub[0].c, iub[0].d, iub[1].c, iub[1].d);
-
- // Bitshifts
- {
- int64_t a = -1;
- int64_t b = a >> 29;
- int64_t c = a >> 32;
- int64_t d = a >> 34;
- printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d);
- uint64_t ua = -1;
- int64_t ub = ua >> 29;
- int64_t uc = ua >> 32;
- int64_t ud = ua >> 34;
- printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud);
- }
-
- // Nonconstant bitshifts
- {
- int64_t a = -1;
- int64_t b = a >> (29 - argc + 1);
- int64_t c = a >> (32 - argc + 1);
- int64_t d = a >> (34 - argc + 1);
- printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d);
- uint64_t ua = -1;
- int64_t ub = ua >> (29 - argc + 1);
- int64_t uc = ua >> (32 - argc + 1);
- int64_t ud = ua >> (34 - argc + 1);
- printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud);
- }
-
- // Math mixtures with doubles
- {
- uint64_t a = 5;
- double b = 6.8;
- uint64_t c = a * b;
- if (truthy()) printf("*%d,%d,%d*\n", (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations
- printf("*prod:%llu*\n", c);
- }
-
- // Basic (rounded, for now) math. Just check compilation.
- int64_t a = 0x1234def123450789ULL;
- a--; if (truthy()) a--; // confuse optimizer
- int64_t b = 0x1234000000450789ULL;
- b++; if (truthy()) b--; // confuse optimizer
- printf("*%Ld,%Ld,%Ld,%Ld*\n", (a+b)/5000, (a-b)/5000, (a*3)/5000, (a/5)/5000);
-
- a -= 17; if (truthy()) a += 5; // confuse optimizer
- b -= 17; if (truthy()) b += 121; // confuse optimizer
- printf("*%Lx,%Lx,%Lx,%Lx*\n", b - a, b - a/2, b/2 - a, b - 20);
-
- if (truthy()) a += 5/b; // confuse optimizer
- if (truthy()) b += 121*(3+a/b); // confuse optimizer
- printf("*%Lx,%Lx,%Lx,%Lx*\n", a - b, a - b/2, a/2 - b, a - 20);
-
- return 0;
- }
- '''
- self.do_run(src, '*1311918518731868041\n' +
- '0,0,0,1,1\n' +
- '1,0,1,0,1*\n' +
- '*245127260211081*\n' +
- '*245127260209443*\n' +
- '*18446744073709551615*\n' +
- '*576460752303423487*\n' +
- 'm1: 127\n' +
- '*123*\n' +
- '*127*\n' +
- '*55,17179869201*\n' +
- '*122,25769803837*\n' +
- '*-1,-1,-1,-1*\n' +
- '*-1,34359738367,4294967295,1073741823*\n' +
- '*-1,-1,-1,-1*\n' +
- '*-1,34359738367,4294967295,1073741823*\n' +
- '*prod:34*\n' +
- '*524718382041609,49025451137,787151111239120,52476740749274*\n' +
- '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' +
- '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n')
-
- src = r'''
- #include <stdio.h>
- #include <limits>
-
- int main()
- {
- long long i,j,k;
-
- i = 0;
- j = -1,
- k = 1;
-
- printf( "*\n" );
- printf( "%s\n", i > j ? "Ok": "Fail" );
- printf( "%s\n", k > i ? "Ok": "Fail" );
- printf( "%s\n", k > j ? "Ok": "Fail" );
- printf( "%s\n", i < j ? "Fail": "Ok" );
- printf( "%s\n", k < i ? "Fail": "Ok" );
- printf( "%s\n", k < j ? "Fail": "Ok" );
- printf( "%s\n", (i-j) >= k ? "Ok": "Fail" );
- printf( "%s\n", (i-j) <= k ? "Ok": "Fail" );
- printf( "%s\n", i > std::numeric_limits<long long>::min() ? "Ok": "Fail" );
- printf( "%s\n", i < std::numeric_limits<long long>::max() ? "Ok": "Fail" );
- printf( "*\n" );
- }
- '''
-
- self.do_run(src, '*\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\n*')
-
- # stuff that also needs sign corrections
-
- Settings.CORRECT_SIGNS = 1
-
- src = r'''
- #include <stdio.h>
- #include <stdint.h>
-
- int main()
- {
- // i32 vs i64
- int32_t small = -1;
- int64_t large = -1;
- printf("*%d*\n", small == large);
- small++;
- printf("*%d*\n", small == large);
- uint32_t usmall = -1;
- uint64_t ularge = -1;
- printf("*%d*\n", usmall == ularge);
- return 0;
- }
- '''
-
- self.do_run(src, '*1*\n*0*\n*0*\n')
-
- def test_i64_b(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdio.h>
- #include <sys/time.h>
-
- typedef long long int64;
-
- #define PRMJ_USEC_PER_SEC 1000000L
-
- int main(int argc, char * argv[]) {
- int64 sec = 1329409675 + argc;
- int64 usec = 2329509675;
- int64 mul = int64(sec) * PRMJ_USEC_PER_SEC;
- int64 add = mul + int64(usec);
- int add_low = add;
- int add_high = add >> 32;
- printf("*%lld,%lld,%u,%u*\n", mul, add, add_low, add_high);
- int64 x = sec + (usec << 25);
- x >>= argc*3;
- printf("*%llu*\n", x);
- return 0;
- }
- '''
-
- self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n*9770671914067409*\n')
-
- def test_i64_cmp(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdio.h>
-
- typedef long long int64;
-
- bool compare(int64 val) {
- return val == -12;
- }
-
- bool compare2(int64 val) {
- return val < -12;
- }
-
- int main(int argc, char * argv[]) {
- printf("*%d,%d,%d,%d,%d,%d*\n", argc, compare(argc-1-12), compare(1000+argc), compare2(argc-1-10), compare2(argc-1-14), compare2(argc+1000));
- return 0;
- }
- '''
-
- self.do_run(src, '*1,1,0,0,1,0*\n')
-
- def test_i64_cmp2(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <inttypes.h>
- #include <stdio.h>
-
- typedef int32_t INT32;
- typedef int64_t INT64;
- typedef uint8_t UINT8;
-
- void interface_clock_changed()
- {
- UINT8 m_divshift;
- INT32 m_divisor;
-
- //INT64 attos = m_attoseconds_per_cycle;
- INT64 attos = 279365114840;
- m_divshift = 0;
- while (attos >= (1UL << 31))
- {
- m_divshift++;
- printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31);
- attos >>= 1;
- }
- m_divisor = attos;
-
- printf("m_divisor is %i\n",m_divisor);
- }
-
- int main() {
- interface_clock_changed();
- return 0;
- }
- '''
- self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648
-m_divshift is 2, on 139682557420 >?= 2147483648
-m_divshift is 3, on 69841278710 >?= 2147483648
-m_divshift is 4, on 34920639355 >?= 2147483648
-m_divshift is 5, on 17460319677 >?= 2147483648
-m_divshift is 6, on 8730159838 >?= 2147483648
-m_divshift is 7, on 4365079919 >?= 2147483648
-m_divshift is 8, on 2182539959 >?= 2147483648
-m_divisor is 1091269979
-''')
-
- def test_i64_double(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
-
- src = r'''
- #include <stdio.h>
-
- typedef long long int64;
- #define JSDOUBLE_HI32_SIGNBIT 0x80000000
-
- bool JSDOUBLE_IS_NEGZERO(double d)
- {
- union {
- struct {
- unsigned int lo, hi;
- } s;
- double d;
- } x;
- if (d != 0)
- return false;
- x.d = d;
- return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
- }
-
- bool JSINT64_IS_NEGZERO(int64 l)
- {
- union {
- int64 i;
- double d;
- } x;
- if (l != 0)
- return false;
- x.i = l;
- return x.d == -0;
- }
-
- int main(int argc, char * argv[]) {
- printf("*%d,%d,%d,%d*\n", JSDOUBLE_IS_NEGZERO(0), JSDOUBLE_IS_NEGZERO(-0), JSDOUBLE_IS_NEGZERO(-1), JSDOUBLE_IS_NEGZERO(+1));
- printf("*%d,%d,%d,%d*\n", JSINT64_IS_NEGZERO(0), JSINT64_IS_NEGZERO(-0), JSINT64_IS_NEGZERO(-1), JSINT64_IS_NEGZERO(+1));
- return 0;
- }
- '''
- self.do_run(src, '*0,0,0,0*\n*1,1,0,0*\n') # same as gcc
-
- def test_i64_umul(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <inttypes.h>
- #include <stdio.h>
-
- typedef uint32_t UINT32;
- typedef uint64_t UINT64;
-
- int main() {
- volatile UINT32 testu32a = 2375724032U;
- UINT32 bigu32 = 0xffffffffU;
- volatile UINT64 testu64a = 14746250828952703000U;
-
- while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) {
- printf("testu64a is %llu\n", testu64a);
- testu64a /= 2;
- }
-
- return 0;
- }
- '''
- self.do_run(src, 'testu64a is 14746250828952703000\n')
-
- def test_i64_precise(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <inttypes.h>
- #include <stdio.h>
-
- int main() {
- uint64_t x = 0, y = 0;
- for (int i = 0; i < 64; i++) {
- x += 1ULL << i;
- y += x;
- x /= 3;
- y *= 5;
- printf("unsigned %d: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i, x, y, x+y, x-y, x*y, y ? x/y : 0, x ? y/x : 0, y ? x%y : 0, x ? y%x : 0);
- }
- int64_t x2 = 0, y2 = 0;
- for (int i = 0; i < 64; i++) {
- x2 += 1LL << i;
- y2 += x2;
- x2 /= 3 * (i % 7 ? -1 : 1);
- y2 *= 5 * (i % 2 ? -1 : 1);
- printf("signed %d: %lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld\n", i, x2, y2, x2+y2, x2-y2, x2*y2, y2 ? x2/y2 : 0, x2 ? y2/x2 : 0, y2 ? x2%y2 : 0, x2 ? y2%x2 : 0);
- }
- return 0;
- }
- '''
- self.do_run(src, open(path_from_root('tests', 'i64_precise.txt')).read())
-
- # Verify that even if we ask for precision, if it is not needed it is not included
- Settings.PRECISE_I64_MATH = 1
- src = '''
- #include <inttypes.h>
- #include <stdio.h>
-
- int main(int argc, char **argv) {
- uint64_t x = 2125299906845564, y = 1225891506842664;
- if (argc == 12) {
- x = x >> 1;
- y = y >> 1;
- }
- x = x & 12ULL;
- y = y | 12ULL;
- x = x ^ y;
- x <<= 2;
- y >>= 3;
- printf("*%llu, %llu*\\n", x, y);
- }
- '''
- self.do_run(src, '*4903566027370624, 153236438355333*')
- code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
- assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not actually used'
-
- # But if we force it to be included, it is. First, a case where we don't need it
- Settings.PRECISE_I64_MATH = 2
- self.do_run(open(path_from_root('tests', 'hello_world.c')).read(), 'hello')
- code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
- assert 'goog.math.Long' in code, 'i64 precise math should be included if forced'
-
- # and now one where we do
- self.do_run(r'''
- #include <stdio.h>
-
- int main( int argc, char ** argv )
- {
- unsigned long a = 0x60DD1695U;
- unsigned long b = 0xCA8C4E7BU;
- unsigned long long c = (unsigned long long)a * b;
- printf( "c = %016llx\n", c );
-
- return 0;
- }
- ''', 'c = 4ca38a6bd2973f97')
-
- def test_i64_llabs(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
- Settings.PRECISE_I64_MATH = 2
- self.do_run(r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main(int argc, char ** argv) {
- printf("%lld,%lld\n", llabs(-576460752303423489), llabs(576460752303423489));
- return 0;
- }
- ''', '576460752303423489,576460752303423489')
-
- def test_i64_zextneg(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdint.h>
- #include <stdio.h>
-
- int main(int argc, char *argv[])
- {
- uint8_t byte = 0x80;
- uint16_t two = byte;
- uint32_t four = byte;
- uint64_t eight = byte;
-
- printf("value: %d,%d,%d,%lld.\n", byte, two, four, eight);
-
- return 0;
- }
- '''
- self.do_run(src, 'value: 128,128,128,128.')
-
- def test_i64_7z(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdint.h>
- #include <stdio.h>
- uint64_t a, b;
- int main(int argc, char *argv[])
- {
- a = argc;
- b = argv[1][0];
- printf("%d,%d\n", a, b);
- if (a > a + b || a > a + b + 1) {
- printf("one %lld, %lld", a, b);
- return 0;
- }
- printf("zero %lld, %lld", a, b);
- return 0;
- }
- '''
- self.do_run(src, 'zero 2, 104', ['hallo'])
-
- def test_i64_i16(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdint.h>
- #include <stdio.h>
- int main(int argc, char ** argv){
- int y=-133;
- int64_t x= ((int64_t)((short)(y)))*(100 + argc);
- if(x>0)
- printf(">0\n");
- else
- printf("<=0\n");
- }
- '''
- self.do_run(src, '<=0')
+ ## Does a complete test - builds, runs, checks output, etc.
+ def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
+ if force_c or (main_file is not None and main_file[-2:]) == '.c':
+ basename = 'src.c'
+ Building.COMPILER = to_cc(Building.COMPILER)
+
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, basename)
+ if not no_build:
+ self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
+ build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
+
+ # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
+ if js_engines is None:
+ js_engines = JS_ENGINES
+ if Settings.USE_TYPED_ARRAYS:
+ js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822
+ js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
+ if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
+ for engine in js_engines:
+ js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
+ self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
+ self.assertNotContained('ERROR', js_output)
+
+ #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
+
+ if self.save_JS:
+ global test_index
+ self.hardcode_arguments(filename + '.o.js', args)
+ shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js'))
+ test_index += 1
+
+ # No building - just process an existing .ll file (or .bc, which we turn into .ll)
+ def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]):
+ filename = os.path.join(self.get_dir(), 'src.cpp')
+
+ self.prep_ll_run(filename, ll_file, force_recompile, build_ll_hook)
- def test_i64_qdouble(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdio.h>
- typedef long long qint64; /* 64 bit signed */
- typedef double qreal;
-
-
- int main(int argc, char **argv)
- {
- qreal c = 111;
- qint64 d = -111 + (argc - 1);
- c += d;
- if (c < -1 || c > 1)
- {
- printf("Failed!\n");
- }
- else
- {
- printf("Succeeded!\n");
- }
- };
- '''
- self.do_run(src, 'Succeeded!')
-
- def test_i64_varargs(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
-
- src = r'''
- #include <stdio.h>
- #include <stdint.h>
- #include <stdarg.h>
-
- int64_t ccv_cache_generate_signature(char *msg, int len, int64_t sig_start, ...) {
- if (sig_start < 10123)
- printf("%s\n", msg+len);
- va_list v;
- va_start(v, sig_start);
- if (sig_start > 1413)
- printf("%d\n", va_arg(v, int));
- else
- printf("nada\n");
- va_end(v);
- return len*sig_start*(msg[0]+1);
- }
-
- int main(int argc, char **argv)
- {
- for (int i = 0; i < argc; i++) {
- int64_t x;
- if (i % 123123 == 0)
- x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 54.111);
- else
- x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 13);
- printf("%lld\n", x);
- }
- };
- '''
- self.do_run(src, '''in/this.program
-nada
-1536
-a
-nada
-5760
-fl
-nada
-6592
-sdfasdfasdf
-nada
-7840
-''', 'waka fleefl asdfasdfasdfasdf'.split(' '))
-
- def test_i32_mul_precise(self):
- if self.emcc_args == None: return self.skip('needs ta2')
-
- src = r'''
- #include <stdio.h>
-
- int main(int argc, char **argv) {
- unsigned long d1 = 0x847c9b5d;
- unsigned long q = 0x549530e1;
- if (argc > 1000) { q += argc; d1 -= argc; } // confuse optimizer
- printf("%lu\n", d1*q);
- return 0;
- }
- '''
- self.do_run(src, '3217489085')
-
- def test_i32_mul_semiprecise(self):
- if Settings.ASM_JS: return self.skip('asm is always fully precise')
-
- Settings.PRECISE_I32_MUL = 0 # we want semiprecise here
-
- src = r'''
- #include <stdio.h>
-
- typedef unsigned int uint;
-
- // from cube2, zlib licensed
-
- #define N (624)
- #define M (397)
- #define K (0x9908B0DFU)
-
- static uint state[N];
- static int next = N;
-
- void seedMT(uint seed)
- {
- state[0] = seed;
- for(uint i = 1; i < N; i++) // if we do not do this precisely, at least we should coerce to int immediately, not wait
- state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i;
- next = 0;
- }
-
- int main() {
- seedMT(5497);
- for (int i = 0; i < 10; i++) printf("%d: %u\n", i, state[i]);
- return 0;
- }
- '''
- self.do_run(src, '''0: 5497
-1: 2916432318
-2: 2502517762
-3: 3151524867
-4: 2323729668
-5: 2053478917
-6: 2409490438
-7: 848473607
-8: 691103752
-9: 3915535113
-''')
-
- def test_i16_emcc_intrinsic(self):
- Settings.CORRECT_SIGNS = 1 # Relevant to this test
-
- src = r'''
- #include <stdio.h>
-
- int test(unsigned short a, unsigned short b) {
- unsigned short result = a;
- result += b;
- if (result < b) printf("C!");
- return result;
- }
-
- int main(void) {
- printf(",%d,", test(0, 0));
- printf(",%d,", test(1, 1));
- printf(",%d,", test(65535, 1));
- printf(",%d,", test(1, 65535));
- printf(",%d,", test(32768, 32767));
- printf(",%d,", test(32768, 32768));
- return 0;
- }
- '''
- self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,')
-
- def test_negative_zero(self):
- src = r'''
- #include <stdio.h>
- #include <math.h>
-
- int main() {
- #define TEST(x, y) \
- printf("%.2f, %.2f ==> %.2f\n", x, y, copysign(x, y));
- TEST( 5.0f, 5.0f);
- TEST( 5.0f, -5.0f);
- TEST(-5.0f, 5.0f);
- TEST(-5.0f, -5.0f);
- TEST( 5.0f, 4.0f);
- TEST( 5.0f, -4.0f);
- TEST(-5.0f, 4.0f);
- TEST(-5.0f, -4.0f);
- TEST( 0.0f, 5.0f);
- TEST( 0.0f, -5.0f);
- TEST(-0.0f, 5.0f);
- TEST(-0.0f, -5.0f);
- TEST( 5.0f, 0.0f);
- TEST( 5.0f, -0.0f);
- TEST(-5.0f, 0.0f);
- TEST(-5.0f, -0.0f);
- TEST( 0.0f, 0.0f);
- TEST( 0.0f, -0.0f);
- TEST(-0.0f, 0.0f);
- TEST(-0.0f, -0.0f);
- return 0;
- }
- '''
- self.do_run(src, '''5.00, 5.00 ==> 5.00
-5.00, -5.00 ==> -5.00
--5.00, 5.00 ==> 5.00
--5.00, -5.00 ==> -5.00
-5.00, 4.00 ==> 5.00
-5.00, -4.00 ==> -5.00
--5.00, 4.00 ==> 5.00
--5.00, -4.00 ==> -5.00
-0.00, 5.00 ==> 0.00
-0.00, -5.00 ==> -0.00
--0.00, 5.00 ==> 0.00
--0.00, -5.00 ==> -0.00
-5.00, 0.00 ==> 5.00
-5.00, -0.00 ==> -5.00
--5.00, 0.00 ==> 5.00
--5.00, -0.00 ==> -5.00
-0.00, 0.00 ==> 0.00
-0.00, -0.00 ==> -0.00
--0.00, 0.00 ==> 0.00
--0.00, -0.00 ==> -0.00
-''')
-
- def test_llvm_intrinsics(self):
- if self.emcc_args == None: return self.skip('needs ta2')
-
- Settings.PRECISE_I64_MATH = 2 # for bswap64
-
- src = r'''
- #include <stdio.h>
- #include <sys/types.h>
-
- extern "C" {
- extern unsigned short llvm_bswap_i16(unsigned short x);
- extern unsigned int llvm_bswap_i32(unsigned int x);
- extern int32_t llvm_ctlz_i32(int32_t x);
- extern int64_t llvm_ctlz_i64(int64_t x);
- extern int32_t llvm_cttz_i32(int32_t x);
- extern int64_t llvm_cttz_i64(int64_t x);
- extern int32_t llvm_ctpop_i32(int32_t x);
- extern int64_t llvm_ctpop_i64(int64_t x);
- extern int llvm_expect_i32(int x, int y);
- }
-
- int main(void) {
- unsigned short x = 0xc8ef;
- printf("%x,%x\n", x&0xff, x >> 8);
- x = llvm_bswap_i16(x);
- printf("%x,%x\n", x&0xff, x >> 8);
-
- unsigned int y = 0xc5de158a;
- printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff);
- y = llvm_bswap_i32(y);
- printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff);
-
- printf("%d,%d\n", (int)llvm_ctlz_i64(((int64_t)1) << 40), llvm_ctlz_i32(1<<10));
- printf("%d,%d\n", (int)llvm_cttz_i64(((int64_t)1) << 40), llvm_cttz_i32(1<<10));
- printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1), llvm_ctpop_i32(0x3101));
- printf("%d\n", (int)llvm_ctpop_i32(-594093059));
-
- printf("%d\n", llvm_expect_i32(x % 27, 3));
-
- int64_t a = 1;
- a = __builtin_bswap64(a);
- printf("%lld\n", a);
-
- return 0;
- }
- '''
- self.do_run(src, '''ef,c8
-c8,ef
-8a,15,de,c5
-c5,de,15,8a
-23,21
-40,10
-5,4
-22
-13
-72057594037927936
-''')
-
- def test_bswap64(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- #include <iostream>
- #include <string>
- #include <sstream>
-
- typedef unsigned long long quint64;
-
- using namespace std;
-
- inline quint64 qbswap(quint64 source)
- {
- return 0
- | ((source & quint64(0x00000000000000ffLL)) << 56)
- | ((source & quint64(0x000000000000ff00LL)) << 40)
- | ((source & quint64(0x0000000000ff0000LL)) << 24)
- | ((source & quint64(0x00000000ff000000LL)) << 8)
- | ((source & quint64(0x000000ff00000000LL)) >> 8)
- | ((source & quint64(0x0000ff0000000000LL)) >> 24)
- | ((source & quint64(0x00ff000000000000LL)) >> 40)
- | ((source & quint64(0xff00000000000000LL)) >> 56);
- }
-
- int main()
- {
- quint64 v = strtoull("4433ffeeddccbb00", NULL, 16);
- printf("%lld\n", v);
-
- const string string64bitInt = "4433ffeeddccbb00";
- stringstream s(string64bitInt);
- quint64 int64bitInt = 0;
- printf("1\n");
- s >> hex >> int64bitInt;
- printf("2\n");
-
- stringstream out;
- out << hex << qbswap(int64bitInt);
-
- cout << out.str() << endl;
- cout << hex << int64bitInt << endl;
- cout << string64bitInt << endl;
-
- if (out.str() != "bbccddeeff3344")
- {
- cout << "Failed!" << endl;
- }
- else
- {
- cout << "Succeeded!" << endl;
- }
-
- return 0;
- }
- '''
- self.do_run(src, '''4914553019779824384
-1
-2
-bbccddeeff3344
-4433ffeeddccbb00
-4433ffeeddccbb00
-Succeeded!
-''')
-
- def test_sha1(self):
- if self.emcc_args == None: return self.skip('needs ta2')
-
- self.do_run(open(path_from_root('tests', 'sha1.c')).read(), 'SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6')
-
- def test_cube2md5(self):
- if self.emcc_args == None: return self.skip('needs emcc')
- self.emcc_args += ['--embed-file', 'cube2md5.txt']
- shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt'))
- self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read())
-
- def test_cube2hash(self):
-
- try:
- old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
- os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = '1' # test splitting out each function to a chunk in emscripten.py (21 functions here)
-
- # A good test of i64 math
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
- self.do_run('', 'Usage: hashstring <seed>',
- libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None),
- includes=[path_from_root('tests', 'cube2hash')])
-
- for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
- ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
- ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
- self.do_run('', 'hash value: ' + output, [text], no_build=True)
- finally:
- os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
-
- def test_unaligned(self):
- if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
-
- src = r'''
- #include<stdio.h>
-
- struct S {
- double x;
- int y;
- };
-
- int main() {
- // the 64-bit value here will not be 8-byte aligned
- S s0[3] = { {0x12a751f430142, 22}, {0x17a5c85bad144, 98}, {1, 1}};
- char buffer[10*sizeof(S)];
- int b = int(buffer);
- S *s = (S*)(b + 4-b%8);
- s[0] = s0[0];
- s[1] = s0[1];
- s[2] = s0[2];
-
- printf("*%d : %d : %d\n", sizeof(S), ((unsigned int)&s[0]) % 8 != ((unsigned int)&s[1]) % 8,
- ((unsigned int)&s[1]) - ((unsigned int)&s[0]));
- s[0].x++;
- s[0].y++;
- s[1].x++;
- s[1].y++;
- printf("%.1f,%d,%.1f,%d\n", s[0].x, s[0].y, s[1].x, s[1].y);
- return 0;
- }
- '''
-
- # TODO: A version of this with int64s as well
-
- if self.is_le32():
- return self.skip('LLVM marks the reads of s as fully aligned, making this test invalid')
- else:
- self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n')
-
- return # TODO: continue to the next part here
-
- # Test for undefined behavior in C. This is not legitimate code, but does exist
-
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('No meaning to unaligned addresses without t2')
-
- src = r'''
- #include <stdio.h>
-
- int main()
- {
- int x[10];
- char *p = (char*)&x[0];
- p++;
- short *q = (short*)p;
- *q = 300;
- printf("*%d:%d*\n", *q, ((int)q)%2);
- int *r = (int*)p;
- *r = 515559;
- printf("*%d*\n", *r);
- long long *t = (long long*)p;
- *t = 42949672960;
- printf("*%Ld*\n", *t);
- return 0;
- }
- '''
-
- try:
- self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n')
- except Exception, e:
- assert 'must be aligned' in str(e), e # expected to fail without emulation
-
- def test_align64(self):
- src = r'''
- #include <stdio.h>
-
- // inspired by poppler
-
- enum Type {
- A = 10,
- B = 20
- };
-
- struct Object {
- Type type;
- union {
- int intg;
- double real;
- char *name;
- };
- };
-
- struct Principal {
- double x;
- Object a;
- double y;
- };
-
- int main(int argc, char **argv)
- {
- int base = argc-1;
- Object *o = NULL;
- printf("%d,%d\n", sizeof(Object), sizeof(Principal));
- printf("%d,%d,%d,%d\n", (int)&o[base].type, (int)&o[base].intg, (int)&o[base].real, (int)&o[base].name);
- printf("%d,%d,%d,%d\n", (int)&o[base+1].type, (int)&o[base+1].intg, (int)&o[base+1].real, (int)&o[base+1].name);
- Principal p, q;
- p.x = p.y = q.x = q.y = 0;
- p.a.type = A;
- p.a.real = 123.456;
- *(&q.a) = p.a;
- printf("%.2f,%d,%.2f,%.2f : %.2f,%d,%.2f,%.2f\n", p.x, p.a.type, p.a.real, p.y, q.x, q.a.type, q.a.real, q.y);
- return 0;
- }
- '''
+ self.ll_to_js(filename, extra_emscripten_args, post_build)
- if self.is_le32():
- self.do_run(src, '''16,32
-0,8,8,8
-16,24,24,24
-0.00,10,123.46,0.00 : 0.00,10,123.46,0.00
-''')
+ self.do_run(None,
+ expected_output,
+ args,
+ no_build=True,
+ js_engines=js_engines,
+ output_nicerizer=output_nicerizer,
+ post_build=None) # post_build was already done in ll_to_js, this do_run call is just to test the output
+
+
+# Run a server and a web page. When a test runs, we tell the server about it,
+# which tells the web page, which then opens a window with the test. Doing
+# it this way then allows the page to close() itself when done.
+def harness_server_func(q):
+ class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def do_GET(s):
+ s.send_response(200)
+ s.send_header("Content-type", "text/html")
+ s.end_headers()
+ if s.path == '/run_harness':
+ s.wfile.write(open(path_from_root('tests', 'browser_harness.html')).read())
else:
- self.do_run(src, '''12,28
-0,4,4,4
-12,16,16,16
-0.00,10,123.46,0.00 : 0.00,10,123.46,0.00
-''')
-
- def test_unsigned(self):
- Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here
- Settings.CHECK_SIGNS = 0
- src = '''
- #include <stdio.h>
- const signed char cvals[2] = { -1, -2 }; // compiler can store this is a string, so -1 becomes \FF, and needs re-signing
- int main()
- {
- {
- unsigned char x = 200;
- printf("*%d*\\n", x);
- unsigned char y = -22;
- printf("*%d*\\n", y);
- }
-
- int varey = 100;
- unsigned int MAXEY = -1, MAXEY2 = -77;
- printf("*%u,%d,%u*\\n", MAXEY, varey >= MAXEY, MAXEY2); // 100 >= -1? not in unsigned!
-
- int y = cvals[0];
- printf("*%d,%d,%d,%d*\\n", cvals[0], cvals[0] < 0, y, y < 0);
- y = cvals[1];
- printf("*%d,%d,%d,%d*\\n", cvals[1], cvals[1] < 0, y, y < 0);
-
- // zext issue - see mathop in jsifier
- unsigned char x8 = -10;
- unsigned long hold = 0;
- hold += x8;
- int y32 = hold+50;
- printf("*%u,%u*\\n", hold, y32);
-
- // Comparisons
- x8 = 0;
- for (int i = 0; i < 254; i++) x8++; // make it an actual 254 in JS - not a -2
- printf("*%d,%d*\\n", x8+1 == 0xff, x8+1 != 0xff); // 0xff may be '-1' in the bitcode
-
- return 0;
- }
- '''
- self.do_run(src, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*')
-
- # Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires
- # corrections otherwise
- if Settings.USE_TYPED_ARRAYS == 2:
- Settings.CORRECT_SIGNS = 0
- Settings.CHECK_SIGNS = 1 if not Settings.ASM_JS else 0
+ result = 'False'
+ if not q.empty():
+ result = q.get()
+ s.wfile.write(result)
+ s.wfile.close()
+ def log_request(code=0, size=0):
+ # don't log; too noisy
+ pass
+ httpd = BaseHTTPServer.HTTPServer(('localhost', 9999), TestServerHandler)
+ httpd.serve_forever() # test runner will kill us
+
+def server_func(dir, q):
+ class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def do_GET(s):
+ if 'report_' in s.path:
+ q.put(s.path)
+ else:
+ filename = s.path.split('?')[0][1:]
+ if os.path.exists(filename):
+ s.send_response(200)
+ s.send_header("Content-type", "text/html")
+ s.end_headers()
+ s.wfile.write(open(filename).read())
+ s.wfile.close()
else:
- Settings.CORRECT_SIGNS = 1
- Settings.CHECK_SIGNS = 0
-
- src = '''
- #include <stdio.h>
- int main()
- {
- {
- unsigned char x;
- unsigned char *y = &x;
- *y = -1;
- printf("*%d*\\n", x);
- }
- {
- unsigned short x;
- unsigned short *y = &x;
- *y = -1;
- printf("*%d*\\n", x);
- }
- /*{ // This case is not checked. The hint for unsignedness is just the %u in printf, and we do not analyze that
- unsigned int x;
- unsigned int *y = &x;
- *y = -1;
- printf("*%u*\\n", x);
- }*/
- {
- char x;
- char *y = &x;
- *y = 255;
- printf("*%d*\\n", x);
- }
- {
- char x;
- char *y = &x;
- *y = 65535;
- printf("*%d*\\n", x);
- }
- {
- char x;
- char *y = &x;
- *y = 0xffffffff;
- printf("*%d*\\n", x);
- }
- return 0;
- }
- '''
- self.do_run(src, '*255*\n*65535*\n*-1*\n*-1*\n*-1*')
-
- def test_bitfields(self):
- if self.emcc_args is None: Settings.SAFE_HEAP = 0 # bitfields do loads on invalid areas, by design
- src = '''
- #include <stdio.h>
- struct bitty {
- unsigned x : 1;
- unsigned y : 1;
- unsigned z : 1;
- };
- int main()
- {
- bitty b;
- printf("*");
- for (int i = 0; i <= 1; i++)
- for (int j = 0; j <= 1; j++)
- for (int k = 0; k <= 1; k++) {
- b.x = i;
- b.y = j;
- b.z = k;
- printf("%d,%d,%d,", b.x, b.y, b.z);
- }
- printf("*\\n");
- return 0;
- }
- '''
- self.do_run(src, '*0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,1,0,1,1,1,0,1,1,1,*')
-
- def test_floatvars(self):
- src = '''
- #include <stdio.h>
-
- // headers test, see issue #1013
- #include<cfloat>
- #include<cmath>
-
- int main(int argc, char **argv)
- {
- float x = 1.234, y = 3.5, q = 0.00000001;
- y *= 3;
- int z = x < y;
- printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q);
-
- printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3));
+ s.send_response(500)
+ s.send_header("Content-type", "text/html")
+ s.end_headers()
+ def log_request(code=0, size=0):
+ # don't log; too noisy
+ pass
+ os.chdir(dir)
+ httpd = BaseHTTPServer.HTTPServer(('localhost', 8888), TestServerHandler)
+ httpd.serve_forever() # test runner will kill us
+
+class BrowserCore(RunnerCore):
+ def __init__(self, *args, **kwargs):
+ super(BrowserCore, self).__init__(*args, **kwargs)
+
+ @classmethod
+ def setUpClass(self):
+ super(BrowserCore, self).setUpClass()
+ self.harness_queue = multiprocessing.Queue()
+ self.harness_server = multiprocessing.Process(target=harness_server_func, args=(self.harness_queue,))
+ self.harness_server.start()
+ print '[Browser harness server on process %d]' % self.harness_server.pid
+ webbrowser.open_new('http://localhost:9999/run_harness')
+
+ @classmethod
+ def tearDownClass(self):
+ super(BrowserCore, self).tearDownClass()
+ self.harness_server.terminate()
+ print '[Browser harness server terminated]'
+ # On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit:
+ # WindowsError: [Error 32] The process cannot access the file because it is being used by another process.
+ time.sleep(0.1)
+
+ def run_browser(self, html_file, message, expectedResult=None):
+ if expectedResult is not None:
+ try:
+ queue = multiprocessing.Queue()
+ server = multiprocessing.Process(target=functools.partial(server_func, self.get_dir()), args=(queue,))
+ server.start()
+ self.harness_queue.put('http://localhost:8888/' + html_file)
+ output = '[no http server activity]'
+ start = time.time()
+ while time.time() - start < 60:
+ if not queue.empty():
+ output = queue.get()
+ break
+ time.sleep(0.1)
- printf("small: %.10f\\n", argc * 0.000001);
+ self.assertIdentical(expectedResult, output)
+ finally:
+ server.terminate()
+ time.sleep(0.1) # see comment about Windows above
+ else:
+ webbrowser.open_new(os.path.abspath(html_file))
+ print 'A web browser window should have opened a page containing the results of a part of this test.'
+ print 'You need to manually look at the page to see that it works ok: ' + message
+ print '(sleeping for a bit to keep the directory alive for the web browser..)'
+ time.sleep(5)
+ print '(moving on..)'
+
+ def with_report_result(self, code):
+ return r'''
+ #if EMSCRIPTEN
+ #include <emscripten.h>
+ #define REPORT_RESULT_INTERNAL(sync) \
+ char output[1000]; \
+ sprintf(output, \
+ "xhr = new XMLHttpRequest();" \
+ "xhr.open('GET', 'http://localhost:8888/report_result?%d'%s);" \
+ "xhr.send();", result, sync ? ", false" : ""); \
+ emscripten_run_script(output); \
+ emscripten_run_script("setTimeout(function() { window.close() }, 1000)"); // comment this out to keep the test runner window open to debug
+ #define REPORT_RESULT() REPORT_RESULT_INTERNAL(0)
+ #endif
+''' + code
+ def reftest(self, expected):
+ # make sure the pngs used here have no color correction, using e.g.
+ # pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile outfile
+ basename = os.path.basename(expected)
+ shutil.copyfile(expected, os.path.join(self.get_dir(), basename))
+ open(os.path.join(self.get_dir(), 'reftest.js'), 'w').write('''
+ var Module = eval('Module');
+ function doReftest() {
+ if (doReftest.done) return;
+ doReftest.done = true;
+ var img = new Image();
+ img.onload = function() {
+ assert(img.width == Module.canvas.width, 'Invalid width: ' + Module.canvas.width + ', should be ' + img.width);
+ assert(img.height == Module.canvas.height, 'Invalid height: ' + Module.canvas.height + ', should be ' + img.height);
+
+ var canvas = document.createElement('canvas');
+ canvas.width = img.width;
+ canvas.height = img.height;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0);
+ var expected = ctx.getImageData(0, 0, img.width, img.height).data;
+
+ var actualUrl = Module.canvas.toDataURL();
+ var actualImage = new Image();
+ actualImage.onload = function() {
/*
- // Rounding behavior
- float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
- double ds[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
- for (int i = 0; i < 6; i++)
- printf("*int(%.2f)=%d,%d*\\n", fs[i], int(fs[i]), int(ds[i]));
+ document.body.appendChild(img); // for comparisons
+ var div = document.createElement('div');
+ div.innerHTML = '^=expected, v=actual';
+ document.body.appendChild(div);
+ document.body.appendChild(actualImage); // to grab it for creating the test reference
*/
- return 0;
- }
- '''
- self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\nsmall: 0.0000010000\n')
-
- def test_isnan(self):
- src = r'''
- #include <stdio.h>
-
- int IsNaN(double x){
- int rc; /* The value return */
- volatile double y = x;
- volatile double z = y;
- rc = (y!=z);
- return rc;
- }
-
- int main() {
- double tests[] = { 1.0, 3.333, 1.0/0.0, 0.0/0.0, -1.0/0.0, -0, 0, -123123123, 12.0E200 };
- for (int i = 0; i < sizeof(tests)/sizeof(double); i++)
- printf("%d - %f - %d\n", i, tests[i], IsNaN(tests[i]));
- }
- '''
- self.do_run(src, '''0 - 1.000000 - 0
-1 - 3.333000 - 0
-2 - inf - 0
-3 - nan - 1
-4 - -inf - 0
-5 - 0.000000 - 0
-6 - 0.000000 - 0
-7 - -123123123.000000 - 0
-8 - 1.2e+201 - 0
-''')
-
- def test_globaldoubles(self):
- src = r'''
- #include <stdlib.h>
- #include <stdio.h>
-
- double testVu, testVv, testWu, testWv;
-
- void Test(double _testVu, double _testVv, double _testWu, double _testWv)
- {
- testVu = _testVu;
- testVv = _testVv;
- testWu = _testWu;
- testWv = _testWv;
- printf("BUG?\n");
- printf("Display: Vu=%f Vv=%f Wu=%f Wv=%f\n", testVu, testVv, testWu, testWv);
- }
-
- int main(void)
- {
- double v1 = 465.1;
- double v2 = 465.2;
- double v3 = 160.3;
- double v4 = 111.4;
- Test(v1, v2, v3, v4);
- return 0;
- }
- '''
- self.do_run(src, 'BUG?\nDisplay: Vu=465.100000 Vv=465.200000 Wu=160.300000 Wv=111.400000')
-
- def test_math(self):
- src = '''
- #include <stdio.h>
- #include <stdlib.h>
- #include <cmath>
- int main()
- {
- printf("*%.2f,%.2f,%d", M_PI, -M_PI, (1/0.0) > 1e300); // could end up as infinity, or just a very very big number
- printf(",%d", isfinite(NAN) != 0);
- printf(",%d", isfinite(INFINITY) != 0);
- printf(",%d", isfinite(-INFINITY) != 0);
- printf(",%d", isfinite(12.3) != 0);
- printf(",%d", isinf(NAN) != 0);
- printf(",%d", isinf(INFINITY) != 0);
- printf(",%d", isinf(-INFINITY) != 0);
- printf(",%d", isinf(12.3) != 0);
- div_t div_result = div(23, 10);
- printf(",%d", div_result.quot);
- printf(",%d", div_result.rem);
- double sine = -1.0, cosine = -1.0;
- sincos(0.0, &sine, &cosine);
- printf(",%1.1lf", sine);
- printf(",%1.1lf", cosine);
- float fsine = -1.0f, fcosine = -1.0f;
- sincosf(0.0, &fsine, &fcosine);
- printf(",%1.1f", fsine);
- printf(",%1.1f", fcosine);
- printf("*\\n");
- return 0;
- }
- '''
- self.do_run(src, '*3.14,-3.14,1,0,0,0,1,0,1,1,0,2,3,0.0,1.0,0.0,1.0*')
-
- def test_erf(self):
- src = '''
- #include <math.h>
- #include <stdio.h>
- int main()
- {
- printf("%1.6f, %1.6f, %1.6f, %1.6f, %1.6f, %1.6f\\n",
- erf(1.0),
- erf(3.0),
- erf(-1.0),
- erfc(1.0),
- erfc(3.0),
- erfc(-1.5));
- return 0;
- }
- '''
- self.do_run(src, '0.842701, 0.999978, -0.842701, 0.157299, 0.000022, 1.966105')
-
- def test_math_hyperbolic(self):
- src = open(path_from_root('tests', 'hyperbolic', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read()
- self.do_run(src, expected)
-
- def test_frexp(self):
- src = '''
- #include <stdio.h>
- #include <math.h>
- #include <assert.h>
-
- static const double tol=1e-16;
-
- void test_value(double value)
- {
- int exponent;
- double x=frexp(value, &exponent);
- double expected=x*pow(2.0, exponent);
-
- printf("%f=%f*2^%d\\n", value, x, exponent);
-
- assert(fabs(expected-value)<tol);
- assert(x==0 || (fabs(x)>=5e-1 && fabs(x)<1)); // x has a magnitude in the interval [1/2, 1)
- }
-
- int main()
- {
- test_value(0);
- test_value(100.1);
- test_value(-100.1);
- test_value(.5);
- test_value(-.5);
- test_value(1-1e-16);
- test_value(-(1-1e-16));
-
- return 0;
- }
- '''
- self.do_run(src, '''0.000000=0.000000*2^0
-100.100000=0.782031*2^7
--100.100000=-0.782031*2^7
-0.500000=0.500000*2^0
--0.500000=-0.500000*2^0
-1.000000=1.000000*2^0
--1.000000=-1.000000*2^0''')
-
- def test_rounding(self):
- src = '''
- #include <stdio.h>
- #include <math.h>
-
- int main()
- {
- printf("%.1f ", round(1.4));
- printf("%.1f ", round(1.6));
- printf("%.1f ", round(-1.4));
- printf("%.1f ", round(-1.6));
-
- printf("%.1f ", round(1.5));
- printf("%.1f ", round(2.5));
- printf("%.1f ", round(-1.5));
- printf("%.1f ", round(-2.5));
-
- printf("%ld ", lrint(1.4));
- printf("%ld ", lrint(1.6));
- printf("%ld ", lrint(-1.4));
- printf("%ld ", lrint(-1.6));
-
- printf("%ld ", lrint(1.5));
- printf("%ld ", lrint(2.5));
- printf("%ld ", lrint(-1.5));
- printf("%ld ", lrint(-2.5));
-
- return 0;
- }
- '''
- self.do_run(src, "1.0 2.0 -1.0 -2.0 2.0 3.0 -2.0 -3.0 "
- "1 2 -1 -2 2 2 -2 -2")
-
- def test_llrint(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
- src = r'''
- #include <stdio.h>
- #include <math.h>
- int main() {
- printf("%lld\n%lld\n%lld\n%lld\n", llrint(0.1), llrint(0.6), llrint(1.25), llrint(1099511627776.667));
- return 0;
- }
- '''
- self.do_run(src, '0\n1\n1\n1099511627777\n')
-
- def test_getgep(self):
- # Generated code includes getelementptr (getelementptr, 0, 1), i.e., GEP as the first param to GEP
- src = '''
- #include <stdio.h>
- struct {
- int y[10];
- int z[10];
- } commonblock;
-
- int main()
- {
- for (int i = 0; i < 10; ++i) {
- commonblock.y[i] = 1;
- commonblock.z[i] = 2;
- }
- printf("*%d %d*\\n", commonblock.y[0], commonblock.z[0]);
- return 0;
- }
- '''
- self.do_run(src, '*1 2*')
-
- def test_multiply_defined_symbols(self):
- a1 = "int f() { return 1; }"
- a1_name = os.path.join(self.get_dir(), 'a1.c')
- open(a1_name, 'w').write(a1)
- a2 = "void x() {}"
- a2_name = os.path.join(self.get_dir(), 'a2.c')
- open(a2_name, 'w').write(a2)
- b1 = "int f() { return 2; }"
- b1_name = os.path.join(self.get_dir(), 'b1.c')
- open(b1_name, 'w').write(b1)
- b2 = "void y() {}"
- b2_name = os.path.join(self.get_dir(), 'b2.c')
- open(b2_name, 'w').write(b2)
- main = r'''
- #include <stdio.h>
- int f();
- int main() {
- printf("result: %d\n", f());
- return 0;
- }
- '''
- main_name = os.path.join(self.get_dir(), 'main.c')
- open(main_name, 'w').write(main)
-
- Building.emcc(a1_name)
- Building.emcc(a2_name)
- Building.emcc(b1_name)
- Building.emcc(b2_name)
- Building.emcc(main_name)
-
- liba_name = os.path.join(self.get_dir(), 'liba.a')
- Building.emar('cr', liba_name, [a1_name + '.o', a2_name + '.o'])
- libb_name = os.path.join(self.get_dir(), 'libb.a')
- Building.emar('cr', libb_name, [b1_name + '.o', b2_name + '.o'])
-
- all_name = os.path.join(self.get_dir(), 'all.bc')
- Building.link([main_name + '.o', liba_name, libb_name], all_name)
-
- self.do_ll_run(all_name, 'result: 1')
-
- def test_if(self):
- src = '''
- #include <stdio.h>
- int main()
- {
- int x = 5;
- if (x > 3) {
- printf("*yes*\\n");
- }
- return 0;
- }
- '''
- self.do_run(src, '*yes*')
-
- def test_if_else(self):
- src = '''
- #include <stdio.h>
- int main()
- {
- int x = 5;
- if (x > 10) {
- printf("*yes*\\n");
- } else {
- printf("*no*\\n");
- }
- return 0;
- }
- '''
- self.do_run(src, '*no*')
-
- def test_loop(self):
- src = '''
- #include <stdio.h>
- int main()
- {
- int x = 5;
- for (int i = 0; i < 6; i++) {
- x += x*i;
- if (x > 1000) {
- if (x % 7 == 0) printf("cheez\\n");
- x /= 2;
- break;
- }
- }
- printf("*%d*\\n", x);
- return 0;
- }
- '''
-
- self.do_run(src, '*1800*')
-
- generated = open('src.cpp.o.js', 'r').read()
-
- def test_stack(self):
- Settings.INLINING_LIMIT = 50
-
- src = '''
- #include <stdio.h>
- int test(int i) {
- int x = 10;
- if (i > 0) {
- return test(i-1);
- }
- return int(&x); // both for the number, and forces x to not be nativized
- }
- int main(int argc, char **argv)
- {
- // We should get the same value for the first and last - stack has unwound
- int x1 = test(argc - 2);
- int x2 = test(100);
- int x3 = test((argc - 2) / 4);
- printf("*%d,%d*\\n", x3-x1, x2 != x1);
- return 0;
- }
- '''
- self.do_run(src, '*0,1*')
-
- def test_strings(self):
- src = '''
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- int main(int argc, char **argv)
- {
- int x = 5, y = 9, magic = 7; // fool compiler with magic
- memmove(&x, &y, magic-7); // 0 should not crash us
-
- int xx, yy, zz;
- char s[32];
- int cc = sscanf("abc_10.b1_xyz_543_defg", "abc_%d.%2x_xyz_%3d_%3s", &xx, &yy, &zz, s);
- printf("%d:%d,%d,%d,%s\\n", cc, xx, yy, zz, s);
-
- printf("%d\\n", argc);
- puts(argv[1]);
- puts(argv[2]);
- printf("%d\\n", atoi(argv[3])+2);
- const char *foolingthecompiler = "\\rabcd";
- printf("%d\\n", strlen(foolingthecompiler)); // Tests parsing /0D in llvm - should not be a 0 (end string) then a D!
- printf("%s\\n", NULL); // Should print '(null)', not the string at address 0, which is a real address for us!
- printf("/* a comment */\\n"); // Should not break the generated code!
- printf("// another\\n"); // Should not break the generated code!
-
- char* strdup_val = strdup("test");
- printf("%s\\n", strdup_val);
- free(strdup_val);
-
- {
- char *one = "one 1 ONE !";
- char *two = "two 2 TWO ?";
- char three[1024];
- memset(three, '.', 1024);
- three[50] = 0;
- strncpy(three + argc, one + (argc/2), argc+1);
- strncpy(three + argc*3, two + (argc/3), argc+2);
- printf("waka %s\\n", three);
- }
-
- {
- char *one = "string number one top notch";
- char *two = "fa la sa ho fi FI FO FUM WHEN WHERE WHY HOW WHO";
- char three[1000];
- strcpy(three, &one[argc*2]);
- char *four = strcat(three, &two[argc*3]);
- printf("cat |%s|\\n", three);
- printf("returned |%s|\\n", four);
- }
-
- return 0;
- }
- '''
- for named in (0, 1):
- print named
- Settings.NAMED_GLOBALS = named
- self.do_run(src, '''4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\nwaka ....e 1 O...wo 2 T................................
-cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|
-returned |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too', '74'])
- if self.emcc_args == []:
- gen = open(self.in_dir('src.cpp.o.js')).read()
- assert ('var __str1;' in gen) == named
-
- def test_strcmp_uni(self):
- src = '''
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- #define TEST(func) \
- { \
- char *word = "WORD"; \
- char wordEntry[2] = { -61,-126 }; /* "Â"; */ \
- int cmp = func(word, wordEntry, 2); \
- printf("Compare value " #func " is %d\\n", cmp); \
- }
- TEST(strncmp);
- TEST(strncasecmp);
- TEST(memcmp);
- }
- '''
- self.do_run(src, 'Compare value strncmp is -1\nCompare value strncasecmp is -1\nCompare value memcmp is -1\n')
-
- def test_strndup(self):
- src = '''
- //---------------
- //- http://pubs.opengroup.org/onlinepubs/9699919799/functions/strndup.html
- //---------------
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- int main(int argc, char **argv) {
- const char* source = "strndup - duplicate a specific number of bytes from a string";
-
- char* strdup_val = strndup(source, 0);
- printf("1:%s\\n", strdup_val);
- free(strdup_val);
-
- strdup_val = strndup(source, 7);
- printf("2:%s\\n", strdup_val);
- free(strdup_val);
-
- strdup_val = strndup(source, 1000);
- printf("3:%s\\n", strdup_val);
- free(strdup_val);
-
- strdup_val = strndup(source, 60);
- printf("4:%s\\n", strdup_val);
- free(strdup_val);
-
- strdup_val = strndup(source, 19);
- printf("5:%s\\n", strdup_val);
- free(strdup_val);
-
- strdup_val = strndup(source, -1);
- printf("6:%s\\n", strdup_val);
- free(strdup_val);
-
- return 0;
- }
- '''
- self.do_run(src, '1:\n2:strndup\n3:strndup - duplicate a specific number of bytes from a string\n4:strndup - duplicate a specific number of bytes from a string\n5:strndup - duplicate\n6:\n')
-
- def test_errar(self):
- src = r'''
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
-
- int main() {
- char* err;
- char buffer[200];
-
- err = strerror(EDOM);
- strerror_r(EWOULDBLOCK, buffer, 200);
- printf("<%s>\n", err);
- printf("<%s>\n", buffer);
-
- printf("<%d>\n", strerror_r(EWOULDBLOCK, buffer, 0));
- errno = 123;
- printf("<%d>\n", errno);
-
- return 0;
- }
- '''
- expected = '''
- <Math arg out of domain of func>
- <No more processes>
- <34>
- <123>
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
-
- def test_mainenv(self):
- src = '''
- #include <stdio.h>
- int main(int argc, char **argv, char **envp)
- {
- printf("*%p*\\n", envp);
- return 0;
- }
- '''
- self.do_run(src, '*(nil)*')
-
- def test_funcs(self):
- src = '''
- #include <stdio.h>
- int funcy(int x)
- {
- return x*9;
- }
- int main()
- {
- printf("*%d,%d*\\n", funcy(8), funcy(10));
- return 0;
- }
- '''
- self.do_run(src, '*72,90*')
-
- def test_structs(self):
- src = '''
- #include <stdio.h>
- struct S
- {
- int x, y;
- };
- int main()
- {
- S a, b;
- a.x = 5; a.y = 6;
- b.x = 101; b.y = 7009;
- S *c, *d;
- c = &a;
- c->x *= 2;
- c = &b;
- c->y -= 1;
- d = c;
- d->y += 10;
- printf("*%d,%d,%d,%d,%d,%d,%d,%d*\\n", a.x, a.y, b.x, b.y, c->x, c->y, d->x, d->y);
- return 0;
- }
- '''
- self.do_run(src, '*10,6,101,7018,101,7018,101,7018*')
-
- gen_struct_src = '''
- #include <stdio.h>
- #include <stdlib.h>
- #include "emscripten.h"
-
- struct S
- {
- int x, y;
- };
- int main()
- {
- S* a = {{gen_struct}};
- a->x = 51; a->y = 62;
- printf("*%d,%d*\\n", a->x, a->y);
- {{del_struct}}(a);
- return 0;
- }
- '''
-
- def test_mallocstruct(self):
- self.do_run(self.gen_struct_src.replace('{{gen_struct}}', '(S*)malloc(sizeof(S))').replace('{{del_struct}}', 'free'), '*51,62*')
-
- def test_newstruct(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- self.do_run(self.gen_struct_src.replace('{{gen_struct}}', 'new S').replace('{{del_struct}}', 'delete'), '*51,62*')
-
- def test_addr_of_stacked(self):
- src = '''
- #include <stdio.h>
- void alter(int *y)
- {
- *y += 5;
- }
- int main()
- {
- int x = 2;
- alter(&x);
- printf("*%d*\\n", x);
- return 0;
- }
- '''
- self.do_run(src, '*7*')
-
- def test_globals(self):
- src = '''
- #include <stdio.h>
-
- char cache[256], *next = cache;
-
- int main()
- {
- cache[10] = 25;
- next[20] = 51;
- printf("*%d,%d*\\n", next[10], cache[20]);
- return 0;
- }
- '''
- self.do_run(src, '*25,51*')
-
- def test_linked_list(self):
- src = '''
- #include <stdio.h>
- struct worker_args {
- int value;
- struct worker_args *next;
- };
- int main()
- {
- worker_args a;
- worker_args b;
- a.value = 60;
- a.next = &b;
- b.value = 900;
- b.next = NULL;
- worker_args* c = &a;
- int total = 0;
- while (c) {
- total += c->value;
- c = c->next;
- }
-
- // Chunk of em
- worker_args chunk[10];
- for (int i = 0; i < 9; i++) {
- chunk[i].value = i*10;
- chunk[i].next = &chunk[i+1];
- }
- chunk[9].value = 90;
- chunk[9].next = &chunk[0];
-
- c = chunk;
- do {
- total += c->value;
- c = c->next;
- } while (c != chunk);
-
- printf("*%d,%d*\\n", total, b.next);
- // NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
-
- return 0;
- }
- '''
- self.do_run(src, '*1410,0*')
-
- def test_sup(self):
- src = '''
- #include <stdio.h>
-
- struct S4 { int x; }; // size: 4
- struct S4_2 { short x, y; }; // size: 4, but for alignment purposes, 2
- struct S6 { short x, y, z; }; // size: 6
- struct S6w { char x[6]; }; // size: 6 also
- struct S6z { int x; short y; }; // size: 8, since we align to a multiple of the biggest - 4
-
- struct C___ { S6 a, b, c; int later; };
- struct Carr { S6 a[3]; int later; }; // essentially the same, but differently defined
- struct C__w { S6 a; S6w b; S6 c; int later; }; // same size, different struct
- struct Cp1_ { int pre; short a; S6 b, c; int later; }; // fillers for a
- struct Cp2_ { int a; short pre; S6 b, c; int later; }; // fillers for a (get addr of the other filler)
- struct Cint { S6 a; int b; S6 c; int later; }; // An int (different size) for b
- struct C4__ { S6 a; S4 b; S6 c; int later; }; // Same size as int from before, but a struct
- struct C4_2 { S6 a; S4_2 b; S6 c; int later; }; // Same size as int from before, but a struct with max element size 2
- struct C__z { S6 a; S6z b; S6 c; int later; }; // different size, 8 instead of 6
-
- int main()
- {
- #define TEST(struc) \\
- { \\
- struc *s = 0; \\
- printf("*%s: %d,%d,%d,%d<%d*\\n", #struc, (int)&(s->a), (int)&(s->b), (int)&(s->c), (int)&(s->later), sizeof(struc)); \\
- }
- #define TEST_ARR(struc) \\
- { \\
- struc *s = 0; \\
- printf("*%s: %d,%d,%d,%d<%d*\\n", #struc, (int)&(s->a[0]), (int)&(s->a[1]), (int)&(s->a[2]), (int)&(s->later), sizeof(struc)); \\
- }
- printf("sizeofs:%d,%d\\n", sizeof(S6), sizeof(S6z));
- TEST(C___);
- TEST_ARR(Carr);
- TEST(C__w);
- TEST(Cp1_);
- TEST(Cp2_);
- TEST(Cint);
- TEST(C4__);
- TEST(C4_2);
- TEST(C__z);
- return 0;
- }
- '''
- if Settings.QUANTUM_SIZE == 1:
- self.do_run(src, 'sizeofs:6,8\n*C___: 0,3,6,9<24*\n*Carr: 0,3,6,9<24*\n*C__w: 0,3,9,12<24*\n*Cp1_: 1,2,5,8<24*\n*Cp2_: 0,2,5,8<24*\n*Cint: 0,3,4,7<24*\n*C4__: 0,3,4,7<24*\n*C4_2: 0,3,5,8<20*\n*C__z: 0,3,5,8<28*')
- else:
- self.do_run(src, 'sizeofs:6,8\n*C___: 0,6,12,20<24*\n*Carr: 0,6,12,20<24*\n*C__w: 0,6,12,20<24*\n*Cp1_: 4,6,12,20<24*\n*Cp2_: 0,6,12,20<24*\n*Cint: 0,8,12,20<24*\n*C4__: 0,8,12,20<24*\n*C4_2: 0,6,10,16<20*\n*C__z: 0,8,16,24<28*')
-
- def test_assert(self):
- src = '''
- #include <stdio.h>
- #include <assert.h>
- int main() {
- assert(1 == true); // pass
- assert(1 == false); // fail
- return 0;
- }
- '''
- 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>
- #include <setjmp.h>
-
- static jmp_buf buf;
-
- void second(void) {
- printf("second\n");
- longjmp(buf,-1);
- }
-
- void first(void) {
- printf("first\n"); // prints
- longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
- }
-
- int main() {
- volatile int x = 0;
- int jmpval = setjmp(buf);
- if (!jmpval) {
- x++; // should be properly restored once longjmp jumps back
- first(); // when executed, setjmp returns 1
- printf("skipped\n"); // does not print
- } else if (jmpval == 1) { // when first() jumps back, setjmp returns 1
- printf("result: %d %d\n", x, jmpval); // prints
- x++;
- second(); // when executed, setjmp returns -1
- } else if (jmpval == -1) { // when second() jumps back, setjmp returns -1
- printf("result: %d %d\n", x, jmpval); // prints
- }
-
- return 0;
- }
- '''
- self.do_run(src, 'first\nresult: 1 1\nsecond\nresult: 2 -1')
-
- def test_longjmp2(self):
- src = r'''
- #include <setjmp.h>
- #include <stdio.h>
-
- typedef struct {
- jmp_buf* jmp;
- } jmp_state;
-
- void stack_manipulate_func(jmp_state* s, int level) {
- jmp_buf buf;
-
- printf("Entering stack_manipulate_func, level: %d\n", level);
-
- if (level == 0) {
- s->jmp = &buf;
- if (setjmp(*(s->jmp)) == 0) {
- printf("Setjmp normal execution path, level: %d\n", level);
- stack_manipulate_func(s, level + 1);
- } else {
- printf("Setjmp error execution path, level: %d\n", level);
- }
- } else {
- printf("Perform longjmp at level %d\n", level);
- longjmp(*(s->jmp), 1);
- }
-
- printf("Exiting stack_manipulate_func, level: %d\n", level);
- }
-
- int main(int argc, char *argv[]) {
- jmp_state s;
- s.jmp = NULL;
- stack_manipulate_func(&s, 0);
-
- return 0;
- }
- '''
- self.do_run(src, '''Entering stack_manipulate_func, level: 0
-Setjmp normal execution path, level: 0
-Entering stack_manipulate_func, level: 1
-Perform longjmp at level 1
-Setjmp error execution path, level: 0
-Exiting stack_manipulate_func, level: 0
-''')
-
- def test_longjmp3(self):
- src = r'''
- #include <setjmp.h>
- #include <stdio.h>
-
- typedef struct {
- jmp_buf* jmp;
- } jmp_state;
-
- void setjmp_func(jmp_state* s, int level) {
- jmp_buf* prev_jmp = s->jmp;
- jmp_buf c_jmp;
-
- if (level == 2) {
- printf("level is 2, perform longjmp!\n");
- longjmp(*(s->jmp), 1);
- }
-
- if (setjmp(c_jmp) == 0) {
- printf("setjmp normal execution path, level: %d\n", level);
- s->jmp = &c_jmp;
- setjmp_func(s, level + 1);
- } else {
- printf("setjmp exception execution path, level: %d\n", level);
- if (prev_jmp) {
- printf("prev_jmp is not empty, continue with longjmp!\n");
- s->jmp = prev_jmp;
- longjmp(*(s->jmp), 1);
- }
- }
-
- printf("Exiting setjmp function, level: %d\n", level);
- }
-
- int main(int argc, char *argv[]) {
- jmp_state s;
- s.jmp = NULL;
-
- setjmp_func(&s, 0);
-
- return 0;
- }
- '''
- self.do_run(src, '''setjmp normal execution path, level: 0
-setjmp normal execution path, level: 1
-level is 2, perform longjmp!
-setjmp exception execution path, level: 1
-prev_jmp is not empty, continue with longjmp!
-setjmp exception execution path, level: 0
-Exiting setjmp function, level: 0
-''')
-
- def test_longjmp4(self):
- src = r'''
- #include <setjmp.h>
- #include <stdio.h>
-
- typedef struct {
- jmp_buf* jmp;
- } jmp_state;
-
- void second_func(jmp_state* s);
-
- void first_func(jmp_state* s) {
- jmp_buf* prev_jmp = s->jmp;
- jmp_buf c_jmp;
- volatile int once = 0;
-
- if (setjmp(c_jmp) == 0) {
- printf("Normal execution path of first function!\n");
-
- s->jmp = &c_jmp;
- second_func(s);
- } else {
- printf("Exception execution path of first function! %d\n", once);
-
- if (!once) {
- printf("Calling longjmp the second time!\n");
- once = 1;
- longjmp(*(s->jmp), 1);
- }
- }
- }
-
- void second_func(jmp_state* s) {
- longjmp(*(s->jmp), 1);
- }
-
- int main(int argc, char *argv[]) {
- jmp_state s;
- s.jmp = NULL;
-
- first_func(&s);
-
- return 0;
- }
- '''
- self.do_run(src, '''Normal execution path of first function!
-Exception execution path of first function! 0
-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_longjmp_exc(self):
- src = r'''
- #include <stdlib.h>
- #include <stdio.h>
- #include <setjmp.h>
- #include <emscripten.h>
-
- jmp_buf abortframe;
-
- void dostuff(int a) {
- printf("pre\n");
- if (a != 42) emscripten_run_script("waka_waka()"); // this should fail, and never reach "never"
- printf("never\n");
-
- if (a == 100) {
- longjmp (abortframe, -1);
- }
-
- if (setjmp(abortframe)) {
- printf("got 100");
- }
- }
-
- int main(int argc, char **argv) {
- dostuff(argc);
- exit(1);
- return 1;
- }
- '''
- self.do_run(src, 'waka_waka');
-
- 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')
-
- Settings.EXCEPTION_DEBUG = 1
-
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- if '-O2' in self.emcc_args:
- self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
-
- src = '''
- #include <stdio.h>
- void thrower() {
- printf("infunc...");
- throw(99);
- printf("FAIL");
- }
- int main() {
- try {
- printf("*throw...");
- throw(1);
- printf("FAIL");
- } catch(...) {
- printf("caught!");
- }
- try {
- thrower();
- } catch(...) {
- printf("done!*\\n");
- }
- return 0;
- }
- '''
- self.do_run(src, '*throw...caught!infunc...done!*')
-
- Settings.DISABLE_EXCEPTION_CATCHING = 1
- self.do_run(src, 'Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0')
-
- src = '''
- #include <iostream>
-
- class MyException
- {
- public:
- MyException(){ std::cout << "Construct..."; }
- MyException( const MyException & ) { std::cout << "Copy..."; }
- ~MyException(){ std::cout << "Destruct..."; }
- };
-
- int function()
- {
- std::cout << "Throw...";
- throw MyException();
- }
-
- int function2()
- {
- return function();
- }
-
- int main()
- {
- try
- {
- function2();
- }
- catch (MyException & e)
- {
- std::cout << "Catched...";
- }
-
- try
- {
- function2();
- }
- catch (MyException e)
- {
- std::cout << "Catched...";
- }
-
- return 0;
- }
- '''
-
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- if '-O2' in self.emcc_args:
- self.emcc_args.pop() ; self.emcc_args.pop() # disable closure to work around a closure bug
- self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...')
-
- def test_exception_2(self):
- if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- src = r'''
- #include <stdexcept>
- #include <stdio.h>
-
- typedef void (*FuncPtr)();
-
- void ThrowException()
- {
- throw std::runtime_error("catch me!");
- }
-
- FuncPtr ptr = ThrowException;
-
- int main()
- {
- try
- {
- ptr();
- }
- catch(...)
- {
- printf("Exception caught successfully!\n");
- }
- return 0;
- }
- '''
- self.do_run(src, 'Exception caught successfully!')
-
- def test_white_list_exception(self):
- Settings.DISABLE_EXCEPTION_CATCHING = 2
- Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
- Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified
-
- src = '''
- #include <stdio.h>
-
- void thrower() {
- printf("infunc...");
- throw(99);
- printf("FAIL");
- }
-
- void somefunction() {
- try {
- thrower();
- } catch(...) {
- printf("done!*\\n");
- }
- }
-
- int main() {
- somefunction();
- return 0;
- }
- '''
- self.do_run(src, 'infunc...done!*')
-
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- Settings.EXCEPTION_CATCHING_WHITELIST = []
-
- def test_uncaught_exception(self):
- if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
-
- Settings.DISABLE_EXCEPTION_CATCHING = 0
-
- src = r'''
- #include <stdio.h>
- #include <exception>
- struct X {
- ~X() {
- printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
- }
- };
- int main() {
- printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
- try {
- X x;
- throw 1;
- } catch(...) {
- printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
- }
- printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
- return 0;
- }
- '''
- self.do_run(src, 'exception? no\nexception? yes\nexception? no\nexception? no\n')
-
- src = r'''
- #include <fstream>
- #include <iostream>
- int main() {
- std::ofstream os("test");
- os << std::unitbuf << "foo"; // trigger a call to std::uncaught_exception from
- // std::basic_ostream::sentry::~sentry
- std::cout << "success";
- }
- '''
- self.do_run(src, 'success')
-
- def test_typed_exceptions(self):
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
- src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read()
- expected = open(path_from_root('tests', 'exceptions', 'output.txt'), 'r').read()
- self.do_run(src, expected)
-
- def test_multiexception(self):
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- src = r'''
-#include <stdio.h>
-
-static int current_exception_id = 0;
-
-typedef struct {
- int jmp;
-} jmp_state;
-
-void setjmp_func(jmp_state* s, int level) {
- int prev_jmp = s->jmp;
- int c_jmp;
-
- if (level == 2) {
- printf("level is 2, perform longjmp!\n");
- throw 1;
- }
-
- c_jmp = current_exception_id++;
- try {
- printf("setjmp normal execution path, level: %d, prev_jmp: %d\n", level, prev_jmp);
- s->jmp = c_jmp;
- setjmp_func(s, level + 1);
- } catch (int catched_eid) {
- printf("caught %d\n", catched_eid);
- if (catched_eid == c_jmp) {
- printf("setjmp exception execution path, level: %d, prev_jmp: %d\n", level, prev_jmp);
- if (prev_jmp != -1) {
- printf("prev_jmp is not empty, continue with longjmp!\n");
- s->jmp = prev_jmp;
- throw s->jmp;
- }
- } else {
- throw;
- }
- }
-
- printf("Exiting setjmp function, level: %d, prev_jmp: %d\n", level, prev_jmp);
-}
-
-int main(int argc, char *argv[]) {
- jmp_state s;
- s.jmp = -1;
-
- setjmp_func(&s, 0);
-
- return 0;
-}
-'''
- self.do_run(src, '''setjmp normal execution path, level: 0, prev_jmp: -1
-setjmp normal execution path, level: 1, prev_jmp: 0
-level is 2, perform longjmp!
-caught 1
-setjmp exception execution path, level: 1, prev_jmp: 0
-prev_jmp is not empty, continue with longjmp!
-caught 0
-setjmp exception execution path, level: 0, prev_jmp: -1
-Exiting setjmp function, level: 0, prev_jmp: -1
-''')
-
- def test_std_exception(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- self.emcc_args += ['-s', 'SAFE_HEAP=0']
-
- src = r'''
- #include <stdio.h>
- #include <exception>
-
- int main()
- {
- std::exception e;
- try {
- throw e;
- } catch(std::exception e) {
- printf("caught std::exception\n");
- }
- return 0;
- }
- '''
- self.do_run(src, 'caught std::exception')
-
- def test_exit_stack(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.ASM_JS: return self.skip('uses report_stack without exporting')
-
- Settings.INLINING_LIMIT = 50
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- extern "C" {
- extern void report_stack(int x);
- }
-
- char moar() {
- char temp[125];
- for (int i = 0; i < 125; i++) temp[i] = i*i;
- for (int i = 1; i < 125; i++) temp[i] += temp[i-1]/2;
- if (temp[100] != 99) exit(1);
- return temp[120];
- }
-
- int main(int argc, char *argv[]) {
- report_stack((int)alloca(4));
- printf("*%d*\n", moar());
- return 0;
- }
- '''
-
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- var initialStack = -1;
- var _report_stack = function(x) {
- Module.print('reported');
- initialStack = x;
- }
- var Module = {
- postRun: function() {
- Module.print('postRun');
- assert(initialStack == STACKTOP, [initialStack, STACKTOP]);
- Module.print('ok.');
- }
- };
- ''')
-
- self.emcc_args += ['--pre-js', 'pre.js']
- self.do_run(src, '''reported\nExit Status: 1\npostRun\nok.\n''')
-
- def test_class(self):
- src = '''
- #include <stdio.h>
- struct Random {
- enum { IM = 139968, IA = 3877, IC = 29573 };
- Random() : last(42) {}
- float get( float max = 1.0f ) {
- last = ( last * IA + IC ) % IM;
- return max * last / IM;
- }
- protected:
- unsigned int last;
- } rng1;
- int main()
- {
- Random rng2;
- int count = 0;
- for (int i = 0; i < 100; i++) {
- float x1 = rng1.get();
- float x2 = rng2.get();
- printf("%f, %f\\n", x1, x2);
- if (x1 != x2) count += 1;
- }
- printf("*%d*\\n", count);
- return 0;
- }
- '''
- self.do_run(src, '*0*')
-
- def test_inherit(self):
- src = '''
- #include <stdio.h>
- struct Parent {
- int x1, x2;
- };
- struct Child : Parent {
- int y;
- };
- int main()
- {
- Parent a;
- a.x1 = 50;
- a.x2 = 87;
- Child b;
- b.x1 = 78;
- b.x2 = 550;
- b.y = 101;
- Child* c = (Child*)&a;
- c->x1 ++;
- c = &b;
- c->y --;
- printf("*%d,%d,%d,%d,%d,%d,%d*\\n", a.x1, a.x2, b.x1, b.x2, b.y, c->x1, c->x2);
- return 0;
- }
- '''
- self.do_run(src, '*51,87,78,550,100,78,550*')
-
- def test_isdigit_l(self):
- if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
-
- src = '''
- #include <iostream>
- int main() {
- using namespace std;
- use_facet<num_put<char> >(cout.getloc()).put(cout, cout, '0', 3.14159265);
- }
- '''
- self.do_run(src, '3.14159')
-
- def test_polymorph(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = '''
- #include <stdio.h>
- struct Pure {
- virtual int implme() = 0;
- };
- struct Parent : Pure {
- virtual int getit() { return 11; };
- int implme() { return 32; }
- };
- struct Child : Parent {
- int getit() { return 74; }
- int implme() { return 1012; }
- };
-
- struct Other {
- int one() { return 11; }
- int two() { return 22; }
- };
-
- int main()
- {
- Parent *x = new Parent();
- Parent *y = new Child();
- printf("*%d,%d,%d,%d*\\n", x->getit(), y->getit(), x->implme(), y->implme());
-
- Other *o = new Other;
- int (Other::*Ls)() = &Other::one;
- printf("*%d*\\n", (o->*(Ls))());
- Ls = &Other::two;
- printf("*%d*\\n", (o->*(Ls))());
-
- return 0;
- }
- '''
- self.do_run(src, '*11,74,32,1012*\n*11*\n*22*')
-
- def test_segfault(self):
- if self.emcc_args is None: return self.skip('SAFE_HEAP without ta2 means we check types too, which hide segfaults')
- if Settings.ASM_JS: return self.skip('asm does not support safe heap')
-
- Settings.SAFE_HEAP = 1
-
- for addr in ['0', 'new D2()']:
- print addr
- src = r'''
- #include <stdio.h>
-
- struct Classey {
- virtual void doIt() = 0;
- };
-
- struct D1 : Classey {
- virtual void doIt() { printf("fleefl\n"); }
- };
-
- struct D2 : Classey {
- virtual void doIt() { printf("marfoosh\n"); }
- };
-
- int main(int argc, char **argv)
- {
- Classey *p = argc == 100 ? new D1() : (Classey*)%s;
-
- p->doIt();
-
- return 0;
- }
- ''' % addr
- self.do_run(src, 'segmentation fault' if addr.isdigit() else 'marfoosh')
-
- def test_safe_dyncalls(self):
- if Settings.ASM_JS: return self.skip('asm does not support missing function stack traces')
- if Settings.SAFE_HEAP: return self.skip('safe heap warning will appear instead')
- if self.emcc_args is None: return self.skip('need libc')
-
- Settings.SAFE_DYNCALLS = 1
-
- for cond, body, work in [(True, True, False), (True, False, False), (False, True, True), (False, False, False)]:
- print cond, body, work
- src = r'''
- #include <stdio.h>
-
- struct Classey {
- virtual void doIt() = 0;
- };
-
- struct D1 : Classey {
- virtual void doIt() BODY;
- };
-
- int main(int argc, char **argv)
- {
- Classey *p = argc COND 100 ? new D1() : NULL;
- printf("%p\n", p);
- p->doIt();
-
- return 0;
- }
- '''.replace('COND', '==' if cond else '!=').replace('BODY', r'{ printf("all good\n"); }' if body else '')
- self.do_run(src, 'dyncall error: vi' if not work else 'all good')
-
- def test_dynamic_cast(self):
- if self.emcc_args is None: return self.skip('need libcxxabi')
-
- src = r'''
- #include <stdio.h>
-
- struct Support {
- virtual void f() {
- printf("f()\n");
- }
- };
-
- struct Derived : Support {
- };
-
- int main() {
- Support * p = new Derived;
- dynamic_cast<Derived*>(p)->f();
- }
- '''
- self.do_run(src, 'f()\n')
-
- def test_dynamic_cast_b(self):
- if self.emcc_args is None: return self.skip('need libcxxabi')
-
- src = '''
- #include <stdio.h>
-
- class CBase { virtual void dummy() {} };
- class CDerived : public CBase { int a; };
- class CDerivedest : public CDerived { float b; };
-
- int main ()
- {
- CBase *pa = new CBase;
- CBase *pb = new CDerived;
- CBase *pc = new CDerivedest;
-
- printf("a1: %d\\n", dynamic_cast<CDerivedest*>(pa) != NULL);
- printf("a2: %d\\n", dynamic_cast<CDerived*>(pa) != NULL);
- printf("a3: %d\\n", dynamic_cast<CBase*>(pa) != NULL);
-
- printf("b1: %d\\n", dynamic_cast<CDerivedest*>(pb) != NULL);
- printf("b2: %d\\n", dynamic_cast<CDerived*>(pb) != NULL);
- printf("b3: %d\\n", dynamic_cast<CBase*>(pb) != NULL);
-
- printf("c1: %d\\n", dynamic_cast<CDerivedest*>(pc) != NULL);
- printf("c2: %d\\n", dynamic_cast<CDerived*>(pc) != NULL);
- printf("c3: %d\\n", dynamic_cast<CBase*>(pc) != NULL);
-
- return 0;
- }
- '''
- self.do_run(src, 'a1: 0\na2: 0\na3: 1\nb1: 0\nb2: 1\nb3: 1\nc1: 1\nc2: 1\nc3: 1\n')
-
- def test_dynamic_cast_2(self):
- if self.emcc_args is None: return self.skip('need libcxxabi')
-
- src = r'''
- #include <stdio.h>
- #include <typeinfo>
-
- class Class {};
-
- int main() {
- const Class* dp = dynamic_cast<const Class*>(&typeid(Class));
- // should return dp == NULL,
- printf("pointer: %p\n", dp);
- }
- '''
- self.do_run(src, "pointer: (nil)")
-
- def test_funcptr(self):
- src = '''
- #include <stdio.h>
- int calc1() { return 26; }
- int calc2() { return 90; }
- typedef int (*fp_t)();
-
- fp_t globally1 = calc1;
- fp_t globally2 = calc2;
-
- int nothing(const char *str) { return 0; }
-
- int main()
- {
- fp_t fp = calc1;
- void *vp = (void*)fp;
- fp_t fpb = (fp_t)vp;
- fp_t fp2 = calc2;
- void *vp2 = (void*)fp2;
- fp_t fpb2 = (fp_t)vp2;
- printf("*%d,%d,%d,%d,%d,%d*\\n", fp(), fpb(), fp2(), fpb2(), globally1(), globally2());
-
- fp_t t = calc1;
- printf("*%d,%d", t == calc1, t == calc2);
- t = calc2;
- printf(",%d,%d*\\n", t == calc1, t == calc2);
-
- int (*other)(const char *str);
- other = nothing;
- other("*hello!*");
- other = puts;
- other("*goodbye!*");
-
- return 0;
- }
- '''
- self.do_run(src, '*26,26,90,90,26,90*\n*1,0,0,1*\n*goodbye!*')
-
- def test_mathfuncptr(self):
- src = '''
- #include <math.h>
- #include <stdio.h>
-
- int
- main(int argc, char **argv) {
- float (*fn)(float) = argc != 12 ? &sqrtf : &fabsf;
- float (*fn2)(float) = argc != 13 ? &fabsf : &sqrtf;
- float (*fn3)(float) = argc != 14 ? &erff : &fabsf;
- printf("fn2(-5) = %d, fn(10) = %.2f, erf(10) = %.2f\\n", (int)fn2(-5), fn(10), fn3(10));
- return 0;
- }
- '''
- self.do_run(src, 'fn2(-5) = 5, fn(10) = 3.16, erf(10) = 1.00')
-
- def test_funcptrfunc(self):
- src = r'''
- #include <stdio.h>
-
- typedef void (*funcptr)(int, int);
- typedef funcptr (*funcptrfunc)(int);
-
- funcptr __attribute__ ((noinline)) getIt(int x) {
- return (funcptr)x;
- }
-
- int main(int argc, char **argv)
- {
- funcptrfunc fpf = argc < 100 ? getIt : NULL;
- printf("*%p*\n", fpf(argc));
- return 0;
- }
- '''
- self.do_run(src, '*0x1*')
-
- def test_funcptr_namecollide(self):
- src = r'''
- #include <stdio.h>
-
- void do_call(void (*puts)(const char *), const char *str);
-
- void do_print(const char *str) {
- if (!str) do_call(NULL, "delusion");
- if ((int)str == -1) do_print(str+10);
- puts("====");
- puts(str);
- puts("====");
- }
-
- void do_call(void (*puts)(const char *), const char *str) {
- if (!str) do_print("confusion");
- if ((int)str == -1) do_call(NULL, str-10);
- (*puts)(str);
- }
-
- int main(int argc, char **argv)
- {
- for (int i = 0; i < argc; i++) {
- do_call(i != 10 ? do_print : NULL, i != 15 ? "waka waka" : NULL);
- }
- return 0;
- }
- '''
- self.do_run(src, 'waka', force_c=True)
-
- def test_emptyclass(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = '''
- #include <stdio.h>
-
- struct Randomized {
- Randomized(int x) {
- printf("*zzcheezzz*\\n");
- }
- };
-
- int main( int argc, const char *argv[] ) {
- new Randomized(55);
-
- return 0;
- }
- '''
- self.do_run(src, '*zzcheezzz*')
-
- def test_alloca(self):
- src = '''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- char *pc;
- pc = (char *)alloca(5);
- printf("z:%d*%d*\\n", pc > 0, (int)pc);
- return 0;
- }
- '''
- self.do_run(src, 'z:1*', force_c=True)
-
- def test_rename(self):
- src = open(path_from_root('tests', 'stdio', 'test_rename.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_alloca_stack(self):
- if self.emcc_args is None: return # too slow in other modes
-
- # We should not blow up the stack with numerous allocas
- src = '''
- #include <stdio.h>
- #include <stdlib.h>
-
- func(int i) {
- char *pc = (char *)alloca(100);
- *pc = i;
- (*pc)++;
- return (*pc) % 10;
- }
- int main() {
- int total = 0;
- for (int i = 0; i < 1024*1024; i++)
- total += func(i);
- printf("ok:%d*\\n", total);
- return 0;
- }
- '''
- self.do_run(src, 'ok:-32768*', force_c=True)
-
- def test_stack_byval(self):
- if self.emcc_args is None: return # too slow in other modes
-
- # We should also not blow up the stack with byval arguments
- src = r'''
- #include<stdio.h>
- struct vec {
- int x, y, z;
- vec(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {}
- static vec add(vec a, vec b) {
- return vec(a.x+b.x, a.y+b.y, a.z+b.z);
- }
- };
- int main() {
- int total = 0;
- for (int i = 0; i < 1000; i++) {
- for (int j = 0; j < 1000; j++) {
- vec c(i+i%10, j*2, i%255);
- vec d(j*2, j%255, i%120);
- vec f = vec::add(c, d);
- total += (f.x + f.y + f.z) % 100;
- total %= 10240;
- }
- }
- printf("sum:%d*\n", total);
- return 0;
- }
- '''
- self.do_run(src, 'sum:9780*')
-
- def test_stack_varargs(self):
- if self.emcc_args is None: return # too slow in other modes
-
- Settings.INLINING_LIMIT = 50
-
- # We should not blow up the stack with numerous varargs
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- void func(int i) {
- printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
- i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
- }
- int main() {
- for (int i = 0; i < 1024; i++)
- func(i);
- printf("ok!\n");
- return 0;
- }
- '''
- Settings.TOTAL_STACK = 1024
- self.do_run(src, 'ok!')
-
- def test_stack_void(self):
- Settings.INLINING_LIMIT = 50
-
- src = r'''
- #include <stdio.h>
-
- static char s[100]="aaaaa";
- static int func(void) {
- if(s[0]!='a') return 0;
- printf("iso open %s\n", s, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001);
- return 0;
- }
- int main(){
- int i;
- for(i=0;i<5000;i++)
- func();
- printf(".ok.\n");
- }
- '''
- self.do_run(src, '.ok.\n')
-
- def test_life(self):
- if self.emcc_args is None: return self.skip('need c99')
- self.emcc_args += ['-std=c99']
- src = open(path_from_root('tests', 'life.c'), 'r').read()
- self.do_run(src, '''--------------------------------
-[] [] [][][]
- [] [] [] [][] [] [] []
-[] [][] [][] [][][] []
- [] [] [] [] [][] [] []
- [] [][] [] [] [] [] [][][][]
- [][] [][] [] [][][] [] []
- [] [][] [][] [][] [][][]
- [][] [][][] [] []
- [][] [][] []
- [][][]
- []
-
-
-
-
- [][][]
- [] [][] [][]
- [][] [] [][] [][]
- [][] [][]
- []
- [][]
- [][] []
-[] [][] []
- [][][] []
- [] [][]
-[] [] []
- []
-[] [] []
- [][][]
-
- []
- [][][] []
---------------------------------
-''', ['2'], force_c=True)
-
- def test_array2(self):
- src = '''
- #include <stdio.h>
-
- static const double grid[4][2] = {
- {-3/3.,-1/3.},{+1/3.,-3/3.},
- {-1/3.,+3/3.},{+3/3.,+1/3.}
- };
-
- int main() {
- for (int i = 0; i < 4; i++)
- printf("%d:%.2f,%.2f ", i, grid[i][0], grid[i][1]);
- printf("\\n");
- return 0;
- }
- '''
- self.do_run(src, '0:-1.00,-0.33 1:0.33,-1.00 2:-0.33,1.00 3:1.00,0.33')
-
- def test_array2b(self):
- src = '''
- #include <stdio.h>
-
- static const struct {
- unsigned char left;
- unsigned char right;
- } prioritah[] = {
- {6, 6}, {6, 6}, {7, 95}, {7, 7}
- };
-
- int main() {
- printf("*%d,%d\\n", prioritah[1].left, prioritah[1].right);
- printf("%d,%d*\\n", prioritah[2].left, prioritah[2].right);
- return 0;
- }
- '''
- self.do_run(src, '*6,6\n7,95*')
-
-
- def test_constglobalstructs(self):
- src = '''
- #include <stdio.h>
- struct IUB {
- int c;
- double p;
- unsigned int pi;
- };
-
- IUB iub[] = {
- { 'a', 0.27, 5 },
- { 'c', 0.15, 4 },
- { 'g', 0.12, 3 },
- { 't', 0.27, 2 },
- };
-
- const unsigned char faceedgesidx[6][4] =
- {
- { 4, 5, 8, 10 },
- { 6, 7, 9, 11 },
- { 0, 2, 8, 9 },
- { 1, 3, 10,11 },
- { 0, 1, 4, 6 },
- { 2, 3, 5, 7 },
- };
-
- int main( int argc, const char *argv[] ) {
- printf("*%d,%d,%d,%d*\\n", iub[0].c, int(iub[1].p*100), iub[2].pi, faceedgesidx[3][2]);
- return 0;
- }
- '''
- self.do_run(src, '*97,15,3,10*')
-
- def test_conststructs(self):
- src = '''
- #include <stdio.h>
- struct IUB {
- int c;
- double p;
- unsigned int pi;
- };
-
- int main( int argc, const char *argv[] ) {
- int before = 70;
- IUB iub[] = {
- { 'a', 0.3029549426680, 5 },
- { 'c', 0.15, 4 },
- { 'g', 0.12, 3 },
- { 't', 0.27, 2 },
- };
- int after = 90;
- printf("*%d,%d,%d,%d,%d,%d*\\n", before, iub[0].c, int(iub[1].p*100), iub[2].pi, int(iub[0].p*10000), after);
- return 0;
- }
- '''
- self.do_run(src, '*70,97,15,3,3029,90*')
-
- def test_bigarray(self):
- if self.emcc_args is None: return self.skip('need ta2 to compress type data on zeroinitializers')
-
- # avoid "array initializer too large" errors
- src = r'''
- #include <stdio.h>
- #include <assert.h>
-
- #define SIZE (1024*100)
- struct Struct {
- char x;
- int y;
- };
- Struct buffy[SIZE];
-
- int main() {
- for (int i = 0; i < SIZE; i++) { assert(buffy[i].x == 0 && buffy[i].y == 0); } // we were zeroinitialized
- for (int i = 0; i < SIZE; i++) { buffy[i].x = i*i; buffy[i].y = i*i*i; } // we can save data
- printf("*%d*\n", buffy[SIZE/3].x);
- return 0;
- }
- '''
- self.do_run(src, '*57*')
-
- def test_mod_globalstruct(self):
- src = '''
- #include <stdio.h>
-
- struct malloc_params {
- size_t magic, page_size;
- };
-
- malloc_params mparams;
-
- #define SIZE_T_ONE ((size_t)1)
- #define page_align(S) (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
-
- int main()
- {
- mparams.page_size = 4096;
- printf("*%d,%d,%d,%d*\\n", mparams.page_size, page_align(1000), page_align(6000), page_align(66474));
- return 0;
- }
- '''
- self.do_run(src, '*4096,4096,8192,69632*')
-
- def test_pystruct(self):
- src = '''
- #include <stdio.h>
-
- // Based on CPython code
- union PyGC_Head {
- struct {
- union PyGC_Head *gc_next;
- union PyGC_Head *gc_prev;
- size_t gc_refs;
- } gc;
- long double dummy; /* force worst-case alignment */
- } ;
-
- struct gc_generation {
- PyGC_Head head;
- int threshold; /* collection threshold */
- int count; /* count of allocations or collections of younger
- generations */
- };
-
- #define NUM_GENERATIONS 3
- #define GEN_HEAD(n) (&generations[n].head)
-
- /* linked lists of container objects */
- static struct gc_generation generations[NUM_GENERATIONS] = {
- /* PyGC_Head, threshold, count */
- {{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0},
- {{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0},
- {{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0},
- };
-
- int main()
- {
- gc_generation *n = NULL;
- printf("*%d,%d,%d,%d,%d,%d,%d,%d*\\n",
- (int)(&n[0]),
- (int)(&n[0].head),
- (int)(&n[0].head.gc.gc_next),
- (int)(&n[0].head.gc.gc_prev),
- (int)(&n[0].head.gc.gc_refs),
- (int)(&n[0].threshold), (int)(&n[0].count), (int)(&n[1])
- );
- printf("*%d,%d,%d*\\n",
- (int)(&generations[0]) ==
- (int)(&generations[0].head.gc.gc_next),
- (int)(&generations[0]) ==
- (int)(&generations[0].head.gc.gc_prev),
- (int)(&generations[0]) ==
- (int)(&generations[1])
- );
- int x1 = (int)(&generations[0]);
- int x2 = (int)(&generations[1]);
- printf("*%d*\\n", x1 == x2);
- for (int i = 0; i < NUM_GENERATIONS; i++) {
- PyGC_Head *list = GEN_HEAD(i);
- printf("%d:%d,%d\\n", i, (int)list == (int)(list->gc.gc_prev), (int)list ==(int)(list->gc.gc_next));
- }
- printf("*%d,%d,%d*\\n", sizeof(PyGC_Head), sizeof(gc_generation), int(GEN_HEAD(2)) - int(GEN_HEAD(1)));
- }
- '''
- if Settings.QUANTUM_SIZE == 1:
- # Compressed memory. Note that sizeof() does give the fat sizes, however!
- self.do_run(src, '*0,0,0,1,2,3,4,5*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,5*')
- else:
- if self.is_le32():
- self.do_run(src, '*0,0,0,4,8,16,20,24*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*16,24,24*')
- else:
- self.do_run(src, '*0,0,0,4,8,12,16,20*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,20*')
-
- def test_ptrtoint(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = '''
- #include <stdio.h>
-
- int main( int argc, const char *argv[] ) {
- char *a = new char[10];
- char *a0 = a+0;
- char *a5 = a+5;
- int *b = new int[10];
- int *b0 = b+0;
- int *b5 = b+5;
- int c = (int)b5-(int)b0; // Emscripten should warn!
- int d = (int)b5-(int)b0; // Emscripten should warn!
- printf("*%d*\\n", (int)a5-(int)a0);
- return 0;
- }
- '''
- runner = self
- def check_warnings(output):
- runner.assertEquals(filter(lambda line: 'Warning' in line, output.split('\n')).__len__(), 4)
- self.do_run(src, '*5*', output_processor=check_warnings)
-
- def test_sizeof(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- # Has invalid writes between printouts
- Settings.SAFE_HEAP = 0
-
- src = '''
- #include <stdio.h>
- #include <string.h>
- #include "emscripten.h"
-
- struct A { int x, y; };
-
- int main( int argc, const char *argv[] ) {
- int *a = new int[10];
- int *b = new int[1];
- int *c = new int[10];
- for (int i = 0; i < 10; i++)
- a[i] = 2;
- *b = 5;
- for (int i = 0; i < 10; i++)
- c[i] = 8;
- printf("*%d,%d,%d,%d,%d*\\n", a[0], a[9], *b, c[0], c[9]);
- // Should overwrite a, but not touch b!
- memcpy(a, c, 10*sizeof(int));
- printf("*%d,%d,%d,%d,%d*\\n", a[0], a[9], *b, c[0], c[9]);
-
- // Part 2
- A as[3] = { { 5, 12 }, { 6, 990 }, { 7, 2 } };
- memcpy(&as[0], &as[2], sizeof(A));
-
- printf("*%d,%d,%d,%d,%d,%d*\\n", as[0].x, as[0].y, as[1].x, as[1].y, as[2].x, as[2].y);
- return 0;
- }
- '''
- self.do_run(src, '*2,2,5,8,8***8,8,5,8,8***7,2,6,990,7,2*', [], lambda x, err: x.replace('\n', '*'))
-
- def test_float_h(self):
- process = Popen([PYTHON, EMCC, path_from_root('tests', 'float+.c')], stdout=PIPE, stderr=PIPE)
- process.communicate()
- assert process.returncode is 0, 'float.h should agree with our system'
-
- def test_emscripten_api(self):
- #if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME')
-
- src = r'''
- #include <stdio.h>
- #include "emscripten.h"
-
- extern "C" {
- void save_me_aimee() { printf("mann\n"); }
- }
-
- int main() {
- // EMSCRIPTEN_COMMENT("hello from the source");
- emscripten_run_script("Module.print('hello world' + '!')");
- printf("*%d*\n", emscripten_run_script_int("5*20"));
- printf("*%s*\n", emscripten_run_script_string("'five'+'six'"));
- emscripten_run_script("Module['_save_me_aimee']()");
- return 0;
- }
- '''
-
- check = '''
-def process(filename):
- src = open(filename, 'r').read()
- # TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src
-'''
- Settings.EXPORTED_FUNCTIONS = ['_main', '_save_me_aimee']
- self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
-
- # test EXPORT_ALL
- Settings.EXPORTED_FUNCTIONS = []
- Settings.EXPORT_ALL = 1
- self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
-
- def test_inlinejs(self):
- if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
- src = r'''
- #include <stdio.h>
-
- double get() {
- double ret = 0;
- __asm __volatile__("Math.abs(-12/3.3)":"=r"(ret)); // write to a variable
- return ret;
- }
-
- int main() {
- asm("Module.print('Inline JS is very cool')");
- printf("%.2f\n", get());
- return 0;
- }
- '''
-
- self.do_run(src, 'Inline JS is very cool\n3.64')
-
- def zzztest_inlinejs2(self):
- if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
- src = r'''
- #include <stdio.h>
-
- double get() {
- double ret = 0;
- __asm __volatile__("Math.abs(-12/3.3)":"=r"(ret)); // write to a variable
- return ret;
- }
-
- int mix(int x, int y) {
- int ret;
- asm("Math.pow(2, %0+%1+1)" : "=r"(ret) : "r"(x), "r"(y)); // read and write
- return ret;
- }
-
- void mult() {
- asm("var $_$1 = Math.abs(-100); $_$1 *= 2;"); // multiline
- asm __volatile__("Module.print($_$1); Module.print('\n')");
- }
-
- int main(int argc, char **argv) {
- asm("Module.print('Inline JS is very cool')");
- printf("%.2f\n", get());
- printf("%d\n", mix(argc, argc/2));
- mult();
- return 0;
- }
- '''
-
- self.do_run(src, 'Inline JS is very cool\n3.64\nwaka\nzakai\n')
-
- def test_memorygrowth(self):
- if Settings.USE_TYPED_ARRAYS == 0: return self.skip('memory growth is only supported with typed arrays')
- if Settings.ASM_JS: return self.skip('asm does not support memory growth yet')
-
- # With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY,
- # since we then need to enlarge the heap(s).
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include "emscripten.h"
-
- int main(int argc, char **argv)
- {
- char *buf1 = (char*)malloc(100);
- char *data1 = "hello";
- memcpy(buf1, data1, strlen(data1)+1);
-
- float *buf2 = (float*)malloc(100);
- float pie = 4.955;
- memcpy(buf2, &pie, sizeof(float));
-
- printf("*pre: %s,%.3f*\n", buf1, buf2[0]);
-
- int totalMemory = emscripten_run_script_int("TOTAL_MEMORY");
- char *buf3 = (char*)malloc(totalMemory+1);
- buf3[argc] = (int)buf2;
- if (argc % 7 == 6) printf("%d\n", memcpy(buf3, buf1, argc));
- char *buf4 = (char*)malloc(100);
- float *buf5 = (float*)malloc(100);
- //printf("totalMemory: %d bufs: %d,%d,%d,%d,%d\n", totalMemory, buf1, buf2, buf3, buf4, buf5);
- assert((int)buf4 > (int)totalMemory && (int)buf5 > (int)totalMemory);
-
- printf("*%s,%.3f*\n", buf1, buf2[0]); // the old heap data should still be there
-
- memcpy(buf4, buf1, strlen(data1)+1);
- memcpy(buf5, buf2, sizeof(float));
- printf("*%s,%.3f*\n", buf4, buf5[0]); // and the new heap space should work too
-
- return 0;
- }
- '''
-
- # Fail without memory growth
- self.do_run(src, 'Cannot enlarge memory arrays.')
- fail = open('src.cpp.o.js').read()
-
- # Win with it
- Settings.ALLOW_MEMORY_GROWTH = 1
- self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*')
- win = open('src.cpp.o.js').read()
-
- if self.emcc_args and '-O2' in self.emcc_args:
- # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized)
- code_start = 'var TOTAL_MEMORY = '
- fail = fail[fail.find(code_start):]
- win = win[win.find(code_start):]
- assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller'
-
- def test_ssr(self): # struct self-ref
- src = '''
- #include <stdio.h>
-
- // see related things in openjpeg
- typedef struct opj_mqc_state {
- unsigned int qeval;
- int mps;
- struct opj_mqc_state *nmps;
- struct opj_mqc_state *nlps;
- } opj_mqc_state_t;
-
- static opj_mqc_state_t mqc_states[2] = {
- {0x5600, 0, &mqc_states[2], &mqc_states[3]},
- {0x5602, 1, &mqc_states[3], &mqc_states[2]},
- };
-
- int main() {
- printf("*%d*\\n", (int)(mqc_states+1)-(int)mqc_states);
- for (int i = 0; i < 2; i++)
- printf("%d:%d,%d,%d,%d\\n", i, mqc_states[i].qeval, mqc_states[i].mps,
- (int)mqc_states[i].nmps-(int)mqc_states, (int)mqc_states[i].nlps-(int)mqc_states);
- return 0;
- }
- '''
- if Settings.QUANTUM_SIZE == 1:
- self.do_run(src, '''*4*\n0:22016,0,8,12\n1:22018,1,12,8\n''')
- else:
- self.do_run(src, '''*16*\n0:22016,0,32,48\n1:22018,1,48,32\n''')
-
- def test_tinyfuncstr(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = '''
- #include <stdio.h>
-
- struct Class {
- static char *name1() { return "nameA"; }
- char *name2() { return "nameB"; }
- };
-
- int main() {
- printf("*%s,%s*\\n", Class::name1(), (new Class())->name2());
- return 0;
- }
- '''
- self.do_run(src, '*nameA,nameB*')
-
- def test_llvmswitch(self):
- Settings.CORRECT_SIGNS = 1
-
- src = '''
- #include <stdio.h>
- #include <string.h>
-
- int switcher(int p)
- {
- switch(p) {
- case 'a':
- case 'b':
- case 'c':
- return p-1;
- case -15:
- return p+1;
- }
- return p;
- }
-
- int main( int argc, const char *argv[] ) {
- unsigned int x = 0xfffffff1;
- x >>= (argc-1); // force it to be unsigned for purpose of checking our switch comparison in signed/unsigned
- printf("*%d,%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher(x), switcher(-15), switcher('e'));
- return 0;
- }
- '''
- self.do_run(src, '*96,97,98,-14,-14,101*')
-
- # By default, when user has not specified a -std flag, Emscripten should always build .cpp files using the C++03 standard,
- # i.e. as if "-std=c++03" had been passed on the command line. On Linux with Clang 3.2 this is the case, but on Windows
- # with Clang 3.2 -std=c++11 has been chosen as default, because of
- # < jrose> clb: it's deliberate, with the idea that for people who don't care about the standard, they should be using the "best" thing we can offer on that platform
- def test_cxx03_do_run(self):
- src = '''
- #include <stdio.h>
-
- #if __cplusplus != 199711L
- #error By default, if no -std is specified, emscripten should be compiling with -std=c++03!
- #endif
-
- int main( int argc, const char *argv[] ) {
- printf("Hello world!\\n");
- return 0;
- }
- '''
- self.do_run(src, 'Hello world!')
-
- def test_bigswitch(self):
- if Settings.RELOOP: return self.skip('TODO: switch in relooper, issue #781')
- if Settings.ASM_JS: return self.skip('TODO: switch too large for asm')
-
- src = open(path_from_root('tests', 'bigswitch.cpp')).read()
- self.do_run(src, '''34962: GL_ARRAY_BUFFER (0x8892)
-26214: what?
-35040: GL_STREAM_DRAW (0x88E0)
-''', args=['34962', '26214', '35040'])
-
- def test_indirectbr(self):
- Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS)
-
- src = '''
- #include <stdio.h>
- int main(void) {
- const void *addrs[2] = { &&FOO, &&BAR };
-
- // confuse the optimizer so it doesn't hardcode the jump and avoid generating an |indirectbr| instruction
- int which = 0;
- for (int x = 0; x < 1000; x++) which = (which + x*x) % 7;
- which = (which % 2) + 1;
-
- goto *addrs[which];
-
- FOO:
- printf("bad\\n");
- return 0;
- BAR:
- printf("good\\n");
- const void *addr = &&FOO;
- goto *addr;
- }
- '''
- self.do_run(src, 'good\nbad')
-
- def test_indirectbr_many(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('blockaddr > 255 requires ta2')
-
- blocks = range(1500)
- init = ', '.join(['&&B%d' % b for b in blocks])
- defs = '\n'.join(['B%d: printf("%d\\n"); return 0;' % (b,b) for b in blocks])
- src = '''
- #include <stdio.h>
- int main(int argc, char **argv) {
- printf("\\n");
- const void *addrs[] = { %s };
- goto *addrs[argc*argc + 1000];
-
-%s
- return 0;
- }
- ''' % (init, defs)
- self.do_run(src, '\n1001\n')
-
- def test_pack(self):
- src = '''
- #include <stdio.h>
- #include <string.h>
-
- #pragma pack(push,1)
- typedef struct header
- {
- unsigned char id;
- unsigned short colour;
- unsigned char desc;
- } header;
- #pragma pack(pop)
-
- typedef struct fatheader
- {
- unsigned char id;
- unsigned short colour;
- unsigned char desc;
- } fatheader;
-
- int main( int argc, const char *argv[] ) {
- header h, *ph = 0;
- fatheader fh, *pfh = 0;
- printf("*%d,%d,%d*\\n", sizeof(header), (int)((int)&h.desc - (int)&h.id), (int)(&ph[1])-(int)(&ph[0]));
- printf("*%d,%d,%d*\\n", sizeof(fatheader), (int)((int)&fh.desc - (int)&fh.id), (int)(&pfh[1])-(int)(&pfh[0]));
- return 0;
- }
- '''
- if Settings.QUANTUM_SIZE == 1:
- self.do_run(src, '*4,2,3*\n*6,2,3*')
- else:
- self.do_run(src, '*4,3,4*\n*6,4,6*')
-
- def test_varargs(self):
- if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
- if not self.is_le32(): return self.skip('we do not support all varargs stuff without le32')
-
- src = '''
- #include <stdio.h>
- #include <stdarg.h>
-
- void vary(const char *s, ...)
- {
- va_list v;
- va_start(v, s);
- char d[20];
- vsnprintf(d, 20, s, v);
- puts(d);
-
- // Try it with copying
- va_list tempva;
- va_copy(tempva, v);
- vsnprintf(d, 20, s, tempva);
- puts(d);
-
- va_end(v);
- }
-
- void vary2(char color, const char *s, ...)
- {
- va_list v;
- va_start(v, s);
- char d[21];
- d[0] = color;
- vsnprintf(d+1, 20, s, v);
- puts(d);
- va_end(v);
- }
-
- void varargs_listoffsets_list_evaluate(int count, va_list ap, int vaIteration)
- {
- while(count > 0)
- {
- const char* string = va_arg(ap, const char*);
- printf("%s", string);
- count--;
- }
- printf("\\n");
- }
-
- void varags_listoffsets_list_copy(int count, va_list ap, int iteration)
- {
- va_list ap_copy;
- va_copy(ap_copy, ap);
- varargs_listoffsets_list_evaluate(count, ap_copy, iteration);
- va_end(ap_copy);
- }
-
- void varargs_listoffsets_args(int type, int count, ...)
- {
- va_list ap;
- va_start(ap, count);
-
- // evaluate a copied list
- varags_listoffsets_list_copy(count, ap, 1);
- varags_listoffsets_list_copy(count, ap, 2);
- varags_listoffsets_list_copy(count, ap, 3);
- varags_listoffsets_list_copy(count, ap, 4);
-
- varargs_listoffsets_list_evaluate(count, ap, 1);
-
- // NOTE: we expect this test to fail, so we will check the stdout for <BAD+0><BAD+1>.....
- varargs_listoffsets_list_evaluate(count, ap, 2);
-
- // NOTE: this test has to work again, as we restart the list
- va_end(ap);
- va_start(ap, count);
- varargs_listoffsets_list_evaluate(count, ap, 3);
- va_end(ap);
- }
-
- void varargs_listoffsets_main()
- {
- varargs_listoffsets_args(0, 5, "abc", "def", "ghi", "jkl", "mno", "<BAD+0>", "<BAD+1>", "<BAD+2>", "<BAD+3>", "<BAD+4>", "<BAD+5>", "<BAD+6>", "<BAD+7>", "<BAD+8>", "<BAD+9>", "<BAD+10>", "<BAD+11>", "<BAD+12>", "<BAD+13>", "<BAD+14>", "<BAD+15>", "<BAD+16>");
- }
-
- #define GETMAX(pref, type) \
- type getMax##pref(int num, ...) \
- { \
- va_list vv; \
- va_start(vv, num); \
- type maxx = va_arg(vv, type); \
- for (int i = 1; i < num; i++) \
- { \
- type curr = va_arg(vv, type); \
- maxx = curr > maxx ? curr : maxx; \
- } \
- va_end(vv); \
- return maxx; \
- }
- GETMAX(i, int);
- GETMAX(D, double);
-
- int main(int argc, char **argv) {
- vary("*cheez: %d+%d*", 0, 24); // Also tests that '0' is not special as an array ender
- vary("*albeit*"); // Should not fail with no var args in vararg function
- vary2('Q', "%d*", 85);
-
- int maxxi = getMaxi(6, 2, 5, 21, 4, -10, 19);
- printf("maxxi:%d*\\n", maxxi);
- double maxxD = getMaxD(6, (double)2.1, (double)5.1, (double)22.1, (double)4.1, (double)-10.1, (double)19.1, (double)2);
- printf("maxxD:%.2f*\\n", (float)maxxD);
-
- // And, as a function pointer
- void (*vfp)(const char *s, ...) = argc == 1211 ? NULL : vary;
- vfp("*vfp:%d,%d*", 22, 199);
-
- // ensure lists work properly when copied, reinited etc.
- varargs_listoffsets_main();
-
- return 0;
- }
- '''
- self.do_run(src, '*cheez: 0+24*\n*cheez: 0+24*\n*albeit*\n*albeit*\nQ85*\nmaxxi:21*\nmaxxD:22.10*\n*vfp:22,199*\n*vfp:22,199*\n'+
- 'abcdefghijklmno\nabcdefghijklmno\nabcdefghijklmno\nabcdefghijklmno\nabcdefghijklmno\n<BAD+0><BAD+1><BAD+2><BAD+3><BAD+4>\nabcdefghijklmno\n')
-
- def test_varargs_byval(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('FIXME: Add support for this')
- if self.is_le32(): return self.skip('clang cannot compile this code with that target yet')
-
- src = r'''
- #include <stdio.h>
- #include <stdarg.h>
-
- typedef struct type_a {
- union {
- double f;
- void *p;
- int i;
- short sym;
- } value;
- } type_a;
-
- enum mrb_vtype {
- MRB_TT_FALSE = 0, /* 0 */
- MRB_TT_CLASS = 9 /* 9 */
- };
-
- typedef struct type_b {
- enum mrb_vtype tt:8;
- } type_b;
-
- void print_type_a(int argc, ...);
- void print_type_b(int argc, ...);
-
- int main(int argc, char *argv[])
- {
- type_a a;
- type_b b;
- a.value.p = (void*) 0x12345678;
- b.tt = MRB_TT_CLASS;
-
- printf("The original address of a is: %p\n", a.value.p);
- printf("The original type of b is: %d\n", b.tt);
-
- print_type_a(1, a);
- print_type_b(1, b);
-
- return 0;
- }
-
- void print_type_a(int argc, ...) {
- va_list ap;
- type_a a;
-
- va_start(ap, argc);
- a = va_arg(ap, type_a);
- va_end(ap);
-
- printf("The current address of a is: %p\n", a.value.p);
- }
-
- void print_type_b(int argc, ...) {
- va_list ap;
- type_b b;
-
- va_start(ap, argc);
- b = va_arg(ap, type_b);
- va_end(ap);
-
- printf("The current type of b is: %d\n", b.tt);
- }
- '''
- self.do_run(src, '''The original address of a is: 0x12345678
-The original type of b is: 9
-The current address of a is: 0x12345678
-The current type of b is: 9
-''')
-
- def test_functionpointer_libfunc_varargs(self):
- src = r'''
- #include <stdio.h>
- #include <fcntl.h>
- typedef int (*fp_t)(int, int, ...);
- int main(int argc, char **argv) {
- fp_t fp = &fcntl;
- if (argc == 1337) fp = (fp_t)&main;
- (*fp)(0, 10);
- (*fp)(0, 10, 5);
- printf("waka\n");
- return 0;
- }
- '''
- self.do_run(src, '''waka''')
-
- def test_structbyval(self):
- Settings.INLINING_LIMIT = 50
-
- # part 1: make sure that normally, passing structs by value works
-
- src = r'''
- #include <stdio.h>
-
- struct point
- {
- int x, y;
- };
-
- void dump(struct point p) {
- p.x++; // should not modify
- p.y++; // anything in the caller!
- printf("dump: %d,%d\n", p.x, p.y);
- }
-
- void dumpmod(struct point *p) {
- p->x++; // should not modify
- p->y++; // anything in the caller!
- printf("dump: %d,%d\n", p->x, p->y);
- }
-
- int main( int argc, const char *argv[] ) {
- point p = { 54, 2 };
- printf("pre: %d,%d\n", p.x, p.y);
- dump(p);
- void (*dp)(point p) = dump; // And, as a function pointer
- dp(p);
- printf("post: %d,%d\n", p.x, p.y);
- dumpmod(&p);
- dumpmod(&p);
- printf("last: %d,%d\n", p.x, p.y);
- return 0;
- }
- '''
- self.do_run(src, 'pre: 54,2\ndump: 55,3\ndump: 55,3\npost: 54,2\ndump: 55,3\ndump: 56,4\nlast: 56,4')
-
- # Check for lack of warning in the generated code (they should appear in part 2)
- generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
- assert 'Casting a function pointer type to another with a different number of arguments.' not in generated, 'Unexpected warning'
-
- # part 2: make sure we warn about mixing c and c++ calling conventions here
-
- if not (self.emcc_args is None or self.emcc_args == []): return # Optimized code is missing the warning comments
-
- header = r'''
- struct point
- {
- int x, y;
- };
-
- '''
- open(os.path.join(self.get_dir(), 'header.h'), 'w').write(header)
-
- supp = r'''
- #include <stdio.h>
- #include "header.h"
-
- void dump(struct point p) {
- p.x++; // should not modify
- p.y++; // anything in the caller!
- printf("dump: %d,%d\n", p.x, p.y);
- }
- '''
- supp_name = os.path.join(self.get_dir(), 'supp.c')
- open(supp_name, 'w').write(supp)
-
- main = r'''
- #include <stdio.h>
- #include "header.h"
-
- #ifdef __cplusplus
- extern "C" {
- #endif
- void dump(struct point p);
- #ifdef __cplusplus
- }
- #endif
-
- int main( int argc, const char *argv[] ) {
- struct point p = { 54, 2 };
- printf("pre: %d,%d\n", p.x, p.y);
- dump(p);
- void (*dp)(struct point p) = dump; // And, as a function pointer
- dp(p);
- printf("post: %d,%d\n", p.x, p.y);
- return 0;
- }
- '''
- main_name = os.path.join(self.get_dir(), 'main.cpp')
- open(main_name, 'w').write(main)
-
- Building.emcc(supp_name)
- Building.emcc(main_name)
- all_name = os.path.join(self.get_dir(), 'all.bc')
- Building.link([supp_name + '.o', main_name + '.o'], all_name)
-
- # This will fail! See explanation near the warning we check for, in the compiler source code
- output = Popen([PYTHON, EMCC, all_name], stderr=PIPE).communicate()
-
- # Check for warning in the generated code
- generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
- if 'i386-pc-linux-gnu' in COMPILER_OPTS:
- assert 'Casting a function pointer type to a potentially incompatible one' in output[1], 'Missing expected warning'
- else:
- print >> sys.stderr, 'skipping C/C++ conventions warning check, since not i386-pc-linux-gnu'
-
- def test_stdlibs(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.USE_TYPED_ARRAYS == 2:
- # Typed arrays = 2 + safe heap prints a warning that messes up our output.
- Settings.SAFE_HEAP = 0
- src = '''
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/time.h>
-
- void clean()
- {
- printf("*cleaned*\\n");
- }
-
- int comparer(const void *a, const void *b) {
- int aa = *((int*)a);
- int bb = *((int*)b);
- return aa - bb;
- }
-
- int main() {
- // timeofday
- timeval t;
- gettimeofday(&t, NULL);
- printf("*%d,%d\\n", int(t.tv_sec), int(t.tv_usec)); // should not crash
-
- // atexit
- atexit(clean);
-
- // qsort
- int values[6] = { 3, 2, 5, 1, 5, 6 };
- qsort(values, 5, sizeof(int), comparer);
- printf("*%d,%d,%d,%d,%d,%d*\\n", values[0], values[1], values[2], values[3], values[4], values[5]);
-
- printf("*stdin==0:%d*\\n", stdin == 0); // check that external values are at least not NULL
- printf("*%%*\\n");
- printf("*%.1ld*\\n", 5);
-
- printf("*%.1f*\\n", strtod("66", NULL)); // checks dependency system, as our strtod needs _isspace etc.
-
- printf("*%ld*\\n", strtol("10", NULL, 0));
- printf("*%ld*\\n", strtol("0", NULL, 0));
- printf("*%ld*\\n", strtol("-10", NULL, 0));
- printf("*%ld*\\n", strtol("12", NULL, 16));
-
- printf("*%lu*\\n", strtoul("10", NULL, 0));
- printf("*%lu*\\n", strtoul("0", NULL, 0));
- printf("*%lu*\\n", strtoul("-10", NULL, 0));
-
- printf("*malloc(0)!=0:%d*\\n", malloc(0) != 0); // We should not fail horribly
-
- return 0;
- }
- '''
-
- self.do_run(src, '*1,2,3,5,5,6*\n*stdin==0:0*\n*%*\n*5*\n*66.0*\n*10*\n*0*\n*-10*\n*18*\n*10*\n*0*\n*4294967286*\n*malloc(0)!=0:1*\n*cleaned*')
-
- src = r'''
- #include <stdio.h>
- #include <stdbool.h>
-
- int main() {
- bool x = true;
- bool y = false;
- printf("*%d*\n", x != y);
- return 0;
- }
- '''
-
- self.do_run(src, '*1*', force_c=True)
-
- def test_strtoll_hex(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- # tests strtoll for hex strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "0x4 -0x3A +0xDEADBEEF";
- char *end_char;
-
- // undefined base
- long long int l1 = strtoll(STRING, &end_char, 0);
- long long int l2 = strtoll(end_char, &end_char, 0);
- long long int l3 = strtoll(end_char, NULL, 0);
-
- // defined base
- long long int l4 = strtoll(STRING, &end_char, 16);
- long long int l5 = strtoll(end_char, &end_char, 16);
- long long int l6 = strtoll(end_char, NULL, 16);
-
- printf("%d%d%d%d%d%d\n", l1==0x4, l2==-0x3a, l3==0xdeadbeef, l4==0x4, l5==-0x3a, l6==0xdeadbeef);
- return 0;
- }
- '''
- self.do_run(src, '111111')
-
- def test_strtoll_dec(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- # tests strtoll for decimal strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "4 -38 +4711";
- char *end_char;
-
- // undefined base
- long long int l1 = strtoll(STRING, &end_char, 0);
- long long int l2 = strtoll(end_char, &end_char, 0);
- long long int l3 = strtoll(end_char, NULL, 0);
-
- // defined base
- long long int l4 = strtoll(STRING, &end_char, 10);
- long long int l5 = strtoll(end_char, &end_char, 10);
- long long int l6 = strtoll(end_char, NULL, 10);
-
- printf("%d%d%d%d%d%d\n", l1==4, l2==-38, l3==4711, l4==4, l5==-38, l6==4711);
- return 0;
- }
- '''
- self.do_run(src, '111111')
-
- def test_strtoll_bin(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- # tests strtoll for binary strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "1 -101 +1011";
- char *end_char;
-
- // defined base
- long long int l4 = strtoll(STRING, &end_char, 2);
- long long int l5 = strtoll(end_char, &end_char, 2);
- long long int l6 = strtoll(end_char, NULL, 2);
-
- printf("%d%d%d\n", l4==1, l5==-5, l6==11);
- return 0;
- }
- '''
- self.do_run(src, '111')
-
- def test_strtoll_oct(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- # tests strtoll for decimal strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "0 -035 +04711";
- char *end_char;
-
- // undefined base
- long long int l1 = strtoll(STRING, &end_char, 0);
- long long int l2 = strtoll(end_char, &end_char, 0);
- long long int l3 = strtoll(end_char, NULL, 0);
-
- // defined base
- long long int l4 = strtoll(STRING, &end_char, 8);
- long long int l5 = strtoll(end_char, &end_char, 8);
- long long int l6 = strtoll(end_char, NULL, 8);
-
- printf("%d%d%d%d%d%d\n", l1==0, l2==-29, l3==2505, l4==0, l5==-29, l6==2505);
- return 0;
- }
- '''
- self.do_run(src, '111111')
-
- def test_strtol_hex(self):
- # tests strtoll for hex strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "0x4 -0x3A +0xDEAD";
- char *end_char;
-
- // undefined base
- long l1 = strtol(STRING, &end_char, 0);
- long l2 = strtol(end_char, &end_char, 0);
- long l3 = strtol(end_char, NULL, 0);
-
- // defined base
- long l4 = strtol(STRING, &end_char, 16);
- long l5 = strtol(end_char, &end_char, 16);
- long l6 = strtol(end_char, NULL, 16);
-
- printf("%d%d%d%d%d%d\n", l1==0x4, l2==-0x3a, l3==0xdead, l4==0x4, l5==-0x3a, l6==0xdead);
- return 0;
- }
- '''
- self.do_run(src, '111111')
-
- def test_strtol_dec(self):
- # tests strtoll for decimal strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "4 -38 +4711";
- char *end_char;
-
- // undefined base
- long l1 = strtol(STRING, &end_char, 0);
- long l2 = strtol(end_char, &end_char, 0);
- long l3 = strtol(end_char, NULL, 0);
-
- // defined base
- long l4 = strtol(STRING, &end_char, 10);
- long l5 = strtol(end_char, &end_char, 10);
- long l6 = strtol(end_char, NULL, 10);
-
- printf("%d%d%d%d%d%d\n", l1==4, l2==-38, l3==4711, l4==4, l5==-38, l6==4711);
- return 0;
- }
- '''
- self.do_run(src, '111111')
-
- def test_strtol_bin(self):
- # tests strtoll for binary strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "1 -101 +1011";
- char *end_char;
-
- // defined base
- long l4 = strtol(STRING, &end_char, 2);
- long l5 = strtol(end_char, &end_char, 2);
- long l6 = strtol(end_char, NULL, 2);
-
- printf("%d%d%d\n", l4==1, l5==-5, l6==11);
- return 0;
- }
- '''
- self.do_run(src, '111')
-
- def test_strtol_oct(self):
- # tests strtoll for decimal strings (0x...)
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- const char *STRING = "0 -035 +04711";
- char *end_char;
-
- // undefined base
- long l1 = strtol(STRING, &end_char, 0);
- long l2 = strtol(end_char, &end_char, 0);
- long l3 = strtol(end_char, NULL, 0);
-
- // defined base
- long l4 = strtol(STRING, &end_char, 8);
- long l5 = strtol(end_char, &end_char, 8);
- long l6 = strtol(end_char, NULL, 8);
-
- printf("%d%d%d%d%d%d\n", l1==0, l2==-29, l3==2505, l4==0, l5==-29, l6==2505);
- return 0;
- }
- '''
- self.do_run(src, '111111')
-
- def test_atexit(self):
- # Confirms they are called in reverse order
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- static void cleanA() {
- printf("A");
- }
- static void cleanB() {
- printf("B");
- }
-
- int main() {
- atexit(cleanA);
- atexit(cleanB);
- return 0;
- }
- '''
- self.do_run(src, 'BA')
-
- def test_time(self):
- # XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again.
- src = open(path_from_root('tests', 'time', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read()
- expected2 = open(path_from_root('tests', 'time', 'output2.txt'), 'r').read()
- self.do_run(src, [expected, expected2],
- extra_emscripten_args=['-H', 'libc/time.h'])
- #extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
-
- def test_timeb(self):
- # Confirms they are called in reverse order
- src = r'''
- #include <stdio.h>
- #include <assert.h>
- #include <sys/timeb.h>
-
- int main() {
- timeb tb;
- tb.timezone = 1;
- printf("*%d\n", ftime(&tb));
- assert(tb.time > 10000);
- assert(tb.timezone == 0);
- assert(tb.dstflag == 0);
- return 0;
- }
- '''
- self.do_run(src, '*0\n')
-
- def test_time_c(self):
- src = r'''
- #include <time.h>
- #include <stdio.h>
-
- int main() {
- time_t t = time(0);
- printf("time: %s\n", ctime(&t));
- }
- '''
- self.do_run(src, 'time: ') # compilation check, mainly
-
- def test_gmtime(self):
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <assert.h>
-
- int main(void)
- {
- time_t t=time(NULL);
- struct tm *ptm=gmtime(&t);
- struct tm tmCurrent=*ptm;
- int hour=tmCurrent.tm_hour;
-
- t-=hour*3600; // back to midnight
- int yday = -1;
- for(hour=0;hour<24;hour++)
- {
- ptm=gmtime(&t);
- // tm_yday must be constant all day...
- printf("yday: %d, hour: %d\n", ptm->tm_yday, hour);
- if (yday == -1) yday = ptm->tm_yday;
- else assert(yday == ptm->tm_yday);
- t+=3600; // add one hour
- }
- printf("ok!\n");
- return(0);
- }
- '''
- self.do_run(src, '''ok!''')
-
- def test_strptime_tm(self):
- src=r'''
- #include <time.h>
- #include <stdio.h>
- #include <string.h>
-
- int main() {
- struct tm tm;
- char *ptr = strptime("17410105012000", "%H%M%S%d%m%Y", &tm);
-
- printf("%s: %s, %d/%d/%d %d:%d:%d",
- (ptr != NULL && *ptr=='\0') ? "OK" : "ERR",
- tm.tm_wday == 0 ? "Sun" : (tm.tm_wday == 1 ? "Mon" : (tm.tm_wday == 2 ? "Tue" : (tm.tm_wday == 3 ? "Wed" : (tm.tm_wday == 4 ? "Thu" : (tm.tm_wday == 5 ? "Fri" : (tm.tm_wday == 6 ? "Sat" : "ERR")))))),
- tm.tm_mon+1,
- tm.tm_mday,
- tm.tm_year+1900,
- tm.tm_hour,
- tm.tm_min,
- tm.tm_sec
- );
- }
- '''
- self.do_run(src, 'OK: Wed, 1/5/2000 17:41:1')
-
- def test_strptime_days(self):
- src = r'''
- #include <time.h>
- #include <stdio.h>
- #include <string.h>
-
- static const struct {
- const char *input;
- const char *format;
- } day_tests[] = {
- { "2000-01-01", "%Y-%m-%d"},
- { "03/03/00", "%D"},
- { "9/9/99", "%x"},
- { "19990502123412", "%Y%m%d%H%M%S"},
- { "2001 20 Mon", "%Y %U %a"},
- { "2006 4 Fri", "%Y %U %a"},
- { "2001 21 Mon", "%Y %W %a"},
- { "2013 29 Wed", "%Y %W %a"},
- { "2000-01-01 08:12:21 AM", "%Y-%m-%d %I:%M:%S %p"},
- { "2000-01-01 08:12:21 PM", "%Y-%m-%d %I:%M:%S %p"},
- { "2001 17 Tue", "%Y %U %a"},
- { "2001 8 Thursday", "%Y %W %a"},
- };
-
- int main() {
- struct tm tm;
-
- for (int i = 0; i < sizeof (day_tests) / sizeof (day_tests[0]); ++i) {
- memset (&tm, '\0', sizeof (tm));
- char *ptr = strptime(day_tests[i].input, day_tests[i].format, &tm);
-
- printf("%s: %d/%d/%d (%dth DoW, %dth DoY)\n", (ptr != NULL && *ptr=='\0') ? "OK" : "ERR", tm.tm_mon+1, tm.tm_mday, 1900+tm.tm_year, tm.tm_wday, tm.tm_yday);
- }
- }
- '''
- self.do_run(src, 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
- 'OK: 3/3/2000 (5th DoW, 62th DoY)\n'\
- 'OK: 9/9/1999 (4th DoW, 251th DoY)\n'\
- 'OK: 5/2/1999 (0th DoW, 121th DoY)\n'\
- 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
- 'OK: 1/27/2006 (5th DoW, 26th DoY)\n'\
- 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
- 'OK: 7/24/2013 (3th DoW, 204th DoY)\n'\
- 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
- 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
- 'OK: 5/1/2001 (2th DoW, 120th DoY)\n'\
- 'OK: 2/22/2001 (4th DoW, 52th DoY)\n'\
- )
-
- def test_strptime_reentrant(self):
- src=r'''
- #include <time.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- int main () {
- int result = 0;
- struct tm tm;
-
- memset (&tm, 0xaa, sizeof (tm));
-
- /* Test we don't crash on uninitialized struct tm.
- Some fields might contain bogus values until everything
- needed is initialized, but we shouldn't crash. */
- if (strptime ("2007", "%Y", &tm) == NULL
- || strptime ("12", "%d", &tm) == NULL
- || strptime ("Feb", "%b", &tm) == NULL
- || strptime ("13", "%M", &tm) == NULL
- || strptime ("21", "%S", &tm) == NULL
- || strptime ("16", "%H", &tm) == NULL) {
- printf("ERR: returned NULL");
- exit(EXIT_FAILURE);
- }
-
- if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
- || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
- || tm.tm_wday != 1 || tm.tm_yday != 42) {
- printf("ERR: unexpected tm content (1) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
- exit(EXIT_FAILURE);
- }
-
- if (strptime ("8", "%d", &tm) == NULL) {
- printf("ERR: strptime failed");
- exit(EXIT_FAILURE);
- }
-
- if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
- || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
- || tm.tm_wday != 4 || tm.tm_yday != 38) {
- printf("ERR: unexpected tm content (2) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
- exit(EXIT_FAILURE);
- }
-
- printf("OK");
- }
- '''
- self.do_run(src, 'OK')
-
- def test_strftime(self):
- src=r'''
- #include <time.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- void test(int result, const char* comment, const char* parsed = "") {
- printf("%d",result);
- if (!result) {
- printf("\nERROR: %s (\"%s\")\n", comment, parsed);
- }
- }
-
- int cmp(const char *s1, const char *s2) {
- for ( ; *s1 == *s2 ; s1++,s2++ ) {
- if ( *s1 == '\0' )
- break;
- }
-
- return (*s1 - *s2);
- }
-
- int main() {
- struct tm tm;
- char s[1000];
- size_t size;
-
- tm.tm_sec = 4;
- tm.tm_min = 23;
- tm.tm_hour = 20;
- tm.tm_mday = 21;
- tm.tm_mon = 1;
- tm.tm_year = 74;
- tm.tm_wday = 4;
- tm.tm_yday = 51;
- tm.tm_isdst = 0;
-
- size = strftime(s, 1000, "", &tm);
- test((size==0) && (*s=='\0'), "strftime test #1", s);
-
- size = strftime(s, 1000, "%a", &tm);
- test((size==3) && !cmp(s, "Thu"), "strftime test #2", s);
-
- size = strftime(s, 1000, "%A", &tm);
- test((size==8) && !cmp(s, "Thursday"), "strftime test #3", s);
-
- size = strftime(s, 1000, "%b", &tm);
- test((size==3) && !cmp(s, "Feb"), "strftime test #4", s);
-
- size = strftime(s, 1000, "%B", &tm);
- test((size==8) && !cmp(s, "February"),
- "strftime test #5", s);
-
- size = strftime(s, 1000, "%d", &tm);
- test((size==2) && !cmp(s, "21"),
- "strftime test #6", s);
-
- size = strftime(s, 1000, "%H", &tm);
- test((size==2) && !cmp(s, "20"),
- "strftime test #7", s);
-
- size = strftime(s, 1000, "%I", &tm);
- test((size==2) && !cmp(s, "08"),
- "strftime test #8", s);
-
- size = strftime(s, 1000, "%j", &tm);
- test((size==3) && !cmp(s, "052"),
- "strftime test #9", s);
-
- size = strftime(s, 1000, "%m", &tm);
- test((size==2) && !cmp(s, "02"),
- "strftime test #10", s);
-
- size = strftime(s, 1000, "%M", &tm);
- test((size==2) && !cmp(s, "23"),
- "strftime test #11", s);
-
- size = strftime(s, 1000, "%p", &tm);
- test((size==2) && !cmp(s, "PM"),
- "strftime test #12", s);
-
- size = strftime(s, 1000, "%S", &tm);
- test((size==2) && !cmp(s, "04"),
- "strftime test #13", s);
-
- size = strftime(s, 1000, "%U", &tm);
- test((size==2) && !cmp(s, "07"),
- "strftime test #14", s);
-
- size = strftime(s, 1000, "%w", &tm);
- test((size==1) && !cmp(s, "4"),
- "strftime test #15", s);
-
- size = strftime(s, 1000, "%W", &tm);
- test((size==2) && !cmp(s, "07"),
- "strftime test #16", s);
-
- size = strftime(s, 1000, "%y", &tm);
- test((size==2) && !cmp(s, "74"),
- "strftime test #17", s);
-
- size = strftime(s, 1000, "%Y", &tm);
- test((size==4) && !cmp(s, "1974"),
- "strftime test #18", s);
-
- size = strftime(s, 1000, "%%", &tm);
- test((size==1) && !cmp(s, "%"),
- "strftime test #19", s);
-
- size = strftime(s, 5, "%Y", &tm);
- test((size==4) && !cmp(s, "1974"),
- "strftime test #20", s);
-
- size = strftime(s, 4, "%Y", &tm);
- test((size==0), "strftime test #21", s);
-
- tm.tm_mon = 0;
- tm.tm_mday = 1;
- size = strftime(s, 10, "%U", &tm);
- test((size==2) && !cmp(s, "00"), "strftime test #22", s);
-
- size = strftime(s, 10, "%W", &tm);
- test((size==2) && !cmp(s, "00"), "strftime test #23", s);
-
- // 1/1/1973 was a Sunday and is in CW 1
- tm.tm_year = 73;
- size = strftime(s, 10, "%W", &tm);
- test((size==2) && !cmp(s, "01"), "strftime test #24", s);
-
- // 1/1/1978 was a Monday and is in CW 1
- tm.tm_year = 78;
- size = strftime(s, 10, "%U", &tm);
- test((size==2) && !cmp(s, "01"), "strftime test #25", s);
-
- // 2/1/1999
- tm.tm_year = 99;
- tm.tm_yday = 1;
- size = strftime(s, 10, "%G (%V)", &tm);
- test((size==9) && !cmp(s, "1998 (53)"), "strftime test #26", s);
-
- size = strftime(s, 10, "%g", &tm);
- test((size==2) && !cmp(s, "98"), "strftime test #27", s);
-
- // 30/12/1997
- tm.tm_year = 97;
- tm.tm_yday = 363;
- size = strftime(s, 10, "%G (%V)", &tm);
- test((size==9) && !cmp(s, "1998 (01)"), "strftime test #28", s);
-
- size = strftime(s, 10, "%g", &tm);
- test((size==2) && !cmp(s, "98"), "strftime test #29", s);
- }
- '''
- self.do_run(src, '11111111111111111111111111111')
-
- def test_intentional_fault(self):
- # Some programs intentionally segfault themselves, we should compile that into a throw
- src = r'''
- int main () {
- *(volatile char *)0 = 0;
- return 0;
- }
- '''
- self.do_run(src, 'fault on write to 0' if not Settings.ASM_JS else 'abort()')
-
- def test_trickystring(self):
- src = r'''
- #include <stdio.h>
-
- typedef struct
- {
- int (*f)(void *);
- void *d;
- char s[16];
- } LMEXFunctionStruct;
-
- int f(void *user)
- {
- return 0;
- }
-
- static LMEXFunctionStruct const a[] =
- {
- {f, (void *)(int)'a', "aa"}
- };
-
- int main()
- {
- printf("ok\n");
- return a[0].f(a[0].d);
- }
- '''
- self.do_run(src, 'ok\n')
-
- def test_statics(self):
- # static initializers save i16 but load i8 for some reason (or i64 and load i8)
- if Settings.SAFE_HEAP:
- Settings.SAFE_HEAP = 3
- Settings.SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26', 'src.cpp:28']
-
- src = '''
- #include <stdio.h>
- #include <string.h>
-
- #define CONSTRLEN 32
-
- char * (*func)(char *, const char *) = NULL;
-
- void conoutfv(const char *fmt)
- {
- static char buf[CONSTRLEN];
- func(buf, fmt); // call by function pointer to make sure we test strcpy here
- puts(buf);
- }
-
- struct XYZ {
- float x, y, z;
- XYZ(float a, float b, float c) : x(a), y(b), z(c) { }
- static const XYZ& getIdentity()
- {
- static XYZ iT(1,2,3);
- return iT;
- }
- };
- struct S {
- static const XYZ& getIdentity()
- {
- static const XYZ iT(XYZ::getIdentity());
- return iT;
- }
- };
-
- int main() {
- func = &strcpy;
- conoutfv("*staticccz*");
- printf("*%.2f,%.2f,%.2f*\\n", S::getIdentity().x, S::getIdentity().y, S::getIdentity().z);
- return 0;
- }
- '''
- self.do_run(src, '*staticccz*\n*1.00,2.00,3.00*')
-
- def test_copyop(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- # clang generated code is vulnerable to this, as it uses
- # memcpy for assignments, with hardcoded numbers of bytes
- # (llvm-gcc copies items one by one). See QUANTUM_SIZE in
- # settings.js.
- src = '''
- #include <stdio.h>
- #include <math.h>
- #include <string.h>
-
- struct vec {
- double x,y,z;
- vec() : x(0), y(0), z(0) { };
- vec(const double a, const double b, const double c) : x(a), y(b), z(c) { };
- };
-
- struct basis {
- vec a, b, c;
- basis(const vec& v) {
- a=v; // should not touch b!
- printf("*%.2f,%.2f,%.2f*\\n", b.x, b.y, b.z);
- }
- };
-
- int main() {
- basis B(vec(1,0,0));
-
- // Part 2: similar problem with memset and memmove
- int x = 1, y = 77, z = 2;
- memset((void*)&x, 0, sizeof(int));
- memset((void*)&z, 0, sizeof(int));
- printf("*%d,%d,%d*\\n", x, y, z);
- memcpy((void*)&x, (void*)&z, sizeof(int));
- memcpy((void*)&z, (void*)&x, sizeof(int));
- printf("*%d,%d,%d*\\n", x, y, z);
- memmove((void*)&x, (void*)&z, sizeof(int));
- memmove((void*)&z, (void*)&x, sizeof(int));
- printf("*%d,%d,%d*\\n", x, y, z);
- return 0;
- }
- '''
- self.do_run(src, '*0.00,0.00,0.00*\n*0,77,0*\n*0,77,0*\n*0,77,0*')
-
- def test_memcpy_memcmp(self):
- src = '''
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
-
- #define MAXX 48
- void reset(unsigned char *buffer) {
- for (int i = 0; i < MAXX; i++) buffer[i] = i+1;
- }
- void dump(unsigned char *buffer) {
- for (int i = 0; i < MAXX-1; i++) printf("%2d,", buffer[i]);
- printf("%d\\n", buffer[MAXX-1]);
- }
- int main() {
- unsigned char buffer[MAXX];
- for (int i = MAXX/4; i < MAXX-MAXX/4; i++) {
- for (int j = MAXX/4; j < MAXX-MAXX/4; j++) {
- for (int k = 1; k < MAXX/4; k++) {
- if (i == j) continue;
- if (i < j && i+k > j) continue;
- if (j < i && j+k > i) continue;
- printf("[%d,%d,%d] ", i, j, k);
- reset(buffer);
- memcpy(buffer+i, buffer+j, k);
- dump(buffer);
- assert(memcmp(buffer+i, buffer+j, k) == 0);
- buffer[i + k/2]++;
- if (buffer[i + k/2] != 0) {
- assert(memcmp(buffer+i, buffer+j, k) > 0);
- } else {
- assert(memcmp(buffer+i, buffer+j, k) < 0);
- }
- buffer[i + k/2]--;
- buffer[j + k/2]++;
- if (buffer[j + k/2] != 0) {
- assert(memcmp(buffer+i, buffer+j, k) < 0);
- } else {
- assert(memcmp(buffer+i, buffer+j, k) > 0);
- }
- }
- }
- }
- return 0;
- }
- '''
- def check(result, err):
- return hashlib.sha1(result).hexdigest()
- self.do_run(src, '6c9cdfe937383b79e52ca7a2cce83a21d9f5422c',
- output_nicerizer = check)
-
- def test_memcpy2(self):
- src = r'''
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- int main() {
- char buffer[256];
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < 10; j++) {
- for (int k = 0; k < 35; k++) {
- for (int t = 0; t < 256; t++) buffer[t] = t;
- char *dest = buffer + i + 128;
- char *src = buffer+j;
- //printf("%d, %d, %d\n", i, j, k);
- assert(memcpy(dest, src, k) == dest);
- assert(memcmp(dest, src, k) == 0);
+ var actualCanvas = document.createElement('canvas');
+ actualCanvas.width = actualImage.width;
+ actualCanvas.height = actualImage.height;
+ var actualCtx = actualCanvas.getContext('2d');
+ actualCtx.drawImage(actualImage, 0, 0);
+ var actual = actualCtx.getImageData(0, 0, actualImage.width, actualImage.height).data;
+
+ var total = 0;
+ var width = img.width;
+ var height = img.height;
+ for (var x = 0; x < width; x++) {
+ for (var y = 0; y < height; y++) {
+ total += Math.abs(expected[y*width*4 + x*4 + 0] - actual[y*width*4 + x*4 + 0]);
+ total += Math.abs(expected[y*width*4 + x*4 + 1] - actual[y*width*4 + x*4 + 1]);
+ total += Math.abs(expected[y*width*4 + x*4 + 2] - actual[y*width*4 + x*4 + 2]);
}
}
- }
- printf("ok.\n");
- return 1;
- }
- '''
- self.do_run(src, 'ok.');
-
- def test_getopt(self):
- if self.emcc_args is None: return self.skip('needs emcc for libc')
-
- src = '''
- #pragma clang diagnostic ignored "-Winvalid-pp-token"
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- int
- main(int argc, char *argv[])
- {
- int flags, opt;
- int nsecs, tfnd;
-
- nsecs = 0;
- tfnd = 0;
- flags = 0;
- while ((opt = getopt(argc, argv, "nt:")) != -1) {
- switch (opt) {
- case 'n':
- flags = 1;
- break;
- case 't':
- nsecs = atoi(optarg);
- tfnd = 1;
- break;
- default: /* '?' */
- fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\\n",
- argv[0]);
- exit(EXIT_FAILURE);
- }
- }
-
- printf("flags=%d; tfnd=%d; optind=%d\\n", flags, tfnd, optind);
-
- if (optind >= argc) {
- fprintf(stderr, "Expected argument after options\\n");
- exit(EXIT_FAILURE);
- }
-
- printf("name argument = %s\\n", argv[optind]);
-
- /* Other code omitted */
-
- exit(EXIT_SUCCESS);
- }
- '''
- self.do_run(src, 'flags=1; tfnd=1; optind=4\nname argument = foobar', args=['-t', '12', '-n', 'foobar'])
-
- def test_getopt_long(self):
- if self.emcc_args is None: return self.skip('needs emcc for libc')
-
- src = '''
- #pragma clang diagnostic ignored "-Winvalid-pp-token"
- #pragma clang diagnostic ignored "-Wdeprecated-writable-strings"
- #include <stdio.h> /* for printf */
- #include <stdlib.h> /* for exit */
- #include <getopt.h>
-
- int
- main(int argc, char **argv)
- {
- int c;
- int digit_optind = 0;
-
- while (1) {
- int this_option_optind = optind ? optind : 1;
- int option_index = 0;
- static struct option long_options[] = {
- {"add", required_argument, 0, 0 },
- {"append", no_argument, 0, 0 },
- {"delete", required_argument, 0, 0 },
- {"verbose", no_argument, 0, 0 },
- {"create", required_argument, 0, 'c'},
- {"file", required_argument, 0, 0 },
- {0, 0, 0, 0 }
- };
-
- c = getopt_long(argc, argv, "abc:d:012",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 0:
- printf("option %s", long_options[option_index].name);
- if (optarg)
- printf(" with arg %s", optarg);
- printf("\\n");
- break;
-
- case '0':
- case '1':
- case '2':
- if (digit_optind != 0 && digit_optind != this_option_optind)
- printf("digits occur in two different argv-elements.\\n");
- digit_optind = this_option_optind;
- printf("option %c\\n", c);
- break;
-
- case 'a':
- printf("option a\\n");
- break;
-
- case 'b':
- printf("option b\\n");
- break;
-
- case 'c':
- printf("option c with value '%s'\\n", optarg);
- break;
-
- case 'd':
- printf("option d with value '%s'\\n", optarg);
- break;
-
- case '?':
- break;
-
- default:
- printf("?? getopt returned character code 0%o ??\\n", c);
- }
- }
-
- if (optind < argc) {
- printf("non-option ARGV-elements: ");
- while (optind < argc)
- printf("%s ", argv[optind++]);
- printf("\\n");
- }
-
- exit(EXIT_SUCCESS);
- }
- '''
- self.do_run(src, 'option file with arg foobar\noption b', args=['--file', 'foobar', '-b'])
-
- def test_memmove(self):
- src = '''
- #include <stdio.h>
- #include <string.h>
- int main() {
- char str[] = "memmove can be very useful....!";
- memmove (str+20, str+15, 11);
- puts(str);
- return 0;
- }
- '''
- self.do_run(src, 'memmove can be very very useful')
-
- def test_memmove2(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('need ta2')
-
- src = r'''
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- int main() {
- int sum = 0;
- char buffer[256];
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < 10; j++) {
- for (int k = 0; k < 35; k++) {
- for (int t = 0; t < 256; t++) buffer[t] = t;
- char *dest = buffer + i;
- char *src = buffer + j;
- if (dest == src) continue;
- //printf("%d, %d, %d\n", i, j, k);
- assert(memmove(dest, src, k) == dest);
- for (int t = 0; t < 256; t++) sum += buffer[t];
- }
- }
- }
- printf("final: %d.\n", sum);
- return 1;
- }
- '''
- self.do_run(src, 'final: -403200.');
-
- def test_memmove3(self):
- src = '''
- #include <stdio.h>
- #include <string.h>
- int main() {
- char str[] = "memmove can be vvery useful....!";
- memmove(str+15, str+16, 17);
- puts(str);
- return 0;
- }
- '''
- self.do_run(src, 'memmove can be very useful....!')
-
- def test_bsearch(self):
- if Settings.QUANTUM_SIZE == 1: return self.skip('Test cannot work with q1')
-
- src = '''
- #include <stdlib.h>
- #include <stdio.h>
-
- int cmp(const void* key, const void* member) {
- return *(int *)key - *(int *)member;
- }
-
- void printResult(int* needle, int* haystack, unsigned int len) {
- void *result = bsearch(needle, haystack, len, sizeof(unsigned int), cmp);
-
- if (result == NULL) {
- printf("null\\n");
- } else {
- printf("%d\\n", *(unsigned int *)result);
- }
- }
-
- int main() {
- int a[] = { -2, -1, 0, 6, 7, 9 };
- int b[] = { 0, 1 };
-
- /* Find all keys that exist. */
- for(int i = 0; i < 6; i++) {
- int val = a[i];
-
- printResult(&val, a, 6);
- }
-
- /* Keys that are covered by the range of the array but aren't in
- * the array cannot be found.
- */
- int v1 = 3;
- int v2 = 8;
- printResult(&v1, a, 6);
- printResult(&v2, a, 6);
-
- /* Keys outside the range of the array cannot be found. */
- int v3 = -1;
- int v4 = 2;
-
- printResult(&v3, b, 2);
- printResult(&v4, b, 2);
-
- return 0;
- }
- '''
-
- self.do_run(src, '-2\n-1\n0\n6\n7\n9\nnull\nnull\nnull\nnull')
-
- def test_nestedstructs(self):
- src = '''
- #include <stdio.h>
- #include "emscripten.h"
-
- struct base {
- int x;
- float y;
- union {
- int a;
- float b;
- };
- char c;
- };
-
- struct hashtableentry {
- int key;
- base data;
- };
-
- struct hashset {
- typedef hashtableentry entry;
- struct chain { entry elem; chain *next; };
- // struct chainchunk { chain chains[100]; chainchunk *next; };
- };
-
- struct hashtable : hashset {
- hashtable() {
- base *b = NULL;
- entry *e = NULL;
- chain *c = NULL;
- printf("*%d,%d,%d,%d,%d,%d|%d,%d,%d,%d,%d,%d,%d,%d|%d,%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n",
- sizeof(base),
- int(&(b->x)), int(&(b->y)), int(&(b->a)), int(&(b->b)), int(&(b->c)),
- sizeof(hashtableentry),
- int(&(e->key)), int(&(e->data)), int(&(e->data.x)), int(&(e->data.y)), int(&(e->data.a)), int(&(e->data.b)), int(&(e->data.c)),
- sizeof(hashset::chain),
- int(&(c->elem)), int(&(c->next)), int(&(c->elem.key)), int(&(c->elem.data)), int(&(c->elem.data.x)), int(&(c->elem.data.y)), int(&(c->elem.data.a)), int(&(c->elem.data.b)), int(&(c->elem.data.c))
- );
- }
- };
-
- struct B { char buffer[62]; int last; char laster; char laster2; };
-
- struct Bits {
- unsigned short A : 1;
- unsigned short B : 1;
- unsigned short C : 1;
- unsigned short D : 1;
- unsigned short x1 : 1;
- unsigned short x2 : 1;
- unsigned short x3 : 1;
- unsigned short x4 : 1;
- };
-
- int main() {
- hashtable t;
-
- // Part 2 - the char[] should be compressed, BUT have a padding space at the end so the next
- // one is aligned properly. Also handle char; char; etc. properly.
- B *b = NULL;
- printf("*%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n", int(b), int(&(b->buffer)), int(&(b->buffer[0])), int(&(b->buffer[1])), int(&(b->buffer[2])),
- int(&(b->last)), int(&(b->laster)), int(&(b->laster2)), sizeof(B));
-
- // Part 3 - bitfields, and small structures
- Bits *b2 = NULL;
- printf("*%d*\\n", sizeof(Bits));
-
- return 0;
- }
- '''
- if Settings.QUANTUM_SIZE == 1:
- # Compressed memory. Note that sizeof() does give the fat sizes, however!
- self.do_run(src, '*16,0,1,2,2,3|20,0,1,1,2,3,3,4|24,0,5,0,1,1,2,3,3,4*\n*0,0,0,1,2,62,63,64,72*\n*2*')
- else:
- # Bloated memory; same layout as C/C++
- self.do_run(src, '*16,0,4,8,8,12|20,0,4,4,8,12,12,16|24,0,20,0,4,4,8,12,12,16*\n*0,0,0,1,2,64,68,69,72*\n*2*')
-
- def test_runtimelink(self):
- return self.skip('shared libs are deprecated')
- if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize printf into puts in the parent, and the child will still look for puts')
- if Settings.ASM_JS: return self.skip('asm does not support runtime linking')
-
- main, supp = self.setup_runtimelink_test()
-
- self.banned_js_engines = [NODE_JS] # node's global scope behaves differently than everything else, needs investigation FIXME
- Settings.LINKABLE = 1
- Settings.BUILD_AS_SHARED_LIB = 2
- Settings.NAMED_GLOBALS = 1
-
- self.build(supp, self.get_dir(), self.in_dir('supp.cpp'))
- shutil.move(self.in_dir('supp.cpp.o.js'), self.in_dir('liblib.so'))
- Settings.BUILD_AS_SHARED_LIB = 0
-
- Settings.RUNTIME_LINKED_LIBS = ['liblib.so'];
- self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.')
-
- def test_dlfcn_basic(self):
- return self.skip('shared libs are deprecated')
- if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
-
- Settings.NAMED_GLOBALS = 1
- Settings.LINKABLE = 1
-
- lib_src = '''
- #include <cstdio>
-
- class Foo {
- public:
- Foo() {
- printf("Constructing lib object.\\n");
- }
- };
-
- Foo global;
- '''
- dirname = self.get_dir()
- filename = os.path.join(dirname, 'liblib.cpp')
- Settings.BUILD_AS_SHARED_LIB = 1
- self.build(lib_src, dirname, filename)
- shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
-
- src = '''
- #include <cstdio>
- #include <dlfcn.h>
-
- class Bar {
- public:
- Bar() {
- printf("Constructing main object.\\n");
- }
- };
-
- Bar global;
-
- int main() {
- dlopen("liblib.so", RTLD_NOW);
- return 0;
- }
- '''
- Settings.BUILD_AS_SHARED_LIB = 0
- add_pre_run_and_checks = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
- )
- open(filename, 'w').write(src)
-'''
- self.do_run(src, 'Constructing main object.\nConstructing lib object.\n',
- post_build=add_pre_run_and_checks)
-
- def test_dlfcn_qsort(self):
- return self.skip('shared libs are deprecated')
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
-
- Settings.LINKABLE = 1
- Settings.NAMED_GLOBALS = 1
-
- if Settings.USE_TYPED_ARRAYS == 2:
- Settings.CORRECT_SIGNS = 1 # Needed for unsafe optimizations
-
- lib_src = '''
- int lib_cmp(const void* left, const void* right) {
- const int* a = (const int*) left;
- const int* b = (const int*) right;
- if(*a > *b) return 1;
- else if(*a == *b) return 0;
- else return -1;
- }
-
- typedef int (*CMP_TYPE)(const void*, const void*);
-
- extern "C" CMP_TYPE get_cmp() {
- return lib_cmp;
- }
- '''
- dirname = self.get_dir()
- filename = os.path.join(dirname, 'liblib.cpp')
- Settings.BUILD_AS_SHARED_LIB = 1
- Settings.EXPORTED_FUNCTIONS = ['_get_cmp']
- self.build(lib_src, dirname, filename)
- shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
-
- src = '''
- #include <stdio.h>
- #include <stdlib.h>
- #include <dlfcn.h>
-
- typedef int (*CMP_TYPE)(const void*, const void*);
-
- int main_cmp(const void* left, const void* right) {
- const int* a = (const int*) left;
- const int* b = (const int*) right;
- if(*a < *b) return 1;
- else if(*a == *b) return 0;
- else return -1;
- }
-
- int main() {
- void* lib_handle;
- CMP_TYPE (*getter_ptr)();
- CMP_TYPE lib_cmp_ptr;
- int arr[5] = {4, 2, 5, 1, 3};
-
- lib_handle = dlopen("liblib.so", RTLD_NOW);
- if (lib_handle == NULL) {
- printf("Could not load lib.\\n");
- return 1;
- }
- getter_ptr = (CMP_TYPE (*)()) dlsym(lib_handle, "get_cmp");
- if (getter_ptr == NULL) {
- printf("Could not find func.\\n");
- return 1;
- }
- lib_cmp_ptr = getter_ptr();
-
- qsort((void*)arr, 5, sizeof(int), main_cmp);
- printf("Sort with main comparison: ");
- for (int i = 0; i < 5; i++) {
- printf("%d ", arr[i]);
- }
- printf("\\n");
-
- qsort((void*)arr, 5, sizeof(int), lib_cmp_ptr);
- printf("Sort with lib comparison: ");
- for (int i = 0; i < 5; i++) {
- printf("%d ", arr[i]);
- }
- printf("\\n");
-
- return 0;
- }
- '''
- Settings.BUILD_AS_SHARED_LIB = 0
- Settings.EXPORTED_FUNCTIONS = ['_main']
- add_pre_run_and_checks = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
- )
- open(filename, 'w').write(src)
-'''
- self.do_run(src, 'Sort with main comparison: 5 4 3 2 1 *Sort with lib comparison: 1 2 3 4 5 *',
- output_nicerizer=lambda x, err: x.replace('\n', '*'),
- post_build=add_pre_run_and_checks)
-
- def test_dlfcn_data_and_fptr(self):
- return self.skip('shared libs are deprecated')
- if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
- if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func')
-
- Settings.LINKABLE = 1
- Settings.NAMED_GLOBALS = 1
-
- lib_src = '''
- #include <stdio.h>
-
- int global = 42;
-
- extern void parent_func(); // a function that is defined in the parent
-
- void lib_fptr() {
- printf("Second calling lib_fptr from main.\\n");
- parent_func();
- // call it also through a pointer, to check indexizing
- void (*p_f)();
- p_f = parent_func;
- p_f();
- }
-
- extern "C" void (*func(int x, void(*fptr)()))() {
- printf("In func: %d\\n", x);
- fptr();
- return lib_fptr;
- }
- '''
- dirname = self.get_dir()
- filename = os.path.join(dirname, 'liblib.cpp')
- Settings.BUILD_AS_SHARED_LIB = 1
- Settings.EXPORTED_FUNCTIONS = ['_func']
- Settings.EXPORTED_GLOBALS = ['_global']
- self.build(lib_src, dirname, filename)
- shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
-
- src = '''
- #include <stdio.h>
- #include <dlfcn.h>
-
- typedef void (*FUNCTYPE(int, void(*)()))();
-
- FUNCTYPE func;
-
- void parent_func() {
- printf("parent_func called from child\\n");
- }
-
- void main_fptr() {
- printf("First calling main_fptr from lib.\\n");
- }
-
- int main() {
- void* lib_handle;
- FUNCTYPE* func_fptr;
-
- // Test basic lib loading.
- lib_handle = dlopen("liblib.so", RTLD_NOW);
- if (lib_handle == NULL) {
- printf("Could not load lib.\\n");
- return 1;
- }
-
- // Test looked up function.
- func_fptr = (FUNCTYPE*) dlsym(lib_handle, "func");
- // Load twice to test cache.
- func_fptr = (FUNCTYPE*) dlsym(lib_handle, "func");
- if (func_fptr == NULL) {
- printf("Could not find func.\\n");
- return 1;
- }
-
- // Test passing function pointers across module bounds.
- void (*fptr)() = func_fptr(13, main_fptr);
- fptr();
-
- // Test global data.
- int* global = (int*) dlsym(lib_handle, "global");
- if (global == NULL) {
- printf("Could not find global.\\n");
- return 1;
- }
-
- printf("Var: %d\\n", *global);
-
- return 0;
- }
- '''
- Settings.BUILD_AS_SHARED_LIB = 0
- Settings.EXPORTED_FUNCTIONS = ['_main']
- Settings.EXPORTED_GLOBALS = []
- add_pre_run_and_checks = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
- )
- open(filename, 'w').write(src)
-'''
- self.do_run(src, 'In func: 13*First calling main_fptr from lib.*Second calling lib_fptr from main.*parent_func called from child*parent_func called from child*Var: 42*',
- output_nicerizer=lambda x, err: x.replace('\n', '*'),
- post_build=add_pre_run_and_checks)
-
- def test_dlfcn_alias(self):
- return self.skip('shared libs are deprecated')
- if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
-
- Settings.LINKABLE = 1
- Settings.NAMED_GLOBALS = 1
-
- if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize away stuff we expect from the shared library')
-
- lib_src = r'''
- #include <stdio.h>
- extern int parent_global;
- extern "C" void func() {
- printf("Parent global: %d.\n", parent_global);
- }
- '''
- dirname = self.get_dir()
- filename = os.path.join(dirname, 'liblib.cpp')
- Settings.BUILD_AS_SHARED_LIB = 1
- Settings.EXPORTED_FUNCTIONS = ['_func']
- self.build(lib_src, dirname, filename)
- shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
-
- src = r'''
- #include <dlfcn.h>
-
- int parent_global = 123;
-
- int main() {
- void* lib_handle;
- void (*fptr)();
-
- lib_handle = dlopen("liblib.so", RTLD_NOW);
- fptr = (void (*)())dlsym(lib_handle, "func");
- fptr();
- parent_global = 456;
- fptr();
-
- return 0;
- }
- '''
- Settings.BUILD_AS_SHARED_LIB = 0
- Settings.INCLUDE_FULL_LIBRARY = 1
- Settings.EXPORTED_FUNCTIONS = ['_main']
- add_pre_run_and_checks = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
- )
- open(filename, 'w').write(src)
-'''
- self.do_run(src, 'Parent global: 123.*Parent global: 456.*',
- output_nicerizer=lambda x, err: x.replace('\n', '*'),
- post_build=add_pre_run_and_checks,
- extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/time.h,libc/langinfo.h'])
- Settings.INCLUDE_FULL_LIBRARY = 0
-
- def test_dlfcn_varargs(self):
- return self.skip('shared libs are deprecated')
- if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
-
- Settings.LINKABLE = 1
- Settings.NAMED_GLOBALS = 1
-
- if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize things that prevent shared objects from working')
- if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
-
- lib_src = r'''
- void print_ints(int n, ...);
- extern "C" void func() {
- print_ints(2, 13, 42);
- }
- '''
- dirname = self.get_dir()
- filename = os.path.join(dirname, 'liblib.cpp')
- Settings.BUILD_AS_SHARED_LIB = 1
- Settings.EXPORTED_FUNCTIONS = ['_func']
- self.build(lib_src, dirname, filename)
- shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
-
- src = r'''
- #include <stdarg.h>
- #include <stdio.h>
- #include <dlfcn.h>
-
- void print_ints(int n, ...) {
- va_list args;
- va_start(args, n);
- for (int i = 0; i < n; i++) {
- printf("%d\n", va_arg(args, int));
- }
- va_end(args);
- }
-
- int main() {
- void* lib_handle;
- void (*fptr)();
-
- print_ints(2, 100, 200);
-
- lib_handle = dlopen("liblib.so", RTLD_NOW);
- fptr = (void (*)())dlsym(lib_handle, "func");
- fptr();
-
- return 0;
- }
- '''
- Settings.BUILD_AS_SHARED_LIB = 0
- Settings.EXPORTED_FUNCTIONS = ['_main']
- add_pre_run_and_checks = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
- )
- open(filename, 'w').write(src)
-'''
- self.do_run(src, '100\n200\n13\n42\n',
- post_build=add_pre_run_and_checks)
-
- def test_dlfcn_self(self):
- if Settings.USE_TYPED_ARRAYS == 1: return self.skip('Does not work with USE_TYPED_ARRAYS=1')
- Settings.DLOPEN_SUPPORT = 1
-
- src = r'''
-#include <stdio.h>
-#include <dlfcn.h>
-
-int global = 123;
-
-extern "C" __attribute__((noinline)) void foo(int x) {
- printf("%d\n", x);
-}
-
-extern "C" __attribute__((noinline)) void repeatable() {
- void* self = dlopen(NULL, RTLD_LAZY);
- int* global_ptr = (int*)dlsym(self, "global");
- void (*foo_ptr)(int) = (void (*)(int))dlsym(self, "foo");
- foo_ptr(*global_ptr);
- dlclose(self);
-}
-
-int main() {
- repeatable();
- repeatable();
- return 0;
-}'''
- def post(filename):
- with open(filename) as f:
- for line in f:
- if 'var SYMBOL_TABLE' in line:
- table = line
- break
- else:
- raise Exception('Could not find symbol table!')
- import json
- table = json.loads(table[table.find('{'):table.rfind('}')+1])
- actual = list(sorted(table.keys()))
- # ensure there aren't too many globals; we don't want unnamed_addr
- assert actual == ['_foo', '_global', '_main', '_repeatable'], \
- "Symbol table does not match: %s" % actual
-
- self.do_run(src, '123\n123', post_build=(None, post))
-
- def test_rand(self):
- return self.skip('rand() is now random') # FIXME
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- printf("%d\n", rand());
- printf("%d\n", rand());
-
- srand(123);
- printf("%d\n", rand());
- printf("%d\n", rand());
- srand(123);
- printf("%d\n", rand());
- printf("%d\n", rand());
-
- unsigned state = 0;
- int r;
- r = rand_r(&state);
- printf("%d, %u\n", r, state);
- r = rand_r(&state);
- printf("%d, %u\n", r, state);
- state = 0;
- r = rand_r(&state);
- printf("%d, %u\n", r, state);
-
- return 0;
- }
- '''
- expected = '''
- 1250496027
- 1116302336
- 440917656
- 1476150784
- 440917656
- 1476150784
- 12345, 12345
- 1406932606, 3554416254
- 12345, 12345
- '''
- self.do_run(src, re.sub(r'(^|\n)\s+', r'\1', expected))
-
- def test_strtod(self):
- if self.emcc_args is None: return self.skip('needs emcc for libc')
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- char* endptr;
-
- printf("\n");
- printf("%g\n", strtod("0", &endptr));
- printf("%g\n", strtod("0.", &endptr));
- printf("%g\n", strtod("0.0", &endptr));
- printf("%g\n", strtod("-0.0", &endptr));
- printf("%g\n", strtod("1", &endptr));
- printf("%g\n", strtod("1.", &endptr));
- printf("%g\n", strtod("1.0", &endptr));
- printf("%g\n", strtod("z1.0", &endptr));
- printf("%g\n", strtod("0.5", &endptr));
- printf("%g\n", strtod(".5", &endptr));
- printf("%g\n", strtod(".a5", &endptr));
- printf("%g\n", strtod("123", &endptr));
- printf("%g\n", strtod("123.456", &endptr));
- printf("%g\n", strtod("-123.456", &endptr));
- printf("%g\n", strtod("1234567891234567890", &endptr));
- printf("%g\n", strtod("1234567891234567890e+50", &endptr));
- printf("%g\n", strtod("84e+220", &endptr));
- printf("%g\n", strtod("123e-50", &endptr));
- printf("%g\n", strtod("123e-250", &endptr));
- printf("%g\n", strtod("123e-450", &endptr));
-
- char str[] = " 12.34e56end";
- printf("%g\n", strtod(str, &endptr));
- printf("%d\n", endptr - str);
- printf("%g\n", strtod("84e+420", &endptr));
-
- printf("%.12f\n", strtod("1.2345678900000000e+08", NULL));
-
- return 0;
- }
- '''
- expected = '''
- 0
- 0
- 0
- -0
- 1
- 1
- 1
- 0
- 0.5
- 0.5
- 0
- 123
- 123.456
- -123.456
- 1.23457e+18
- 1.23457e+68
- 8.4e+221
- 1.23e-48
- 1.23e-248
- 0
- 1.234e+57
- 10
- inf
- 123456789.000000000000
- '''
-
- self.do_run(src, re.sub(r'\n\s+', '\n', expected))
- self.do_run(src.replace('strtod', 'strtold'), re.sub(r'\n\s+', '\n', expected)) # XXX add real support for long double
-
- def test_strtok(self):
- src = r'''
- #include<stdio.h>
- #include<string.h>
-
- int main() {
- char test[80], blah[80];
- char *sep = "\\/:;=-";
- char *word, *phrase, *brkt, *brkb;
-
- strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
-
- for (word = strtok_r(test, sep, &brkt); word; word = strtok_r(NULL, sep, &brkt)) {
- strcpy(blah, "blah:blat:blab:blag");
- for (phrase = strtok_r(blah, sep, &brkb); phrase; phrase = strtok_r(NULL, sep, &brkb)) {
- printf("at %s:%s\n", word, phrase);
- }
- }
- return 0;
- }
- '''
-
- expected = '''at This:blah
-at This:blat
-at This:blab
-at This:blag
-at is.a:blah
-at is.a:blat
-at is.a:blab
-at is.a:blag
-at test:blah
-at test:blat
-at test:blab
-at test:blag
-at of:blah
-at of:blat
-at of:blab
-at of:blag
-at the:blah
-at the:blat
-at the:blab
-at the:blag
-at string:blah
-at string:blat
-at string:blab
-at string:blag
-at tokenizer:blah
-at tokenizer:blat
-at tokenizer:blab
-at tokenizer:blag
-at function.:blah
-at function.:blat
-at function.:blab
-at function.:blag
-'''
- self.do_run(src, expected)
-
- def test_parseInt(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
- if Settings.QUANTUM_SIZE == 1: return self.skip('Q1 and I64_1 do not mix well yet')
- src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read()
- self.do_run(src, expected)
-
- def test_transtrcase(self):
- src = '''
- #include <stdio.h>
- #include <string.h>
- int main() {
- char szToupr[] = "hello, ";
- char szTolwr[] = "EMSCRIPTEN";
- strupr(szToupr);
- strlwr(szTolwr);
- printf(szToupr);
- printf(szTolwr);
- return 0;
- }
- '''
- self.do_run(src, 'HELLO, emscripten')
-
- def test_printf(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
- self.banned_js_engines = [NODE_JS, V8_ENGINE] # SpiderMonkey and V8 do different things to float64 typed arrays, un-NaNing, etc.
- src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read()
- expected = [open(path_from_root('tests', 'printf', 'output.txt'), 'r').read(),
- open(path_from_root('tests', 'printf', 'output_i64_1.txt'), 'r').read()]
- self.do_run(src, expected)
-
- def test_printf_2(self):
- src = r'''
- #include <stdio.h>
-
- int main() {
- char c = '1';
- short s = 2;
- int i = 3;
- long long l = 4;
- float f = 5.5;
- double d = 6.6;
-
- printf("%c,%hd,%d,%lld,%.1f,%.1llf\n", c, s, i, l, f, d);
- printf("%#x,%#x\n", 1, 0);
-
- return 0;
- }
- '''
- self.do_run(src, '1,2,3,4,5.5,6.6\n0x1,0\n')
-
- def test_vprintf(self):
- src = r'''
- #include <stdio.h>
- #include <stdarg.h>
-
- void print(char* format, ...) {
- va_list args;
- va_start (args, format);
- vprintf (format, args);
- va_end (args);
- }
-
- int main () {
- print("Call with %d variable argument.\n", 1);
- print("Call with %d variable %s.\n", 2, "arguments");
-
- return 0;
- }
- '''
- expected = '''
- Call with 1 variable argument.
- Call with 2 variable arguments.
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
-
- def test_vsnprintf(self):
- if self.emcc_args is None: return self.skip('needs i64 math')
-
- src = r'''
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdint.h>
-
- void printy(const char *f, ...)
- {
- char buffer[256];
- va_list args;
- va_start(args, f);
- vsnprintf(buffer, 256, f, args);
- puts(buffer);
- va_end(args);
- }
-
- int main(int argc, char **argv) {
- int64_t x = argc - 1;
- int64_t y = argc - 1 + 0x400000;
- if (x % 3 == 2) y *= 2;
-
- printy("0x%llx_0x%llx", x, y);
- printy("0x%llx_0x%llx", x, x);
- printy("0x%llx_0x%llx", y, x);
- printy("0x%llx_0x%llx", y, y);
-
- {
- uint64_t A = 0x800000;
- uint64_t B = 0x800000000000ULL;
- printy("0x%llx_0x%llx", A, B);
- }
- {
- uint64_t A = 0x800;
- uint64_t B = 0x12340000000000ULL;
- printy("0x%llx_0x%llx", A, B);
- }
- {
- uint64_t A = 0x000009182746756;
- uint64_t B = 0x192837465631ACBDULL;
- printy("0x%llx_0x%llx", A, B);
- }
-
- return 0;
- }
- '''
- self.do_run(src, '''0x0_0x400000
-0x0_0x0
-0x400000_0x0
-0x400000_0x400000
-0x800000_0x800000000000
-0x800_0x12340000000000
-0x9182746756_0x192837465631acbd
-''')
-
- def test_printf_more(self):
- src = r'''
- #include <stdio.h>
- int main() {
- int size = snprintf(NULL, 0, "%s %d %.2f\n", "me and myself", 25, 1.345);
- char buf[size];
- snprintf(buf, size, "%s %d %.2f\n", "me and myself", 25, 1.345);
- printf("%d : %s\n", size, buf);
- char *buff = NULL;
- asprintf(&buff, "%d waka %d\n", 21, 95);
- puts(buff);
- return 0;
- }
- '''
- self.do_run(src, '22 : me and myself 25 1.34\n21 waka 95\n')
-
- def test_perrar(self):
- src = r'''
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
-
- int main( int argc, char** argv ){
- int retval = open( "NonExistingFile", O_RDONLY );
- if( retval == -1 )
- perror( "Cannot open NonExistingFile" );
- return 0;
- }
- '''
- self.do_run(src, 'Cannot open NonExistingFile: No such file or directory\n')
-
- def test_atoX(self):
- if self.emcc_args is None: return self.skip('requires ta2')
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main () {
- printf("%d*", atoi(""));
- printf("%d*", atoi("a"));
- printf("%d*", atoi(" b"));
- printf("%d*", atoi(" c "));
- printf("%d*", atoi("6"));
- printf("%d*", atoi(" 5"));
- printf("%d*", atoi("4 "));
- printf("%d*", atoi("3 6"));
- printf("%d*", atoi(" 3 7"));
- printf("%d*", atoi("9 d"));
- printf("%d\n", atoi(" 8 e"));
- printf("%d*", atol(""));
- printf("%d*", atol("a"));
- printf("%d*", atol(" b"));
- printf("%d*", atol(" c "));
- printf("%d*", atol("6"));
- printf("%d*", atol(" 5"));
- printf("%d*", atol("4 "));
- printf("%d*", atol("3 6"));
- printf("%d*", atol(" 3 7"));
- printf("%d*", atol("9 d"));
- printf("%d\n", atol(" 8 e"));
- printf("%lld*", atoll("6294967296"));
- printf("%lld*", atoll(""));
- printf("%lld*", atoll("a"));
- printf("%lld*", atoll(" b"));
- printf("%lld*", atoll(" c "));
- printf("%lld*", atoll("6"));
- printf("%lld*", atoll(" 5"));
- printf("%lld*", atoll("4 "));
- printf("%lld*", atoll("3 6"));
- printf("%lld*", atoll(" 3 7"));
- printf("%lld*", atoll("9 d"));
- printf("%lld\n", atoll(" 8 e"));
- return 0;
- }
- '''
- self.do_run(src, '0*0*0*0*6*5*4*3*3*9*8\n0*0*0*0*6*5*4*3*3*9*8\n6294967296*0*0*0*0*6*5*4*3*3*9*8\n')
-
- def test_strstr(self):
- src = r'''
- #include <stdio.h>
- #include <string.h>
-
- int main()
- {
- printf("%d\n", !!strstr("\\n", "\\n"));
- printf("%d\n", !!strstr("cheezy", "ez"));
- printf("%d\n", !!strstr("cheeezy", "ez"));
- printf("%d\n", !!strstr("cheeeeeeeeeezy", "ez"));
- printf("%d\n", !!strstr("cheeeeeeeeee1zy", "ez"));
- printf("%d\n", !!strstr("che1ezy", "ez"));
- printf("%d\n", !!strstr("che1ezy", "che"));
- printf("%d\n", !!strstr("ce1ezy", "che"));
- printf("%d\n", !!strstr("ce1ezy", "ezy"));
- printf("%d\n", !!strstr("ce1ezyt", "ezy"));
- printf("%d\n", !!strstr("ce1ez1y", "ezy"));
- printf("%d\n", !!strstr("cheezy", "a"));
- printf("%d\n", !!strstr("cheezy", "b"));
- printf("%d\n", !!strstr("cheezy", "c"));
- printf("%d\n", !!strstr("cheezy", "d"));
- printf("%d\n", !!strstr("cheezy", "g"));
- printf("%d\n", !!strstr("cheezy", "h"));
- printf("%d\n", !!strstr("cheezy", "i"));
- printf("%d\n", !!strstr("cheezy", "e"));
- printf("%d\n", !!strstr("cheezy", "x"));
- printf("%d\n", !!strstr("cheezy", "y"));
- printf("%d\n", !!strstr("cheezy", "z"));
- printf("%d\n", !!strstr("cheezy", "_"));
-
- const char *str = "a big string";
- printf("%d\n", strstr(str, "big") - str);
- return 0;
- }
- '''
- self.do_run(src, '''1
-1
-1
-1
-0
-1
-1
-0
-1
-1
-0
-0
-0
-1
-0
-0
-1
-0
-1
-0
-1
-1
-0
-2
-''')
-
- def test_sscanf(self):
- if self.emcc_args is None: return self.skip('needs emcc for libc')
-
- src = r'''
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- int main () {
- #define CHECK(str) \
- { \
- char name[1000]; \
- memset(name, 0, 1000); \
- int prio = 99; \
- sscanf(str, "%s %d", name, &prio); \
- printf("%s : %d\n", name, prio); \
- }
- CHECK("en-us 2");
- CHECK("en-r");
- CHECK("en 3");
-
- printf("%f, %f\n", atof("1.234567"), atof("cheez"));
-
- char float_formats[] = "fegE";
- char format[] = "%_";
- for(int i = 0; i < 4; ++i) {
- format[1] = float_formats[i];
-
- float n = -1;
- sscanf(" 2.8208", format, &n);
- printf("%.4f\n", n);
-
- float a = -1;
- sscanf("-3.03", format, &a);
- printf("%.4f\n", a);
- }
-
- char buffy[100];
- sscanf("cheez some thing moar 123\nyet more\n", "cheez %s", buffy);
- printf("|%s|\n", buffy);
- sscanf("cheez something\nmoar 123\nyet more\n", "cheez %s", buffy);
- printf("|%s|\n", buffy);
- sscanf("cheez somethingmoar\tyet more\n", "cheez %s", buffy);
- printf("|%s|\n", buffy);
-
- int numverts = -1;
- printf("%d\n", sscanf(" numverts 1499\n", " numverts %d", &numverts)); // white space is the same, even if tab vs space
- printf("%d\n", numverts);
-
- int index;
- float u, v;
- short start, count;
- printf("%d\n", sscanf(" vert 87 ( 0.481565 0.059481 ) 0 1\n", " vert %d ( %f %f ) %hu %hu", &index, &u, &v, &start, &count));
- printf("%d,%.6f,%.6f,%hu,%hu\n", index, u, v, start, count);
-
- int neg, neg2, neg3 = 0;
- printf("%d\n", sscanf("-123 -765 -34-6", "%d %u %d", &neg, &neg2, &neg3));
- printf("%d,%u,%d\n", neg, neg2, neg3);
-
- {
- int a = 0;
- sscanf("1", "%i", &a);
- printf("%i\n", a);
- }
-
- return 0;
- }
- '''
- self.do_run(src, 'en-us : 2\nen-r : 99\nen : 3\n1.234567, 0.000000\n2.8208\n-3.0300\n2.8208\n-3.0300\n2.8208\n-3.0300\n2.8208\n-3.0300\n|some|\n|something|\n|somethingmoar|\n' +
- '1\n1499\n' +
- '5\n87,0.481565,0.059481,0,1\n' +
- '3\n-123,4294966531,-34\n' +
- '1\n')
-
- def test_sscanf_2(self):
- # doubles
- if Settings.USE_TYPED_ARRAYS == 2:
- for ftype in ['float', 'double']:
- src = r'''
- #include <stdio.h>
-
- int main(){
- char strval1[] = "1.2345678901";
- char strval2[] = "1.23456789e5";
- char strval3[] = "1.23456789E5";
- char strval4[] = "1.2345678e-5";
- char strval5[] = "1.2345678E-5";
- double dblval = 1.2345678901;
- double tstval;
-
- sscanf(strval1, "%lf", &tstval);
- if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
- else printf("Pass: %lf %lf\n", tstval, dblval);
-
- sscanf(strval2, "%lf", &tstval);
- dblval = 123456.789;
- if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
- else printf("Pass: %lf %lf\n", tstval, dblval);
-
- sscanf(strval3, "%lf", &tstval);
- dblval = 123456.789;
- if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
- else printf("Pass: %lf %lf\n", tstval, dblval);
-
- sscanf(strval4, "%lf", &tstval);
- dblval = 0.000012345678;
- if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
- else printf("Pass: %lf %lf\n", tstval, dblval);
-
- sscanf(strval5, "%lf", &tstval);
- dblval = 0.000012345678;
- if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
- else printf("Pass: %lf %lf\n", tstval, dblval);
-
- return 0;
- }
- '''
- if ftype == 'float':
- self.do_run(src.replace('%lf', '%f').replace('double', 'float'), '''Pass: 1.234568 1.234568
-Pass: 123456.789063 123456.789063
-Pass: 123456.789063 123456.789063
-Pass: 0.000012 0.000012
-Pass: 0.000012 0.000012''')
- else:
- self.do_run(src, '''Pass: 1.234568 1.234568
-Pass: 123456.789000 123456.789000
-Pass: 123456.789000 123456.789000
-Pass: 0.000012 0.000012
-Pass: 0.000012 0.000012''')
-
- def test_sscanf_n(self):
- src = r'''
- #include<stdio.h>
- int main() {
- char *line = "version 1.0";
- int i, l, lineno;
- char word[80];
- if (sscanf(line, "%s%n", word, &l) != 1) {
- printf("Header format error, line %d\n", lineno);
- }
- printf("[DEBUG] word 1: %s, l: %d\n", word, l);
-
- int x = sscanf("one %n two", "%s %n", word, &l);
- printf("%d,%s,%d\n", x, word, l);
- {
- int a, b, c, count;
- count = sscanf("12345 6789", "%d %n%d", &a, &b, &c);
- printf("%i %i %i %i\n", count, a, b, c);
- }
- return 0;
- }
- '''
- self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4\n2 12345 6 6789\n''')
-
- def test_sscanf_whitespace(self):
- src = r'''
- #include<stdio.h>
-
- int main() {
- short int x;
- short int y;
-
- const char* buffer[] = {
- "173,16",
- " 16,173",
- "183, 173",
- " 17, 287",
- " 98, 123, "
- };
-
- for (int i=0; i<5; ++i) {
- sscanf(buffer[i], "%hd,%hd", &x, &y);
- printf("%d:%d,%d ", i, x, y);
- }
-
- return 0;
- }
- '''
- self.do_run(src, '''0:173,16 1:16,173 2:183,173 3:17,287 4:98,123''')
-
- def test_sscanf_other_whitespace(self):
- Settings.SAFE_HEAP = 0 # use i16s in printf
-
- src = r'''
- #include<stdio.h>
-
- int main() {
- short int x;
- short int y;
-
- const char* buffer[] = {
- "\t2\t3\t", /* TAB - horizontal tab */
- "\t\t5\t\t7\t\t",
- "\n11\n13\n", /* LF - line feed */
- "\n\n17\n\n19\n\n",
- "\v23\v29\v", /* VT - vertical tab */
- "\v\v31\v\v37\v\v",
- "\f41\f43\f", /* FF - form feed */
- "\f\f47\f\f53\f\f",
- "\r59\r61\r", /* CR - carrage return */
- "\r\r67\r\r71\r\r"
- };
-
- for (int i=0; i<10; ++i) {
- x = 0; y = 0;
- sscanf(buffer[i], " %d %d ", &x, &y);
- printf("%d, %d, ", x, y);
- }
-
- return 0;
- }
- '''
- self.do_run(src, '''2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, ''')
-
- def test_sscanf_3(self):
- # i64
- if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('64-bit sscanf only supported in ta2')
- src = r'''
- #include <stdint.h>
- #include <stdio.h>
-
- int main(){
-
- int64_t s, m, l;
- printf("%d\n", sscanf("123 1073741823 1125899906842620", "%lld %lld %lld", &s, &m, &l));
- printf("%lld,%lld,%lld\n", s, m, l);
-
- int64_t negS, negM, negL;
- printf("%d\n", sscanf("-123 -1073741823 -1125899906842620", "%lld %lld %lld", &negS, &negM, &negL));
- printf("%lld,%lld,%lld\n", negS, negM, negL);
-
- return 0;
- }
- '''
-
- self.do_run(src, '3\n123,1073741823,1125899906842620\n' +
- '3\n-123,-1073741823,-1125899906842620\n')
-
- def test_sscanf_4(self):
- src = r'''
- #include <stdio.h>
-
- int main()
- {
- char pYear[16], pMonth[16], pDay[16], pDate[64];
- printf("%d\n", sscanf("Nov 19 2012", "%s%s%s", pMonth, pDay, pYear));
- printf("day %s, month %s, year %s \n", pDay, pMonth, pYear);
- return(0);
- }
- '''
- self.do_run(src, '3\nday 19, month Nov, year 2012');
-
- def test_sscanf_5(self):
- src = r'''
- #include "stdio.h"
-
- static const char *colors[] = {
- " c black",
- ". c #001100",
- "X c #111100"
- };
-
- int main(){
- unsigned char code;
- char color[32];
- int rcode;
- for(int i = 0; i < 3; i++) {
- rcode = sscanf(colors[i], "%c c %s", &code, color);
- printf("%i, %c, %s\n", rcode, code, color);
- }
- }
- '''
- self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100');
-
- def test_sscanf_6(self):
- src = r'''
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- char *date = "18.07.2013w";
- char c[10];
- memset(c, 0, 10);
- int y, m, d, i;
- i = sscanf(date, "%d.%d.%4d%c", &d, &m, &y, c);
- printf("date: %s; day %2d, month %2d, year %4d, extra: %c, %d\n", date, d, m, y, c[0], i);
- i = sscanf(date, "%d.%d.%3c", &d, &m, c);
- printf("date: %s; day %2d, month %2d, year %4d, extra: %s, %d\n", date, d, m, y, c, i);
- }
- '''
- self.do_run(src, '''date: 18.07.2013w; day 18, month 7, year 2013, extra: w, 4
-date: 18.07.2013w; day 18, month 7, year 2013, extra: 201, 3
-''');
-
- def test_sscanf_skip(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip("need ta2 for full i64")
-
- src = r'''
- #include <stdint.h>
- #include <stdio.h>
-
- int main(){
- int val1;
- printf("%d\n", sscanf("10 20 30 40", "%*lld %*d %d", &val1));
- printf("%d\n", val1);
-
- int64_t large, val2;
- printf("%d\n", sscanf("1000000 -1125899906842620 -123 -1073741823", "%lld %*lld %ld %*d", &large, &val2));
- printf("%lld,%d\n", large, val2);
-
- return 0;
- }
- '''
- self.do_run(src, '1\n30\n2\n1000000,-123\n')
-
- def test_sscanf_caps(self):
- src = r'''
- #include "stdio.h"
-
- int main(){
- unsigned int a;
- float e, f, g;
- sscanf("a 1.1 1.1 1.1", "%X %E %F %G", &a, &e, &f, &g);
- printf("%d %.1F %.1F %.1F\n", a, e, f, g);
- }
- '''
- self.do_run(src, '10 1.1 1.1 1.1');
-
- def test_langinfo(self):
- src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
- expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
- self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h'])
-
- def test_files(self):
- if self.emcc_args is not None and '-O2' in self.emcc_args:
- self.emcc_args += ['--closure', '1'] # Use closure here, to test we don't break FS stuff
-
- Settings.CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both.
- post = '''
-def process(filename):
- src = \'\'\'
- var Module = {
- 'noFSInit': true,
- 'preRun': function() {
- FS.createLazyFile('/', 'test.file', 'test.file', true, false);
- // Test FS_* exporting
- Module['FS_createDataFile']('/', 'somefile.binary', [100, 200, 50, 25, 10, 77, 123], true, false); // 200 becomes -56, since signed chars are used in memory
- var test_files_input = 'hi there!';
- var test_files_input_index = 0;
- FS.init(function() {
- return test_files_input.charCodeAt(test_files_input_index++) || null;
- });
- }
- };
- \'\'\' + open(filename, 'r').read()
- open(filename, 'w').write(src)
-'''
- other = open(os.path.join(self.get_dir(), 'test.file'), 'w')
- other.write('some data');
- other.close()
-
- src = open(path_from_root('tests', 'files.cpp'), 'r').read()
- self.do_run(src, 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n',
- post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
-
- def test_files_m(self):
- # Test for Module.stdin etc.
-
- Settings.CORRECT_SIGNS = 1
-
- post = '''
-def process(filename):
- src = \'\'\'
- var data = [10, 20, 40, 30];
- var Module = {
- stdin: function() { return data.pop() || null },
- stdout: function(x) { Module.print('got: ' + x) }
- };
- \'\'\' + open(filename, 'r').read()
- open(filename, 'w').write(src)
-'''
- src = r'''
- #include <stdio.h>
- #include <unistd.h>
-
- int main () {
- char c;
- fprintf(stderr, "isatty? %d,%d,%d\n", isatty(fileno(stdin)), isatty(fileno(stdout)), isatty(fileno(stderr)));
- while ((c = fgetc(stdin)) != EOF) {
- putc(c+5, stdout);
- }
- return 0;
- }
- '''
- self.do_run(src, 'got: 35\ngot: 45\ngot: 25\ngot: 15\nisatty? 0,0,1\n', post_build=post)
-
- def test_fwrite_0(self):
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main ()
- {
- FILE *fh;
-
- fh = fopen("a.txt", "wb");
- if (!fh) exit(1);
- fclose(fh);
-
- fh = fopen("a.txt", "rb");
- if (!fh) exit(1);
-
- char data[] = "foobar";
- size_t written = fwrite(data, 1, sizeof(data), fh);
-
- printf("written=%zu\n", written);
- }
- '''
- self.do_run(src, 'written=0')
-
- def test_fgetc_ungetc(self):
- src = open(path_from_root('tests', 'stdio', 'test_fgetc_ungetc.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_fgetc_unsigned(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = r'''
- #include <stdio.h>
- int main() {
- FILE *file = fopen("file_with_byte_234.txt", "rb");
- int c = fgetc(file);
- printf("*%d\n", c);
- }
- '''
- open('file_with_byte_234.txt', 'wb').write('\xea')
- self.emcc_args += ['--embed-file', 'file_with_byte_234.txt']
- self.do_run(src, '*234\n')
-
- def test_fgets_eol(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = r'''
- #include <stdio.h>
- char buf[32];
- int main()
- {
- char *r = "SUCCESS";
- FILE *f = fopen("eol.txt", "r");
- while (fgets(buf, 32, f) != NULL) {
- if (buf[0] == '\0') {
- r = "FAIL";
- break;
- }
- }
- printf("%s\n", r);
- fclose(f);
- return 0;
- }
- '''
- open('eol.txt', 'wb').write('\n')
- self.emcc_args += ['--embed-file', 'eol.txt']
- self.do_run(src, 'SUCCESS\n')
-
- def test_fscanf(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- open(os.path.join(self.get_dir(), 'three_numbers.txt'), 'w').write('''-1 0.1 -.1''')
- src = r'''
- #include <stdio.h>
- #include <assert.h>
- #include <float.h>
- int main()
- {
- float x = FLT_MAX, y = FLT_MAX, z = FLT_MAX;
-
- FILE* fp = fopen("three_numbers.txt", "r");
- if (fp) {
- int match = fscanf(fp, " %f %f %f ", &x, &y, &z);
- printf("match = %d\n", match);
- printf("x = %0.1f, y = %0.1f, z = %0.1f\n", x, y, z);
- } else {
- printf("failed to open three_numbers.txt\n");
- }
- return 0;
- }
- '''
- self.emcc_args += ['--embed-file', 'three_numbers.txt']
- self.do_run(src, 'match = 3\nx = -1.0, y = 0.1, z = -0.1\n')
-
- def test_readdir(self):
- src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_stat(self):
- src = open(path_from_root('tests', 'stat', 'test_stat.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_stat_chmod(self):
- src = open(path_from_root('tests', 'stat', 'test_chmod.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_stat_mknod(self):
- src = open(path_from_root('tests', 'stat', 'test_mknod.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_fcntl(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createDataFile('/', 'test', 'abcdef', true, true);"
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'fcntl', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'fcntl', 'output.txt'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
-
- def test_fcntl_open(self):
- src = open(path_from_root('tests', 'fcntl-open', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read()
- self.do_run(src, expected, force_c=True, extra_emscripten_args=['-H', 'libc/fcntl.h'])
-
- def test_fcntl_misc(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createDataFile('/', 'test', 'abcdef', true, true);"
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'fcntl-misc', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'fcntl-misc', 'output.txt'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
-
- def test_poll(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- \'\'\'
- FS.createDataFile('/', 'file', 'abcdef', true, true);
- FS.createDevice('/', 'device', function() {}, function() {});
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
- src = r'''
- #include <stdio.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <poll.h>
-
- int main() {
- struct pollfd multi[5];
- multi[0].fd = open("/file", O_RDONLY, 0777);
- multi[1].fd = open("/device", O_RDONLY, 0777);
- multi[2].fd = 123;
- multi[3].fd = open("/file", O_RDONLY, 0777);
- multi[4].fd = open("/file", O_RDONLY, 0777);
- multi[0].events = POLLIN | POLLOUT | POLLNVAL | POLLERR;
- multi[1].events = POLLIN | POLLOUT | POLLNVAL | POLLERR;
- multi[2].events = POLLIN | POLLOUT | POLLNVAL | POLLERR;
- multi[3].events = 0x00;
- multi[4].events = POLLOUT | POLLNVAL | POLLERR;
-
- printf("ret: %d\n", poll(multi, 5, 123));
- printf("errno: %d\n", errno);
- printf("multi[0].revents: %d\n", multi[0].revents == (POLLIN | POLLOUT));
- printf("multi[1].revents: %d\n", multi[1].revents == (POLLIN | POLLOUT));
- printf("multi[2].revents: %d\n", multi[2].revents == POLLNVAL);
- printf("multi[3].revents: %d\n", multi[3].revents == 0);
- printf("multi[4].revents: %d\n", multi[4].revents == POLLOUT);
-
- return 0;
- }
- '''
- expected = r'''
- ret: 4
- errno: 0
- multi[0].revents: 1
- multi[1].revents: 1
- multi[2].revents: 1
- multi[3].revents: 1
- multi[4].revents: 1
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h,poll.h'])
-
- def test_statvfs(self):
- src = r'''
- #include <stdio.h>
- #include <errno.h>
- #include <sys/statvfs.h>
-
- int main() {
- struct statvfs s;
-
- printf("result: %d\n", statvfs("/test", &s));
- printf("errno: %d\n", errno);
-
- printf("f_bsize: %lu\n", s.f_bsize);
- printf("f_frsize: %lu\n", s.f_frsize);
- printf("f_blocks: %lu\n", s.f_blocks);
- printf("f_bfree: %lu\n", s.f_bfree);
- printf("f_bavail: %lu\n", s.f_bavail);
- printf("f_files: %d\n", s.f_files > 5);
- printf("f_ffree: %lu\n", s.f_ffree);
- printf("f_favail: %lu\n", s.f_favail);
- printf("f_fsid: %lu\n", s.f_fsid);
- printf("f_flag: %lu\n", s.f_flag);
- printf("f_namemax: %lu\n", s.f_namemax);
-
- return 0;
- }
- '''
- expected = r'''
- result: 0
- errno: 0
- f_bsize: 4096
- f_frsize: 4096
- f_blocks: 1000000
- f_bfree: 500000
- f_bavail: 500000
- f_files: 1
- f_ffree: 1000000
- f_favail: 1000000
- f_fsid: 42
- f_flag: 2
- f_namemax: 255
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
-
- def test_libgen(self):
- src = r'''
- #include <stdio.h>
- #include <libgen.h>
-
- int main() {
- char p1[16] = "/usr/lib", p1x[16] = "/usr/lib";
- printf("%s -> ", p1);
- printf("%s : %s\n", dirname(p1x), basename(p1));
-
- char p2[16] = "/usr", p2x[16] = "/usr";
- printf("%s -> ", p2);
- printf("%s : %s\n", dirname(p2x), basename(p2));
-
- char p3[16] = "/usr/", p3x[16] = "/usr/";
- printf("%s -> ", p3);
- printf("%s : %s\n", dirname(p3x), basename(p3));
-
- char p4[16] = "/usr/lib///", p4x[16] = "/usr/lib///";
- printf("%s -> ", p4);
- printf("%s : %s\n", dirname(p4x), basename(p4));
-
- char p5[16] = "/", p5x[16] = "/";
- printf("%s -> ", p5);
- printf("%s : %s\n", dirname(p5x), basename(p5));
-
- char p6[16] = "///", p6x[16] = "///";
- printf("%s -> ", p6);
- printf("%s : %s\n", dirname(p6x), basename(p6));
-
- char p7[16] = "/usr/../lib/..", p7x[16] = "/usr/../lib/..";
- printf("%s -> ", p7);
- printf("%s : %s\n", dirname(p7x), basename(p7));
-
- char p8[16] = "", p8x[16] = "";
- printf("(empty) -> %s : %s\n", dirname(p8x), basename(p8));
-
- printf("(null) -> %s : %s\n", dirname(0), basename(0));
-
- return 0;
- }
- '''
- expected = '''
- /usr/lib -> /usr : lib
- /usr -> / : usr
- /usr/ -> / : usr
- /usr/lib/// -> /usr : lib
- / -> / : /
- /// -> / : /
- /usr/../lib/.. -> /usr/../lib : ..
- (empty) -> . : .
- (null) -> . : .
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
-
- def test_utime(self):
- src = open(path_from_root('tests', 'utime', 'test_utime.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_utf(self):
- self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well
- Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc']
-
- src = r'''
- #include <stdio.h>
- #include <emscripten.h>
-
- int main() {
- char *c = "μ†ℱ ╋ℯ╳╋";
- printf("%d %d %d %d %s\n", c[0]&0xff, c[1]&0xff, c[2]&0xff, c[3]&0xff, c);
- emscripten_run_script("cheez = _malloc(100);"
- "Module.writeStringToMemory(\"μ†ℱ ╋ℯ╳╋\", cheez);"
- "Module.print([Pointer_stringify(cheez), Module.getValue(cheez, 'i8')&0xff, Module.getValue(cheez+1, 'i8')&0xff, Module.getValue(cheez+2, 'i8')&0xff, Module.getValue(cheez+3, 'i8')&0xff, ]);");
- }
- '''
- self.do_run(src, '206 188 226 128 μ†ℱ ╋ℯ╳╋\nμ†ℱ ╋ℯ╳╋,206,188,226,128\n');
-
- def test_direct_string_constant_usage(self):
- if self.emcc_args is None: return self.skip('requires libcxx')
-
- src = '''
- #include <iostream>
- template<int i>
- void printText( const char (&text)[ i ] )
- {
- std::cout << text;
- }
- int main()
- {
- printText( "some string constant" );
- return 0;
- }
- '''
- self.do_run(src, "some string constant")
-
- def test_std_cout_new(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- src = '''
- #include <iostream>
-
- struct NodeInfo { //structure that we want to transmit to our shaders
- float x;
- float y;
- float s;
- float c;
- };
- const int nbNodes = 100;
- NodeInfo * data = new NodeInfo[nbNodes]; //our data that will be transmitted using float texture.
-
- template<int i>
- void printText( const char (&text)[ i ] )
- {
- std::cout << text << std::endl;
- }
-
- int main()
- {
- printText( "some string constant" );
- return 0;
- }
- '''
-
- self.do_run(src, "some string constant")
-
- def test_istream(self):
- if self.emcc_args is None: return self.skip('requires libcxx')
-
- src = '''
- #include <string>
- #include <sstream>
- #include <iostream>
-
- int main()
- {
- std::string mystring("1 2 3");
- std::istringstream is(mystring);
- int one, two, three;
-
- is >> one >> two >> three;
-
- printf( "%i %i %i", one, two, three );
- }
- '''
- for linkable in [0]:#, 1]:
- print linkable
- Settings.LINKABLE = linkable # regression check for issue #273
- self.do_run(src, "1 2 3")
-
- def test_fs_base(self):
- Settings.INCLUDE_FULL_LIBRARY = 1
- try:
- addJS = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace('FS.init();', '').replace( # Disable normal initialization, replace with ours
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'filesystem', 'src.js'), 'r').read())
- open(filename, 'w').write(src)
-'''
- src = 'int main() {return 0;}\n'
- expected = open(path_from_root('tests', 'filesystem', 'output.txt'), 'r').read()
- self.do_run(src, expected, post_build=addJS, extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
- finally:
- Settings.INCLUDE_FULL_LIBRARY = 0
-
- def test_unistd_access(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'access.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'unistd', 'access.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'access.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
-
- def test_unistd_curdir(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'curdir.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'unistd', 'curdir.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'curdir.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
-
- def test_unistd_close(self):
- src = open(path_from_root('tests', 'unistd', 'close.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'close.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_confstr(self):
- src = open(path_from_root('tests', 'unistd', 'confstr.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'confstr.out'), 'r').read()
- self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/unistd.h'])
-
- def test_unistd_ttyname(self):
- src = open(path_from_root('tests', 'unistd', 'ttyname.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_unistd_dup(self):
- src = open(path_from_root('tests', 'unistd', 'dup.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'dup.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_pathconf(self):
- src = open(path_from_root('tests', 'unistd', 'pathconf.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'pathconf.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_truncate(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'truncate.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'unistd', 'truncate.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'truncate.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
-
- def test_unistd_swab(self):
- src = open(path_from_root('tests', 'unistd', 'swab.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'swab.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_isatty(self):
- src = open(path_from_root('tests', 'unistd', 'isatty.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_unistd_sysconf(self):
- src = open(path_from_root('tests', 'unistd', 'sysconf.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'sysconf.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_login(self):
- src = open(path_from_root('tests', 'unistd', 'login.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'login.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_unlink(self):
- src = open(path_from_root('tests', 'unistd', 'unlink.c'), 'r').read()
- self.do_run(src, 'success', force_c=True)
-
- def test_unistd_links(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'links.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'unistd', 'links.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'links.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
-
- def test_unistd_sleep(self):
- src = open(path_from_root('tests', 'unistd', 'sleep.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'sleep.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_unistd_io(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'io.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'unistd', 'io.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'io.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
-
- def test_unistd_misc(self):
- src = open(path_from_root('tests', 'unistd', 'misc.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'misc.out'), 'r').read()
- self.do_run(src, expected)
-
- def test_uname(self):
- src = r'''
- #include <stdio.h>
- #include <sys/utsname.h>
-
- int main() {
- struct utsname u;
- printf("ret: %d\n", uname(&u));
- printf("sysname: %s\n", u.sysname);
- printf("nodename: %s\n", u.nodename);
- printf("release: %s\n", u.release);
- printf("version: %s\n", u.version);
- printf("machine: %s\n", u.machine);
- printf("invalid: %d\n", uname(0));
- return 0;
- }
- '''
- expected = '''
- ret: 0
- sysname: Emscripten
- nodename: emscripten
- release: 1.0
- version: #1
- machine: x86-JS
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
-
- def test_env(self):
- src = open(path_from_root('tests', 'env', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'env', 'output.txt'), 'r').read()
- self.do_run(src, expected)
-
- def test_systypes(self):
- src = open(path_from_root('tests', 'systypes', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'systypes', 'output.txt'), 'r').read()
- self.do_run(src, expected)
-
- def test_getloadavg(self):
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main() {
- double load[5] = {42.13, 42.13, 42.13, 42.13, 42.13};
- printf("ret: %d\n", getloadavg(load, 5));
- printf("load[0]: %.3lf\n", load[0]);
- printf("load[1]: %.3lf\n", load[1]);
- printf("load[2]: %.3lf\n", load[2]);
- printf("load[3]: %.3lf\n", load[3]);
- printf("load[4]: %.3lf\n", load[4]);
- return 0;
- }
- '''
- expected = '''
- ret: 3
- load[0]: 0.100
- load[1]: 0.100
- load[2]: 0.100
- load[3]: 42.130
- load[4]: 42.130
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
-
- def test_inet(self):
- src = r'''
- #include <stdio.h>
- #include <arpa/inet.h>
-
- int main() {
- printf("*%x,%x,%x,%x,%x,%x*\n", htonl(0xa1b2c3d4), htonl(0xfe3572e0), htonl(0x07abcdf0), htons(0xabcd), ntohl(0x43211234), ntohs(0xbeaf));
- in_addr_t i = inet_addr("190.180.10.78");
- printf("%x\n", i);
- return 0;
- }
- '''
- self.do_run(src, '*d4c3b2a1,e07235fe,f0cdab07,cdab,34122143,afbe*\n4e0ab4be\n')
-
- def test_inet2(self):
- src = r'''
- #include <stdio.h>
- #include <arpa/inet.h>
-
- int main() {
- struct in_addr x, x2;
- int *y = (int*)&x;
- *y = 0x12345678;
- printf("%s\n", inet_ntoa(x));
- int r = inet_aton(inet_ntoa(x), &x2);
- printf("%s\n", inet_ntoa(x2));
- return 0;
- }
- '''
- self.do_run(src, '120.86.52.18\n120.86.52.18\n')
-
- def test_inet3(self):
- src = r'''
- #include <stdio.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- int main() {
- char dst[64];
- struct in_addr x, x2;
- int *y = (int*)&x;
- *y = 0x12345678;
- printf("%s\n", inet_ntop(AF_INET,&x,dst,sizeof dst));
- int r = inet_aton(inet_ntoa(x), &x2);
- printf("%s\n", inet_ntop(AF_INET,&x2,dst,sizeof dst));
- return 0;
- }
- '''
- self.do_run(src, '120.86.52.18\n120.86.52.18\n')
-
- def test_inet4(self):
- src = r'''
- #include <stdio.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
-
- void test(char *test_addr){
- char str[40];
- struct in6_addr addr;
- unsigned char *p = (unsigned char*)&addr;
- int ret;
- ret = inet_pton(AF_INET6,test_addr,&addr);
- if(ret == -1) return;
- if(ret == 0) return;
- if(inet_ntop(AF_INET6,&addr,str,sizeof(str)) == NULL ) return;
- printf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x - %s\n",
- p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15],str);
- }
- int main(){
- test("::");
- test("::1");
- test("::1.2.3.4");
- test("::17.18.19.20");
- test("::ffff:1.2.3.4");
- test("1::ffff");
- test("::255.255.255.255");
- test("0:ff00:1::");
- test("0:ff::");
- test("abcd::");
- test("ffff::a");
- test("ffff::a:b");
- test("ffff::a:b:c");
- test("ffff::a:b:c:d");
- test("ffff::a:b:c:d:e");
- test("::1:2:0:0:0");
- test("0:0:1:2:3::");
- test("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
- test("1::255.255.255.255");
-
- //below should fail and not produce results..
- test("1.2.3.4");
- test("");
- test("-");
- }
- '''
- self.do_run(src,
- "0000:0000:0000:0000:0000:0000:0000:0000 - ::\n"
- "0000:0000:0000:0000:0000:0000:0000:0001 - ::1\n"
- "0000:0000:0000:0000:0000:0000:0102:0304 - ::1.2.3.4\n"
- "0000:0000:0000:0000:0000:0000:1112:1314 - ::17.18.19.20\n"
- "0000:0000:0000:0000:0000:ffff:0102:0304 - ::ffff:1.2.3.4\n"
- "0001:0000:0000:0000:0000:0000:0000:ffff - 1::ffff\n"
- "0000:0000:0000:0000:0000:0000:ffff:ffff - ::255.255.255.255\n"
- "0000:ff00:0001:0000:0000:0000:0000:0000 - 0:ff00:1::\n"
- "0000:00ff:0000:0000:0000:0000:0000:0000 - 0:ff::\n"
- "abcd:0000:0000:0000:0000:0000:0000:0000 - abcd::\n"
- "ffff:0000:0000:0000:0000:0000:0000:000a - ffff::a\n"
- "ffff:0000:0000:0000:0000:0000:000a:000b - ffff::a:b\n"
- "ffff:0000:0000:0000:0000:000a:000b:000c - ffff::a:b:c\n"
- "ffff:0000:0000:0000:000a:000b:000c:000d - ffff::a:b:c:d\n"
- "ffff:0000:0000:000a:000b:000c:000d:000e - ffff::a:b:c:d:e\n"
- "0000:0000:0000:0001:0002:0000:0000:0000 - ::1:2:0:0:0\n"
- "0000:0000:0001:0002:0003:0000:0000:0000 - 0:0:1:2:3::\n"
- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\n"
- "0001:0000:0000:0000:0000:0000:ffff:ffff - 1::ffff:ffff\n"
- )
-
- def test_gethostbyname(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip("assume t2 in gethostbyname")
-
- src = r'''
- #include <netdb.h>
- #include <stdio.h>
-
- void test(char *hostname) {
- hostent *host = gethostbyname(hostname);
- if (!host) {
- printf("no such thing\n");
- return;
- }
- printf("%s : %d : %d\n", host->h_name, host->h_addrtype, host->h_length);
- char **name = host->h_aliases;
- while (*name) {
- printf("- %s\n", *name);
- name++;
- }
- name = host->h_addr_list;
- while (name && *name) {
- printf("* ");
- for (int i = 0; i < host->h_length; i++)
- printf("%d.", (*name)[i]);
- printf("\n");
- name++;
- }
- }
-
- int main() {
- test("www.cheezburger.com");
- test("fail.on.this.never.work"); // we will "work" on this - because we are just making aliases of names to ips
- test("localhost");
- return 0;
- }
- '''
- self.do_run(src, '''www.cheezburger.com : 2 : 4
-* -84.29.1.0.
-fail.on.this.never.work : 2 : 4
-* -84.29.2.0.
-localhost : 2 : 4
-* -84.29.3.0.
-''')
-
- def test_799(self):
- src = open(path_from_root('tests', '799.cpp'), 'r').read()
- self.do_run(src, '''Set PORT family: 0, port: 3979
-Get PORT family: 0
-PORT: 3979
-''')
-
- def test_ctype(self):
- # The bit fiddling done by the macros using __ctype_b_loc requires this.
- Settings.CORRECT_SIGNS = 1
- src = open(path_from_root('tests', 'ctype', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read()
- self.do_run(src, expected)
-
- def test_strcasecmp(self):
- src = r'''
- #include <stdio.h>
- #include <strings.h>
- int sign(int x) {
- if (x < 0) return -1;
- if (x > 0) return 1;
- return 0;
- }
- int main() {
- printf("*\n");
-
- printf("%d\n", sign(strcasecmp("hello", "hello")));
- printf("%d\n", sign(strcasecmp("hello1", "hello")));
- printf("%d\n", sign(strcasecmp("hello", "hello1")));
- printf("%d\n", sign(strcasecmp("hello1", "hello1")));
- printf("%d\n", sign(strcasecmp("iello", "hello")));
- printf("%d\n", sign(strcasecmp("hello", "iello")));
- printf("%d\n", sign(strcasecmp("A", "hello")));
- printf("%d\n", sign(strcasecmp("Z", "hello")));
- printf("%d\n", sign(strcasecmp("a", "hello")));
- printf("%d\n", sign(strcasecmp("z", "hello")));
- printf("%d\n", sign(strcasecmp("hello", "a")));
- printf("%d\n", sign(strcasecmp("hello", "z")));
-
- printf("%d\n", sign(strcasecmp("Hello", "hello")));
- printf("%d\n", sign(strcasecmp("Hello1", "hello")));
- printf("%d\n", sign(strcasecmp("Hello", "hello1")));
- printf("%d\n", sign(strcasecmp("Hello1", "hello1")));
- printf("%d\n", sign(strcasecmp("Iello", "hello")));
- printf("%d\n", sign(strcasecmp("Hello", "iello")));
- printf("%d\n", sign(strcasecmp("A", "hello")));
- printf("%d\n", sign(strcasecmp("Z", "hello")));
- printf("%d\n", sign(strcasecmp("a", "hello")));
- printf("%d\n", sign(strcasecmp("z", "hello")));
- printf("%d\n", sign(strcasecmp("Hello", "a")));
- printf("%d\n", sign(strcasecmp("Hello", "z")));
-
- printf("%d\n", sign(strcasecmp("hello", "Hello")));
- printf("%d\n", sign(strcasecmp("hello1", "Hello")));
- printf("%d\n", sign(strcasecmp("hello", "Hello1")));
- printf("%d\n", sign(strcasecmp("hello1", "Hello1")));
- printf("%d\n", sign(strcasecmp("iello", "Hello")));
- printf("%d\n", sign(strcasecmp("hello", "Iello")));
- printf("%d\n", sign(strcasecmp("A", "Hello")));
- printf("%d\n", sign(strcasecmp("Z", "Hello")));
- printf("%d\n", sign(strcasecmp("a", "Hello")));
- printf("%d\n", sign(strcasecmp("z", "Hello")));
- printf("%d\n", sign(strcasecmp("hello", "a")));
- printf("%d\n", sign(strcasecmp("hello", "z")));
-
- printf("%d\n", sign(strcasecmp("Hello", "Hello")));
- printf("%d\n", sign(strcasecmp("Hello1", "Hello")));
- printf("%d\n", sign(strcasecmp("Hello", "Hello1")));
- printf("%d\n", sign(strcasecmp("Hello1", "Hello1")));
- printf("%d\n", sign(strcasecmp("Iello", "Hello")));
- printf("%d\n", sign(strcasecmp("Hello", "Iello")));
- printf("%d\n", sign(strcasecmp("A", "Hello")));
- printf("%d\n", sign(strcasecmp("Z", "Hello")));
- printf("%d\n", sign(strcasecmp("a", "Hello")));
- printf("%d\n", sign(strcasecmp("z", "Hello")));
- printf("%d\n", sign(strcasecmp("Hello", "a")));
- printf("%d\n", sign(strcasecmp("Hello", "z")));
-
- printf("%d\n", sign(strncasecmp("hello", "hello", 3)));
- printf("%d\n", sign(strncasecmp("hello1", "hello", 3)));
- printf("%d\n", sign(strncasecmp("hello", "hello1", 3)));
- printf("%d\n", sign(strncasecmp("hello1", "hello1", 3)));
- printf("%d\n", sign(strncasecmp("iello", "hello", 3)));
- printf("%d\n", sign(strncasecmp("hello", "iello", 3)));
- printf("%d\n", sign(strncasecmp("A", "hello", 3)));
- printf("%d\n", sign(strncasecmp("Z", "hello", 3)));
- printf("%d\n", sign(strncasecmp("a", "hello", 3)));
- printf("%d\n", sign(strncasecmp("z", "hello", 3)));
- printf("%d\n", sign(strncasecmp("hello", "a", 3)));
- printf("%d\n", sign(strncasecmp("hello", "z", 3)));
-
- printf("*\n");
-
- return 0;
- }
- '''
- self.do_run(src, '''*\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n0\n0\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n*\n''')
-
- def test_atomic(self):
- src = '''
- #include <stdio.h>
- int main() {
- int x = 10;
- int y = __sync_add_and_fetch(&x, 5);
- printf("*%d,%d*\\n", x, y);
- x = 10;
- y = __sync_fetch_and_add(&x, 5);
- printf("*%d,%d*\\n", x, y);
- x = 10;
- y = __sync_lock_test_and_set(&x, 6);
- printf("*%d,%d*\\n", x, y);
- x = 10;
- y = __sync_bool_compare_and_swap(&x, 9, 7);
- printf("*%d,%d*\\n", x, y);
- y = __sync_bool_compare_and_swap(&x, 10, 7);
- printf("*%d,%d*\\n", x, y);
- return 0;
- }
- '''
-
- self.do_run(src, '*15,15*\n*15,10*\n*6,10*\n*10,0*\n*7,1*')
-
- def test_phiundef(self):
- src = r'''
-#include <stdlib.h>
-#include <stdio.h>
-
-static int state;
-
-struct my_struct {
- union {
- struct {
- unsigned char a;
- unsigned char b;
- } c;
- unsigned int d;
- } e;
- unsigned int f;
-};
-
-int main(int argc, char **argv) {
- struct my_struct r;
-
- state = 0;
-
- for (int i=0;i<argc+10;i++)
- {
- if (state % 2 == 0)
- r.e.c.a = 3;
- else
- printf("%d\n", r.e.c.a);
- state++;
- }
- return 0;
-}
- '''
-
- self.do_run(src, '3\n3\n3\n3\n3\n')
-
- # libc++ tests
-
- def test_iostream(self):
- if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
-
- if self.emcc_args is None:
- if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion')
- self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc
- Settings.SAFE_HEAP = 0 # Some spurious warnings from libc++ internals
-
- src = '''
- #include <iostream>
-
- int main()
- {
- std::cout << "hello world" << std::endl << 77 << "." << std::endl;
- return 0;
- }
- '''
-
- # FIXME: should not have so many newlines in output here
- self.do_run(src, 'hello world\n77.\n')
-
- def test_stdvec(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- src = '''
- #include <vector>
- #include <stdio.h>
-
- struct S {
- int a;
- float b;
- };
-
- void foo(int a, float b)
- {
- printf("%d:%.2f\\n", a, b);
- }
-
- int main ( int argc, char *argv[] )
- {
- std::vector<S> ar;
- S s;
-
- s.a = 789;
- s.b = 123.456f;
- ar.push_back(s);
-
- s.a = 0;
- s.b = 100.1f;
- ar.push_back(s);
-
- foo(ar[0].a, ar[0].b);
- foo(ar[1].a, ar[1].b);
- }
- '''
-
- self.do_run(src, '789:123.46\n0:100.1')
-
- def test_reinterpreted_ptrs(self):
- if self.emcc_args is None: return self.skip('needs emcc and libc')
-
- src = r'''
-#include <stdio.h>
-
-class Foo {
-private:
- float bar;
-public:
- int baz;
-
- Foo(): bar(0), baz(4711) {};
-
- int getBar() const;
-};
-
-int Foo::getBar() const {
- return this->bar;
-};
-
-const Foo *magic1 = reinterpret_cast<Foo*>(0xDEAD111F);
-const Foo *magic2 = reinterpret_cast<Foo*>(0xDEAD888F);
-
-static void runTest() {
-
- const Foo *a = new Foo();
- const Foo *b = a;
-
- if (a->getBar() == 0) {
- if (a->baz == 4712)
- b = magic1;
- else
- b = magic2;
- }
-
- printf("%s\n", (b == magic1 ? "magic1" : (b == magic2 ? "magic2" : "neither")));
-};
-
-extern "C" {
- int main(int argc, char **argv) {
- runTest();
- }
-}
-'''
- self.do_run(src, 'magic2')
-
- def test_jansson(self):
- return self.skip('currently broken')
-
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
- if Settings.SAFE_HEAP: return self.skip('jansson is not safe-heap safe')
-
- src = '''
- #include <jansson.h>
- #include <stdio.h>
- #include <string.h>
-
- int main()
- {
- const char* jsonString = "{\\"key\\": \\"value\\",\\"array\\": [\\"array_item1\\",\\"array_item2\\",\\"array_item3\\"],\\"dict\\":{\\"number\\": 3,\\"float\\": 2.2}}";
-
- json_error_t error;
- json_t *root = json_loadb(jsonString, strlen(jsonString), 0, &error);
-
- if(!root) {
- printf("Node `root` is `null`.");
- return 0;
- }
-
- if(!json_is_object(root)) {
- printf("Node `root` is no object.");
- return 0;
- }
-
- printf("%s\\n", json_string_value(json_object_get(root, "key")));
-
- json_t *array = json_object_get(root, "array");
- if(!array) {
- printf("Node `array` is `null`.");
- return 0;
- }
-
- if(!json_is_array(array)) {
- printf("Node `array` is no array.");
- return 0;
- }
-
- for(size_t i=0; i<json_array_size(array); ++i)
- {
- json_t *arrayNode = json_array_get(array, i);
- if(!root || !json_is_string(arrayNode))
- return 0;
- printf("%s\\n", json_string_value(arrayNode));
- }
-
- json_t *dict = json_object_get(root, "dict");
- if(!dict || !json_is_object(dict))
- return 0;
-
- json_t *numberNode = json_object_get(dict, "number");
- json_t *floatNode = json_object_get(dict, "float");
-
- if(!numberNode || !json_is_number(numberNode) ||
- !floatNode || !json_is_real(floatNode))
- return 0;
-
- printf("%i\\n", json_integer_value(numberNode));
- printf("%.2f\\n", json_number_value(numberNode));
- printf("%.2f\\n", json_real_value(floatNode));
-
- json_t *invalidNode = json_object_get(dict, "invalidNode");
- if(invalidNode)
- return 0;
-
- printf("%i\\n", json_number_value(invalidNode));
-
- json_decref(root);
-
- if(!json_is_object(root))
- printf("jansson!\\n");
-
- return 0;
- }
- '''
- self.do_run(src, 'value\narray_item1\narray_item2\narray_item3\n3\n3.00\n2.20\nJansson: Node with ID `0` not found. Context has `10` nodes.\n0\nJansson: No JSON context.\njansson!')
-
- ### 'Medium' tests
-
- def test_fannkuch(self):
- results = [ (1,0), (2,1), (3,2), (4,4), (5,7), (6,10), (7, 16), (8,22) ]
- for i, j in results:
- src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read()
- self.do_run(src, 'Pfannkuchen(%d) = %d.' % (i,j), [str(i)], no_build=i>1)
-
- def test_raytrace(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Relies on double value rounding, extremely sensitive')
-
- src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read().replace('double', 'float')
- output = open(path_from_root('tests', 'raytrace.ppm'), 'r').read()
- self.do_run(src, output, ['3', '16'])#, build_ll_hook=self.do_autodebug)
-
- def test_fasta(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- results = [ (1,'''GG*ctt**tgagc*'''), (20,'''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tacgtgtagcctagtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaa**tgacgtcttttgatctgacggcgttaacaaagatactctg*'''),
-(50,'''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA*TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa**NtactMcSMtYtcMgRtacttctWBacgaa**agatactctgggcaacacacatacttctctcatgttgtttcttcggacctttcataacct**ttcctggcacatggttagctgcacatcacaggattgtaagggtctagtggttcagtgagc**ggaatatcattcgtcggtggtgttaatctatctcggtgtagcttataaatgcatccgtaa**gaatattatgtttatttgtcggtacgttcatggtagtggtgtcgccgatttagacgtaaa**ggcatgtatg*''') ]
- for i, j in results:
- src = open(path_from_root('tests', 'fasta.cpp'), 'r').read()
- self.do_run(src, j, [str(i)], lambda x, err: x.replace('\n', '*'), no_build=i>1)
-
- def test_whets(self):
- if not Settings.ASM_JS: return self.skip('mainly a test for asm validation here')
- self.do_run(open(path_from_root('tests', 'whets.cpp')).read(), 'Single Precision C Whetstone Benchmark')
-
- def test_dlmalloc(self):
- if self.emcc_args is None: self.emcc_args = [] # dlmalloc auto-inclusion is only done if we use emcc
-
- self.banned_js_engines = [NODE_JS] # slower, and fail on 64-bit
- Settings.CORRECT_SIGNS = 2
- Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
- Settings.TOTAL_MEMORY = 128*1024*1024 # needed with typed arrays
-
- src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
- self.do_run(src, '*1,0*', ['200', '1'])
- self.do_run(src, '*400,0*', ['400', '400'], no_build=True)
-
- # Linked version
- src = open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
- self.do_run(src, '*1,0*', ['200', '1'], extra_emscripten_args=['-m'])
- self.do_run(src, '*400,0*', ['400', '400'], extra_emscripten_args=['-m'], no_build=True)
-
- if self.emcc_args == []: # TODO: do this in other passes too, passing their opts into emcc
- # emcc should build in dlmalloc automatically, and do all the sign correction etc. for it
-
- try_delete(os.path.join(self.get_dir(), 'src.cpp.o.js'))
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'dlmalloc_test.c'), '-s', 'TOTAL_MEMORY=' + str(128*1024*1024),
- '-o', os.path.join(self.get_dir(), 'src.cpp.o.js')], stdout=PIPE, stderr=self.stderr_redirect).communicate()
-
- self.do_run('x', '*1,0*', ['200', '1'], no_build=True)
- self.do_run('x', '*400,0*', ['400', '400'], no_build=True)
-
- # The same for new and all its variants
- src = open(path_from_root('tests', 'new.cpp')).read()
- for new, delete in [
- ('malloc(100)', 'free'),
- ('new char[100]', 'delete[]'),
- ('new Structy', 'delete'),
- ('new int', 'delete'),
- ('new Structy[10]', 'delete[]'),
- ]:
- self.do_run(src.replace('{{{ NEW }}}', new).replace('{{{ DELETE }}}', delete), '*1,0*')
-
- def test_dlmalloc_partial(self):
- if self.emcc_args is None: return self.skip('only emcc will link in dlmalloc')
- # present part of the symbols of dlmalloc, not all
- src = open(path_from_root('tests', 'new.cpp')).read().replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + '''
-void *
-operator new(size_t size)
-{
- printf("new %d!\\n", size);
- return malloc(size);
-}
-'''
- self.do_run(src, 'new 4!\n*1,0*')
-
- def test_dlmalloc_partial_2(self):
- if self.emcc_args is None or 'SAFE_HEAP' in str(self.emcc_args) or 'CHECK_HEAP_ALIGN' in str(self.emcc_args): return self.skip('only emcc will link in dlmalloc, and we do unsafe stuff')
- # present part of the symbols of dlmalloc, not all. malloc is harder to link than new which is weak.
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
- void *malloc(size_t size)
- {
- return (void*)123;
- }
- int main() {
- void *x = malloc(10);
- printf("got %p\n", x);
- free(x);
- printf("freed the faker\n");
- return 1;
- }
-'''
- self.do_run(src, 'got 0x7b\nfreed')
-
- def test_libcxx(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- self.do_run(open(path_from_root('tests', 'hashtest.cpp')).read(),
- 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march')
-
- self.do_run('''
- #include <set>
- #include <stdio.h>
- int main() {
- std::set<int> *fetchOriginatorNums = new std::set<int>();
- fetchOriginatorNums->insert(171);
- printf("hello world\\n");
- return 0;
- }
- ''', 'hello world');
-
- def test_typeid(self):
- self.do_run(r'''
- #include <stdio.h>
- #include <string.h>
- #include <typeinfo>
- int main() {
- printf("*\n");
- #define MAX 100
- int ptrs[MAX];
- int groups[MAX];
- memset(ptrs, 0, MAX*sizeof(int));
- memset(groups, 0, MAX*sizeof(int));
- int next_group = 1;
- #define TEST(X) { \
- int ptr = (int)&typeid(X); \
- int group = 0; \
- int i; \
- for (i = 0; i < MAX; i++) { \
- if (!groups[i]) break; \
- if (ptrs[i] == ptr) { \
- group = groups[i]; \
- break; \
- } \
- } \
- if (!group) { \
- groups[i] = group = next_group++; \
- ptrs[i] = ptr; \
- } \
- printf("%s:%d\n", #X, group); \
- }
- TEST(int);
- TEST(unsigned int);
- TEST(unsigned);
- TEST(signed int);
- TEST(long);
- TEST(unsigned long);
- TEST(signed long);
- TEST(long long);
- TEST(unsigned long long);
- TEST(signed long long);
- TEST(short);
- TEST(unsigned short);
- TEST(signed short);
- TEST(char);
- TEST(unsigned char);
- TEST(signed char);
- TEST(float);
- TEST(double);
- TEST(long double);
- TEST(void);
- TEST(void*);
- printf("*\n");
- }
- ''', '''*
-int:1
-unsigned int:2
-unsigned:2
-signed int:1
-long:3
-unsigned long:4
-signed long:3
-long long:5
-unsigned long long:6
-signed long long:5
-short:7
-unsigned short:8
-signed short:7
-char:9
-unsigned char:10
-signed char:11
-float:12
-double:13
-long double:14
-void:15
-void*:16
-*
-''');
-
- def test_static_variable(self):
- if self.emcc_args is None: Settings.SAFE_HEAP = 0 # LLVM mixes i64 and i8 in the guard check
- src = '''
- #include <stdio.h>
-
- struct DATA
- {
- int value;
-
- DATA()
- {
- value = 0;
- }
- };
-
- DATA & GetData()
- {
- static DATA data;
-
- return data;
- }
-
- int main()
- {
- GetData().value = 10;
- printf( "value:%i", GetData().value );
- }
- '''
- self.do_run(src, 'value:10')
-
- def test_fakestat(self):
- src = r'''
- #include <stdio.h>
- struct stat { int x, y; };
- int main() {
- stat s;
- s.x = 10;
- s.y = 22;
- printf("*%d,%d*\n", s.x, s.y);
- }
- '''
- self.do_run(src, '*10,22*')
-
- def test_mmap(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- Settings.TOTAL_MEMORY = 128*1024*1024
-
- src = '''
- #include <stdio.h>
- #include <sys/mman.h>
- #include <assert.h>
-
- int main(int argc, char *argv[]) {
- for (int i = 0; i < 10; i++) {
- int* map = (int*)mmap(0, 5000, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANON, -1, 0);
- /* TODO: Should we align to 4k?
- assert(((int)map) % 4096 == 0); // aligned
- */
- assert(munmap(map, 5000) == 0);
- }
-
- const int NUM_BYTES = 8 * 1024 * 1024;
- const int NUM_INTS = NUM_BYTES / sizeof(int);
-
- int* map = (int*)mmap(0, NUM_BYTES, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANON, -1, 0);
- assert(map != MAP_FAILED);
-
- int i;
-
- for (i = 0; i < NUM_INTS; i++) {
- map[i] = i;
- }
-
- for (i = 0; i < NUM_INTS; i++) {
- assert(map[i] == i);
- }
-
- assert(munmap(map, NUM_BYTES) == 0);
-
- printf("hello,world");
- return 0;
- }
- '''
- self.do_run(src, 'hello,world')
- self.do_run(src, 'hello,world', force_c=True)
-
- def test_mmap_file(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- self.emcc_args += ['--embed-file', 'data.dat']
-
- open(self.in_dir('data.dat'), 'w').write('data from the file ' + ('.' * 9000))
-
- src = r'''
- #include <stdio.h>
- #include <sys/mman.h>
-
- int main() {
- printf("*\n");
- FILE *f = fopen("data.dat", "r");
- char *m;
- m = (char*)mmap(NULL, 9000, PROT_READ, MAP_PRIVATE, fileno(f), 0);
- for (int i = 0; i < 20; i++) putchar(m[i]);
- munmap(m, 9000);
- printf("\n");
- m = (char*)mmap(NULL, 9000, PROT_READ, MAP_PRIVATE, fileno(f), 5);
- for (int i = 0; i < 20; i++) putchar(m[i]);
- munmap(m, 9000);
- printf("\n*\n");
- return 0;
- }
- '''
- self.do_run(src, '*\ndata from the file .\nfrom the file ......\n*\n')
-
- def test_cubescript(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if self.run_name == 'o2':
- self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
-
- Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default
- if self.emcc_args is None: Settings.SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
-
- # Overflows happen in hash loop
- Settings.CORRECT_OVERFLOWS = 1
- Settings.CHECK_OVERFLOWS = 0
-
- if Settings.USE_TYPED_ARRAYS == 2:
- Settings.CORRECT_SIGNS = 1
-
- self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
-
- assert 'asm2g' in test_modes
- if self.run_name == 'asm2g':
- results = {}
- original = open('src.cpp.o.js').read()
- results[Settings.ALIASING_FUNCTION_POINTERS] = len(original)
- Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS
- self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
- final = open('src.cpp.o.js').read()
- results[Settings.ALIASING_FUNCTION_POINTERS] = len(final)
- open('original.js', 'w').write(original)
- print results
- assert results[1] < 0.99*results[0]
- assert ' & 3]()' in original, 'small function table exists'
- assert ' & 3]()' not in final, 'small function table does not exist'
- assert ' & 255]()' not in original, 'big function table does not exist'
- assert ' & 255]()' in final, 'big function table exists'
-
- def test_gcc_unmangler(self):
- Settings.NAMED_GLOBALS = 1 # test coverage for this
-
- Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('third_party')]
-
- self.do_run(open(path_from_root('third_party', 'gcc_demangler.c')).read(), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'])
-
- #### Code snippet that is helpful to search for nonportable optimizations ####
- #global LLVM_OPT_OPTS
- #for opt in ['-aa-eval', '-adce', '-always-inline', '-argpromotion', '-basicaa', '-basiccg', '-block-placement', '-break-crit-edges', '-codegenprepare', '-constmerge', '-constprop', '-correlated-propagation', '-count-aa', '-dce', '-deadargelim', '-deadtypeelim', '-debug-aa', '-die', '-domfrontier', '-domtree', '-dse', '-extract-blocks', '-functionattrs', '-globaldce', '-globalopt', '-globalsmodref-aa', '-gvn', '-indvars', '-inline', '-insert-edge-profiling', '-insert-optimal-edge-profiling', '-instcombine', '-instcount', '-instnamer', '-internalize', '-intervals', '-ipconstprop', '-ipsccp', '-iv-users', '-jump-threading', '-lazy-value-info', '-lcssa', '-lda', '-libcall-aa', '-licm', '-lint', '-live-values', '-loop-deletion', '-loop-extract', '-loop-extract-single', '-loop-index-split', '-loop-reduce', '-loop-rotate', '-loop-unroll', '-loop-unswitch', '-loops', '-loopsimplify', '-loweratomic', '-lowerinvoke', '-lowersetjmp', '-lowerswitch', '-mem2reg', '-memcpyopt', '-memdep', '-mergefunc', '-mergereturn', '-module-debuginfo', '-no-aa', '-no-profile', '-partial-inliner', '-partialspecialization', '-pointertracking', '-postdomfrontier', '-postdomtree', '-preverify', '-prune-eh', '-reassociate', '-reg2mem', '-regions', '-scalar-evolution', '-scalarrepl', '-sccp', '-scev-aa', '-simplify-libcalls', '-simplify-libcalls-halfpowr', '-simplifycfg', '-sink', '-split-geps', '-sretpromotion', '-strip', '-strip-dead-debug-info', '-strip-dead-prototypes', '-strip-debug-declare', '-strip-nondebug', '-tailcallelim', '-tailduplicate', '-targetdata', '-tbaa']:
- # LLVM_OPT_OPTS = [opt]
- # try:
- # self.do_run(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
- # print opt, "ok"
- # except:
- # print opt, "FAIL"
-
- def test_lua(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
-
- self.do_run('',
- 'hello lua world!\n17\n1\n2\n3\n4\n7',
- args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
- libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None),
- includes=[path_from_root('tests', 'lua')],
- output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n'))
-
- def get_freetype(self):
- Settings.DEAD_FUNCTIONS += ['_inflateEnd', '_inflate', '_inflateReset', '_inflateInit2_']
-
- return self.get_library('freetype',
- os.path.join('objs', '.libs', 'libfreetype.a'))
-
- def test_freetype(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
- if Settings.ASM_JS and '-O2' not in self.emcc_args: return self.skip('mozilla bug 863867')
-
- if Settings.CORRECT_SIGNS == 0: Settings.CORRECT_SIGNS = 1 # Not sure why, but needed
-
- post = '''
-def process(filename):
- import tools.shared as shared
- # Embed the font into the document
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createDataFile('/', 'font.ttf', %s, true, false);" % str(
- map(ord, open(shared.path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), 'rb').read())
- )
- )
- open(filename, 'w').write(src)
-'''
-
- # Not needed for js, but useful for debugging
- shutil.copyfile(path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), os.path.join(self.get_dir(), 'font.ttf'))
-
- # Main
- self.do_run(open(path_from_root('tests', 'freetype', 'main.c'), 'r').read(),
- open(path_from_root('tests', 'freetype', 'ref.txt'), 'r').read(),
- ['font.ttf', 'test!', '150', '120', '25'],
- libraries=self.get_freetype(),
- includes=[path_from_root('tests', 'freetype', 'include')],
- post_build=post)
- #build_ll_hook=self.do_autodebug)
-
- # github issue 324
- print '[issue 324]'
- self.do_run(open(path_from_root('tests', 'freetype', 'main_2.c'), 'r').read(),
- open(path_from_root('tests', 'freetype', 'ref_2.txt'), 'r').read(),
- ['font.ttf', 'w', '32', '32', '25'],
- libraries=self.get_freetype(),
- includes=[path_from_root('tests', 'freetype', 'include')],
- post_build=post)
-
- print '[issue 324 case 2]'
- self.do_run(open(path_from_root('tests', 'freetype', 'main_3.c'), 'r').read(),
- open(path_from_root('tests', 'freetype', 'ref_3.txt'), 'r').read(),
- ['font.ttf', 'W', '32', '32', '0'],
- libraries=self.get_freetype(),
- includes=[path_from_root('tests', 'freetype', 'include')],
- post_build=post)
-
- print '[issue 324 case 3]'
- self.do_run('',
- open(path_from_root('tests', 'freetype', 'ref_4.txt'), 'r').read(),
- ['font.ttf', 'ea', '40', '32', '0'],
- no_build=True)
-
- def test_sqlite(self):
- # gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
- if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc')
- if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
- self.banned_js_engines = [NODE_JS] # OOM in older node
-
- Settings.CORRECT_SIGNS = 1
- Settings.CORRECT_OVERFLOWS = 0
- Settings.CORRECT_ROUNDINGS = 0
- if self.emcc_args is None: Settings.SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
- Settings.DISABLE_EXCEPTION_CATCHING = 1
- Settings.FAST_MEMORY = 4*1024*1024
- Settings.EXPORTED_FUNCTIONS += ['_sqlite3_open', '_sqlite3_close', '_sqlite3_exec', '_sqlite3_free', '_callback'];
- if Settings.ASM_JS == 1 and '-g' in self.emcc_args:
- print "disabling inlining" # without registerize (which -g disables), we generate huge amounts of code
- Settings.INLINING_LIMIT = 50
-
- self.do_run(r'''
- #define SQLITE_DISABLE_LFS
- #define LONGDOUBLE_TYPE double
- #define SQLITE_INT64_TYPE long long int
- #define SQLITE_THREADSAFE 0
- ''' + open(path_from_root('tests', 'sqlite', 'sqlite3.c'), 'r').read() +
- open(path_from_root('tests', 'sqlite', 'benchmark.c'), 'r').read(),
- open(path_from_root('tests', 'sqlite', 'benchmark.txt'), 'r').read(),
- includes=[path_from_root('tests', 'sqlite')],
- force_c=True)
-
- def test_zlib(self):
- if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('works in general, but cached build will be optimized and fail, so disable this')
-
- if Settings.ASM_JS:
- self.banned_js_engines = [NODE_JS] # TODO investigate
-
- if self.emcc_args is not None and '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args: # without asm, closure minifies Math.imul badly
- self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
-
- Settings.CORRECT_SIGNS = 1
-
- self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
- open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
- libraries=self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
- includes=[path_from_root('tests', 'zlib')],
- force_c=True)
-
- def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
- if self.emcc_args is None: return self.skip('requires emcc')
- if Building.LLVM_OPTS and self.emcc_args is None: Settings.SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore
-
- Settings.DEAD_FUNCTIONS = ['__ZSt9terminatev']
-
- # Note: this is also a good test of per-file and per-line changes (since we have multiple files, and correct specific lines)
- if Settings.SAFE_HEAP:
- # Ignore bitfield warnings
- Settings.SAFE_HEAP = 3
- Settings.SAFE_HEAP_LINES = ['btVoronoiSimplexSolver.h:40', 'btVoronoiSimplexSolver.h:41',
- 'btVoronoiSimplexSolver.h:42', 'btVoronoiSimplexSolver.h:43']
-
- def test():
- self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
- [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
- open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
- open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
- libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
- os.path.join('src', '.libs', 'libBulletCollision.a'),
- os.path.join('src', '.libs', 'libLinearMath.a')],
- configure_args=['--disable-demos','--disable-dependency-tracking']),
- includes=[path_from_root('tests', 'bullet', 'src')])
- test()
-
- assert 'asm2g' in test_modes
- if self.run_name == 'asm2g':
- # Test forced alignment
- print >> sys.stderr, 'testing FORCE_ALIGNED_MEMORY'
- old = open('src.cpp.o.js').read()
- Settings.FORCE_ALIGNED_MEMORY = 1
- test()
- new = open('src.cpp.o.js').read()
- print len(old), len(new), old.count('tempBigInt'), new.count('tempBigInt')
- assert len(old) > len(new)
- assert old.count('tempBigInt') > new.count('tempBigInt')
-
- def test_poppler(self):
- if self.emcc_args is None: return self.skip('very slow, we only do this in emcc runs')
-
- Settings.CORRECT_OVERFLOWS = 1
- Settings.CORRECT_SIGNS = 1
-
- Building.COMPILER_TEST_OPTS += [
- '-I' + path_from_root('tests', 'freetype', 'include'),
- '-I' + path_from_root('tests', 'poppler', 'include'),
- ]
-
- Settings.INVOKE_RUN = 0 # We append code that does run() ourselves
-
- # See post(), below
- input_file = open(os.path.join(self.get_dir(), 'paper.pdf.js'), 'w')
- input_file.write(str(map(ord, open(path_from_root('tests', 'poppler', 'paper.pdf'), 'rb').read())))
- input_file.close()
-
- post = '''
-def process(filename):
- # To avoid loading this large file to memory and altering it, we simply append to the end
- src = open(filename, 'a')
- src.write(
- \'\'\'
- FS.createDataFile('/', 'paper.pdf', eval(Module.read('paper.pdf.js')), true, false);
- Module.callMain(Module.arguments);
- Module.print("Data: " + JSON.stringify(FS.root.contents['filename-1.ppm'].contents.map(function(x) { return unSign(x, 8) })));
- \'\'\'
- )
- src.close()
-'''
-
- #fontconfig = self.get_library('fontconfig', [os.path.join('src', '.libs', 'libfontconfig.a')]) # Used in file, but not needed, mostly
-
- freetype = self.get_freetype()
-
- poppler = self.get_library('poppler',
- [os.path.join('utils', 'pdftoppm.o'),
- os.path.join('utils', 'parseargs.o'),
- os.path.join('poppler', '.libs', 'libpoppler.a')],
- env_init={ 'FONTCONFIG_CFLAGS': ' ', 'FONTCONFIG_LIBS': ' ' },
- configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--enable-shared=no'])
-
- # Combine libraries
-
- combined = os.path.join(self.get_dir(), 'poppler-combined.bc')
- Building.link(poppler + freetype, combined)
-
- self.do_ll_run(combined,
- map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''),
- args='-scale-to 512 paper.pdf filename'.split(' '),
- post_build=post)
- #, build_ll_hook=self.do_autodebug)
-
- def test_openjpeg(self):
- if self.emcc_args is None: return self.skip('needs libc for getopt')
-
- Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default
-
- if Settings.USE_TYPED_ARRAYS == 2:
- Settings.CORRECT_SIGNS = 1
- else:
- Settings.CORRECT_SIGNS = 2
- Settings.CORRECT_SIGNS_LINES = ["mqc.c:566", "mqc.c:317"]
-
- post = '''
-def process(filename):
- import tools.shared as shared
- original_j2k = shared.path_from_root('tests', 'openjpeg', 'syntensity_lobby_s.j2k')
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createDataFile('/', 'image.j2k', %s, true, false);" % shared.line_splitter(str(
- map(ord, open(original_j2k, 'rb').read())
- ))
- ).replace(
- '// {{POST_RUN_ADDITIONS}}',
- "Module.print('Data: ' + JSON.stringify(FS.analyzePath('image.raw').object.contents));"
- )
- open(filename, 'w').write(src)
-'''
-
- shutil.copy(path_from_root('tests', 'openjpeg', 'opj_config.h'), self.get_dir())
-
- lib = self.get_library('openjpeg',
- [os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')),
- os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')),
- os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')),
- os.path.join('bin', 'libopenjpeg.so.1.4.0')],
- configure=['cmake', '.'],
- #configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'],
- make_args=[]) # no -j 2, since parallel builds can fail
-
- # We use doubles in JS, so we get slightly different values than native code. So we
- # check our output by comparing the average pixel difference
- def image_compare(output, err):
- # Get the image generated by JS, from the JSON.stringify'd array
- m = re.search('\[[\d, -]*\]', output)
- try:
- js_data = eval(m.group(0))
- except AttributeError:
- print 'Failed to find proper image output in: ' + output
- raise
-
- js_data = map(lambda x: x if x >= 0 else 256+x, js_data) # Our output may be signed, so unsign it
-
- # Get the correct output
- true_data = open(path_from_root('tests', 'openjpeg', 'syntensity_lobby_s.raw'), 'rb').read()
-
- # Compare them
- assert(len(js_data) == len(true_data))
- num = len(js_data)
- diff_total = js_total = true_total = 0
- for i in range(num):
- js_total += js_data[i]
- true_total += ord(true_data[i])
- diff_total += abs(js_data[i] - ord(true_data[i]))
- js_mean = js_total/float(num)
- true_mean = true_total/float(num)
- diff_mean = diff_total/float(num)
-
- image_mean = 83.265
- #print '[image stats:', js_mean, image_mean, true_mean, diff_mean, num, ']'
- assert abs(js_mean - image_mean) < 0.01
- assert abs(true_mean - image_mean) < 0.01
- assert diff_mean < 0.01
-
- return output
-
- self.emcc_args += ['--minify', '0'] # to compare the versions
-
- def do_test():
- self.do_run(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(),
- 'Successfully generated', # The real test for valid output is in image_compare
- '-i image.j2k -o image.raw'.split(' '),
- libraries=lib,
- includes=[path_from_root('tests', 'openjpeg', 'libopenjpeg'),
- path_from_root('tests', 'openjpeg', 'codec'),
- path_from_root('tests', 'openjpeg', 'common'),
- os.path.join(self.get_build_dir(), 'openjpeg')],
- force_c=True,
- post_build=post,
- output_nicerizer=image_compare)#, build_ll_hook=self.do_autodebug)
-
- do_test()
-
- # some test coverage for EMCC_DEBUG 1 and 2
- if self.emcc_args and '-O2' in self.emcc_args and 'EMCC_DEBUG' not in os.environ:
- shutil.copyfile('src.c.o.js', 'release.js')
- try:
- os.environ['EMCC_DEBUG'] = '1'
- print '2'
- do_test()
- shutil.copyfile('src.c.o.js', 'debug1.js')
- os.environ['EMCC_DEBUG'] = '2'
- print '3'
- do_test()
- shutil.copyfile('src.c.o.js', 'debug2.js')
- finally:
- del os.environ['EMCC_DEBUG']
- for debug in [1,2]:
- def clean(text):
- return text.replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('{\n}', '{}')
- self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code!
- print >> sys.stderr, 'debug check %d passed too' % debug
-
- try:
- os.environ['EMCC_FORCE_STDLIBS'] = '1'
- print 'EMCC_FORCE_STDLIBS'
- do_test()
- finally:
- del os.environ['EMCC_FORCE_STDLIBS']
- print >> sys.stderr, 'EMCC_FORCE_STDLIBS ok'
-
- try_delete(CANONICAL_TEMP_DIR)
- else:
- print >> sys.stderr, 'not doing debug check'
-
- def test_python(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
- if not self.is_le32(): return self.skip('fails on non-le32') # FIXME
-
- #Settings.EXPORTED_FUNCTIONS += ['_PyRun_SimpleStringFlags'] # for the demo
-
- if self.is_le32():
- bitcode = path_from_root('tests', 'python', 'python.le32.bc')
- else:
- bitcode = path_from_root('tests', 'python', 'python.small.bc')
-
- self.do_ll_run(bitcode,
- 'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
- args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''])
-
- def test_lifetime(self):
- if self.emcc_args is None: return self.skip('test relies on emcc opts')
-
- self.do_ll_run(path_from_root('tests', 'lifetime.ll'), 'hello, world!\n')
- if '-O1' in self.emcc_args or '-O2' in self.emcc_args:
- assert 'a18' not in open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read(), 'lifetime stuff and their vars must be culled'
-
- # Test cases in separate files. Note that these files may contain invalid .ll!
- # They are only valid enough for us to read for test purposes, not for llvm-as
- # to process.
- def test_cases(self):
- if Building.LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
-
- try:
- os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
- Settings.CHECK_OVERFLOWS = 0
-
- for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
- shortname = name.replace('.ll', '')
- if '' not in shortname: continue
- if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2:
- print self.skip('case "%s" only relevant for ta2' % shortname)
- continue
- if '_noasm' in shortname and Settings.ASM_JS:
- print self.skip('case "%s" not relevant for asm.js' % shortname)
- continue
- print >> sys.stderr, "Testing case '%s'..." % shortname
- output_file = path_from_root('tests', 'cases', shortname + '.txt')
- if Settings.QUANTUM_SIZE == 1:
- q1_output_file = path_from_root('tests', 'cases', shortname + '_q1.txt')
- if os.path.exists(q1_output_file):
- output_file = q1_output_file
- if os.path.exists(output_file):
- output = open(output_file, 'r').read()
- else:
- output = 'hello, world!'
- if output.rstrip() != 'skip':
- self.do_ll_run(path_from_root('tests', 'cases', name), output)
- # Optional source checking, a python script that gets a global generated with the source
- src_checker = path_from_root('tests', 'cases', shortname + '.py')
- if os.path.exists(src_checker):
- generated = open('src.cpp.o.js').read()
- exec(open(src_checker).read())
-
- finally:
- del os.environ['EMCC_LEAVE_INPUTS_RAW']
-
- def test_fuzz(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
-
- Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('tests', 'fuzz')]
-
- def run_all(x):
- print x
- for name in glob.glob(path_from_root('tests', 'fuzz', '*.c')):
- print name
- self.do_run(open(path_from_root('tests', 'fuzz', name)).read(),
- open(path_from_root('tests', 'fuzz', name + '.txt')).read(), force_c=True)
-
- run_all('normal')
-
- self.emcc_args += ['--llvm-lto', '1']
-
- run_all('lto')
-
- # Autodebug the code
- def do_autodebug(self, filename):
- output = Popen([PYTHON, AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
- assert 'Success.' in output, output
- self.prep_ll_run(filename, filename+'.o.ll.ll', force_recompile=True) # rebuild .bc # TODO: use code in do_autodebug_post for this
-
- # Autodebug the code, after LLVM opts. Will only work once!
- def do_autodebug_post(self, filename):
- if not hasattr(self, 'post'):
- print 'Asking for post re-call'
- self.post = True
- return True
- print 'Autodebugging during post time'
- delattr(self, 'post')
- output = Popen([PYTHON, AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
- assert 'Success.' in output, output
- shutil.copyfile(filename + '.o.ll.ll', filename + '.o.ll')
- Building.llvm_as(filename)
- Building.llvm_dis(filename)
-
- def test_autodebug(self):
- if Building.LLVM_OPTS: return self.skip('LLVM opts mess us up')
- Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
-
- # Run a test that should work, generating some code
- self.test_structs()
-
- filename = os.path.join(self.get_dir(), 'src.cpp')
- self.do_autodebug(filename)
-
- # Compare to each other, and to expected output
- self.do_ll_run(path_from_root('tests', filename+'.o.ll.ll'), '''AD:-1,1''')
- assert open('stdout').read().startswith('AD:-1'), 'We must note when we enter functions'
-
- # Test using build_ll_hook
- src = '''
- #include <stdio.h>
-
- char cache[256], *next = cache;
-
- int main()
- {
- cache[10] = 25;
- next[20] = 51;
- int x = cache[10];
- double y = 11.52;
- printf("*%d,%d,%.2f*\\n", x, cache[20], y);
- return 0;
- }
- '''
- self.do_run(src, '''AD:-1,1''', build_ll_hook=self.do_autodebug)
-
- def test_corruption(self):
- if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
-
- Settings.CORRUPTION_CHECK = 1
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int main(int argc, char **argv) {
- int size = 1024*argc;
- char *buffer = (char*)malloc(size);
- #if CORRUPT
- memset(buffer, argc, size+15);
- #else
- memset(buffer, argc, size);
- #endif
- for (int x = 0; x < size; x += argc*3) buffer[x] = x/3;
- int ret = 0;
- for (int x = 0; x < size; x++) ret += buffer[x];
- free(buffer);
- printf("All ok, %d\n", ret);
- }
- '''
-
- for corrupt in [1]:
- self.do_run(src.replace('CORRUPT', str(corrupt)), 'Heap corruption detected!' if corrupt else 'All ok, 4209')
-
- def test_corruption_2(self):
- if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
-
- Settings.SAFE_HEAP = 1
- Settings.CORRUPTION_CHECK = 1
-
- # test for free(0), malloc(0), etc.
- src = r'''
- #include <iostream>
- #include <fstream>
- #include <stdlib.h>
- #include <stdio.h>
-
- void bye() {
- printf("all ok\n");
- }
-
- int main() {
- atexit(bye);
-
- std::string testPath = "/Script/WA-KA.txt";
- std::fstream str(testPath.c_str(), std::ios::in | std::ios::binary);
-
- if (str.is_open())
- {
- std::cout << "open!" << std::endl;
- } else {
- std::cout << "missing!" << std::endl;
- }
-
- return 1;
- }
- '''
- self.do_run(src, 'missing!\nall ok\n')
-
- def test_corruption_3(self):
- if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
-
- Settings.CORRUPTION_CHECK = 1
-
- # realloc
- src = r'''
- #include <stdlib.h>
- #include <stdio.h>
- #include <assert.h>
-
- void bye() {
- printf("all ok\n");
- }
-
- int main(int argc, char **argv) {
- atexit(bye);
-
- char *buffer = (char*)malloc(100);
- for (int i = 0; i < 100; i++) buffer[i] = (i*i)%256;
- buffer = (char*)realloc(buffer, argc + 50);
- for (int i = 0; i < argc + 50; i++) {
- //printf("%d : %d : %d : %d\n", i, (int)(buffer + i), buffer[i], (char)((i*i)%256));
- assert(buffer[i] == (char)((i*i)%256));
- }
- return 1;
- }
- '''
- self.do_run(src, 'all ok\n')
-
- ### Integration tests
-
- def test_ccall(self):
- if self.emcc_args is not None and '-O2' in self.emcc_args:
- self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- extern "C" {
- int get_int() { return 5; }
- float get_float() { return 3.14; }
- char * get_string() { return "hello world"; }
- void print_int(int x) { printf("%d\n", x); }
- void print_float(float x) { printf("%.2f\n", x); }
- void print_string(char *x) { printf("%s\n", x); }
- int multi(int x, float y, int z, char *str) { if (x) puts(str); return (x+y)*z; }
- int * pointer(int *in) { printf("%d\n", *in); static int ret = 21; return &ret; }
- }
-
- int main(int argc, char **argv) {
- return 0;
- }
- '''
-
- post = '''
-def process(filename):
- src = \'\'\'
- var Module = { 'noInitialRun': true };
- \'\'\' + open(filename, 'r').read() + \'\'\'
- Module.addOnExit(function () {
- Module.print('*');
- var ret;
- ret = Module['ccall']('get_int', 'number'); Module.print([typeof ret, ret]);
- ret = ccall('get_float', 'number'); Module.print([typeof ret, ret.toFixed(2)]);
- ret = ccall('get_string', 'string'); Module.print([typeof ret, ret]);
- ret = ccall('print_int', null, ['number'], [12]); Module.print(typeof ret);
- ret = ccall('print_float', null, ['number'], [14.56]); Module.print(typeof ret);
- ret = ccall('print_string', null, ['string'], ["cheez"]); Module.print(typeof ret);
- ret = ccall('print_string', null, ['array'], [[97, 114, 114, 45, 97, 121, 0]]); Module.print(typeof ret);
- ret = ccall('multi', 'number', ['number', 'number', 'number', 'string'], [2, 1.4, 3, 'more']); Module.print([typeof ret, ret]);
- var p = ccall('malloc', 'pointer', ['number'], [4]);
- setValue(p, 650, 'i32');
- ret = ccall('pointer', 'pointer', ['pointer'], [p]); Module.print([typeof ret, getValue(ret, 'i32')]);
- Module.print('*');
- // part 2: cwrap
- var multi = Module['cwrap']('multi', 'number', ['number', 'number', 'number', 'string']);
- Module.print(multi(2, 1.4, 3, 'atr'));
- Module.print(multi(8, 5.4, 4, 'bret'));
- Module.print('*');
- // part 3: avoid stack explosion
- for (var i = 0; i < TOTAL_STACK/60; i++) {
- ccall('multi', 'number', ['number', 'number', 'number', 'string'], [0, 0, 0, '123456789012345678901234567890123456789012345678901234567890']);
- }
- Module.print('stack is ok.');
- });
- Module.callMain();
- \'\'\'
- open(filename, 'w').write(src)
-'''
-
- Settings.EXPORTED_FUNCTIONS += ['_get_int', '_get_float', '_get_string', '_print_int', '_print_float', '_print_string', '_multi', '_pointer', '_malloc']
-
- self.do_run(src, '*\nnumber,5\nnumber,3.14\nstring,hello world\n12\nundefined\n14.56\nundefined\ncheez\nundefined\narr-ay\nundefined\nmore\nnumber,10\n650\nnumber,21\n*\natr\n10\nbret\n53\n*\nstack is ok.\n', post_build=post)
-
- def test_pgo(self):
- if Settings.ASM_JS: return self.skip('PGO does not work in asm mode')
-
- def run_all(name, src):
- print name
- def test(expected, args=[], no_build=False):
- self.do_run(src, expected, args=args, no_build=no_build)
- return open(self.in_dir('src.cpp.o.js')).read()
-
- # Sanity check that it works and the dead function is emitted
- js = test('*9*')
- assert 'function _unused(' in js
-
- # Run with PGO, see that unused is true to its name
- Settings.PGO = 1
- test("*9*\n-s DEAD_FUNCTIONS='[\"_unused\"]'")
- Settings.PGO = 0
-
- # 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 # 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(('missing function: unused'), args=['a', 'b'], no_build=True)
-
- # Normal stuff
- run_all('normal', r'''
- #include <stdio.h>
- extern "C" {
- int used(int x) {
- if (x == 0) return -1;
- return used(x/3) + used(x/17) + x%5;
- }
- int unused(int x) {
- if (x == 0) return -1;
- return unused(x/4) + unused(x/23) + x%7;
- }
- }
- int main(int argc, char **argv) {
- printf("*%d*\n", argc == 3 ? unused(argv[0][0] + 1024) : used(argc + 1555));
- return 0;
- }
- ''')
-
- # Call by function pointer
- run_all('function pointers', r'''
- #include <stdio.h>
- extern "C" {
- int used(int x) {
- if (x == 0) return -1;
- return used(x/3) + used(x/17) + x%5;
- }
- int unused(int x) {
- if (x == 0) return -1;
- return unused(x/4) + unused(x/23) + x%7;
- }
- }
- typedef int (*ii)(int);
- int main(int argc, char **argv) {
- ii pointers[256];
- for (int i = 0; i < 256; i++) {
- pointers[i] = (i == 3) ? unused : used;
- }
- printf("*%d*\n", pointers[argc](argc + 1555));
- return 0;
- }
- ''')
-
- def test_asm_pgo(self):
- if not Settings.ASM_JS: return self.skip('this is a test for PGO for asm (NB: not *in* asm)')
-
- src = open(path_from_root('tests', 'hello_libcxx.cpp')).read()
- output = 'hello, world!'
-
- self.do_run(src, output)
- shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('normal.js'))
-
- Settings.ASM_JS = 0
- Settings.PGO = 1
- self.do_run(src, output)
- Settings.ASM_JS = 1
- Settings.PGO = 0
-
- shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js'))
- pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1]
- open('pgo_data.rsp', 'w').write(pgo_output)
-
- # with response file
-
- self.emcc_args += ['@pgo_data.rsp']
- self.do_run(src, output)
- self.emcc_args.pop()
- shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed.js'))
-
- before = len(open('normal.js').read())
- after = len(open('pgoed.js').read())
- assert after < 0.90 * before, [before, after] # expect a size reduction
-
- # with response in settings element itself
-
- open('dead_funcs', 'w').write(pgo_output[pgo_output.find('['):-1])
- self.emcc_args += ['-s', 'DEAD_FUNCTIONS=@' + self.in_dir('dead_funcs')]
- self.do_run(src, output)
- self.emcc_args.pop()
- self.emcc_args.pop()
- shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js'))
- assert open('pgoed.js').read() == open('pgoed2.js').read()
-
- # with relative response in settings element itself
-
- open('dead_funcs', 'w').write(pgo_output[pgo_output.find('['):-1])
- self.emcc_args += ['-s', 'DEAD_FUNCTIONS=@dead_funcs']
- self.do_run(src, output)
- self.emcc_args.pop()
- self.emcc_args.pop()
- shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js'))
- assert open('pgoed.js').read() == open('pgoed2.js').read()
-
- def test_exported_response(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- extern "C" {
- int other_function() { return 5; }
- }
-
- int main() {
- printf("waka!\n");
- return 0;
- }
- '''
- open('exps', 'w').write('["_main","_other_function"]')
-
- self.emcc_args += ['-s', 'EXPORTED_FUNCTIONS=@exps']
- self.do_run(src, '''waka!''')
- assert 'other_function' in open('src.cpp.o.js').read()
-
- def test_add_function(self):
- if self.emcc_args is None: return self.skip('requires emcc')
+ var wrong = Math.floor(total / (img.width*img.height*3)); // floor, to allow some margin of error for antialiasing
- Settings.INVOKE_RUN = 0
- Settings.RESERVED_FUNCTION_POINTERS = 1
-
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
-
- int main(int argc, char **argv) {
- int fp = atoi(argv[1]);
- printf("fp: %d\n", fp);
- void (*f)(int) = reinterpret_cast<void (*)(int)>(fp);
- f(7);
- return 0;
- }
- '''
-
- open(os.path.join(self.get_dir(), 'post.js'), 'w').write('''
- var newFuncPtr = Runtime.addFunction(function(num) {
- Module.print('Hello ' + num + ' from JS!');
- });
- Module.callMain([newFuncPtr.toString()]);
- ''')
-
- self.emcc_args += ['--post-js', 'post.js']
- self.do_run(src, '''Hello 7 from JS!''')
-
- if Settings.ASM_JS:
- Settings.RESERVED_FUNCTION_POINTERS = 0
- self.do_run(src, '''Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.''')
- generated = open('src.cpp.o.js').read()
- assert 'jsCall' not in generated
- Settings.RESERVED_FUNCTION_POINTERS = 1
-
- Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS # flip the test
- self.do_run(src, '''Hello 7 from JS!''')
-
- def test_embind(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- Building.COMPILER_TEST_OPTS += ['--bind']
-
- src = r'''
- #include<stdio.h>
- #include<emscripten/val.h>
-
- using namespace emscripten;
-
- int main() {
- val Math = val::global("Math");
-
- // two ways to call Math.abs
- printf("abs(-10): %d\n", Math.call<int>("abs", -10));
- printf("abs(-11): %d\n", Math["abs"](-11).as<int>());
-
- return 0;
- }
- '''
- self.do_run(src, 'abs(-10): 10\nabs(-11): 11');
-
- def test_embind_2(self):
- if self.emcc_args is None: return self.skip('requires emcc')
- Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js']
- open('post.js', 'w').write('''
- Module.print('lerp ' + Module.lerp(1, 2, 0.66) + '.');
- ''')
- src = r'''
- #include <stdio.h>
- #include <SDL/SDL.h>
- #include <emscripten/bind.h>
- using namespace emscripten;
- float lerp(float a, float b, float t) {
- return (1 - t) * a + t * b;
- }
- EMSCRIPTEN_BINDINGS(my_module) {
- function("lerp", &lerp);
- }
- '''
- self.do_run(src, 'lerp 1.66');
-
- def test_scriptaclass(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- Settings.EXPORT_BINDINGS = 1
-
- header_filename = os.path.join(self.get_dir(), 'header.h')
- header = '''
- struct ScriptMe {
- int value;
- ScriptMe(int val);
- int getVal(); // XXX Sadly, inlining these will result in LLVM not
- // producing any code for them (when just building
- // as a library)
- void mulVal(int mul);
- };
- '''
- h = open(header_filename, 'w')
- h.write(header)
- h.close()
-
- src = '''
- #include "header.h"
-
- ScriptMe::ScriptMe(int val) : value(val) { }
- int ScriptMe::getVal() { return value; }
- void ScriptMe::mulVal(int mul) { value *= mul; }
- '''
-
- # Way 1: use demangler and namespacer
-
- script_src = '''
- var sme = Module._.ScriptMe.__new__(83); // malloc(sizeof(ScriptMe)), ScriptMe::ScriptMe(sme, 83) / new ScriptMe(83) (at addr sme)
- Module._.ScriptMe.mulVal(sme, 2); // ScriptMe::mulVal(sme, 2) sme.mulVal(2)
- Module.print('*' + Module._.ScriptMe.getVal(sme) + '*');
- _free(sme);
- Module.print('*ok*');
- '''
- post = '''
-def process(filename):
- Popen([PYTHON, DEMANGLER, filename], stdout=open(filename + '.tmp', 'w')).communicate()
- Popen([PYTHON, NAMESPACER, filename, filename + '.tmp'], stdout=open(filename + '.tmp2', 'w')).communicate()
- src = open(filename, 'r').read().replace(
- '// {{MODULE_ADDITIONS}',
- 'Module["_"] = ' + open(filename + '.tmp2', 'r').read().replace('var ModuleNames = ', '').rstrip() + ';\n\n' + script_src + '\n\n' +
- '// {{MODULE_ADDITIONS}'
- )
- open(filename, 'w').write(src)
-'''
- # XXX disable due to possible v8 bug -- self.do_run(src, '*166*\n*ok*', post_build=post)
-
- if self.emcc_args is not None and '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args: # without asm, closure minifies Math.imul badly
- self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
-
- # Way 2: use CppHeaderParser
-
- Settings.RUNTIME_TYPE_INFO = 1
-
- header = '''
- #include <stdio.h>
-
- class Parent {
- protected:
- int value;
- public:
- Parent(int val);
- Parent(Parent *p, Parent *q); // overload constructor
- int getVal() { return value; }; // inline should work just fine here, unlike Way 1 before
- void mulVal(int mul);
- };
-
- class Child1 : public Parent {
- public:
- Child1() : Parent(7) { printf("Child1:%d\\n", value); };
- Child1(int val) : Parent(val*2) { value -= 1; printf("Child1:%d\\n", value); };
- int getValSqr() { return value*value; }
- int getValSqr(int more) { return value*value*more; }
- int getValTimes(int times=1) { return value*times; }
- };
-
- class Child2 : public Parent {
- public:
- Child2() : Parent(9) { printf("Child2:%d\\n", value); };
- int getValCube() { return value*value*value; }
- static void printStatic() { printf("*static*\\n"); }
-
- virtual void virtualFunc() { printf("*virtualf*\\n"); }
- virtual void virtualFunc2() { printf("*virtualf2*\\n"); }
- static void runVirtualFunc(Child2 *self) { self->virtualFunc(); };
- private:
- void doSomethingSecret() { printf("security breached!\\n"); }; // we should not be able to do this
- };
- '''
- open(header_filename, 'w').write(header)
-
- basename = os.path.join(self.get_dir(), 'bindingtest')
- output = Popen([PYTHON, BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
- #print output
- assert 'Traceback' not in output, 'Failure in binding generation: ' + output
-
- src = '''
- #include "header.h"
-
- Parent::Parent(int val) : value(val) { printf("Parent:%d\\n", val); }
- Parent::Parent(Parent *p, Parent *q) : value(p->value + q->value) { printf("Parent:%d\\n", value); }
- void Parent::mulVal(int mul) { value *= mul; }
-
- #include "bindingtest.cpp"
- '''
-
- post2 = '''
-def process(filename):
- src = open(filename, 'a')
- src.write(open('bindingtest.js').read() + '\\n\\n')
- src.close()
-'''
-
- def post3(filename):
- script_src_2 = '''
- var sme = new Module.Parent(42);
- sme.mulVal(2);
- Module.print('*')
- Module.print(sme.getVal());
-
- Module.print('c1');
-
- var c1 = new Module.Child1();
- Module.print(c1.getVal());
- c1.mulVal(2);
- Module.print(c1.getVal());
- Module.print(c1.getValSqr());
- Module.print(c1.getValSqr(3));
- Module.print(c1.getValTimes()); // default argument should be 1
- Module.print(c1.getValTimes(2));
-
- Module.print('c1 v2');
-
- c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
- Module.print(c1.getVal());
- c1.mulVal(2);
- Module.print(c1.getVal());
- Module.print(c1.getValSqr());
- Module.print(c1.getValSqr(3));
-
- Module.print('c2')
-
- var c2 = new Module.Child2();
- Module.print(c2.getVal());
- c2.mulVal(2);
- Module.print(c2.getVal());
- Module.print(c2.getValCube());
- var succeeded;
- try {
- succeeded = 0;
- Module.print(c2.doSomethingSecret()); // should fail since private
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
- try {
- succeeded = 0;
- Module.print(c2.getValSqr()); // function from the other class
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
- try {
- succeeded = 0;
- c2.getValCube(); // sanity
- succeeded = 1;
- } catch(e) {}
- Module.print(succeeded);
-
- Module.Child2.prototype.printStatic(); // static calls go through the prototype
-
- // virtual function
- c2.virtualFunc();
- Module.Child2.prototype.runVirtualFunc(c2);
- c2.virtualFunc2();
-
- // extend the class from JS
- var c3 = new Module.Child2;
- Module.customizeVTable(c3, [{
- original: Module.Child2.prototype.virtualFunc,
- replacement: function() {
- Module.print('*js virtualf replacement*');
- }
- }, {
- original: Module.Child2.prototype.virtualFunc2,
- replacement: function() {
- Module.print('*js virtualf2 replacement*');
- }
- }]);
- c3.virtualFunc();
- Module.Child2.prototype.runVirtualFunc(c3);
- c3.virtualFunc2();
-
- c2.virtualFunc(); // original should remain the same
- Module.Child2.prototype.runVirtualFunc(c2);
- c2.virtualFunc2();
- Module.print('*ok*');
- '''
- code = open(filename).read()
- src = open(filename, 'w')
- src.write('var Module = {};\n') # name Module
- src.write(code)
- src.write(script_src_2 + '\n')
- src.close()
-
- Settings.RESERVED_FUNCTION_POINTERS = 20
-
- self.do_run(src, '''*
-84
-c1
-Parent:7
-Child1:7
-7
-14
-196
-588
-14
-28
-c1 v2
-Parent:16
-Child1:15
-15
-30
-900
-2700
-c2
-Parent:9
-Child2:9
-9
-18
-5832
-0
-0
-1
-*static*
-*virtualf*
-*virtualf*
-*virtualf2*''' + ('''
-Parent:9
-Child2:9
-*js virtualf replacement*
-*js virtualf replacement*
-*js virtualf2 replacement*
-*virtualf*
-*virtualf*
-*virtualf2*''') + '''
-*ok*
-''', post_build=(post2, post3))
-
- def test_scriptaclass_2(self):
- if self.emcc_args is None: return self.skip('requires emcc')
-
- Settings.EXPORT_BINDINGS = 1
-
- header_filename = os.path.join(self.get_dir(), 'header.h')
- header = '''
- #include <stdio.h>
- #include <string.h>
-
- class StringUser {
- char *s;
- int i;
- public:
- StringUser(char *string, int integer) : s(strdup(string)), i(integer) {}
- void Print(int anotherInteger, char *anotherString) {
- printf("|%s|%d|%s|%d|\\n", s, i, anotherString, anotherInteger);
- }
- void CallOther(StringUser *fr) { fr->Print(i, s); }
+ xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?' + wrong);
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
};
- '''
- open(header_filename, 'w').write(header)
-
- basename = os.path.join(self.get_dir(), 'bindingtest')
- output = Popen([PYTHON, BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
- #print output
- assert 'Traceback' not in output, 'Failure in binding generation: ' + output
-
- src = '''
- #include "header.h"
-
- #include "bindingtest.cpp"
- '''
-
- post = '''
-def process(filename):
- src = open(filename, 'a')
- src.write(open('bindingtest.js').read() + '\\n\\n')
- src.write(\'\'\'
- var user = new Module.StringUser("hello", 43);
- user.Print(41, "world");
- \'\'\')
- src.close()
-'''
- self.do_run(src, '|hello|43|world|41|', post_build=post)
-
- def test_typeinfo(self):
- if self.emcc_args is not None and self.emcc_args != []: return self.skip('full LLVM opts optimize out all the code that uses the type')
-
- Settings.RUNTIME_TYPE_INFO = 1
- if Settings.QUANTUM_SIZE != 4: return self.skip('We assume normal sizes in the output here')
-
- src = '''
- #include<stdio.h>
- struct UserStruct {
- int x;
- char y;
- short z;
- };
- struct Encloser {
- short x;
- UserStruct us;
- int y;
- };
- int main() {
- Encloser e;
- e.us.y = 5;
- printf("*ok:%d*\\n", e.us.y);
- return 0;
- }
- '''
-
- post = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{POST_RUN_ADDITIONS}}',
- \'\'\'
- if (Runtime.typeInfo) {
- Module.print('|' + Runtime.typeInfo.UserStruct.fields + '|' + Runtime.typeInfo.UserStruct.flatIndexes + '|');
- var t = Runtime.generateStructInfo(['x', { us: ['x', 'y', 'z'] }, 'y'], 'Encloser')
- Module.print('|' + [t.x, t.us.x, t.us.y, t.us.z, t.y] + '|');
- Module.print('|' + JSON.stringify(Runtime.generateStructInfo(['x', 'y', 'z'], 'UserStruct')) + '|');
- } else {
- Module.print('No type info.');
- }
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
-
- self.do_run(src,
- '*ok:5*\n|i32,i8,i16|0,4,6|\n|0,4,8,10,12|\n|{"__size__":8,"x":0,"y":4,"z":6}|',
- post_build=post)
-
- # Make sure that without the setting, we don't spam the .js with the type info
- Settings.RUNTIME_TYPE_INFO = 0
- self.do_run(src, 'No type info.', post_build=post)
-
- ### Tests for tools
-
- def test_safe_heap(self):
- if not Settings.SAFE_HEAP: return self.skip('We need SAFE_HEAP to test SAFE_HEAP')
- if Settings.USE_TYPED_ARRAYS == 2: return self.skip('It is ok to violate the load-store assumption with TA2')
- if Building.LLVM_OPTS: return self.skip('LLVM can optimize away the intermediate |x|')
-
- src = '''
- #include<stdio.h>
- #include<stdlib.h>
- int main() { int *x = (int*)malloc(sizeof(int));
- *x = 20;
- float *y = (float*)x;
- printf("%f\\n", *y);
- printf("*ok*\\n");
- return 0;
- }
- '''
-
- try:
- self.do_run(src, '*nothingatall*')
- except Exception, e:
- # This test *should* fail, by throwing this exception
- assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
-
- # And we should not fail if we disable checking on that line
-
- Settings.SAFE_HEAP = 3
- Settings.SAFE_HEAP_LINES = ["src.cpp:7"]
-
- self.do_run(src, '*ok*')
-
- # But if we disable the wrong lines, we still fail
-
- Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
-
- try:
- self.do_run(src, '*nothingatall*')
- except Exception, e:
- # This test *should* fail, by throwing this exception
- assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
-
- # And reverse the checks with = 2
-
- Settings.SAFE_HEAP = 2
- Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
-
- self.do_run(src, '*ok*')
-
- Settings.SAFE_HEAP = 1
-
- # Linking multiple files should work too
-
- module = '''
- #include<stdio.h>
- #include<stdlib.h>
- void callFunc() { int *x = (int*)malloc(sizeof(int));
- *x = 20;
- float *y = (float*)x;
- printf("%f\\n", *y);
- }
- '''
- module_name = os.path.join(self.get_dir(), 'module.cpp')
- open(module_name, 'w').write(module)
-
- main = '''
- #include<stdio.h>
- #include<stdlib.h>
- extern void callFunc();
- int main() { callFunc();
- int *x = (int*)malloc(sizeof(int));
- *x = 20;
- float *y = (float*)x;
- printf("%f\\n", *y);
- printf("*ok*\\n");
- return 0;
- }
- '''
- main_name = os.path.join(self.get_dir(), 'main.cpp')
- open(main_name, 'w').write(main)
-
- Building.emcc(module_name, ['-g'])
- Building.emcc(main_name, ['-g'])
- all_name = os.path.join(self.get_dir(), 'all.bc')
- Building.link([module_name + '.o', main_name + '.o'], all_name)
-
- try:
- self.do_ll_run(all_name, '*nothingatall*')
- except Exception, e:
- # This test *should* fail, by throwing this exception
- assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
-
- # And we should not fail if we disable checking on those lines
-
- Settings.SAFE_HEAP = 3
- Settings.SAFE_HEAP_LINES = ["module.cpp:7", "main.cpp:9"]
-
- self.do_ll_run(all_name, '*ok*')
-
- # But we will fail if we do not disable exactly what we need to - any mistake leads to error
-
- for lines in [["module.cpp:22", "main.cpp:9"], ["module.cpp:7", "main.cpp:29"], ["module.cpp:127", "main.cpp:449"], ["module.cpp:7"], ["main.cpp:9"]]:
- Settings.SAFE_HEAP_LINES = lines
- try:
- self.do_ll_run(all_name, '*nothingatall*')
- except Exception, e:
- # This test *should* fail, by throwing this exception
- assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
-
- def test_debug(self):
- if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
- if self.emcc_args is not None:
- if '-O1' in self.emcc_args or '-O2' in self.emcc_args: return self.skip('optimizations remove LLVM debug info')
-
- src = '''
- #include <stdio.h>
- #include <assert.h>
-
- void checker(int x) {
- x += 20;
- assert(x < 15); // this is line 7!
- }
-
- int main() {
- checker(10);
- return 0;
- }
- '''
- try:
- self.do_run(src, '*nothingatall*')
- except Exception, e:
- # This test *should* fail
- assert 'Assertion failed: x < 15' in str(e), str(e)
-
- lines = open('src.cpp.o.js', 'r').readlines()
- lines = filter(lambda line: '___assert_fail(' in line or '___assert_func(' in line, lines)
- found_line_num = any(('//@line 7 "' in line) for line in lines)
- found_filename = any(('src.cpp"\n' in line) for line in lines)
- assert found_line_num, 'Must have debug info with the line number'
- assert found_filename, 'Must have debug info with the filename'
-
- def test_source_map(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
- if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
- if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
-
- src = '''
- #include <stdio.h>
- #include <assert.h>
-
- __attribute__((noinline)) int foo() {
- printf("hi"); // line 6
- return 1; // line 7
- }
-
- int main() {
- printf("%d", foo()); // line 11
- return 0; // line 12
- }
- '''
-
- dirname = self.get_dir()
- src_filename = os.path.join(dirname, 'src.cpp')
- out_filename = os.path.join(dirname, 'a.out.js')
- no_maps_filename = os.path.join(dirname, 'no-maps.out.js')
-
- with open(src_filename, 'w') as f: f.write(src)
- assert '-g4' not in Building.COMPILER_TEST_OPTS
- Building.emcc(src_filename, Settings.serialize() + self.emcc_args +
- Building.COMPILER_TEST_OPTS, out_filename)
- # the file name may find its way into the generated code, so make sure we
- # can do an apples-to-apples comparison by compiling with the same file name
- shutil.move(out_filename, no_maps_filename)
- with open(no_maps_filename) as f: no_maps_file = f.read()
- no_maps_file = re.sub(' *//@.*$', '', no_maps_file, flags=re.MULTILINE)
- Building.COMPILER_TEST_OPTS.append('-g4')
-
- def build_and_check():
- import json
- Building.emcc(src_filename, Settings.serialize() + self.emcc_args +
- Building.COMPILER_TEST_OPTS, out_filename, stderr=PIPE)
- with open(out_filename) as f: out_file = f.read()
- # after removing the @line and @sourceMappingURL comments, the build
- # result should be identical to the non-source-mapped debug version.
- # this is worth checking because the parser AST swaps strings for token
- # objects when generating source maps, so we want to make sure the
- # optimizer can deal with both types.
- out_file = re.sub(' *//@.*$', '', out_file, flags=re.MULTILINE)
- def clean(code):
- return code.replace('{\n}', '{}')
- self.assertIdentical(clean(no_maps_file), clean(out_file))
- map_filename = out_filename + '.map'
- data = json.load(open(map_filename, 'r'))
- self.assertIdentical(out_filename, data['file'])
- self.assertIdentical(src_filename, data['sources'][0])
- self.assertIdentical(src, data['sourcesContent'][0])
- mappings = json.loads(jsrun.run_js(
- path_from_root('tools', 'source-maps', 'sourcemap2json.js'),
- tools.shared.NODE_JS, [map_filename]))
- seen_lines = set()
- for m in mappings:
- self.assertIdentical(src_filename, m['source'])
- seen_lines.add(m['originalLine'])
- # ensure that all the 'meaningful' lines in the original code get mapped
- assert seen_lines.issuperset([6, 7, 11, 12])
-
- # EMCC_DEBUG=2 causes lots of intermediate files to be written, and so
- # serves as a stress test for source maps because it needs to correlate
- # line numbers across all those files.
- old_emcc_debug = os.environ.get('EMCC_DEBUG', None)
- os.environ.pop('EMCC_DEBUG', None)
- try:
- build_and_check()
- os.environ['EMCC_DEBUG'] = '2'
- build_and_check()
- finally:
- if old_emcc_debug is not None:
- os.environ['EMCC_DEBUG'] = old_emcc_debug
- else:
- os.environ.pop('EMCC_DEBUG', None)
-
- def test_exception_source_map(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
- if '-g4' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g4')
- if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
-
- src = '''
- #include <stdio.h>
-
- __attribute__((noinline)) void foo(int i) {
- if (i < 10) throw i; // line 5
- }
-
- int main() {
- int i;
- scanf("%d", &i);
- foo(i);
- return 0;
- }
- '''
-
- def post(filename):
- import json
- map_filename = filename + '.map'
- mappings = json.loads(jsrun.run_js(
- path_from_root('tools', 'source-maps', 'sourcemap2json.js'),
- tools.shared.NODE_JS, [map_filename]))
- with open(filename) as f: lines = f.readlines()
- for m in mappings:
- if m['originalLine'] == 5 and '__cxa_throw' in lines[m['generatedLine']]:
- return
- assert False, 'Must label throw statements with line numbers'
-
- dirname = self.get_dir()
- self.build(src, dirname, os.path.join(dirname, 'src.cpp'), post_build=(None, post))
-
- def test_linespecific(self):
- if Settings.ASM_JS: return self.skip('asm always has corrections on')
-
- if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
- if self.emcc_args:
- self.emcc_args += ['--llvm-opts', '0'] # llvm full opts make the expected failures here not happen
- Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
-
- Settings.CHECK_SIGNS = 0
- Settings.CHECK_OVERFLOWS = 0
-
- # Signs
-
- src = '''
- #include <stdio.h>
- #include <assert.h>
-
- int main()
- {
- int varey = 100;
- unsigned int MAXEY = -1;
- printf("*%d*\\n", varey >= MAXEY); // 100 >= -1? not in unsigned!
- }
- '''
-
- Settings.CORRECT_SIGNS = 0
- self.do_run(src, '*1*') # This is a fail - we expect 0
-
- Settings.CORRECT_SIGNS = 1
- self.do_run(src, '*0*') # Now it will work properly
-
- # And now let's fix just that one line
- Settings.CORRECT_SIGNS = 2
- Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
- self.do_run(src, '*0*')
-
- # Fixing the wrong line should not work
- Settings.CORRECT_SIGNS = 2
- Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"]
- self.do_run(src, '*1*')
-
- # And reverse the checks with = 2
- Settings.CORRECT_SIGNS = 3
- Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"]
- self.do_run(src, '*0*')
- Settings.CORRECT_SIGNS = 3
- Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
- self.do_run(src, '*1*')
-
- Settings.CORRECT_SIGNS = 0
-
- # Overflows
-
- src = '''
- #include<stdio.h>
- int main() {
- int t = 77;
- for (int i = 0; i < 30; i++) {
- t = t + t + t + t + t + 1;
- }
- printf("*%d,%d*\\n", t, t & 127);
- return 0;
- }
- '''
-
- correct = '*186854335,63*'
- Settings.CORRECT_OVERFLOWS = 0
- try:
- self.do_run(src, correct)
- raise Exception('UNEXPECTED-PASS')
- except Exception, e:
- assert 'UNEXPECTED' not in str(e), str(e)
- assert 'Expected to find' in str(e), str(e)
-
- Settings.CORRECT_OVERFLOWS = 1
- self.do_run(src, correct) # Now it will work properly
-
- # And now let's fix just that one line
- Settings.CORRECT_OVERFLOWS = 2
- Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
- self.do_run(src, correct)
-
- # Fixing the wrong line should not work
- Settings.CORRECT_OVERFLOWS = 2
- Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
- try:
- self.do_run(src, correct)
- raise Exception('UNEXPECTED-PASS')
- except Exception, e:
- assert 'UNEXPECTED' not in str(e), str(e)
- assert 'Expected to find' in str(e), str(e)
-
- # And reverse the checks with = 2
- Settings.CORRECT_OVERFLOWS = 3
- Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
- self.do_run(src, correct)
- Settings.CORRECT_OVERFLOWS = 3
- Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
- try:
- self.do_run(src, correct)
- raise Exception('UNEXPECTED-PASS')
- except Exception, e:
- assert 'UNEXPECTED' not in str(e), str(e)
- assert 'Expected to find' in str(e), str(e)
-
- Settings.CORRECT_OVERFLOWS = 0
-
- # Roundings
-
- src = '''
- #include <stdio.h>
- #include <assert.h>
-
- int main()
- {
- TYPE x = -5;
- printf("*%d*", x/2);
- x = 5;
- printf("*%d*", x/2);
-
- float y = -5.33;
- x = y;
- printf("*%d*", x);
- y = 5.33;
- x = y;
- printf("*%d*", x);
-
- printf("\\n");
- }
- '''
-
- if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
- Settings.CORRECT_ROUNDINGS = 0
- self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here!
- self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick
- self.do_run(src.replace('TYPE', 'unsigned int'), '*-2**2**-6**5*')
-
- Settings.CORRECT_ROUNDINGS = 1
- Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
- self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') # Correct
- self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Correct
- self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') # Correct
- Settings.CORRECT_SIGNS = 0
-
- if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
- Settings.CORRECT_ROUNDINGS = 2
- Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
- self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*')
- self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right
- self.do_run(src.replace('TYPE', 'unsigned int'), '*-2**2**-5**5*')
-
- # And reverse the check with = 2
- if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
- Settings.CORRECT_ROUNDINGS = 3
- Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"]
- self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*')
- self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*')
- Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
- self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*')
- Settings.CORRECT_SIGNS = 0
-
- def test_exit_status(self):
- src = r'''
- #include <stdio.h>
- #include <stdlib.h>
- static void cleanup() {
- printf("cleanup\n");
- }
-
- int main()
- {
- atexit(cleanup); // this atexit should still be called
- printf("hello, world!\n");
- exit(118); // Unusual exit status to make sure it's working!
- }
- '''
- self.do_run(src, 'hello, world!\ncleanup\nExit Status: 118')
-
- def test_gc(self):
- if self.emcc_args == None: return self.skip('needs ta2')
- if Settings.ASM_JS: return self.skip('asm cannot support generic function table')
-
- Settings.GC_SUPPORT = 1
-
- src = r'''
- #include <stdio.h>
- #include <gc.h>
- #include <assert.h>
-
- void *global;
-
- void finalizer(void *ptr, void *arg) {
- printf("finalizing %d (global == %d)\n", (int)arg, ptr == global);
- }
-
- void finalizer2(void *ptr, void *arg) {
- printf("finalizing2 %d (global == %d)\n", (int)arg, ptr == global);
- }
-
- int main() {
- GC_INIT();
-
- void *local, *local2, *local3, *local4, *local5, *local6;
-
- // Hold on to global, drop locals
-
- global = GC_MALLOC(1024); // rooted since in a static allocation
- GC_REGISTER_FINALIZER_NO_ORDER(global, finalizer, 0, 0, 0);
- printf("alloc %p\n", global);
-
- local = GC_MALLOC(1024); // not rooted since stack is not scanned
- GC_REGISTER_FINALIZER_NO_ORDER(local, finalizer, (void*)1, 0, 0);
- printf("alloc %p\n", local);
-
- assert((char*)local - (char*)global >= 1024 || (char*)global - (char*)local >= 1024);
-
- local2 = GC_MALLOC(1024); // no finalizer
- printf("alloc %p\n", local2);
-
- local3 = GC_MALLOC(1024); // with finalizable2
- GC_REGISTER_FINALIZER_NO_ORDER(local3, finalizer2, (void*)2, 0, 0);
- printf("alloc %p\n", local);
-
- local4 = GC_MALLOC(1024); // yet another
- GC_REGISTER_FINALIZER_NO_ORDER(local4, finalizer2, (void*)3, 0, 0);
- printf("alloc %p\n", local);
-
- printf("basic test\n");
-
- GC_FORCE_COLLECT();
-
- printf("*\n");
-
- GC_FREE(global); // force free will actually work
-
- // scanning inside objects
-
- global = GC_MALLOC(12);
- GC_REGISTER_FINALIZER_NO_ORDER(global, finalizer, 0, 0, 0);
- local = GC_MALLOC(12);
- GC_REGISTER_FINALIZER_NO_ORDER(local, finalizer, (void*)1, 0, 0);
- local2 = GC_MALLOC_ATOMIC(12);
- GC_REGISTER_FINALIZER_NO_ORDER(local2, finalizer, (void*)2, 0, 0);
- local3 = GC_MALLOC(12);
- GC_REGISTER_FINALIZER_NO_ORDER(local3, finalizer, (void*)3, 0, 0);
- local4 = GC_MALLOC(12);
- GC_REGISTER_FINALIZER_NO_ORDER(local4, finalizer, (void*)4, 0, 0);
- local5 = GC_MALLOC_UNCOLLECTABLE(12);
- // This should never trigger since local5 is uncollectable
- GC_REGISTER_FINALIZER_NO_ORDER(local5, finalizer, (void*)5, 0, 0);
-
- printf("heap size = %d\n", GC_get_heap_size());
-
- local4 = GC_REALLOC(local4, 24);
-
- printf("heap size = %d\n", GC_get_heap_size());
-
- local6 = GC_MALLOC(12);
- GC_REGISTER_FINALIZER_NO_ORDER(local6, finalizer, (void*)6, 0, 0);
- // This should be the same as a free
- GC_REALLOC(local6, 0);
-
- void **globalData = (void**)global;
- globalData[0] = local;
- globalData[1] = local2;
-
- void **localData = (void**)local;
- localData[0] = local3;
-
- void **local2Data = (void**)local2;
- local2Data[0] = local4; // actually ignored, because local2 is atomic, so 4 is freeable
-
- printf("object scan test test\n");
-
- GC_FORCE_COLLECT();
-
- printf("*\n");
-
- GC_FREE(global); // force free will actually work
-
- printf("*\n");
-
- GC_FORCE_COLLECT();
-
- printf(".\n");
-
- global = 0;
-
- return 0;
- }
- '''
- self.do_run(src, '''basic test
-finalizing 1 (global == 0)
-finalizing2 2 (global == 0)
-finalizing2 3 (global == 0)
-*
-finalizing 0 (global == 1)
-heap size = 72
-heap size = 84
-finalizing 6 (global == 0)
-object scan test test
-finalizing 4 (global == 0)
-*
-finalizing 0 (global == 1)
-*
-finalizing 1 (global == 0)
-finalizing 2 (global == 0)
-finalizing 3 (global == 0)
-.
-''')
-
- # Generate tests for everything
- def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0,
- typed_arrays=0, emcc_args=None, env=None):
-
- if env is None: env = {}
-
- TT = type(fullname, (T,), dict(run_name = fullname, env = env))
-
- def tearDown(self):
- super(TT, self).tearDown()
-
- for k, v in self.env.iteritems():
- del os.environ[k]
-
- # clear global changes to Building
- Building.COMPILER_TEST_OPTS = []
- Building.COMPILER = CLANG
- Building.LLVM_OPTS = 0
-
- TT.tearDown = tearDown
-
- def setUp(self):
- super(TT, self).setUp()
- for k, v in self.env.iteritems():
- assert k not in os.environ, k + ' should not be in environment'
- os.environ[k] = v
-
- global checked_sanity
- if not checked_sanity:
- print '(checking sanity from test runner)' # do this after we set env stuff
- check_sanity(force=True)
- checked_sanity = True
-
- Building.COMPILER_TEST_OPTS = ['-g']
- os.chdir(self.get_dir()) # Ensure the directory exists and go there
- Building.COMPILER = compiler
-
- self.emcc_args = None if emcc_args is None else emcc_args[:]
- if self.emcc_args is not None:
- Settings.load(self.emcc_args)
- Building.LLVM_OPTS = 0
- if '-O2' in self.emcc_args:
- Building.COMPILER_TEST_OPTS = [] # remove -g in -O2 tests, for more coverage
- #Building.COMPILER_TEST_OPTS += self.emcc_args
- for arg in self.emcc_args:
- if arg.startswith('-O'):
- Building.COMPILER_TEST_OPTS.append(arg) # so bitcode is optimized too, this is for cpp to ll
- else:
- try:
- key, value = arg.split('=')
- Settings[key] = value # forward -s K=V
- except:
- pass
- return
-
- # TODO: Move much of these to a init() function in shared.py, and reuse that
- Settings.USE_TYPED_ARRAYS = typed_arrays
- Settings.INVOKE_RUN = 1
- Settings.RELOOP = 0 # we only do them in the "o2" pass
- Settings.MICRO_OPTS = embetter
- Settings.QUANTUM_SIZE = quantum_size
- Settings.ASSERTIONS = 1-embetter
- Settings.SAFE_HEAP = 1-embetter
- Settings.CHECK_OVERFLOWS = 1-embetter
- Settings.CORRECT_OVERFLOWS = 1-embetter
- Settings.CORRECT_SIGNS = 0
- Settings.CORRECT_ROUNDINGS = 0
- Settings.CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
- Settings.CHECK_SIGNS = 0 #1-embetter
- Settings.RUNTIME_TYPE_INFO = 0
- Settings.DISABLE_EXCEPTION_CATCHING = 0
- Settings.INCLUDE_FULL_LIBRARY = 0
- Settings.BUILD_AS_SHARED_LIB = 0
- Settings.RUNTIME_LINKED_LIBS = []
- Settings.EMULATE_UNALIGNED_ACCESSES = int(Settings.USE_TYPED_ARRAYS == 2 and Building.LLVM_OPTS == 2)
- Settings.DOUBLE_MODE = 1 if Settings.USE_TYPED_ARRAYS and Building.LLVM_OPTS == 0 else 0
- Settings.PRECISE_I64_MATH = 0
- Settings.NAMED_GLOBALS = 0 if not embetter else 1
-
- TT.setUp = setUp
-
- return TT
-
- # Make one run with the defaults
- default = make_run("default", compiler=CLANG, emcc_args=[])
-
- # Make one run with -O1, with safe heap
- o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=0", "-s", "SAFE_HEAP=1"])
-
- # Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow)
- o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "JS_CHUNK_SIZE=1024"])
-
- # asm.js
- asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "CHECK_HEAP_ALIGN=1"])
- asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])
- asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])
- asm2x86 = make_run("asm2x86", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "CHECK_HEAP_ALIGN=1"], env={"EMCC_LLVM_TARGET": "i386-pc-linux-gnu"})
-
- # Make custom runs with various options
- for compiler, quantum, embetter, typed_arrays in [
- (CLANG, 4, 0, 0),
- (CLANG, 4, 1, 1),
- ]:
- fullname = 's_0_%d%s%s' % (
- embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays)
- )
- locals()[fullname] = make_run(fullname, fullname, compiler, embetter, quantum, typed_arrays)
-
- del T # T is just a shape for the specific subclasses, we don't test it itself
-
- class other(RunnerCore):
- def test_emcc(self):
- for compiler in [EMCC, EMXX]:
- shortcompiler = os.path.basename(compiler)
- suffix = '.c' if compiler == EMCC else '.cpp'
-
- # --version
- output = Popen([PYTHON, compiler, '--version'], stdout=PIPE, stderr=PIPE).communicate()
- output = output[0].replace('\r', '')
- self.assertContained('''emcc (Emscripten GCC-like replacement)''', output)
- self.assertContained('''Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt)
-This is free and open source software under the MIT license.
-There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-''', output)
-
- # -v, without input files
- output = Popen([PYTHON, compiler, '-v'], stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('''clang version''', output[1].replace('\r', ''), output[1].replace('\r', ''))
-
- # --help
- output = Popen([PYTHON, compiler, '--help'], stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('''%s [options] file...
-
-Most normal gcc/g++ options will work, for example:
- --help Display this information
- --version Display compiler version information
-
-Options that are modified or new in %s include:
- -O0 No optimizations (default)
-''' % (shortcompiler, shortcompiler), output[0].replace('\r', ''), output[1].replace('\r', ''))
-
- # emcc src.cpp ==> writes a.out.js
- self.clear()
- output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix)], stdout=PIPE, stderr=PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists('a.out.js'), '\n'.join(output)
- self.assertContained('hello, world!', run_js('a.out.js'))
-
- # properly report source code errors, and stop there
- self.clear()
- assert not os.path.exists('a.out.js')
- process = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_error' + suffix)], stdout=PIPE, stderr=PIPE)
- output = process.communicate()
- assert not os.path.exists('a.out.js'), 'compilation failed, so no output file is expected'
- assert len(output[0]) == 0, output[0]
- assert process.returncode is not 0, 'Failed compilation must return a nonzero error code!'
- self.assertNotContained('IOError', output[1]) # no python stack
- self.assertNotContained('Traceback', output[1]) # no python stack
- self.assertContained('error: invalid preprocessing directive', output[1])
- self.assertContained(["error: use of undeclared identifier 'cheez", "error: unknown type name 'cheez'"], output[1])
- self.assertContained('errors generated', output[1])
- assert 'compiler frontend failed to generate LLVM bitcode, halting' in output[1].split('errors generated.')[1]
-
- # emcc src.cpp -c and emcc src.cpp -o src.[o|bc] ==> should give a .bc file
- # regression check: -o js should create "js", with bitcode content
- for args in [['-c'], ['-o', 'src.o'], ['-o', 'src.bc'], ['-o', 'src.so'], ['-o', 'js']]:
- target = args[1] if len(args) == 2 else 'hello_world.o'
- self.clear()
- Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate()
- syms = Building.llvm_nm(target)
- assert len(syms.defs) == 1 and 'main' in syms.defs, 'Failed to generate valid bitcode'
- if target == 'js': # make sure emcc can recognize the target as a bitcode file
- shutil.move(target, target + '.bc')
- target += '.bc'
- output = Popen([PYTHON, compiler, target, '-o', target + '.js'], stdout = PIPE, stderr = PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists(target + '.js'), 'Expected %s to exist since args are %s : %s' % (target + '.js', str(args), '\n'.join(output))
- self.assertContained('hello, world!', run_js(target + '.js'))
-
- # handle singleton archives
- self.clear()
- Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix), '-o', 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
- Popen([LLVM_AR, 'r', 'a.a', 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists('a.a')
- output = Popen([PYTHON, compiler, 'a.a']).communicate()
- assert os.path.exists('a.out.js'), output
- self.assertContained('hello, world!', run_js('a.out.js'))
-
- # emcc src.ll ==> generates .js
- self.clear()
- output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.ll')], stdout=PIPE, stderr=PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists('a.out.js'), '\n'.join(output)
- self.assertContained('hello, world!', run_js('a.out.js'))
-
- # emcc [..] -o [path] ==> should work with absolute paths
- try:
- for path in [os.path.abspath(os.path.join('..', 'file1.js')), os.path.join('b_dir', 'file2.js')]:
- print path
- self.clear(in_curr=True)
- os.chdir(self.get_dir())
- if not os.path.exists('a_dir'): os.mkdir('a_dir')
- os.chdir('a_dir')
- if not os.path.exists('b_dir'): os.mkdir('b_dir')
- output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.ll'), '-o', path], stdout=PIPE, stderr=PIPE).communicate()
- print output
- assert os.path.exists(path), path + ' does not exist; ' + '\n'.join(output)
- last = os.getcwd()
- os.chdir(os.path.dirname(path))
- self.assertContained('hello, world!', run_js(os.path.basename(path)))
- os.chdir(last)
- finally:
- os.chdir(self.get_dir())
- self.clear()
-
- # dlmalloc. dlmalloc is special in that it is the only part of libc that is (1) hard to write well, and
- # very speed-sensitive. So we do not implement it in JS in library.js, instead we compile it from source
- for source, has_malloc in [('hello_world' + suffix, False), ('hello_malloc.cpp', True)]:
- print source, has_malloc
- self.clear()
- output = Popen([PYTHON, compiler, path_from_root('tests', source)], stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists('a.out.js'), '\n'.join(output)
- self.assertContained('hello, world!', run_js('a.out.js'))
- generated = open('a.out.js').read()
- assert ('function _malloc(bytes) {' in generated) == (not has_malloc), 'If malloc is needed, it should be there, if not not'
-
- # Optimization: emcc src.cpp -o something.js [-Ox]. -O0 is the same as not specifying any optimization setting
- for params, opt_level, bc_params, closure, has_malloc in [ # bc params are used after compiling to bitcode
- (['-o', 'something.js'], 0, None, 0, 1),
- (['-o', 'something.js', '-O0'], 0, None, 0, 0),
- (['-o', 'something.js', '-O1'], 1, None, 0, 0),
- (['-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), # no closure since debug
- (['-o', 'something.js', '-O1', '--closure', '1'], 1, None, 1, 0),
- (['-o', 'something.js', '-O1', '--closure', '1', '-s', 'ASM_JS=0'], 1, None, 1, 0),
- (['-o', 'something.js', '-O2'], 2, None, 0, 1),
- (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0),
- (['-o', 'something.js', '-Os'], 2, None, 0, 1),
- (['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 1, 1),
- # and, test compiling to bitcode first
- (['-o', 'something.bc'], 0, [], 0, 0),
- (['-o', 'something.bc', '-O0'], 0, [], 0, 0),
- (['-o', 'something.bc', '-O1'], 1, ['-O1'], 0, 0),
- (['-o', 'something.bc', '-O2'], 2, ['-O2'], 0, 0),
- (['-o', 'something.bc', '-O3'], 3, ['-O3', '-s', 'ASM_JS=0'], 1, 0),
- (['-O1', '-o', 'something.bc'], 1, [], 0, 0),
- ]:
- print params, opt_level, bc_params, closure, has_malloc
- self.clear()
- keep_debug = '-g' in params
- args = [PYTHON, compiler, path_from_root('tests', 'hello_world_loop' + ('_malloc' if has_malloc else '') + '.cpp')] + params
- print '..', args
- output = Popen(args,
- stdout=PIPE, stderr=PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- if bc_params is not None:
- assert os.path.exists('something.bc'), output[1]
- bc_args = [PYTHON, compiler, 'something.bc', '-o', 'something.js'] + bc_params
- print '....', bc_args
- output = Popen(bc_args, stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists('something.js'), output[1]
- assert ('Applying some potentially unsafe optimizations!' in output[1]) == (opt_level >= 3), 'unsafe warning should appear in opt >= 3'
- self.assertContained('hello, world!', run_js('something.js'))
-
- # Verify optimization level etc. in the generated code
- # XXX these are quite sensitive, and will need updating when code generation changes
- generated = open('something.js').read() # TODO: parse out the _main function itself, not support code, if the tests below need that some day
- assert 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 should be used by default'
- assert 'SAFE_HEAP' not in generated, 'safe heap should not be used by default'
- assert ': while(' not in generated, 'when relooping we also js-optimize, so there should be no labelled whiles'
- if closure:
- if opt_level == 0: assert '._main =' in generated, 'closure compiler should have been run'
- elif opt_level >= 1: assert '._main=' in generated, 'closure compiler should have been run (and output should be minified)'
- else:
- # closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure
- assert '._main = ' not in generated, 'closure compiler should not have been run'
- if keep_debug:
- assert ('(label)' in generated or '(label | 0)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2'
- assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0'
- assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated or 'var $original = 0' in generated, 'micro opts should always be on'
- if opt_level >= 2 and '-g' in params:
- assert re.search('HEAP8\[\$?\w+ ?\+ ?\(+\$?\w+ ?', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2
- assert ('_puts(' in generated) == (opt_level >= 1), 'with opt >= 1, llvm opts are run and they should optimize printf to puts'
- if opt_level == 0 or '-g' in params: assert 'function _main() {' in generated, 'Should be unminified, including whitespace'
- elif opt_level >= 2: assert ('function _main(){' in generated or '"use asm";var a=' in generated), 'Should be whitespace-minified'
-
- # emcc -s RELOOP=1 src.cpp ==> should pass -s to emscripten.py. --typed-arrays is a convenient alias for -s USE_TYPED_ARRAYS
- for params, test, text in [
- (['-O2'], lambda generated: 'function intArrayToString' in generated, 'shell has unminified utilities'),
- (['-O2', '--closure', '1'], lambda generated: 'function intArrayToString' not in generated, 'closure minifies the shell'),
- (['-O2'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2'),
- (['-O2', '--minify', '0'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'minify is cancelled, but not registerize'),
- (['-O2', '-g'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize/minify is cancelled by -g'),
- (['-O2', '-g0'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2 -g0'),
- (['-O2', '-g1'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'compress is cancelled by -g1'),
- (['-O2', '-g2'], lambda generated: ('var b = 0' in generated or 'var i1 = 0' in generated) and 'function _main' in generated, 'minify is cancelled by -g2'),
- (['-O2', '-g3'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize is cancelled by -g3'),
- #(['-O2', '-g4'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'same as -g3 for now'),
- (['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'),
- (['-O3', '-s', 'INLINING_LIMIT=0', '--closure', '0'], lambda generated: 'function _dump' not in generated, 'lto/inlining'),
- (['-Os', '--llvm-lto', '1', '-s', 'ASM_JS=0'], lambda generated: 'function _dump' in generated, '-Os disables inlining'),
- (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
- (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
- ([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'),
- (['-s', 'EXPORTED_FUNCTIONS=["_main", "_dump"]'], lambda generated: 'Module["_dump"]' in generated, 'dump is now exported'),
- (['--typed-arrays', '0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
- (['--typed-arrays', '1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
- (['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'),
- (['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'),
- ]:
- print params, text
- self.clear()
- output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop.cpp'), '-o', 'a.out.js'] + params, stdout=PIPE, stderr=PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists('a.out.js'), '\n'.join(output)
- self.assertContained('hello, world!', run_js('a.out.js'))
- assert test(open('a.out.js').read()), text
-
- # Compiling two source files into a final JS.
- for args, target in [([], 'a.out.js'), (['-o', 'combined.js'], 'combined.js')]:
- self.clear()
- output = Popen([PYTHON, compiler, path_from_root('tests', 'twopart_main.cpp'), path_from_root('tests', 'twopart_side.cpp')] + args,
- stdout=PIPE, stderr=PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists(target), '\n'.join(output)
- self.assertContained('side got: hello from main, over', run_js(target))
-
- # Compiling two files with -c will generate separate .bc files
- self.clear()
- output = Popen([PYTHON, compiler, path_from_root('tests', 'twopart_main.cpp'), path_from_root('tests', 'twopart_side.cpp'), '-c'] + args,
- stdout=PIPE, stderr=PIPE).communicate()
- if '-o' in args:
- # specifying -o and -c is an error
- assert 'fatal error' in output[1], output[1]
- continue
-
- assert os.path.exists('twopart_main.o'), '\n'.join(output)
- assert os.path.exists('twopart_side.o'), '\n'.join(output)
- assert not os.path.exists(target), 'We should only have created bitcode here: ' + '\n'.join(output)
-
- # Compiling one of them alone is expected to fail
- output = Popen([PYTHON, compiler, 'twopart_main.o', '-O1', '-g'] + args, stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists(target), '\n'.join(output)
- #print '\n'.join(output)
- self.assertContained('missing function', run_js(target, stderr=STDOUT))
- try_delete(target)
-
- # Combining those bc files into js should work
- output = Popen([PYTHON, compiler, 'twopart_main.o', 'twopart_side.o'] + args, stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists(target), '\n'.join(output)
- self.assertContained('side got: hello from main, over', run_js(target))
-
- # Combining bc files into another bc should also work
- try_delete(target)
- assert not os.path.exists(target)
- output = Popen([PYTHON, compiler, 'twopart_main.o', 'twopart_side.o', '-o', 'combined.bc'] + args, stdout=PIPE, stderr=PIPE).communicate()
- syms = Building.llvm_nm('combined.bc')
- assert len(syms.defs) == 2 and 'main' in syms.defs, 'Failed to generate valid bitcode'
- output = Popen([PYTHON, compiler, 'combined.bc', '-o', 'combined.bc.js'], stdout = PIPE, stderr = PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists('combined.bc.js'), 'Expected %s to exist' % ('combined.bc.js')
- self.assertContained('side got: hello from main, over', run_js('combined.bc.js'))
-
- # --js-transform <transform>
- self.clear()
- trans = os.path.join(self.get_dir(), 't.py')
- trans_file = open(trans, 'w')
- trans_file.write('''
-import sys
-f = open(sys.argv[1], 'w')
-f.write('transformed!')
-f.close()
-''')
- trans_file.close()
- output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix), '--js-transform', '%s t.py' % (PYTHON)], stdout=PIPE, stderr=PIPE).communicate()
- assert open('a.out.js').read() == 'transformed!', 'Transformed output must be as expected'
-
- # TODO: Add in files test a clear example of using disablePermissions, and link to it from the wiki
- # TODO: test normal project linking, static and dynamic: get_library should not need to be told what to link!
- # TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
-
- def test_cmake(self):
- # On Windows, we want to build cmake-generated Makefiles with mingw32-make instead of e.g. cygwin make, since mingw32-make
- # understands Windows paths, and cygwin make additionally produces a cryptic 'not valid bitcode file' errors on files that
- # *are* valid bitcode files.
-
- if os.name == 'nt':
- make_command = 'mingw32-make'
- emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten.cmake')
- else:
- make_command = 'make'
- emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten_unix.cmake')
-
- cmake_cases = ['target_js', 'target_html']
- cmake_outputs = ['hello_world.js', 'hello_world_gles.html']
- for i in range(0, 2):
- for configuration in ['Debug', 'Release']:
-
- # Create a temp workspace folder
- cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i])
- tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
- try:
- os.chdir(tempdirname)
-
- # Run Cmake
- cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain,
- '-DCMAKE_BUILD_TYPE=' + configuration,
- '-DCMAKE_MODULE_PATH=' + path_from_root('cmake').replace('\\', '/'),
- '-G' 'Unix Makefiles', cmakelistsdir]
- ret = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
- if ret[1] != None and len(ret[1].strip()) > 0:
- print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics.
- if 'error' in ret[1].lower():
- print >> sys.stderr, 'Failed command: ' + ' '.join(cmd)
- print >> sys.stderr, 'Result:\n' + ret[1]
- raise Exception('cmake call failed!')
- assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
-
- # Build
- cmd = [make_command]
- ret = Popen(cmd, stdout=PIPE).communicate()
- if ret[1] != None and len(ret[1].strip()) > 0:
- print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics.
- if 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower():
- print >> sys.stderr, 'Failed command: ' + ' '.join(cmd)
- print >> sys.stderr, 'Result:\n' + ret[0]
- raise Exception('make failed!')
- assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i]
-
- # Run through node, if CMake produced a .js file.
- if cmake_outputs[i].endswith('.js'):
- ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0]
- assert 'hello, world!' in ret, 'Running cmake-based .js application failed!'
- finally:
- os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove.
- shutil.rmtree(tempdirname)
-
- def test_nostdincxx(self):
- try:
- old = os.environ.get('EMCC_LLVM_TARGET') or ''
- for compiler in [EMCC, EMXX]:
- for target in ['i386-pc-linux-gnu', 'le32-unknown-nacl']:
- print compiler, target
- os.environ['EMCC_LLVM_TARGET'] = target
- out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v'], stdout=PIPE, stderr=PIPE).communicate()
- out2, err2 = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE).communicate()
- assert out == out2
- def focus(e):
- assert 'search starts here:' in e, e
- assert e.count('End of search list.') == 1, e
- return e[e.index('search starts here:'):e.index('End of search list.')+20]
- err = focus(err)
- err2 = focus(err2)
- assert err == err2, err + '\n\n\n\n' + err2
- finally:
- if old:
- os.environ['EMCC_LLVM_TARGET'] = old
-
- def test_failure_error_code(self):
- for compiler in [EMCC, EMXX]:
- # Test that if one file is missing from the build, then emcc shouldn't succeed, and shouldn't try to produce an output file.
- process = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.c'), 'this_file_is_missing.c', '-o', 'this_output_file_should_never_exist.js'], stdout=PIPE, stderr=PIPE)
- process.communicate()
- assert process.returncode is not 0, 'Trying to compile a nonexisting file should return with a nonzero error code!'
- assert os.path.exists('this_output_file_should_never_exist.js') == False, 'Emcc should not produce an output file when build fails!'
-
- def test_cxx03(self):
- for compiler in [EMCC, EMXX]:
- process = Popen([PYTHON, compiler, path_from_root('tests', 'hello_cxx03.cpp')], stdout=PIPE, stderr=PIPE)
- process.communicate()
- assert process.returncode is 0, 'By default, emscripten should build using -std=c++03!'
-
- def test_cxx11(self):
- for compiler in [EMCC, EMXX]:
- process = Popen([PYTHON, compiler, '-std=c++11', path_from_root('tests', 'hello_cxx11.cpp')], stdout=PIPE, stderr=PIPE)
- process.communicate()
- assert process.returncode is 0, 'User should be able to specify custom -std= on the command line!'
-
- def test_catch_undef(self):
- open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
- #include <vector>
- #include <stdio.h>
-
- class Test {
- public:
- std::vector<int> vector;
- };
-
- Test globalInstance;
-
- int main() {
- printf("hello, world!\n");
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-fsanitize=undefined']).communicate()
- self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_unaligned_memory(self):
- open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
- #include <stdio.h>
-
- typedef unsigned char Bit8u;
- typedef unsigned short Bit16u;
- typedef unsigned int Bit32u;
-
- int main()
- {
- Bit8u data[4] = {0x01,0x23,0x45,0x67};
-
- printf("data: %x\n", *(Bit32u*)data);
- printf("data[0,1] 16bit: %x\n", *(Bit16u*)data);
- printf("data[1,2] 16bit: %x\n", *(Bit16u*)(data+1));
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
- self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_unaligned_memory_2(self):
- open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
- #include <string>
- #include <stdio.h>
-
- int main( int argc, char ** argv )
- {
- std::string testString( "Hello, World!" );
-
- printf( "testString = %s\n", testString.c_str() );
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
- self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_asm_minify(self):
- def test(args):
- Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop_malloc.cpp')] + args).communicate()
- self.assertContained('hello, world!', run_js(self.in_dir('a.out.js')))
- return open(self.in_dir('a.out.js')).read()
-
- src = test([])
- assert 'function _malloc' in src
-
- src = test(['-O2', '-s', 'ASM_JS=1'])
- normal_size = len(src)
- print 'normal', normal_size
- assert 'function _malloc' not in src
-
- src = test(['-O2', '-s', 'ASM_JS=1', '--minify', '0'])
- unminified_size = len(src)
- print 'unminified', unminified_size
- assert unminified_size > normal_size
- assert 'function _malloc' not in src
-
- src = test(['-O2', '-s', 'ASM_JS=1', '-g'])
- debug_size = len(src)
- print 'debug', debug_size
- assert debug_size > unminified_size
- assert 'function _malloc' in src
-
- def test_dangerous_func_cast(self):
- src = r'''
- #include <stdio.h>
- typedef void (*voidfunc)();
- int my_func() {
- printf("my func\n");
- return 10;
- }
- int main(int argc, char **argv) {
- voidfunc fps[10];
- for (int i = 0; i < 10; i++) fps[i] = (i == argc) ? (void (*)())my_func : NULL;
- fps[2*(argc-1) + 1]();
- return 0;
- }
- '''
- open('src.c', 'w').write(src)
- def test(args, expected, err_expected=None):
- out, err = Popen([PYTHON, EMCC, 'src.c'] + args, stderr=PIPE).communicate()
- if err_expected: self.assertContained(err_expected, err)
- self.assertContained(expected, run_js(self.in_dir('a.out.js'), stderr=PIPE, full_output=True))
- return open(self.in_dir('a.out.js')).read()
-
- test([], 'my func') # no asm, so casting func works
- test(['-O2'], 'abort', ['Casting potentially incompatible function pointer i32 ()* to void (...)*, for my_func',
- 'Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these']) # asm, so failure
- test(['-O2', '-s', 'ASSERTIONS=1'],
- 'Invalid function pointer called. Perhaps a miscast function pointer (check compilation warnings) or bad vtable lookup (maybe due to derefing a bad pointer, like NULL)?',
- ['Casting potentially incompatible function pointer i32 ()* to void (...)*, for my_func',
- 'Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these']) # asm, so failure
-
- def test_l_link(self):
- # Linking with -lLIBNAME and -L/DIRNAME should work
-
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- extern void printey();
- int main() {
- printey();
- return 0;
- }
- ''')
-
- try:
- os.makedirs(os.path.join(self.get_dir(), 'libdir'));
- except:
- pass
-
- open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
- #include <stdio.h>
- void printey() {
- printf("hello from lib\\n");
- }
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-c']).communicate()
- shutil.move(os.path.join(self.get_dir(), 'libfile.o'), os.path.join(self.get_dir(), 'libdir', 'libfile.so'))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile']).communicate()
- self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js')))
- assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs'
-
- def test_static_link(self):
- def test(name, header, main, side, expected, args=[], suffix='cpp', first=True):
- print name
- #t = main ; main = side ; side = t
- original_main = main
- original_side = side
- if header: open(os.path.join(self.get_dir(), 'header.h'), 'w').write(header)
- if type(main) == str:
- open(os.path.join(self.get_dir(), 'main.' + suffix), 'w').write(main)
- main = ['main.' + suffix]
- if type(side) == str:
- open(os.path.join(self.get_dir(), 'side.' + suffix), 'w').write(side)
- side = ['side.' + suffix]
- Popen([PYTHON, EMCC] + side + ['-o', 'side.js', '-s', 'SIDE_MODULE=1', '-O2'] + args).communicate()
- # TODO: test with and without DISABLE_GL_EMULATION, check that file sizes change
- Popen([PYTHON, EMCC] + main + ['-o', 'main.js', '-s', 'MAIN_MODULE=1', '-O2', '-s', 'DISABLE_GL_EMULATION=1'] + args).communicate()
- Popen([PYTHON, EMLINK, 'main.js', 'side.js', 'together.js'], stdout=PIPE).communicate()
- assert os.path.exists('together.js')
- for engine in JS_ENGINES:
- out = run_js('together.js', engine=engine, stderr=PIPE, full_output=True)
- self.assertContained(expected, out)
- if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
- if first:
- shutil.copyfile('together.js', 'first.js')
- test(name + ' (reverse)', header, original_side, original_main, expected, args, suffix, False) # test reverse order
-
- # test a simple call from one module to another. only one has a string (and constant memory initialization for it)
- test('basics', '', '''
- #include <stdio.h>
- extern int sidey();
- int main() {
- printf("other says %d.", sidey());
- return 0;
- }
- ''', '''
- int sidey() { return 11; }
- ''', 'other says 11.')
-
- # finalization of float variables should pass asm.js validation
- test('floats', '', '''
- #include <stdio.h>
- extern float sidey();
- int main() {
- printf("other says %.2f.", sidey()+1);
- return 0;
- }
- ''', '''
- float sidey() { return 11.5; }
- ''', 'other says 12.50')
-
- # memory initialization in both
- test('multiple memory inits', '', r'''
- #include <stdio.h>
- extern void sidey();
- int main() {
- printf("hello from main\n");
- sidey();
- return 0;
- }
- ''', r'''
- #include <stdio.h>
- void sidey() { printf("hello from side\n"); }
- ''', 'hello from main\nhello from side\n')
-
- # function pointers
- test('fp1', 'typedef void (*voidfunc)();', r'''
- #include <stdio.h>
- #include "header.h"
- voidfunc sidey(voidfunc f);
- void a() { printf("hello from funcptr\n"); }
- int main() {
- sidey(a)();
- return 0;
- }
- ''', '''
- #include "header.h"
- voidfunc sidey(voidfunc f) { return f; }
- ''', 'hello from funcptr\n')
-
- # function pointers with 'return' in the name
- test('fp2', 'typedef void (*voidfunc)();', r'''
- #include <stdio.h>
- #include "header.h"
- int sidey(voidfunc f);
- void areturn0() { printf("hello 0\n"); }
- void areturn1() { printf("hello 1\n"); }
- void areturn2() { printf("hello 2\n"); }
- int main(int argc, char **argv) {
- voidfunc table[3] = { areturn0, areturn1, areturn2 };
- table[sidey(NULL)]();
- return 0;
- }
- ''', '''
- #include "header.h"
- int sidey(voidfunc f) { if (f) f(); return 1; }
- ''', 'hello 1\n')
-
- # Global initializer
- test('global init', '', r'''
- #include <stdio.h>
- struct Class {
- Class() { printf("a new Class\n"); }
- };
- static Class c;
- int main() {
- return 0;
- }
- ''', r'''
- void nothing() {}
- ''', 'a new Class\n')
-
- # Multiple global initializers (LLVM generates overlapping names for them)
- test('global inits', r'''
- #include <stdio.h>
- struct Class {
- Class(const char *name) { printf("new %s\n", name); }
- };
- ''', r'''
- #include "header.h"
- static Class c("main");
- int main() {
- return 0;
- }
- ''', r'''
- #include "header.h"
- static Class c("side");
- ''', ['new main\nnew side\n', 'new side\nnew main\n'])
-
- # Class code used across modules
- test('codecall', r'''
- #include <stdio.h>
- struct Class {
- Class(const char *name);
- };
- ''', r'''
- #include "header.h"
- int main() {
- Class c("main");
- return 0;
- }
- ''', r'''
- #include "header.h"
- Class::Class(const char *name) { printf("new %s\n", name); }
- ''', ['new main\n'])
-
- # malloc usage in both modules
- test('malloc', r'''
- #include <stdlib.h>
- #include <string.h>
- char *side(const char *data);
- ''', r'''
- #include <stdio.h>
- #include "header.h"
- int main() {
- char *temp = side("hello through side\n");
- char *ret = (char*)malloc(strlen(temp)+1);
- strcpy(ret, temp);
- temp[1] = 'x';
- puts(ret);
- return 0;
- }
- ''', r'''
- #include "header.h"
- char *side(const char *data) {
- char *ret = (char*)malloc(strlen(data)+1);
- strcpy(ret, data);
- return ret;
- }
- ''', ['hello through side\n'])
-
- # libc usage in one modules. must force libc inclusion in the main module if that isn't the one using mallinfo()
- try:
- os.environ['EMCC_FORCE_STDLIBS'] = 'libc'
- test('malloc-1', r'''
- #include <string.h>
- int side();
- ''', r'''
- #include <stdio.h>
- #include "header.h"
- int main() {
- printf("|%d|\n", side());
- return 0;
- }
- ''', r'''
- #include <stdlib.h>
- #include <malloc.h>
- #include "header.h"
- int side() {
- struct mallinfo m = mallinfo();
- return m.arena > 1;
- }
- ''', ['|1|\n'])
- finally:
- del os.environ['EMCC_FORCE_STDLIBS']
-
- # iostream usage in one and std::string in both
- test('iostream', r'''
- #include <iostream>
- #include <string>
- std::string side();
- ''', r'''
- #include "header.h"
- int main() {
- std::cout << "hello from main " << side() << std::endl;
- return 0;
- }
- ''', r'''
- #include "header.h"
- std::string side() { return "and hello from side"; }
- ''', ['hello from main and hello from side\n'])
-
- # followup to iostream test: a second linking
- print 'second linking of a linking output'
- open('moar.cpp', 'w').write(r'''
- #include <iostream>
- struct Moar {
- Moar() { std::cout << "moar!" << std::endl; }
- };
- Moar m;
- ''')
- Popen([PYTHON, EMCC, 'moar.cpp', '-o', 'moar.js', '-s', 'SIDE_MODULE=1', '-O2']).communicate()
- Popen([PYTHON, EMLINK, 'together.js', 'moar.js', 'triple.js'], stdout=PIPE).communicate()
- assert os.path.exists('triple.js')
- for engine in JS_ENGINES:
- out = run_js('triple.js', engine=engine, stderr=PIPE, full_output=True)
- self.assertContained('moar!\nhello from main and hello from side\n', out)
- if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
-
- # zlib compression library. tests function pointers in initializers and many other things
- test('zlib', '', open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
- self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
- open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
- args=['-I' + path_from_root('tests', 'zlib')], suffix='c')
-
- # bullet physics engine. tests all the things
- test('bullet', '', open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
- self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
- os.path.join('src', '.libs', 'libBulletCollision.a'),
- os.path.join('src', '.libs', 'libLinearMath.a')]),
- [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
- open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
- open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
- args=['-I' + path_from_root('tests', 'bullet', 'src')])
-
-
- def test_outline(self):
- def test(name, src, libs, expected, expected_ranges, args=[], suffix='cpp', test_sizes=True):
- print name
-
- def measure_funcs(filename):
- i = 0
- start = -1
- curr = None
- ret = {}
- for line in open(filename):
- i += 1
- if line.startswith('function '):
- start = i
- curr = line
- elif line.startswith('}') and curr:
- size = i - start
- ret[curr] = size
- curr = None
- return ret
-
- for debug, outlining_limits in [
- ([], (1000,)),
- (['-g1'], (1000,)),
- (['-g2'], (1000,)),
- (['-g'], (100, 250, 500, 1000, 2000, 5000, 0))
- ]:
- for outlining_limit in outlining_limits:
- print '\n', debug, outlining_limit, '\n'
- # TODO: test without -g3, tell all sorts
- Popen([PYTHON, EMCC, src] + libs + ['-o', 'test.js', '-O2'] + debug + ['-s', 'OUTLINING_LIMIT=%d' % outlining_limit] + args).communicate()
- assert os.path.exists('test.js')
- shutil.copyfile('test.js', '%d_test.js' % outlining_limit)
- for engine in JS_ENGINES:
- out = run_js('test.js', engine=engine, stderr=PIPE, full_output=True)
- self.assertContained(expected, out)
- if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
- if debug == ['-g']:
- low = expected_ranges[outlining_limit][0]
- seen = max(measure_funcs('test.js').values())
- high = expected_ranges[outlining_limit][1]
- print outlining_limit, ' ', low, '<=', seen, '<=', high
- if test_sizes: assert low <= seen <= high
-
- for test_opts, test_sizes in [([], True), (['-O2'], False)]:
- Building.COMPILER_TEST_OPTS = test_opts
- test('zlib', path_from_root('tests', 'zlib', 'example.c'),
- self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
- open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
- {
- 100: (190, 250),
- 250: (200, 330),
- 500: (250, 310),
- 1000: (230, 300),
- 2000: (380, 450),
- 5000: (800, 1100),
- 0: (1500, 1800)
- },
- args=['-I' + path_from_root('tests', 'zlib')], suffix='c', test_sizes=test_sizes)
-
- def test_symlink(self):
- if os.name == 'nt':
- return self.skip('Windows FS does not need to be tested for symlinks support, since it does not have them.')
- open(os.path.join(self.get_dir(), 'foobar.xxx'), 'w').write('int main(){ return 0; }')
- os.symlink(os.path.join(self.get_dir(), 'foobar.xxx'), os.path.join(self.get_dir(), 'foobar.c'))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foobar.c'), '-o', os.path.join(self.get_dir(), 'foobar')], stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'foobar'))
- try_delete(os.path.join(self.get_dir(), 'foobar'))
- try_delete(os.path.join(self.get_dir(), 'foobar.xxx'))
- try_delete(os.path.join(self.get_dir(), 'foobar.c'))
-
- open(os.path.join(self.get_dir(), 'foobar.c'), 'w').write('int main(){ return 0; }')
- os.symlink(os.path.join(self.get_dir(), 'foobar.c'), os.path.join(self.get_dir(), 'foobar.xxx'))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foobar.xxx'), '-o', os.path.join(self.get_dir(), 'foobar')], stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'foobar'))
- try_delete(os.path.join(self.get_dir(), 'foobar'))
- try_delete(os.path.join(self.get_dir(), 'foobar.xxx'))
- try_delete(os.path.join(self.get_dir(), 'foobar.c'))
-
- def test_multiply_defined_libsymbols(self):
- lib = "int mult() { return 1; }"
- lib_name = os.path.join(self.get_dir(), 'libA.c')
- open(lib_name, 'w').write(lib)
- a2 = "void x() {}"
- a2_name = os.path.join(self.get_dir(), 'a2.c')
- open(a2_name, 'w').write(a2)
- b2 = "void y() {}"
- b2_name = os.path.join(self.get_dir(), 'b2.c')
- open(b2_name, 'w').write(b2)
- main = r'''
- #include <stdio.h>
- int mult();
- int main() {
- printf("result: %d\n", mult());
- return 0;
- }
- '''
- main_name = os.path.join(self.get_dir(), 'main.c')
- open(main_name, 'w').write(main)
-
- Building.emcc(lib_name, output_filename='libA.so')
-
- Building.emcc(a2_name, ['-L.', '-lA'])
- Building.emcc(b2_name, ['-L.', '-lA'])
-
- Building.emcc(main_name, ['-L.', '-lA', a2_name+'.o', b2_name+'.o'], output_filename='a.out.js')
-
- self.assertContained('result: 1', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_multiply_defined_libsymbols_2(self):
- a = "int x() { return 55; }"
- a_name = os.path.join(self.get_dir(), 'a.c')
- open(a_name, 'w').write(a)
- b = "int y() { return 2; }"
- b_name = os.path.join(self.get_dir(), 'b.c')
- open(b_name, 'w').write(b)
- c = "int z() { return 5; }"
- c_name = os.path.join(self.get_dir(), 'c.c')
- open(c_name, 'w').write(c)
- main = r'''
- #include <stdio.h>
- int x();
- int y();
- int z();
- int main() {
- printf("result: %d\n", x() + y() + z());
- return 0;
- }
- '''
- main_name = os.path.join(self.get_dir(), 'main.c')
- open(main_name, 'w').write(main)
-
- Building.emcc(a_name) # a.c.o
- Building.emcc(b_name) # b.c.o
- Building.emcc(c_name) # c.c.o
- lib_name = os.path.join(self.get_dir(), 'libLIB.a')
- Building.emar('cr', lib_name, [a_name + '.o', b_name + '.o']) # libLIB.a with a and b
-
- # a is in the lib AND in an .o, so should be ignored in the lib. We do still need b from the lib though
- Building.emcc(main_name, ['-L.', '-lLIB', a_name+'.o', c_name + '.o'], output_filename='a.out.js')
-
- self.assertContained('result: 62', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_redundant_link(self):
- lib = "int mult() { return 1; }"
- lib_name = os.path.join(self.get_dir(), 'libA.c')
- open(lib_name, 'w').write(lib)
- main = r'''
- #include <stdio.h>
- int mult();
- int main() {
- printf("result: %d\n", mult());
- return 0;
- }
- '''
- main_name = os.path.join(self.get_dir(), 'main.c')
- open(main_name, 'w').write(main)
-
- Building.emcc(lib_name, output_filename='libA.so')
-
- Building.emcc(main_name, ['libA.so']*2, output_filename='a.out.js')
-
- self.assertContained('result: 1', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_export_all(self):
- lib = r'''
- #include <stdio.h>
- void libf1() { printf("libf1\n"); }
- void libf2() { printf("libf2\n"); }
- '''
- lib_name = os.path.join(self.get_dir(), 'lib.c')
- open(lib_name, 'w').write(lib)
-
- open('main.js', 'w').write('''
- _libf1();
- _libf2();
- ''')
-
- Building.emcc(lib_name, ['-s', 'EXPORT_ALL=1', '--post-js', 'main.js'], output_filename='a.out.js')
-
- self.assertContained('libf1\nlibf2\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_stdin(self):
- open('main.cpp', 'w').write(r'''
-#include <stdio.h>
-int main(int argc, char const *argv[])
-{
- char str[10] = {0};
- scanf("%10s", str);
- printf("%s\n", str);
- return 0;
-}
-''')
- Building.emcc('main.cpp', output_filename='a.out.js')
- open('in.txt', 'w').write('abc')
- # node's stdin support is broken
- self.assertContained('abc', Popen(listify(SPIDERMONKEY_ENGINE) + ['a.out.js'], stdin=open('in.txt'), stdout=PIPE, stderr=PIPE).communicate()[0])
-
- def test_ungetc_fscanf(self):
- open('main.cpp', 'w').write(r'''
- #include <stdio.h>
- int main(int argc, char const *argv[])
- {
- char str[4] = {0};
- FILE* f = fopen("my_test.input", "r");
- if (f == NULL) {
- printf("cannot open file\n");
- return -1;
- }
- ungetc('x', f);
- ungetc('y', f);
- ungetc('z', f);
- fscanf(f, "%3s", str);
- printf("%s\n", str);
- return 0;
- }
- ''')
- open('my_test.input', 'w').write('abc')
- Building.emcc('main.cpp', ['--embed-file', 'my_test.input'], output_filename='a.out.js')
- self.assertContained('zyx', Popen(listify(JS_ENGINES[0]) + ['a.out.js'], stdout=PIPE, stderr=PIPE).communicate()[0])
-
- def test_abspaths(self):
- # Includes with absolute paths are generally dangerous, things like -I/usr/.. will get to system local headers, not our portable ones.
-
- shutil.copyfile(path_from_root('tests', 'hello_world.c'), 'main.c')
-
- for args, expected in [(['-I/usr/something'], True),
- (['-L/usr/something'], True),
- (['-Isubdir/something'], False),
- (['-Lsubdir/something'], False),
- ([], False)]:
- err = Popen([PYTHON, EMCC, 'main.c'] + args, stderr=PIPE).communicate()[1]
- assert ('encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' in err) == expected, err
-
- def test_local_link(self):
- # Linking a local library directly, like /usr/lib/libsomething.so, cannot work of course since it
- # doesn't contain bitcode. However, when we see that we should look for a bitcode file for that
- # library in the -L paths and system/lib
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- extern void printey();
- int main() {
- printey();
- return 0;
- }
- ''')
-
- try:
- os.makedirs(os.path.join(self.get_dir(), 'subdir'));
- except:
- pass
- open(os.path.join(self.get_dir(), 'subdir', 'libfile.so'), 'w').write('this is not llvm bitcode!')
-
- open(os.path.join(self.get_dir(), 'libfile.cpp'), 'w').write('''
- #include <stdio.h>
- void printey() {
- printf("hello from lib\\n");
- }
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'libfile.cpp'), '-o', 'libfile.so']).communicate()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), os.path.join(self.get_dir(), 'subdir', 'libfile.so'), '-L.'], stderr=PIPE).communicate()
- self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_runtimelink_multi(self):
- return self.skip('shared libs are deprecated')
- if Settings.ASM_JS: return self.skip('asm does not support runtime linking yet')
-
- if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations')
-
- open('testa.h', 'w').write(r'''
- #ifndef _TESTA_H_
- #define _TESTA_H_
-
- class TestA {
- public:
- TestA();
- };
-
- #endif
- ''')
- open('testb.h', 'w').write(r'''
- #ifndef _TESTB_H_
- #define _TESTB_H_
-
- class TestB {
- public:
- TestB();
- };
-
- #endif
- ''')
- open('testa.cpp', 'w').write(r'''
- #include <stdio.h>
- #include <testa.h>
-
- TestA::TestA() {
- printf("TestA\n");
- }
- ''')
- open('testb.cpp', 'w').write(r'''
- #include <stdio.h>
- #include <testb.h>
- #include <testa.h>
- /*
- */
- TestB::TestB() {
- printf("TestB\n");
- TestA* testa = new TestA();
- }
- ''')
- open('main.cpp', 'w').write(r'''
- #include <stdio.h>
- #include <testa.h>
- #include <testb.h>
-
- /*
- */
- int main(int argc, char** argv) {
- printf("Main\n");
- TestA* testa = new TestA();
- TestB* testb = new TestB();
- }
- ''')
-
- Popen([PYTHON, EMCC, 'testa.cpp', '-o', 'liba.js', '-s', 'BUILD_AS_SHARED_LIB=2', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-I.']).communicate()
- Popen([PYTHON, EMCC, 'testb.cpp', '-o', 'libb.js', '-s', 'BUILD_AS_SHARED_LIB=2', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-I.']).communicate()
- Popen([PYTHON, EMCC, 'main.cpp', '-o', 'main.js', '-s', 'RUNTIME_LINKED_LIBS=["liba.js", "libb.js"]', '-s', 'NAMED_GLOBALS=1', '-I.', '-s', 'LINKABLE=1']).communicate()
-
- Popen([PYTHON, EMCC, 'main.cpp', 'testa.cpp', 'testb.cpp', '-o', 'full.js', '-I.']).communicate()
-
- self.assertContained('TestA\nTestB\nTestA\n', run_js('main.js', engine=SPIDERMONKEY_ENGINE))
-
- def test_js_libraries(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- #include <stdio.h>
- extern "C" {
- extern void printey();
- extern int calcey(int x, int y);
- }
- int main() {
- printey();
- printf("*%d*\\n", calcey(10, 22));
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'mylib1.js'), 'w').write('''
- mergeInto(LibraryManager.library, {
- printey: function() {
- Module.print('hello from lib!');
- }
- });
- ''')
- open(os.path.join(self.get_dir(), 'mylib2.js'), 'w').write('''
- mergeInto(LibraryManager.library, {
- calcey: function(x, y) {
- return x + y;
- }
- });
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--js-library', os.path.join(self.get_dir(), 'mylib1.js'),
- '--js-library', os.path.join(self.get_dir(), 'mylib2.js')]).communicate()
- self.assertContained('hello from lib!\n*32*\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_identical_basenames(self):
- # Issue 287: files in different dirs but with the same basename get confused as the same,
- # causing multiply defined symbol errors
- try:
- os.makedirs(os.path.join(self.get_dir(), 'foo'));
- except:
- pass
- try:
- os.makedirs(os.path.join(self.get_dir(), 'bar'));
- except:
- pass
- open(os.path.join(self.get_dir(), 'foo', 'main.cpp'), 'w').write('''
- extern void printey();
- int main() {
- printey();
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'bar', 'main.cpp'), 'w').write('''
- #include<stdio.h>
- void printey() { printf("hello there\\n"); }
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo', 'main.cpp'), os.path.join(self.get_dir(), 'bar', 'main.cpp')]).communicate()
- self.assertContained('hello there', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- # ditto with first creating .o files
- try_delete(os.path.join(self.get_dir(), 'a.out.js'))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo', 'main.cpp'), '-o', os.path.join(self.get_dir(), 'foo', 'main.o')]).communicate()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'bar', 'main.cpp'), '-o', os.path.join(self.get_dir(), 'bar', 'main.o')]).communicate()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo', 'main.o'), os.path.join(self.get_dir(), 'bar', 'main.o')]).communicate()
- self.assertContained('hello there', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_main_a(self):
- # if main() is in a .a, we need to pull in that .a
-
- main_name = os.path.join(self.get_dir(), 'main.c')
- open(main_name, 'w').write(r'''
- #include <stdio.h>
- extern int f();
- int main() {
- printf("result: %d.\n", f());
- return 0;
- }
- ''')
-
- other_name = os.path.join(self.get_dir(), 'other.c')
- open(other_name, 'w').write(r'''
- #include <stdio.h>
- int f() { return 12346; }
- ''')
-
- Popen([PYTHON, EMCC, main_name, '-c', '-o', main_name+'.bc']).communicate()
- Popen([PYTHON, EMCC, other_name, '-c', '-o', other_name+'.bc']).communicate()
-
- Popen([PYTHON, EMAR, 'cr', main_name+'.a', main_name+'.bc']).communicate()
-
- Popen([PYTHON, EMCC, other_name+'.bc', main_name+'.a']).communicate()
-
- self.assertContained('result: 12346.', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_dup_o_in_a(self):
- open('common.c', 'w').write(r'''
- #include <stdio.h>
- void a(void) {
- printf("a\n");
- }
- ''')
- Popen([PYTHON, EMCC, 'common.c', '-c', '-o', 'common.o']).communicate()
- Popen([PYTHON, EMAR, 'rc', 'liba.a', 'common.o']).communicate()
-
- open('common.c', 'w').write(r'''
- #include <stdio.h>
- void b(void) {
- printf("b\n");
- }
- ''')
- Popen([PYTHON, EMCC, 'common.c', '-c', '-o', 'common.o']).communicate()
- Popen([PYTHON, EMAR, 'rc', 'libb.a', 'common.o']).communicate()
-
- open('main.c', 'w').write(r'''
- void a(void);
- void b(void);
- int main() {
- a();
- b();
- }
- ''')
- Popen([PYTHON, EMCC, 'main.c', '-L.', '-la', '-lb']).communicate()
-
- self.assertContained('a\nb\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_embed_file(self):
- open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''hello from a file with lots of data and stuff in it thank you very much''')
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
- int main() {
- FILE *f = fopen("somefile.txt", "r");
- char buf[100];
- fread(buf, 1, 20, f);
- buf[20] = 0;
- fclose(f);
- printf("|%s|\n", buf);
- return 0;
+ actualImage.src = actualUrl;
}
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'somefile.txt']).communicate()
- self.assertContained('|hello from a file wi|', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- # preload twice, should not err
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'somefile.txt', '--embed-file', 'somefile.txt']).communicate()
- self.assertContained('|hello from a file wi|', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_embed_file_dup(self):
- try_delete(os.path.join(self.get_dir(), 'tst'))
- os.mkdir(os.path.join(self.get_dir(), 'tst'))
- os.mkdir(os.path.join(self.get_dir(), 'tst', 'test1'))
- os.mkdir(os.path.join(self.get_dir(), 'tst', 'test2'))
-
- open(os.path.join(self.get_dir(), 'tst', 'aa.txt'), 'w').write('''frist''')
- open(os.path.join(self.get_dir(), 'tst', 'test1', 'aa.txt'), 'w').write('''sacond''')
- open(os.path.join(self.get_dir(), 'tst', 'test2', 'aa.txt'), 'w').write('''thard''')
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
- #include <string.h>
- void print_file(const char *name) {
- FILE *f = fopen(name, "r");
- char buf[100];
- memset(buf, 0, 100);
- fread(buf, 1, 20, f);
- buf[20] = 0;
- fclose(f);
- printf("|%s|\n", buf);
- }
- int main() {
- print_file("tst/aa.txt");
- print_file("tst/test1/aa.txt");
- print_file("tst/test2/aa.txt");
- return 0;
- }
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'tst']).communicate()
- self.assertContained('|frist|\n|sacond|\n|thard|\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_multidynamic_link(self):
- # Linking the same dynamic library in will error, normally, since we statically link it, causing dupe symbols
- # A workaround is to use --ignore-dynamic-linking, see emcc --help for details
-
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
- extern void printey();
- extern void printother();
- int main() {
- printf("*");
- printey();
- printf("\n");
- printother();
- printf("\n");
- printf("*");
- return 0;
- }
- ''')
-
- try:
- os.makedirs(os.path.join(self.get_dir(), 'libdir'));
- except:
- pass
-
- open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
- #include <stdio.h>
- void printey() {
- printf("hello from lib");
- }
- ''')
-
- open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write('''
- #include <stdio.h>
- extern void printey();
- void printother() {
- printf("|");
- printey();
- printf("|");
- }
- ''')
-
- # This lets us link the same dynamic lib twice. We will need to link it in manually at the end.
- compiler = [PYTHON, EMCC, '--ignore-dynamic-linking']
-
- # Build libfile normally into an .so
- Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so')]).communicate()
- # Build libother and dynamically link it to libfile - but add --ignore-dynamic-linking
- Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate()
- # Build the main file, linking in both the libs
- Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother', '-c']).communicate()
-
- # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother']).communicate()
-
- self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_js_link(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- #include <stdio.h>
- int main() {
- printf("hello from main\\n");
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'before.js'), 'w').write('''
- var MESSAGE = 'hello from js';
- if (typeof Module != 'undefined') throw 'This code should run before anything else!';
- ''')
- open(os.path.join(self.get_dir(), 'after.js'), 'w').write('''
- Module.print(MESSAGE);
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'before.js', '--post-js', 'after.js']).communicate()
- self.assertContained('hello from main\nhello from js\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_sdl_endianness(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
- #include <SDL/SDL.h>
-
- int main() {
- printf("%d, %d, %d\n", SDL_BYTEORDER, SDL_LIL_ENDIAN, SDL_BIG_ENDIAN);
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')]).communicate()
- self.assertContained('1234, 1234, 4321\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_link_memcpy(self):
- # memcpy can show up *after* optimizations, so after our opportunity to link in libc, so it must be special-cased
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
-
- int main(int argc, char **argv) {
- int num = argc + 10;
- char buf[num], buf2[num];
- for (int i = 0; i < num; i++) {
- buf[i] = i*i+i/3;
- }
- for (int i = 1; i < num; i++) {
- buf[i] += buf[i-1];
- }
- for (int i = 0; i < num; i++) {
- buf2[i] = buf[i];
- }
- for (int i = 1; i < num; i++) {
- buf2[i] += buf2[i-1];
- }
- for (int i = 0; i < num; i++) {
- printf("%d:%d\n", i, buf2[i]);
- }
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'main.cpp')]).communicate()
- output = run_js(os.path.join(self.get_dir(), 'a.out.js'), full_output=True, stderr=PIPE)
- self.assertContained('''0:0
-1:1
-2:6
-3:21
-4:53
-5:111
-6:-49
-7:98
-8:55
-9:96
-10:-16
-''', output)
- self.assertNotContained('warning: library.js memcpy should not be running, it is only for testing!', output)
-
- def test_warn_undefined(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
-
- extern "C" {
- void something();
- }
-
- int main() {
- something();
- return 0;
- }
- ''')
-
- def clear(): try_delete('a.out.js')
-
- for args in [[], ['-O2']]:
- clear()
- print 'warn', args
- output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'WARN_ON_UNDEFINED_SYMBOLS=1'] + args, stderr=PIPE).communicate()
- self.assertContained('unresolved symbol: something', output[1])
-
- clear()
- output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + args, stderr=PIPE).communicate()
- self.assertNotContained('unresolved symbol: something\n', output[1])
-
- for args in [[], ['-O2']]:
- clear()
- print 'error', args
- output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] + args, stderr=PIPE).communicate()
- self.assertContained('unresolved symbol: something', output[1])
- assert not os.path.exists('a.out.js')
-
- clear()
- output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + args, stderr=PIPE).communicate()
- self.assertNotContained('unresolved symbol: something\n', output[1])
- assert os.path.exists('a.out.js')
-
- def test_toobig(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
-
- #define BYTES 100*1024*1024
-
- int main(int argc, char **argv) {
- if (argc == 100) {
- static char buf[BYTES];
- static char buf2[BYTES];
- for (int i = 0; i < BYTES; i++) {
- buf[i] = i*i;
- buf2[i] = i/3;
- }
- for (int i = 0; i < BYTES; i++) {
- buf[i] = buf2[i/2];
- buf2[i] = buf[i/3];
- }
- printf("%d\n", buf[10] + buf2[20]);
- }
- return 0;
- }
- ''')
- output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate()[1]
- assert 'Emscripten failed' in output, output
- assert 'warning: very large fixed-size structural type' in output, output
-
- def test_prepost(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- #include <stdio.h>
- int main() {
- printf("hello from main\\n");
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- var Module = {
- preRun: function() { Module.print('pre-run') },
- postRun: function() { Module.print('post-run') }
- };
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js']).communicate()
- self.assertContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- # never run, so no preRun or postRun
- src = open(os.path.join(self.get_dir(), 'a.out.js')).read().replace('// {{PRE_RUN_ADDITIONS}}', 'addRunDependency()')
- open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src)
- self.assertNotContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- # noInitialRun prevents run
- for no_initial_run, run_dep in [(0, 0), (1, 0), (0, 1)]:
- print no_initial_run, run_dep
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')]).communicate()
- src = 'var Module = { noInitialRun: %d };\n' % no_initial_run + open(os.path.join(self.get_dir(), 'a.out.js')).read()
- if run_dep:
- src = src.replace('// {{PRE_RUN_ADDITIONS}}', '// {{PRE_RUN_ADDITIONS}}\naddRunDependency("test");') \
- .replace('// {{POST_RUN_ADDITIONS}}', '// {{POST_RUN_ADDITIONS}}\nremoveRunDependency("test");')
- open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src)
- assert ('hello from main' in run_js(os.path.join(self.get_dir(), 'a.out.js'))) != no_initial_run, 'only run if no noInitialRun'
-
- if no_initial_run:
- # Calling main later should still work, filesystem etc. must be set up.
- print 'call main later'
- src = open(os.path.join(self.get_dir(), 'a.out.js')).read() + '\nModule.callMain();\n';
- open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src)
- assert 'hello from main' in run_js(os.path.join(self.get_dir(), 'a.out.js')), 'main should print when called manually'
-
- # Use postInit
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- var Module = {
- preRun: function() { Module.print('pre-run') },
- postRun: function() { Module.print('post-run') },
- preInit: function() { Module.print('pre-init') }
- };
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js']).communicate()
- self.assertContained('pre-init\npre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_prepost2(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- #include <stdio.h>
- int main() {
- printf("hello from main\\n");
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- var Module = {
- preRun: function() { Module.print('pre-run') },
- };
- ''')
- open(os.path.join(self.get_dir(), 'pre2.js'), 'w').write('''
- Module.postRun = function() { Module.print('post-run') };
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate()
- self.assertContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_prepre(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- #include <stdio.h>
- int main() {
- printf("hello from main\\n");
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- var Module = {
- preRun: [function() { Module.print('pre-run') }],
- };
- ''')
- open(os.path.join(self.get_dir(), 'pre2.js'), 'w').write('''
- Module.preRun.push(function() { Module.print('prepre') });
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate()
- self.assertContained('prepre\npre-run\nhello from main\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
- def test_save_bc(self):
- for save in [0, 1]:
- self.clear()
- Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop_malloc.cpp')] + ([] if not save else ['--save-bc', self.in_dir('my_bitcode.bc')])).communicate()
- assert 'hello, world!' in run_js(self.in_dir('a.out.js'))
- assert os.path.exists(self.in_dir('my_bitcode.bc')) == save
- if save:
- try_delete('a.out.js')
- Building.llvm_dis(self.in_dir('my_bitcode.bc'), self.in_dir('my_ll.ll'))
- try:
- os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
- Popen([PYTHON, EMCC, 'my_ll.ll', '-o', 'two.js']).communicate()
- assert 'hello, world!' in run_js(self.in_dir('two.js'))
- finally:
- del os.environ['EMCC_LEAVE_INPUTS_RAW']
-
- def test_fix_closure(self):
- input = path_from_root('tests', 'test-fix-closure.js')
- expected = path_from_root('tests', 'test-fix-closure.out.js')
- Popen([PYTHON, path_from_root('tools', 'fix_closure.py'), input, 'out.js']).communicate(input)
- output = open('out.js').read()
- assert '0,zzz_Q_39fa,0' in output
- assert 'function(a,c)' not in output # should be uninlined, so it gets a name
- assert run_js(input) == run_js('out.js')
-
- def test_js_optimizer(self):
- for input, expected, passes in [
- (path_from_root('tools', 'test-js-optimizer.js'), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(),
- ['hoistMultiples', 'loopOptimizer', 'removeAssignsToUndefined', 'simplifyExpressions']),
- (path_from_root('tools', 'test-js-optimizer-t2c.js'), open(path_from_root('tools', 'test-js-optimizer-t2c-output.js')).read(),
- ['simplifyExpressions', 'optimizeShiftsConservative']),
- (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(),
- ['simplifyExpressions', 'optimizeShiftsAggressive']),
- # Make sure that optimizeShifts handles functions with shift statements.
- (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(),
- ['optimizeShiftsAggressive']),
- (path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(),
- ['registerize']),
- (path_from_root('tools', 'eliminator', 'eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read(),
- ['eliminate']),
- (path_from_root('tools', 'eliminator', 'safe-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'safe-eliminator-test-output.js')).read(),
- ['eliminateMemSafe']),
- (path_from_root('tools', 'eliminator', 'asm-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'asm-eliminator-test-output.js')).read(),
- ['asm', 'eliminate']),
- (path_from_root('tools', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-output.js')).read(),
- ['asm', 'registerize']),
- (path_from_root('tools', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-min-output.js')).read(),
- ['asm', 'registerize']),
- (path_from_root('tools', 'test-js-optimizer-asm-pre.js'), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output.js')).read(),
- ['asm', 'simplifyExpressions']),
- (path_from_root('tools', 'test-js-optimizer-asm-last.js'), open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(),
- ['asm', 'last']),
- (path_from_root('tools', 'test-js-optimizer-asm-relocate.js'), open(path_from_root('tools', 'test-js-optimizer-asm-relocate-output.js')).read(),
- ['asm', 'relocate']),
- (path_from_root('tools', 'test-js-optimizer-asm-outline1.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline1-output.js')).read(),
- ['asm', 'outline']),
- (path_from_root('tools', 'test-js-optimizer-asm-outline2.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline2-output.js')).read(),
- ['asm', 'outline']),
- (path_from_root('tools', 'test-js-optimizer-asm-outline3.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline3-output.js')).read(),
- ['asm', 'outline']),
- ]:
- print input
- output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0]
- self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n'))
-
- def test_m_mm(self):
- open(os.path.join(self.get_dir(), 'foo.c'), 'w').write('''#include <emscripten.h>''')
- for opt in ['M', 'MM']:
- output, err = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo.c'), '-' + opt], stdout=PIPE, stderr=PIPE).communicate()
- assert 'foo.o: ' in output, '-%s failed to produce the right output: %s' % (opt, output)
- assert 'error' not in err, 'Unexpected stderr: ' + err
-
- def test_chunking(self):
- if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
- if os.environ.get('EMCC_CORES'): return self.skip('cannot run if cores are altered')
- if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores')
- try:
- os.environ['EMCC_DEBUG'] = '1'
- os.environ['EMCC_CORES'] = '2'
- for asm, linkable, chunks, js_chunks in [
- (0, 0, 3, 2), (0, 1, 3, 4),
- (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] + (['-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)
- assert ok, err
- ok = False
- for c in range(js_chunks, js_chunks+2):
- ok = ok or ('splitting up js optimization into %d chunks' % c in err)
- assert ok, err
- finally:
- del os.environ['EMCC_DEBUG']
- del os.environ['EMCC_CORES']
-
- def test_debuginfo(self):
- if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
- try:
- os.environ['EMCC_DEBUG'] = '1'
- # llvm debug info is kept only when we can see it, which is without the js optimize, -O0. js debug info is lost by registerize in -O2, so - g disables it
- for args, expect_llvm, expect_js in [
- (['-O0'], True, True),
- (['-O0', '-g'], True, True),
- (['-O1'], False, True),
- (['-O1', '-g'], False, True),
- (['-O2'], False, False),
- (['-O2', '-g'], False, True),
- ]:
- print args, expect_llvm, expect_js
- output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
- assert expect_llvm == ('strip-debug' not in err)
- assert expect_js == ('registerize' not in err)
- finally:
- del os.environ['EMCC_DEBUG']
-
- def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1
- try_delete(os.path.join(self.get_dir(), 'test'))
- shutil.copytree(path_from_root('tests', 'scons'), os.path.join(self.get_dir(), 'test'))
- shutil.copytree(path_from_root('tools', 'scons', 'site_scons'), os.path.join(self.get_dir(), 'test', 'site_scons'))
- os.chdir(os.path.join(self.get_dir(), 'test'))
- Popen(['scons']).communicate()
- output = run_js('scons_integration.js')
- assert 'If you see this - the world is all right!' in output
-
- def test_embind(self):
- for args, fail in [
- ([], True), # without --bind, we fail
- (['--bind'], False),
- (['--bind', '-O1'], False),
- (['--bind', '-O2'], False),
- (['--bind', '-O1', '-s', 'ASM_JS=0'], False),
- (['--bind', '-O2', '-s', 'ASM_JS=0'], False)
- ]:
- print args, fail
- self.clear()
- try_delete(self.in_dir('a.out.js'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate()
- assert os.path.exists(self.in_dir('a.out.js')) == (not fail)
- if not fail:
- output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True)
- assert "FAIL" not in output, output
-
- def test_llvm_nativizer(self):
- try:
- Popen(['as', '--version'], stdout=PIPE, stderr=PIPE).communicate()
- except:
- return self.skip('no gnu as, cannot run nativizer')
-
- # avoid impure_ptr problems etc.
- shutil.copyfile(path_from_root('tests', 'files.cpp'), os.path.join(self.get_dir(), 'files.cpp'))
- open(os.path.join(self.get_dir(), 'somefile.binary'), 'w').write('''waka waka############################''')
- open(os.path.join(self.get_dir(), 'test.file'), 'w').write('''ay file..............,,,,,,,,,,,,,,''')
- open(os.path.join(self.get_dir(), 'stdin'), 'w').write('''inter-active''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'files.cpp'), '-c']).communicate()
- Popen([PYTHON, path_from_root('tools', 'nativize_llvm.py'), os.path.join(self.get_dir(), 'files.o')], stdout=PIPE, stderr=PIPE).communicate(input)
- output = Popen([os.path.join(self.get_dir(), 'files.o.run')], stdin=open(os.path.join(self.get_dir(), 'stdin')), stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('''size: 37
-data: 119,97,107,97,32,119,97,107,97,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35
-loop: 119 97 107 97 32 119 97 107 97 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
-input:inter-active
-texto
-$
-5 : 10,30,20,11,88
-other=ay file...
-seeked= file.
-''', output[0])
- self.assertIdentical('texte\n', output[1])
-
- def test_emconfig(self):
- output = Popen([PYTHON, EMCONFIG, 'LLVM_ROOT'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
- try:
- assert output == LLVM_ROOT
- except:
- print >> sys.stderr, 'Assertion failed: python %s LLVM_ROOT returned "%s" instead of expected "%s"!' % (EMCONFIG, output, LLVM_ROOT)
- raise
- invalid = 'Usage: em-config VAR_NAME'
- # Don't accept variables that do not exist
- output = Popen([PYTHON, EMCONFIG, 'VAR_WHICH_DOES_NOT_EXIST'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
- assert output == invalid
- # Don't accept no arguments
- output = Popen([PYTHON, EMCONFIG], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
- assert output == invalid
- # Don't accept more than one variable
- output = Popen([PYTHON, EMCONFIG, 'LLVM_ROOT', 'EMCC'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
- assert output == invalid
- # Don't accept arbitrary python code
- output = Popen([PYTHON, EMCONFIG, 'sys.argv[1]'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
- assert output == invalid
-
- def test_link_s(self):
- # -s OPT=VALUE can conflict with -s as a linker option. We warn and ignore
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- extern "C" {
- void something();
- }
-
- int main() {
- something();
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'supp.cpp'), 'w').write(r'''
- #include <stdio.h>
-
- extern "C" {
- void something() {
- printf("yello\n");
- }
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'main.o']).communicate()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'supp.cpp'), '-o', 'supp.o']).communicate()
-
- output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o'), '-s', os.path.join(self.get_dir(), 'supp.o'), '-s', 'SAFE_HEAP=1'], stderr=PIPE).communicate()
- self.assertContained('treating -s as linker option', output[1])
- output = run_js('a.out.js')
- assert 'yello' in output, 'code works'
- code = open('a.out.js').read()
- assert 'SAFE_HEAP' in code, 'valid -s option had an effect'
-
- def test_jcache_printf(self):
- open(self.in_dir('src.cpp'), 'w').write(r'''
- #include <stdio.h>
- #include <stdint.h>
- #include <emscripten.h>
- int main() {
- emscripten_jcache_printf("hello world\n");
- emscripten_jcache_printf("hello %d world\n", 5);
- emscripten_jcache_printf("hello %.3f world\n", 123.456789123);
- emscripten_jcache_printf("hello %llx world\n", 0x1234567811223344ULL);
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, self.in_dir('src.cpp')]).communicate()
- output = run_js('a.out.js')
- self.assertIdentical('hello world\nhello 5 world\nhello 123.457 world\nhello 1234567811223300 world\n', output)
-
- def test_conftest_s_flag_passing(self):
- open(os.path.join(self.get_dir(), 'conftest.c'), 'w').write(r'''
- int main() {
- return 0;
- }
- ''')
- os.environ["EMMAKEN_JUST_CONFIGURE"] = "1"
- cmd = [PYTHON, EMCC, '-s', 'ASSERTIONS=1', os.path.join(self.get_dir(), 'conftest.c'), '-o', 'conftest']
- output = Popen(cmd, stderr=PIPE).communicate()
- del os.environ["EMMAKEN_JUST_CONFIGURE"]
- self.assertNotContained('emcc: warning: treating -s as linker option', output[1])
- assert os.path.exists('conftest')
-
- def test_file_packager(self):
- try:
- os.mkdir('subdir')
- except:
- pass
- open('data1.txt', 'w').write('data1')
- os.chdir('subdir')
- open('data2.txt', 'w').write('data2')
- # relative path to below the current dir is invalid
- out, err = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', '../data1.txt'], stdout=PIPE, stderr=PIPE).communicate()
- assert len(out) == 0
- assert 'below the current directory' in err
- # relative path that ends up under us is cool
- out, err = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', '../subdir/data2.txt'], stdout=PIPE, stderr=PIPE).communicate()
- assert len(out) > 0
- assert 'below the current directory' not in err
- # direct path leads to the same code being generated - relative path does not make us do anything different
- out2, err2 = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', 'data2.txt'], stdout=PIPE, stderr=PIPE).communicate()
- assert len(out2) > 0
- assert 'below the current directory' not in err2
- def clean(txt):
- return filter(lambda line: 'PACKAGE_UUID' not in line, txt.split('\n'))
- out = clean(out)
- out2 = clean(out2)
- assert out == out2
- # sanity check that we do generate different code for different inputs
- out3, err3 = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', 'data2.txt', 'data2.txt@waka.txt'], stdout=PIPE, stderr=PIPE).communicate()
- out3 = clean(out3)
- assert out != out3
-
- def test_crunch(self):
- # crunch should not be run if a .crn exists that is more recent than the .dds
- shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds')
- time.sleep(0.1)
- Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate()
- assert os.stat('test.data').st_size < 0.25*os.stat('ship.dds').st_size, 'Compressed should be much smaller than dds'
- crunch_time = os.stat('ship.crn').st_mtime
- dds_time = os.stat('ship.dds').st_mtime
- assert crunch_time > dds_time, 'Crunch is more recent'
- # run again, should not recrunch!
- time.sleep(0.1)
- Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate()
- assert crunch_time == os.stat('ship.crn').st_mtime, 'Crunch is unchanged'
- # update dds, so should recrunch
- time.sleep(0.1)
- os.utime('ship.dds', None)
- Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate()
- assert crunch_time < os.stat('ship.crn').st_mtime, 'Crunch was changed'
-
- def test_headless(self):
- if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations (Uint8ClampedArray etc.)')
-
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'example.png'))
- Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_canvas.c'), '-s', 'HEADLESS=1']).communicate()
- output = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, stderr=PIPE)
- assert '''Init: 0
-Font: 0x1
-Sum: 0
-you should see two lines of text in different colors and a blue rectangle
-SDL_Quit called (and ignored)
-done.
-''' in output, output
-
-elif 'browser' in str(sys.argv):
- # Browser tests.
-
- ''' Enable this code to run in another browser than webbrowser detects as default
- def run_in_other_browser(url):
- execute(['yourbrowser', url])
- webbrowser.open_new = run_in_other_browser
- '''
-
- print
- print 'Running the browser tests. Make sure the browser allows popups from localhost.'
- print
-
- if 'audio' in sys.argv:
- print
- print 'Running the browser audio tests. Make sure to listen to hear the correct results!'
- print
-
- i = sys.argv.index('audio')
- sys.argv = sys.argv[:i] + sys.argv[i+1:]
- i = sys.argv.index('browser')
- sys.argv = sys.argv[:i] + sys.argv[i+1:]
- sys.argv += [
- 'browser.test_sdl_audio',
- 'browser.test_sdl_audio_mix_channels',
- 'browser.test_sdl_audio_mix',
- 'browser.test_sdl_audio_quickload',
- 'browser.test_openal_playback',
- 'browser.test_openal_buffers',
- 'browser.test_freealut'
- ]
-
- # Run a server and a web page. When a test runs, we tell the server about it,
- # which tells the web page, which then opens a window with the test. Doing
- # it this way then allows the page to close() itself when done.
-
- def harness_server_func(q):
- class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def do_GET(s):
- s.send_response(200)
- s.send_header("Content-type", "text/html")
- s.end_headers()
- if s.path == '/run_harness':
- s.wfile.write(open(path_from_root('tests', 'browser_harness.html')).read())
- else:
- result = 'False'
- if not q.empty():
- result = q.get()
- s.wfile.write(result)
- s.wfile.close()
- def log_request(code=0, size=0):
- # don't log; too noisy
- pass
- httpd = BaseHTTPServer.HTTPServer(('localhost', 9999), TestServerHandler)
- httpd.serve_forever() # test runner will kill us
-
- def server_func(dir, q):
- class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def do_GET(s):
- if 'report_' in s.path:
- q.put(s.path)
- else:
- filename = s.path[1:]
- if os.path.exists(filename):
- s.send_response(200)
- s.send_header("Content-type", "text/html")
- s.end_headers()
- s.wfile.write(open(filename).read())
- s.wfile.close()
- else:
- s.send_response(500)
- s.send_header("Content-type", "text/html")
- s.end_headers()
- def log_request(code=0, size=0):
- # don't log; too noisy
- pass
- os.chdir(dir)
- httpd = BaseHTTPServer.HTTPServer(('localhost', 8888), TestServerHandler)
- httpd.serve_forever() # test runner will kill us
-
- class browser(RunnerCore):
- def __init__(self, *args, **kwargs):
- super(browser, self).__init__(*args, **kwargs)
-
- if hasattr(browser, 'harness_server'): return
- browser.harness_queue = multiprocessing.Queue()
- browser.harness_server = multiprocessing.Process(target=harness_server_func, args=(browser.harness_queue,))
- browser.harness_server.start()
- print '[Browser harness server on process %d]' % browser.harness_server.pid
- webbrowser.open_new('http://localhost:9999/run_harness')
-
- @classmethod
- def tearDownClass(cls):
- if not hasattr(browser, 'harness_server'): return
-
- browser.harness_server.terminate()
- delattr(browser, 'harness_server')
- print '[Browser harness server terminated]'
- # On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit:
- # WindowsError: [Error 32] The process cannot access the file because it is being used by another process.
- time.sleep(0.1)
-
- def run_browser(self, html_file, message, expectedResult=None):
- if expectedResult is not None:
- try:
- queue = multiprocessing.Queue()
- server = multiprocessing.Process(target=functools.partial(server_func, self.get_dir()), args=(queue,))
- server.start()
- browser.harness_queue.put('http://localhost:8888/' + html_file)
- output = '[no http server activity]'
- start = time.time()
- while time.time() - start < 60:
- if not queue.empty():
- output = queue.get()
- break
- time.sleep(0.1)
-
- self.assertIdentical(expectedResult, output)
- finally:
- server.terminate()
- time.sleep(0.1) # see comment about Windows above
- else:
- webbrowser.open_new(os.path.abspath(html_file))
- print 'A web browser window should have opened a page containing the results of a part of this test.'
- print 'You need to manually look at the page to see that it works ok: ' + message
- print '(sleeping for a bit to keep the directory alive for the web browser..)'
- time.sleep(5)
- print '(moving on..)'
-
- def with_report_result(self, code):
- return r'''
- #if EMSCRIPTEN
- #include <emscripten.h>
- #define REPORT_RESULT_INTERNAL(sync) \
- char output[1000]; \
- sprintf(output, \
- "xhr = new XMLHttpRequest();" \
- "xhr.open('GET', 'http://localhost:8888/report_result?%d'%s);" \
- "xhr.send();", result, sync ? ", false" : ""); \
- emscripten_run_script(output); \
- emscripten_run_script("setTimeout(function() { window.close() }, 1000)"); // comment this out to keep the test runner window open to debug
- #define REPORT_RESULT() REPORT_RESULT_INTERNAL(0)
- #endif
-''' + code
-
- def reftest(self, expected):
- # make sure the pngs used here have no color correction, using e.g.
- # pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile outfile
- basename = os.path.basename(expected)
- shutil.copyfile(expected, os.path.join(self.get_dir(), basename))
- open(os.path.join(self.get_dir(), 'reftest.js'), 'w').write('''
- var Module = eval('Module');
- function doReftest() {
- if (doReftest.done) return;
- doReftest.done = true;
- var img = new Image();
- img.onload = function() {
- assert(img.width == Module.canvas.width, 'Invalid width: ' + Module.canvas.width + ', should be ' + img.width);
- assert(img.height == Module.canvas.height, 'Invalid height: ' + Module.canvas.height + ', should be ' + img.height);
-
- var canvas = document.createElement('canvas');
- canvas.width = img.width;
- canvas.height = img.height;
- var ctx = canvas.getContext('2d');
- ctx.drawImage(img, 0, 0);
- var expected = ctx.getImageData(0, 0, img.width, img.height).data;
-
- var actualUrl = Module.canvas.toDataURL();
- var actualImage = new Image();
- actualImage.onload = function() {
- /*
- document.body.appendChild(img); // for comparisons
- var div = document.createElement('div');
- div.innerHTML = '^=expected, v=actual';
- document.body.appendChild(div);
- document.body.appendChild(actualImage); // to grab it for creating the test reference
- */
-
- var actualCanvas = document.createElement('canvas');
- actualCanvas.width = actualImage.width;
- actualCanvas.height = actualImage.height;
- var actualCtx = actualCanvas.getContext('2d');
- actualCtx.drawImage(actualImage, 0, 0);
- var actual = actualCtx.getImageData(0, 0, actualImage.width, actualImage.height).data;
-
- var total = 0;
- var width = img.width;
- var height = img.height;
- for (var x = 0; x < width; x++) {
- for (var y = 0; y < height; y++) {
- total += Math.abs(expected[y*width*4 + x*4 + 0] - actual[y*width*4 + x*4 + 0]);
- total += Math.abs(expected[y*width*4 + x*4 + 1] - actual[y*width*4 + x*4 + 1]);
- total += Math.abs(expected[y*width*4 + x*4 + 2] - actual[y*width*4 + x*4 + 2]);
- }
- }
- var wrong = Math.floor(total / (img.width*img.height*3)); // floor, to allow some margin of error for antialiasing
-
- xhr = new XMLHttpRequest();
- xhr.open('GET', 'http://localhost:8888/report_result?' + wrong);
- xhr.send();
- setTimeout(function() { window.close() }, 1000);
- };
- actualImage.src = actualUrl;
- }
- img.src = '%s';
- };
- Module['postRun'] = doReftest;
- Module['preRun'].push(function() {
- setTimeout(doReftest, 1000); // if run() throws an exception and postRun is not called, this will kick in
- });
+ img.src = '%s';
+ };
+ Module['postRun'] = doReftest;
+ Module['preRun'].push(function() {
+ setTimeout(doReftest, 1000); // if run() throws an exception and postRun is not called, this will kick in
+ });
''' % basename)
- def test_html(self):
- # test HTML generation.
- self.btest('hello_world_sdl.cpp', reference='htmltest.png',
- message='You should see "hello, world!" and a colored cube.')
-
- def test_html_source_map(self):
- if 'test_html_source_map' not in str(sys.argv): return self.skip('''This test
- requires manual intervention; will not be run unless explicitly requested''')
- cpp_file = os.path.join(self.get_dir(), 'src.cpp')
- html_file = os.path.join(self.get_dir(), 'src.html')
- # browsers will try to 'guess' the corresponding original line if a
- # generated line is unmapped, so if we want to make sure that our
- # numbering is correct, we need to provide a couple of 'possible wrong
- # answers'. thus, we add some printf calls so that the cpp file gets
- # multiple mapped lines. in other words, if the program consists of a
- # single 'throw' statement, browsers may just map any thrown exception to
- # that line, because it will be the only mapped line.
- with open(cpp_file, 'w') as f:
- f.write(r'''
- #include <cstdio>
-
- int main() {
- printf("Starting test\n");
- try {
- throw 42; // line 8
- } catch (int e) { }
- printf("done\n");
- return 0;
- }
- ''')
- # use relative paths when calling emcc, because file:// URIs can only load
- # sourceContent when the maps are relative paths
- Popen([PYTHON, EMCC, 'src.cpp', '-o', 'src.html', '-g4'],
- cwd=self.get_dir()).communicate()
- webbrowser.open_new('file://' + html_file)
- print '''
-Set the debugger to pause on exceptions
-You should see an exception thrown at src.cpp:7.
-Press any key to continue.'''
- raw_input()
-
- def build_native_lzma(self):
- lzma_native = path_from_root('third_party', 'lzma.js', 'lzma-native')
- if os.path.isfile(lzma_native) and os.access(lzma_native, os.X_OK): return
-
- cwd = os.getcwd()
- try:
- os.chdir(path_from_root('third_party', 'lzma.js'))
- Popen(['sh', './doit.sh']).communicate()
- finally:
- os.chdir(cwd)
-
- def test_split(self):
- # test HTML generation.
- self.reftest(path_from_root('tests', 'htmltest.png'))
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '--split', '100', '--pre-js', 'reftest.js']).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something_functions.js')), 'must be functions js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
-
- open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
-
- <!doctype html>
- <html lang="en-us">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>Emscripten-Generated Code</title>
- <style>
- .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
- canvas.emscripten { border: 1px solid black; }
- textarea.emscripten { font-family: monospace; width: 80%; }
- div.emscripten { text-align: center; }
- </style>
- </head>
- <body>
- <hr/>
- <div class="emscripten" id="status">Downloading...</div>
- <div class="emscripten">
- <progress value="0" max="100" id="progress" hidden=1></progress>
- </div>
- <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
- <hr/>
- <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
- <hr/>
- <textarea class="emscripten" id="output" rows="8"></textarea>
- <hr>
- <script type='text/javascript'>
- // connect to canvas
- var Module = {
- preRun: [],
- postRun: [],
- print: (function() {
- var element = document.getElementById('output');
- element.value = ''; // clear browser cache
- return function(text) {
- // These replacements are necessary if you render to raw HTML
- //text = text.replace(/&/g, "&amp;");
- //text = text.replace(/</g, "&lt;");
- //text = text.replace(/>/g, "&gt;");
- //text = text.replace('\\n', '<br>', 'g');
- element.value += text + "\\n";
- element.scrollTop = 99999; // focus on bottom
- };
- })(),
- printErr: function(text) {
- if (0) { // XXX disabled for safety typeof dump == 'function') {
- dump(text + '\\n'); // fast, straight to the real console
- } else {
- console.log(text);
- }
- },
- canvas: document.getElementById('canvas'),
- setStatus: function(text) {
- if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var statusElement = document.getElementById('status');
- var progressElement = document.getElementById('progress');
- if (m) {
- text = m[1];
- progressElement.value = parseInt(m[2])*100;
- progressElement.max = parseInt(m[4])*100;
- progressElement.hidden = false;
- } else {
- progressElement.value = null;
- progressElement.max = null;
- progressElement.hidden = true;
- }
- statusElement.innerHTML = text;
- },
- totalDependencies: 0,
- monitorRunDependencies: function(left) {
- this.totalDependencies = Math.max(this.totalDependencies, left);
- Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
- }
- };
- Module.setStatus('Downloading...');
- </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
- </body>
- </html>
- ''')
-
- self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
-
- def test_split_in_source_filenames(self):
- self.reftest(path_from_root('tests', 'htmltest.png'))
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '-g', '--split', '100', '--pre-js', 'reftest.js']).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
- assert os.path.exists(self.get_dir() + '/something/' + path_from_root('tests', 'hello_world_sdl.cpp.js')), 'must be functions js file'
- assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
-
- open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
-
- <!doctype html>
- <html lang="en-us">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>Emscripten-Generated Code</title>
- <style>
- .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
- canvas.emscripten { border: 1px solid black; }
- textarea.emscripten { font-family: monospace; width: 80%; }
- div.emscripten { text-align: center; }
- </style>
- </head>
- <body>
- <hr/>
- <div class="emscripten" id="status">Downloading...</div>
- <div class="emscripten">
- <progress value="0" max="100" id="progress" hidden=1></progress>
- </div>
- <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
- <hr/>
- <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
- <hr/>
- <textarea class="emscripten" id="output" rows="8"></textarea>
- <hr>
- <script type='text/javascript'>
- // connect to canvas
- var Module = {
- preRun: [],
- postRun: [],
- print: (function() {
- var element = document.getElementById('output');
- element.value = ''; // clear browser cache
- return function(text) {
- // These replacements are necessary if you render to raw HTML
- //text = text.replace(/&/g, "&amp;");
- //text = text.replace(/</g, "&lt;");
- //text = text.replace(/>/g, "&gt;");
- //text = text.replace('\\n', '<br>', 'g');
- element.value += text + "\\n";
- element.scrollTop = 99999; // focus on bottom
- };
- })(),
- printErr: function(text) {
- if (0) { // XXX disabled for safety typeof dump == 'function') {
- dump(text + '\\n'); // fast, straight to the real console
- } else {
- console.log(text);
- }
- },
- canvas: document.getElementById('canvas'),
- setStatus: function(text) {
- if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var statusElement = document.getElementById('status');
- var progressElement = document.getElementById('progress');
- if (m) {
- text = m[1];
- progressElement.value = parseInt(m[2])*100;
- progressElement.max = parseInt(m[4])*100;
- progressElement.hidden = false;
- } else {
- progressElement.value = null;
- progressElement.max = null;
- progressElement.hidden = true;
- }
- statusElement.innerHTML = text;
- },
- totalDependencies: 0,
- monitorRunDependencies: function(left) {
- this.totalDependencies = Math.max(this.totalDependencies, left);
- Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
- }
- };
- Module.setStatus('Downloading...');
- </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
- </body>
- </html>
- ''')
-
- self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
-
- def test_compression(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
- #include <stdio.h>
- #include <emscripten.h>
- int main() {
- printf("hello compressed world\n");
- int result = 1;
- REPORT_RESULT();
- return 0;
- }
- '''))
-
- self.build_native_lzma()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'page.html',
- '--compression', '%s,%s,%s' % (path_from_root('third_party', 'lzma.js', 'lzma-native'),
- path_from_root('third_party', 'lzma.js', 'lzma-decoder.js'),
- 'LZMA.decompress')]).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'page.js')), 'must be side js'
- assert os.path.exists(os.path.join(self.get_dir(), 'page.js.compress')), 'must be side compressed js'
- assert os.stat(os.path.join(self.get_dir(), 'page.js')).st_size > os.stat(os.path.join(self.get_dir(), 'page.js.compress')).st_size, 'compressed file must be smaller'
- shutil.move(os.path.join(self.get_dir(), 'page.js'), 'page.js.renamedsoitcannotbefound');
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_preload_file(self):
- absolute_src_path = os.path.join(self.get_dir(), 'somefile.txt').replace('\\', '/')
- open(absolute_src_path, 'w').write('''load me right before running the code please''')
-
- absolute_src_path2 = os.path.join(self.get_dir(), '.somefile.txt').replace('\\', '/')
- open(absolute_src_path2, 'w').write('''load me right before running the code please''')
-
- def make_main(path):
- print 'make main at', path
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
- #include <stdio.h>
- #include <string.h>
- #include <emscripten.h>
- int main() {
- FILE *f = fopen("%s", "r");
- char buf[100];
- fread(buf, 1, 20, f);
- buf[20] = 0;
- fclose(f);
- printf("|%%s|\n", buf);
-
- int result = !strcmp("load me right before", buf);
- REPORT_RESULT();
- return 0;
- }
- ''' % path))
-
- test_cases = [
- # (source preload-file string, file on target FS to load)
- ("somefile.txt", "somefile.txt"),
- (".somefile.txt@somefile.txt", "somefile.txt"),
- ("./somefile.txt", "somefile.txt"),
- ("somefile.txt@file.txt", "file.txt"),
- ("./somefile.txt@file.txt", "file.txt"),
- ("./somefile.txt@./file.txt", "file.txt"),
- ("somefile.txt@/file.txt", "file.txt"),
- ("somefile.txt@/", "somefile.txt"),
- (absolute_src_path + "@file.txt", "file.txt"),
- (absolute_src_path + "@/file.txt", "file.txt"),
- (absolute_src_path + "@/", "somefile.txt"),
- ("somefile.txt@/directory/file.txt", "/directory/file.txt"),
- ("somefile.txt@/directory/file.txt", "directory/file.txt"),
- (absolute_src_path + "@/directory/file.txt", "directory/file.txt")]
-
- for test in test_cases:
- (srcpath, dstpath) = test
- print 'Testing', srcpath, dstpath
- make_main(dstpath)
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', srcpath, '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
-
- # By absolute path
-
- make_main('somefile.txt') # absolute becomes relative
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', absolute_src_path, '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
-
- # Test subdirectory handling with asset packaging.
- os.makedirs(os.path.join(self.get_dir(), 'assets/sub/asset1/').replace('\\', '/'))
- os.makedirs(os.path.join(self.get_dir(), 'assets/sub/asset1/.git').replace('\\', '/')) # Test adding directory that shouldn't exist.
- os.makedirs(os.path.join(self.get_dir(), 'assets/sub/asset2/').replace('\\', '/'))
- open(os.path.join(self.get_dir(), 'assets/sub/asset1/file1.txt'), 'w').write('''load me right before running the code please''')
- open(os.path.join(self.get_dir(), 'assets/sub/asset1/.git/shouldnt_be_embedded.txt'), 'w').write('''this file should not get embedded''')
- open(os.path.join(self.get_dir(), 'assets/sub/asset2/file2.txt'), 'w').write('''load me right before running the code please''')
- absolute_assets_src_path = os.path.join(self.get_dir(), 'assets').replace('\\', '/')
- def make_main_two_files(path1, path2, nonexistingpath):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
- #include <stdio.h>
- #include <string.h>
- #include <emscripten.h>
- int main() {
- FILE *f = fopen("%s", "r");
- char buf[100];
- fread(buf, 1, 20, f);
- buf[20] = 0;
- fclose(f);
- printf("|%%s|\n", buf);
-
- int result = !strcmp("load me right before", buf);
-
- f = fopen("%s", "r");
- if (f == NULL)
- result = 0;
- fclose(f);
-
- f = fopen("%s", "r");
- if (f != NULL)
- result = 0;
-
- REPORT_RESULT();
- return 0;
- }
- ''' % (path1, path2, nonexistingpath)))
-
- test_cases = [
- # (source directory to embed, file1 on target FS to load, file2 on target FS to load, name of a file that *shouldn't* exist on VFS)
- ("assets", "assets/sub/asset1/file1.txt", "assets/sub/asset2/file2.txt", "assets/sub/asset1/.git/shouldnt_be_embedded.txt"),
- ("assets/", "assets/sub/asset1/file1.txt", "assets/sub/asset2/file2.txt", "assets/sub/asset1/.git/shouldnt_be_embedded.txt"),
- ("assets@/", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
- ("assets/@/", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
- ("assets@./", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
- (absolute_assets_src_path + "@/", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
- (absolute_assets_src_path + "@/assets", "/assets/sub/asset1/file1.txt", "/assets/sub/asset2/file2.txt", "assets/sub/asset1/.git/shouldnt_be_embedded.txt")]
-
- for test in test_cases:
- (srcpath, dstpath1, dstpath2, nonexistingpath) = test
- make_main_two_files(dstpath1, dstpath2, nonexistingpath)
- print srcpath
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', srcpath, '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
-
- # Should still work with -o subdir/..
-
- make_main('somefile.txt') # absolute becomes relative
- try:
- os.mkdir(os.path.join(self.get_dir(), 'dirrey'))
- except:
- pass
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', absolute_src_path, '-o', 'dirrey/page.html']).communicate()
- self.run_browser('dirrey/page.html', 'You should see |load me right before|.', '/report_result?1')
-
- # With FS.preloadFile
-
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- Module.preRun = function() {
- FS.createPreloadedFile('/', 'someotherfile.txt', 'somefile.txt', true, false);
- };
- ''')
- make_main('someotherfile.txt')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
-
- def test_preload_caching(self):
- open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''load me right before running the code please''')
- def make_main(path):
- print path
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
- #include <stdio.h>
- #include <string.h>
- #include <emscripten.h>
-
- extern "C" {
- extern int checkPreloadResults();
- }
-
- int main(int argc, char** argv) {
- FILE *f = fopen("%s", "r");
- char buf[100];
- fread(buf, 1, 20, f);
- buf[20] = 0;
- fclose(f);
- printf("|%%s|\n", buf);
-
- int result = 0;
-
- result += !strcmp("load me right before", buf);
- result += checkPreloadResults();
-
- REPORT_RESULT();
- return 0;
- }
- ''' % path))
-
- open(os.path.join(self.get_dir(), 'test.js'), 'w').write('''
- mergeInto(LibraryManager.library, {
- checkPreloadResults: function() {
- var cached = 0;
- var packages = Object.keys(Module['preloadResults']);
- packages.forEach(function(package) {
- var fromCache = Module['preloadResults'][package]['fromCache'];
- if (fromCache)
- ++ cached;
- });
- return cached;
- }
- });
- ''')
-
- make_main('somefile.txt')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--use-preload-cache', '--js-library', os.path.join(self.get_dir(), 'test.js'), '--preload-file', 'somefile.txt', '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
- self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?2')
-
- def test_multifile(self):
- # a few files inside a directory
- self.clear()
- os.makedirs(os.path.join(self.get_dir(), 'subdirr'));
- os.makedirs(os.path.join(self.get_dir(), 'subdirr', 'moar'));
- open(os.path.join(self.get_dir(), 'subdirr', 'data1.txt'), 'w').write('''1214141516171819''')
- open(os.path.join(self.get_dir(), 'subdirr', 'moar', 'data2.txt'), 'w').write('''3.14159265358979''')
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
- #include <stdio.h>
- #include <string.h>
- #include <emscripten.h>
- int main() {
- char buf[17];
-
- FILE *f = fopen("subdirr/data1.txt", "r");
- fread(buf, 1, 16, f);
- buf[16] = 0;
- fclose(f);
- printf("|%s|\n", buf);
- int result = !strcmp("1214141516171819", buf);
-
- FILE *f2 = fopen("subdirr/moar/data2.txt", "r");
- fread(buf, 1, 16, f2);
- buf[16] = 0;
- fclose(f2);
- printf("|%s|\n", buf);
- result = result && !strcmp("3.14159265358979", buf);
-
- REPORT_RESULT();
- return 0;
- }
- '''))
-
- # by individual files
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', 'subdirr/data1.txt', '--preload-file', 'subdirr/moar/data2.txt', '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should see two cool numbers', '/report_result?1')
- os.remove('page.html')
-
- # by directory, and remove files to make sure
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', 'subdirr', '-o', 'page.html']).communicate()
- shutil.rmtree(os.path.join(self.get_dir(), 'subdirr'))
- self.run_browser('page.html', 'You should see two cool numbers', '/report_result?1')
-
- def test_compressed_file(self):
- open(os.path.join(self.get_dir(), 'datafile.txt'), 'w').write('compress this please' + (2000*'.'))
- open(os.path.join(self.get_dir(), 'datafile2.txt'), 'w').write('moar' + (100*'!'))
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
- #include <stdio.h>
- #include <string.h>
- #include <emscripten.h>
- int main() {
- char buf[21];
- FILE *f = fopen("datafile.txt", "r");
- fread(buf, 1, 20, f);
- buf[20] = 0;
- fclose(f);
- printf("file says: |%s|\n", buf);
- int result = !strcmp("compress this please", buf);
- FILE *f2 = fopen("datafile2.txt", "r");
- fread(buf, 1, 5, f2);
- buf[5] = 0;
- fclose(f2);
- result = result && !strcmp("moar!", buf);
- printf("file 2 says: |%s|\n", buf);
- REPORT_RESULT();
- return 0;
- }
- '''))
-
- self.build_native_lzma()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'page.html', '--preload-file', 'datafile.txt', '--preload-file', 'datafile2.txt',
- '--compression', '%s,%s,%s' % (path_from_root('third_party', 'lzma.js', 'lzma-native'),
- path_from_root('third_party', 'lzma.js', 'lzma-decoder.js'),
- 'LZMA.decompress')]).communicate()
- assert os.path.exists(os.path.join(self.get_dir(), 'datafile.txt')), 'must be data file'
- assert os.path.exists(os.path.join(self.get_dir(), 'page.data.compress')), 'must be data file in compressed form'
- assert os.stat(os.path.join(self.get_dir(), 'page.js')).st_size != os.stat(os.path.join(self.get_dir(), 'page.js.compress')).st_size, 'compressed file must be different'
- shutil.move(os.path.join(self.get_dir(), 'datafile.txt'), 'datafile.txt.renamedsoitcannotbefound');
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_image(self):
- # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init
- shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpg'))
- open(os.path.join(self.get_dir(), 'sdl_image.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read()))
-
- for mem in [0, 1]:
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-O2', '--preload-file', 'screenshot.jpg', '-o', 'page.html', '--memory-init-file', str(mem)]).communicate()
- self.run_browser('page.html', '', '/report_result?600')
-
- def test_sdl_image_jpeg(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpeg'))
- open(os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image_jpeg.c')).read()))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), '--preload-file', 'screenshot.jpeg', '-o', 'page.html']).communicate()
- self.run_browser('page.html', '', '/report_result?600')
-
- def test_sdl_image_compressed(self):
- for image, width in [(path_from_root('tests', 'screenshot2.png'), 300),
- (path_from_root('tests', 'screenshot.jpg'), 600)]:
- self.clear()
- print image
-
- basename = os.path.basename(image)
- shutil.copyfile(image, os.path.join(self.get_dir(), basename))
- open(os.path.join(self.get_dir(), 'sdl_image.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read()).replace('screenshot.jpg', basename))
-
- self.build_native_lzma()
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '--preload-file', basename, '-o', 'page.html',
- '--compression', '%s,%s,%s' % (path_from_root('third_party', 'lzma.js', 'lzma-native'),
- path_from_root('third_party', 'lzma.js', 'lzma-decoder.js'),
- 'LZMA.decompress')]).communicate()
- shutil.move(os.path.join(self.get_dir(), basename), basename + '.renamedsoitcannotbefound');
- self.run_browser('page.html', '', '/report_result?' + str(width))
-
- def test_sdl_image_prepare(self):
- # load an image file, get pixel data.
- shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
- self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
-
- def test_sdl_image_prepare_data(self):
- # load an image file, get pixel data.
- shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
- self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
-
- def test_sdl_stb_image(self):
- # load an image file, get pixel data.
- shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
- self.btest('sdl_stb_image.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not'])
-
- def test_sdl_stb_image_data(self):
- # load an image file, get pixel data.
- shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
- self.btest('sdl_stb_image_data.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not'])
-
- def test_sdl_canvas(self):
- open(os.path.join(self.get_dir(), 'sdl_canvas.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas.c')).read()))
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_key(self):
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- Module.postRun = function() {
- function doOne() {
- Module._one();
- setTimeout(doOne, 1000/60);
- }
- setTimeout(doOne, 1000/60);
- }
-
- function keydown(c) {
- var event = document.createEvent("KeyboardEvent");
- event.initKeyEvent("keydown", true, true, window,
- 0, 0, 0, 0,
- c, c);
- document.dispatchEvent(event);
- }
-
- function keyup(c) {
- var event = document.createEvent("KeyboardEvent");
- event.initKeyEvent("keyup", true, true, window,
- 0, 0, 0, 0,
- c, c);
- document.dispatchEvent(event);
- }
- ''')
- open(os.path.join(self.get_dir(), 'sdl_key.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_key.c')).read()))
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''']).communicate()
- self.run_browser('page.html', '', '/report_result?223092870')
-
- def test_sdl_text(self):
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- Module.postRun = function() {
- function doOne() {
- Module._one();
- setTimeout(doOne, 1000/60);
- }
- setTimeout(doOne, 1000/60);
- }
-
- function simulateKeyEvent(charCode) {
- var event = document.createEvent("KeyboardEvent");
- event.initKeyEvent("keypress", true, true, window,
- 0, 0, 0, 0, 0, charCode);
- document.body.dispatchEvent(event);
- }
- ''')
- open(os.path.join(self.get_dir(), 'sdl_text.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_text.c')).read()))
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_text.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_mouse(self):
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- function simulateMouseEvent(x, y, button) {
- var event = document.createEvent("MouseEvents");
- if (button >= 0) {
- var event1 = document.createEvent("MouseEvents");
- event1.initMouseEvent('mousedown', true, true, window,
- 1, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y,
- 0, 0, 0, 0,
- button, null);
- Module['canvas'].dispatchEvent(event1);
- var event2 = document.createEvent("MouseEvents");
- event2.initMouseEvent('mouseup', true, true, window,
- 1, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y,
- 0, 0, 0, 0,
- button, null);
- Module['canvas'].dispatchEvent(event2);
- } else {
- var event1 = document.createEvent("MouseEvents");
- event1.initMouseEvent('mousemove', true, true, window,
- 0, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y,
- 0, 0, 0, 0,
- 0, null);
- Module['canvas'].dispatchEvent(event1);
- }
- }
- window['simulateMouseEvent'] = simulateMouseEvent;
- ''')
- open(os.path.join(self.get_dir(), 'sdl_mouse.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_mouse.c')).read()))
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate()
- self.run_browser('page.html', '', '/report_result?740')
-
- def test_sdl_mouse_offsets(self):
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- function simulateMouseEvent(x, y, button) {
- var event = document.createEvent("MouseEvents");
- if (button >= 0) {
- var event1 = document.createEvent("MouseEvents");
- event1.initMouseEvent('mousedown', true, true, window,
- 1, x, y, x, y,
- 0, 0, 0, 0,
- button, null);
- Module['canvas'].dispatchEvent(event1);
- var event2 = document.createEvent("MouseEvents");
- event2.initMouseEvent('mouseup', true, true, window,
- 1, x, y, x, y,
- 0, 0, 0, 0,
- button, null);
- Module['canvas'].dispatchEvent(event2);
- } else {
- var event1 = document.createEvent("MouseEvents");
- event1.initMouseEvent('mousemove', true, true, window,
- 0, x, y, x, y,
- 0, 0, 0, 0,
- 0, null);
- Module['canvas'].dispatchEvent(event1);
- }
- }
- window['simulateMouseEvent'] = simulateMouseEvent;
- ''')
- open(os.path.join(self.get_dir(), 'page.html'), 'w').write('''
- <html>
- <head>
- <style type="text/css">
- html, body { margin: 0; padding: 0; }
- #container {
- position: absolute;
- left: 5px; right: 0;
- top: 5px; bottom: 0;
- }
- #canvas {
- position: absolute;
- left: 0; width: 600px;
- top: 0; height: 450px;
- }
- textarea {
- margin-top: 500px;
- margin-left: 5px;
- width: 600px;
- }
- </style>
- </head>
- <body>
- <div id="container">
- <canvas id="canvas"></canvas>
- </div>
- <textarea id="output" rows="8"></textarea>
- <script type="text/javascript">
- var Module = {
- canvas: document.getElementById('canvas'),
- print: (function() {
- var element = document.getElementById('output');
- element.value = ''; // clear browser cache
- return function(text) {
- text = Array.prototype.slice.call(arguments).join(' ');
- element.value += text + "\\n";
- element.scrollTop = 99999; // focus on bottom
- };
- })()
- };
- </script>
- <script type="text/javascript" src="sdl_mouse.js"></script>
- </body>
- </html>
- ''')
- open(os.path.join(self.get_dir(), 'sdl_mouse.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_mouse.c')).read()))
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js']).communicate()
- self.run_browser('page.html', '', '/report_result?600')
-
- def test_sdl_audio(self):
- shutil.copyfile(path_from_root('tests', 'sounds', 'alarmvictory_1.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
- shutil.copyfile(path_from_root('tests', 'sounds', 'alarmcreatemiltaryfoot_1.wav'), os.path.join(self.get_dir(), 'sound2.wav'))
- shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'noise.ogg'))
- shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'the_entertainer.ogg'))
- open(os.path.join(self.get_dir(), 'bad.ogg'), 'w').write('I claim to be audio, but am lying')
- open(os.path.join(self.get_dir(), 'sdl_audio.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio.c')).read()))
-
- # use closure to check for a possible bug with closure minifying away newer Audio() attributes
- Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--embed-file', 'the_entertainer.ogg', '--preload-file', 'noise.ogg', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_audio_mix_channels(self):
- shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
- open(os.path.join(self.get_dir(), 'sdl_audio_mix_channels.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_mix_channels.c')).read()))
-
- Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_mix_channels.c'), '--preload-file', 'sound.ogg', '-o', 'page.html']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_audio_mix(self):
- shutil.copyfile(path_from_root('tests', 'sounds', 'pluck.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
- shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'music.ogg'))
- shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'noise.ogg'))
- open(os.path.join(self.get_dir(), 'sdl_audio_mix.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_mix.c')).read()))
-
- Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_mix.c'), '--preload-file', 'sound.ogg', '--preload-file', 'music.ogg', '--preload-file', 'noise.ogg', '-o', 'page.html']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_audio_quickload(self):
- open(os.path.join(self.get_dir(), 'sdl_audio_quickload.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_quickload.c')).read()))
-
- Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_quickload.c'), '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play"]']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_sdl_gl_read(self):
- # SDL, OpenGL, readPixels
- open(os.path.join(self.get_dir(), 'sdl_gl_read.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_gl_read.c')).read()))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_gl_read.c'), '-o', 'something.html']).communicate()
- self.run_browser('something.html', '.', '/report_result?1')
-
- def test_sdl_ogl(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_ogl.c', reference='screenshot-gray-purple.png', reference_slack=1,
- args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png'],
- message='You should see an image with gray at the top.')
-
- def test_sdl_ogl_defaultmatrixmode(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_ogl_defaultMatrixMode.c', reference='screenshot-gray-purple.png', reference_slack=1,
- args=['--minify', '0', '--preload-file', 'screenshot.png'],
- message='You should see an image with gray at the top.')
-
- def test_sdl_ogl_p(self):
- # Immediate mode with pointers
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_ogl_p.c', reference='screenshot-gray.png', reference_slack=1,
- args=['--preload-file', 'screenshot.png'],
- message='You should see an image with gray at the top.')
-
- def test_sdl_fog_simple(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_fog_simple.c', reference='screenshot-fog-simple.png',
- args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png'],
- message='You should see an image with fog.')
-
- def test_sdl_fog_negative(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_fog_negative.c', reference='screenshot-fog-negative.png',
- args=['--preload-file', 'screenshot.png'],
- message='You should see an image with fog.')
-
- def test_sdl_fog_density(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_fog_density.c', reference='screenshot-fog-density.png',
- args=['--preload-file', 'screenshot.png'],
- message='You should see an image with fog.')
-
- def test_sdl_fog_exp2(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_fog_exp2.c', reference='screenshot-fog-exp2.png',
- args=['--preload-file', 'screenshot.png'],
- message='You should see an image with fog.')
-
- def test_sdl_fog_linear(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_fog_linear.c', reference='screenshot-fog-linear.png', reference_slack=1,
- args=['--preload-file', 'screenshot.png'],
- message='You should see an image with fog.')
-
- def test_openal_playback(self):
- shutil.copyfile(path_from_root('tests', 'sounds', 'audio.wav'), os.path.join(self.get_dir(), 'audio.wav'))
- open(os.path.join(self.get_dir(), 'openal_playback.cpp'), 'w').write(self.with_report_result(open(path_from_root('tests', 'openal_playback.cpp')).read()))
-
- Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'openal_playback.cpp'), '--preload-file', 'audio.wav', '-o', 'page.html']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_openal_buffers(self):
- shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.wav'), os.path.join(self.get_dir(), 'the_entertainer.wav'))
- self.btest('openal_buffers.c', '0', args=['--preload-file', 'the_entertainer.wav'],)
-
- def test_glfw(self):
- open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read()))
-
- Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
-
- def test_egl_width_height(self):
- open(os.path.join(self.get_dir(), 'test_egl_width_height.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl_width_height.c')).read()))
-
- Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl_width_height.c'), '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'Should print "(300, 150)" -- the size of the canvas in pixels', '/report_result?1')
-
- def test_freealut(self):
- programs = self.get_library('freealut', os.path.join('examples', '.libs', 'hello_world.bc'), make_args=['EXEEXT=.bc'])
- for program in programs:
- assert os.path.exists(program)
- Popen([PYTHON, EMCC, '-O2', program, '-o', 'page.html']).communicate()
- self.run_browser('page.html', 'You should hear "Hello World!"')
-
- def test_worker(self):
- # Test running in a web worker
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'], stdout=PIPE, stderr=PIPE).communicate()
- assert len(output[0]) == 0, output[0]
- assert os.path.exists('worker.js'), output
- self.assertContained('you should not see this text when in a worker!', run_js('worker.js')) # code should run standalone
- html_file = open('main.html', 'w')
- html_file.write('''
- <html>
- <body>
- Worker Test
- <script>
- var worker = new Worker('worker.js');
- worker.onmessage = function(event) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', 'http://localhost:8888/report_result?' + event.data);
- xhr.send();
- setTimeout(function() { window.close() }, 1000);
- };
- </script>
- </body>
- </html>
- ''')
- html_file.close()
- self.run_browser('main.html', 'You should see that the worker was called, and said "hello from worker!"', '/report_result?hello%20from%20worker!')
-
- def test_chunked_synchronous_xhr(self):
- main = 'chunked_sync_xhr.html'
- worker_filename = "download_and_checksum_worker.js"
-
- html_file = open(main, 'w')
- html_file.write(r"""
- <!doctype html>
- <html>
- <head><meta charset="utf-8"><title>Chunked XHR</title></head>
- <html>
- <body>
- Chunked XHR Web Worker Test
- <script>
- var worker = new Worker(""" + json.dumps(worker_filename) + r""");
- var buffer = [];
- worker.onmessage = function(event) {
- if (event.data.channel === "stdout") {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', 'http://localhost:8888/report_result?' + event.data.line);
- xhr.send();
- setTimeout(function() { window.close() }, 1000);
- } else {
- if (event.data.trace) event.data.trace.split("\n").map(function(v) { console.error(v); });
- if (event.data.line) {
- console.error(event.data.line);
- } else {
- var v = event.data.char;
- if (v == 10) {
- var line = buffer.splice(0);
- console.error(line = line.map(function(charCode){return String.fromCharCode(charCode);}).join(''));
- } else {
- buffer.push(v);
- }
- }
- }
- };
- </script>
- </body>
- </html>
- """)
- html_file.close()
-
- c_source_filename = "checksummer.c"
-
- prejs_filename = "worker_prejs.js"
- prejs_file = open(prejs_filename, 'w')
- prejs_file.write(r"""
- if (typeof(Module) === "undefined") Module = {};
- Module["arguments"] = ["/bigfile"];
- Module["preInit"] = function() {
- FS.createLazyFile('/', "bigfile", "http://localhost:11111/bogus_file_path", true, false);
- };
- var doTrace = true;
- Module["print"] = function(s) { self.postMessage({channel: "stdout", line: s}); };
- Module["stderr"] = function(s) { self.postMessage({channel: "stderr", char: s, trace: ((doTrace && s === 10) ? new Error().stack : null)}); doTrace = false; };
- """)
- prejs_file.close()
- # vs. os.path.join(self.get_dir(), filename)
- # vs. path_from_root('tests', 'hello_world_gles.c')
- Popen([PYTHON, EMCC, path_from_root('tests', c_source_filename), '-g', '-s', 'SMALL_CHUNKS=1', '-o', worker_filename,
- '--pre-js', prejs_filename]).communicate()
-
- chunkSize = 1024
- data = os.urandom(10*chunkSize+1) # 10 full chunks and one 1 byte chunk
- expectedConns = 11
- import zlib
- checksum = zlib.adler32(data)
-
- def chunked_server(support_byte_ranges):
- class ChunkedServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- def sendheaders(s, extra=[], length=len(data)):
- s.send_response(200)
- s.send_header("Content-Length", str(length))
- s.send_header("Access-Control-Allow-Origin", "http://localhost:8888")
- s.send_header("Access-Control-Expose-Headers", "Content-Length, Accept-Ranges")
- s.send_header("Content-type", "application/octet-stream")
- if support_byte_ranges:
- s.send_header("Accept-Ranges", "bytes")
- for i in extra:
- s.send_header(i[0], i[1])
- s.end_headers()
-
- def do_HEAD(s):
- s.sendheaders()
-
- def do_OPTIONS(s):
- s.sendheaders([("Access-Control-Allow-Headers", "Range")], 0)
-
- def do_GET(s):
- if not support_byte_ranges:
- s.sendheaders()
- s.wfile.write(data)
- else:
- (start, end) = s.headers.get("range").split("=")[1].split("-")
- start = int(start)
- end = int(end)
- end = min(len(data)-1, end)
- length = end-start+1
- s.sendheaders([],length)
- s.wfile.write(data[start:end+1])
- s.wfile.close()
- httpd = BaseHTTPServer.HTTPServer(('localhost', 11111), ChunkedServerHandler)
- for i in range(expectedConns+1):
- httpd.handle_request()
-
- server = multiprocessing.Process(target=chunked_server, args=(True,))
- server.start()
- self.run_browser(main, 'Chunked binary synchronous XHR in Web Workers!', '/report_result?' + str(checksum))
- server.terminate()
-
- def test_glgears(self):
- self.btest('hello_world_gles.c', reference='gears.png',
- args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html',
- message='You should see animating gears.')
-
- def test_glgears_animation(self):
- es2_suffix = ['', '_full', '_full_944']
- for full_es2 in [0, 1, 2]:
- for emulation in [0, 1]:
- if full_es2 and emulation: continue
- print full_es2, emulation
- Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html',
- '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1',
- '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] +
- (['-s', 'FORCE_GL_EMULATION=1'] if emulation else []) +
- (['-s', 'FULL_ES2=1'] if full_es2 else []),
- ).communicate()
- self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true')
- assert ('var GLEmulation' in open(self.in_dir('something.html')).read()) == emulation, "emulation code should be added when asked for"
-
- def test_fulles2_sdlproc(self):
- self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1'])
-
- def test_glgears_deriv(self):
- self.btest('hello_world_gles_deriv.c', reference='gears.png',
- args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html',
- message='You should see animating gears.')
- with open('something.html') as f:
- assert 'gl-matrix' not in f.read(), 'Should not include glMatrix when not needed'
-
- def test_glbook(self):
- programs = self.get_library('glbook', [
- os.path.join('Chapter_2', 'Hello_Triangle', 'CH02_HelloTriangle.bc'),
- os.path.join('Chapter_8', 'Simple_VertexShader', 'CH08_SimpleVertexShader.bc'),
- os.path.join('Chapter_9', 'Simple_Texture2D', 'CH09_SimpleTexture2D.bc'),
- os.path.join('Chapter_9', 'Simple_TextureCubemap', 'CH09_TextureCubemap.bc'),
- os.path.join('Chapter_9', 'TextureWrap', 'CH09_TextureWrap.bc'),
- os.path.join('Chapter_10', 'MultiTexture', 'CH10_MultiTexture.bc'),
- os.path.join('Chapter_13', 'ParticleSystem', 'CH13_ParticleSystem.bc'),
- ], configure=None)
- def book_path(*pathelems):
- return path_from_root('tests', 'glbook', *pathelems)
- for program in programs:
- print program
- basename = os.path.basename(program)
- args = []
- if basename == 'CH10_MultiTexture.bc':
- shutil.copyfile(book_path('Chapter_10', 'MultiTexture', 'basemap.tga'), os.path.join(self.get_dir(), 'basemap.tga'))
- shutil.copyfile(book_path('Chapter_10', 'MultiTexture', 'lightmap.tga'), os.path.join(self.get_dir(), 'lightmap.tga'))
- args = ['--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga']
- elif basename == 'CH13_ParticleSystem.bc':
- shutil.copyfile(book_path('Chapter_13', 'ParticleSystem', 'smoke.tga'), os.path.join(self.get_dir(), 'smoke.tga'))
- args = ['--preload-file', 'smoke.tga', '-O2'] # test optimizations and closure here as well for more coverage
-
- self.btest(program,
- reference=book_path(basename.replace('.bc', '.png')), args=args)
-
- def btest(self, filename, expected=None, reference=None, reference_slack=0,
- args=[], outfile='test.html', message='.'): # TODO: use in all other tests
- filepath = path_from_root('tests', filename)
- temp_filepath = os.path.join(self.get_dir(), os.path.basename(filename))
- if not reference:
- if '\n' in filename: # if we are provided the source and not a path, use that
- src = filename
- filename = 'main.cpp'
- else:
- with open(filepath) as f: src = f.read()
- with open(temp_filepath, 'w') as f: f.write(self.with_report_result(src))
- else:
- expected = [str(i) for i in range(0, reference_slack+1)]
- shutil.copyfile(filepath, temp_filepath)
- self.reftest(path_from_root('tests', reference))
- args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1']
- Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate()
- if type(expected) is str: expected = [expected]
- self.run_browser(outfile, message, ['/report_result?' + e for e in expected])
-
- def test_gles2_emulation(self):
- shutil.copyfile(path_from_root('tests', 'glbook', 'Chapter_10', 'MultiTexture', 'basemap.tga'), self.in_dir('basemap.tga'))
- shutil.copyfile(path_from_root('tests', 'glbook', 'Chapter_10', 'MultiTexture', 'lightmap.tga'), self.in_dir('lightmap.tga'))
- shutil.copyfile(path_from_root('tests', 'glbook', 'Chapter_13', 'ParticleSystem', 'smoke.tga'), self.in_dir('smoke.tga'))
-
- for source, reference in [
- (os.path.join('glbook', 'Chapter_2', 'Hello_Triangle', 'Hello_Triangle_orig.c'), path_from_root('tests', 'glbook', 'CH02_HelloTriangle.png')),
- #(os.path.join('glbook', 'Chapter_8', 'Simple_VertexShader', 'Simple_VertexShader_orig.c'), path_from_root('tests', 'glbook', 'CH08_SimpleVertexShader.png')), # XXX needs INT extension in WebGL
- (os.path.join('glbook', 'Chapter_9', 'TextureWrap', 'TextureWrap_orig.c'), path_from_root('tests', 'glbook', 'CH09_TextureWrap.png')),
- #(os.path.join('glbook', 'Chapter_9', 'Simple_TextureCubemap', 'Simple_TextureCubemap_orig.c'), path_from_root('tests', 'glbook', 'CH09_TextureCubemap.png')), # XXX needs INT extension in WebGL
- (os.path.join('glbook', 'Chapter_9', 'Simple_Texture2D', 'Simple_Texture2D_orig.c'), path_from_root('tests', 'glbook', 'CH09_SimpleTexture2D.png')),
- (os.path.join('glbook', 'Chapter_10', 'MultiTexture', 'MultiTexture_orig.c'), path_from_root('tests', 'glbook', 'CH10_MultiTexture.png')),
- (os.path.join('glbook', 'Chapter_13', 'ParticleSystem', 'ParticleSystem_orig.c'), path_from_root('tests', 'glbook', 'CH13_ParticleSystem.png')),
- ]:
- print source
- self.btest(source,
- reference=reference,
- args=['-I' + path_from_root('tests', 'glbook', 'Common'),
- path_from_root('tests', 'glbook', 'Common', 'esUtil.c'),
- path_from_root('tests', 'glbook', 'Common', 'esShader.c'),
- path_from_root('tests', 'glbook', 'Common', 'esShapes.c'),
- path_from_root('tests', 'glbook', 'Common', 'esTransform.c'),
- '-s', 'FULL_ES2=1',
- '--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga', '--preload-file', 'smoke.tga'])
-
- def test_emscripten_api(self):
- self.btest('emscripten_api_browser.cpp', '1', args=['-s', '''EXPORTED_FUNCTIONS=['_main', '_third']'''])
-
- def test_emscripten_api_infloop(self):
- self.btest('emscripten_api_browser_infloop.cpp', '7')
-
- def test_emscripten_fs_api(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) # preloaded *after* run
- self.btest('emscripten_fs_api_browser.cpp', '1')
-
- def test_sdl_quit(self):
- self.btest('sdl_quit.c', '1')
-
- def test_sdl_resize(self):
- self.btest('sdl_resize.c', '1')
-
- def test_gc(self):
- self.btest('browser_gc.cpp', '1')
-
- def test_glshaderinfo(self):
- self.btest('glshaderinfo.cpp', '1')
-
- def test_glgetattachedshaders(self):
- self.btest('glgetattachedshaders.c', '1')
-
- def test_sdlglshader(self):
- self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1'])
-
- def test_gl_ps(self):
- # pointers and a shader
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'], reference_slack=1)
-
- def test_gl_ps_packed(self):
- # packed data that needs to be strided
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png'], reference_slack=1)
-
- def test_gl_ps_strides(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png'])
-
- def test_gl_renderers(self):
- self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0'])
-
- def test_gl_stride(self):
- self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0'])
-
- def test_matrix_identity(self):
- self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840'])
-
- def test_cubegeom_pre(self):
- self.btest('cubegeom_pre.c', reference='cubegeom_pre.png')
-
- def test_cubegeom_pre2(self):
- self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1']) # some coverage for GL_DEBUG not breaking the build
-
- def test_cubegeom_pre3(self):
- self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png')
-
- def test_cubegeom(self):
- self.btest('cubegeom.c', args=['-O2', '-g'], reference='cubegeom.png')
-
- def test_cubegeom_glew(self):
- self.btest('cubegeom_glew.c', args=['-O2', '--closure', '1'], reference='cubegeom.png')
-
- def test_cubegeom_color(self):
- self.btest('cubegeom_color.c', reference='cubegeom_color.png')
-
- def test_cubegeom_normal(self):
- self.btest('cubegeom_normal.c', reference='cubegeom_normal.png')
-
- def test_cubegeom_normal_dap(self): # draw is given a direct pointer to clientside memory, no element array buffer
- self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png')
-
- def test_cubegeom_normal_dap_far(self): # indices do nto start from 0
- self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png')
-
- def test_cubegeom_normal_dap_far_range(self): # glDrawRangeElements
- self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png')
-
- def test_cubegeom_normal_dap_far_glda(self): # use glDrawArrays
- self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png')
-
- def test_cubegeom_normal_dap_far_glda_quad(self): # with quad
- self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png')
-
- def test_cubegeom_mt(self):
- self.btest('cubegeom_mt.c', reference='cubegeom_mt.png') # multitexture
-
- def test_cubegeom_color2(self):
- self.btest('cubegeom_color2.c', reference='cubegeom_color2.png')
-
- def test_cubegeom_texturematrix(self):
- self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png')
-
- def test_cubegeom_fog(self):
- self.btest('cubegeom_fog.c', reference='cubegeom_fog.png')
-
- def test_cubegeom_pre_vao(self):
- self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png')
-
- def test_cubegeom_pre2_vao(self):
- self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png')
-
- def test_cubegeom_pre2_vao2(self):
- self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png')
-
- def test_cube_explosion(self):
- self.btest('cube_explosion.c', reference='cube_explosion.png')
-
- def test_sdl_canvas_blank(self):
- self.btest('sdl_canvas_blank.c', reference='sdl_canvas_blank.png')
-
- def test_sdl_canvas_palette(self):
- self.btest('sdl_canvas_palette.c', reference='sdl_canvas_palette.png')
-
- def test_sdl_canvas_twice(self):
- self.btest('sdl_canvas_twice.c', reference='sdl_canvas_twice.png')
-
- def test_sdl_maprgba(self):
- self.btest('sdl_maprgba.c', reference='sdl_maprgba.png', reference_slack=3)
-
- def test_sdl_rotozoom(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('sdl_rotozoom.c', reference='sdl_rotozoom.png', args=['--preload-file', 'screenshot.png'], reference_slack=5)
-
- def test_sdl_gfx_primitives(self):
- self.btest('sdl_gfx_primitives.c', reference='sdl_gfx_primitives.png', reference_slack=1)
-
- def test_sdl_canvas_palette_2(self):
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- Module['preRun'].push(function() {
- SDL.defaults.copyOnLock = false;
- });
- ''')
-
- open(os.path.join(self.get_dir(), 'args-r.js'), 'w').write('''
- Module['arguments'] = ['-r'];
- ''')
-
- open(os.path.join(self.get_dir(), 'args-g.js'), 'w').write('''
- Module['arguments'] = ['-g'];
- ''')
-
- open(os.path.join(self.get_dir(), 'args-b.js'), 'w').write('''
- Module['arguments'] = ['-b'];
- ''')
-
- self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_r.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-r.js'])
- self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_g.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-g.js'])
- self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_b.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-b.js'])
-
- def test_sdl_alloctext(self):
- self.btest('sdl_alloctext.c', expected='1', args=['-O2', '-s', 'TOTAL_MEMORY=' + str(1024*1024*8)])
-
- def test_sdl_surface_refcount(self):
- self.btest('sdl_surface_refcount.c', expected='1')
-
- def test_glbegin_points(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
- self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png'])
-
- def test_s3tc(self):
- shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds'))
- self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds'])
-
- def test_s3tc_crunch(self):
- shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds')
- shutil.copyfile(path_from_root('tests', 'bloom.dds'), 'bloom.dds')
- shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
- Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch', '--preload', 'ship.dds', 'bloom.dds', 'water.dds'], stdout=open('pre.js', 'w')).communicate()
- assert os.stat('test.data').st_size < 0.5*(os.stat('ship.dds').st_size+os.stat('bloom.dds').st_size+os.stat('water.dds').st_size), 'Compressed should be smaller than dds'
- shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed
- shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed
- shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed
- self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js'])
-
- def test_s3tc_crunch_split(self): # load several datafiles/outputs of file packager
- shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds')
- shutil.copyfile(path_from_root('tests', 'bloom.dds'), 'bloom.dds')
- shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
- Popen([PYTHON, FILE_PACKAGER, 'asset_a.data', '--pre-run', '--crunch', '--preload', 'ship.dds', 'bloom.dds'], stdout=open('asset_a.js', 'w')).communicate()
- Popen([PYTHON, FILE_PACKAGER, 'asset_b.data', '--pre-run', '--crunch', '--preload', 'water.dds'], stdout=open('asset_b.js', 'w')).communicate()
- shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed
- shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed
- shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed
- self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js'])
-
- def test_aniso(self):
- shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
- self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds'])
-
- def test_tex_nonbyte(self):
- self.btest('tex_nonbyte.c', reference='tex_nonbyte.png')
-
- def test_float_tex(self):
- self.btest('float_tex.cpp', reference='float_tex.png')
-
- def test_subdata(self):
- self.btest('gl_subdata.cpp', reference='float_tex.png')
-
- def test_perspective(self):
- self.btest('perspective.c', reference='perspective.png')
-
- def test_runtimelink(self):
- return self.skip('shared libs are deprecated')
- main, supp = self.setup_runtimelink_test()
-
- open(self.in_dir('supp.cpp'), 'w').write(supp)
- Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-o', 'supp.js', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'BUILD_AS_SHARED_LIB=2', '-O2', '-s', 'ASM_JS=0']).communicate()
- shutil.move(self.in_dir('supp.js'), self.in_dir('supp.so'))
-
- self.btest(main, args=['-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'RUNTIME_LINKED_LIBS=["supp.so"]', '-DBROWSER=1', '-O2', '-s', 'ASM_JS=0'], expected='76')
-
- def test_pre_run_deps(self):
- # Adding a dependency in preRun will delay run
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- Module.preRun = function() {
- addRunDependency();
- Module.print('preRun called, added a dependency...');
- setTimeout(function() {
- Module.okk = 10;
- removeRunDependency()
- }, 2000);
- };
- ''')
- self.btest('pre_run_deps.cpp', expected='10', args=['--pre-js', 'pre.js'])
-
- def test_worker_api(self):
- Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate()
- self.btest('worker_api_main.cpp', expected='566')
-
- def test_worker_api_2(self):
- Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_2_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-O2', '--minify', '0', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two", "_three", "_four"]']).communicate()
- self.btest('worker_api_2_main.cpp', args=['-O2', '--minify', '0'], expected='11')
-
- def test_emscripten_async_wget2(self):
- self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')])
-
- pids_to_clean = []
- def clean_pids(self):
- import signal, errno
- def pid_exists(pid):
- try:
- # NOTE: may just kill the process in Windows
- os.kill(pid, 0)
- except OSError, e:
- return e.errno == errno.EPERM
- else:
- return True
- def kill_pids(pids, sig):
- for pid in pids:
- if not pid_exists(pid):
- break
- print '[killing %d]' % pid
- try:
- os.kill(pid, sig)
- print '[kill succeeded]'
- except:
- print '[kill fail]'
- # ask nicely (to try and catch the children)
- kill_pids(browser.pids_to_clean, signal.SIGTERM)
- time.sleep(1)
- # extreme prejudice, may leave children
- kill_pids(browser.pids_to_clean, signal.SIGKILL)
- browser.pids_to_clean = []
-
- # Runs a websocket server at a specific port. port is the true tcp socket we forward to, port+1 is the websocket one
- class WebsockHarness:
- def __init__(self, port, server_func=None, no_server=False):
- self.port = port
- self.server_func = server_func
- self.no_server = no_server
-
- def __enter__(self):
- import socket, websockify
- if not self.no_server:
- def server_func(q):
- q.put(None) # No sub-process to start
- ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- ssock.bind(("127.0.0.1", self.port))
- ssock.listen(2)
- while True:
- csock, addr = ssock.accept()
- print "Connection from %s" % repr(addr)
- csock.send("te\x01\xff\x79st\x02")
-
- server_func = self.server_func or server_func
-
- server_queue = multiprocessing.Queue()
- self.server = multiprocessing.Process(target=server_func, args=(server_queue,))
- self.server.start()
- browser.pids_to_clean.append(self.server.pid)
- while True:
- if not server_queue.empty():
- spid = server_queue.get()
- if spid:
- browser.pids_to_clean.append(spid)
- break
- time.sleep(0.1)
- print '[Socket server on processes %s]' % str(browser.pids_to_clean[-2:])
-
- def websockify_func(wsp): wsp.start_server()
-
- print >> sys.stderr, 'running websockify on %d, forward to tcp %d' % (self.port+1, self.port)
- wsp = websockify.WebSocketProxy(verbose=True, listen_port=self.port+1, target_host="127.0.0.1", target_port=self.port, run_once=True)
- self.websockify = multiprocessing.Process(target=websockify_func, args=(wsp,))
- self.websockify.start()
- browser.pids_to_clean.append(self.websockify.pid)
- print '[Websockify on processes %s]' % str(browser.pids_to_clean[-2:])
-
- def __exit__(self, *args, **kwargs):
- if self.websockify.is_alive():
- self.websockify.terminate()
- self.websockify.join()
-
- # always run these tests last
- # make sure to use different ports in each one because it takes a while for the processes to be cleaned up
- def test_websockets(self):
- try:
- with self.WebsockHarness(8990):
- self.btest('websockets.c', expected='571')
- finally:
- self.clean_pids()
-
- def test_websockets_partial(self):
- def partial(q):
- import socket
-
- q.put(None) # No sub-process to start
- ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- ssock.bind(("127.0.0.1", 8990))
- ssock.listen(2)
- while True:
- csock, addr = ssock.accept()
- print "Connection from %s" % repr(addr)
- csock.send("\x09\x01\x02\x03\x04\x05\x06\x07\x08\x09")
- csock.send("\x08\x01\x02\x03\x04\x05\x06\x07\x08")
- csock.send("\x07\x01\x02\x03\x04\x05\x06\x07")
- csock.send("\x06\x01\x02\x03\x04\x05\x06")
- csock.send("\x05\x01\x02\x03\x04\x05")
- csock.send("\x04\x01\x02\x03\x04")
- csock.send("\x03\x01\x02\x03")
- csock.send("\x02\x01\x02")
- csock.send("\x01\x01")
-
- try:
- with self.WebsockHarness(8990, partial):
- self.btest('websockets_partial.c', expected='165')
- finally:
- self.clean_pids()
-
- def make_relay_server(self, port1, port2):
- def relay_server(q):
- print >> sys.stderr, 'creating relay server on ports %d,%d' % (port1, port2)
- proc = Popen([PYTHON, path_from_root('tests', 'socket_relay.py'), str(port1), str(port2)])
- q.put(proc.pid)
- proc.communicate()
- return relay_server
-
- def test_websockets_bi(self):
- for datagram in [0,1]:
- for fileops in [0,1]:
- try:
- print >> sys.stderr, 'test_websocket_bi datagram %d, fileops %d' % (datagram, fileops)
- with self.WebsockHarness(8992, self.make_relay_server(8992, 8994)):
- with self.WebsockHarness(8994, no_server=True):
- Popen([PYTHON, EMCC, path_from_root('tests', 'websockets_bi_side.c'), '-o', 'side.html', '-DSOCKK=8995', '-DTEST_DGRAM=%d' % datagram]).communicate()
- self.btest('websockets_bi.c', expected='2499', args=['-DSOCKK=8993', '-DTEST_DGRAM=%d' % datagram, '-DTEST_FILE_OPS=%s' % fileops])
- finally:
- self.clean_pids()
-
- def test_websockets_bi_listen(self):
- try:
- with self.WebsockHarness(6992, self.make_relay_server(6992, 6994)):
- with self.WebsockHarness(6994, no_server=True):
- Popen([PYTHON, EMCC, path_from_root('tests', 'websockets_bi_side.c'), '-o', 'side.html', '-DSOCKK=6995']).communicate()
- self.btest('websockets_bi_listener.c', expected='2499', args=['-DSOCKK=6993'])
- finally:
- self.clean_pids()
-
- def test_websockets_gethostbyname(self):
- try:
- with self.WebsockHarness(7000):
- self.btest('websockets_gethostbyname.c', expected='571', args=['-O2'])
- finally:
- self.clean_pids()
-
- def test_websockets_bi_bigdata(self):
- try:
- with self.WebsockHarness(3992, self.make_relay_server(3992, 3994)):
- with self.WebsockHarness(3994, no_server=True):
- Popen([PYTHON, EMCC, path_from_root('tests', 'websockets_bi_side_bigdata.c'), '-o', 'side.html', '-DSOCKK=3995', '-s', 'SOCKET_DEBUG=0', '-I' + path_from_root('tests')]).communicate()
- self.btest('websockets_bi_bigdata.c', expected='0', args=['-DSOCKK=3993', '-s', 'SOCKET_DEBUG=0', '-I' + path_from_root('tests')])
- finally:
- self.clean_pids()
-
- def test_websockets_select_server_down(self):
- def closedServer(q):
- import socket
-
- q.put(None) # No sub-process to start
- ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- ssock.bind(("127.0.0.1", 8994))
- try:
- with self.WebsockHarness(8994, closedServer):
- self.btest('websockets_select.c', expected='266')
- finally:
- self.clean_pids()
-
- def test_websockets_select_server_closes_connection(self):
- def closingServer(q):
- import socket
-
- q.put(None) # No sub-process to start
- ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- ssock.bind(("127.0.0.1", 8994))
- ssock.listen(2)
- while True:
- csock, addr = ssock.accept()
- print "Connection from %s" % repr(addr)
- csock.send("1234567")
- csock.close()
-
- try:
- with self.WebsockHarness(8994, closingServer):
- self.btest('websockets_select_server_closes_connection.c', expected='266')
- finally:
- self.clean_pids()
-
- def test_websockets_select_server_closes_connection_rw(self):
- def closingServer_rw(q):
- import socket
-
- q.put(None) # No sub-process to start
- ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- ssock.bind(("127.0.0.1", 8998))
- ssock.listen(2)
- while True:
- csock, addr = ssock.accept()
- print "Connection from %s" % repr(addr)
- readArray = bytearray(10)
- #readBuffer = buffer(readArray)
- bytesRead = 0
- # Let the client start to write data
- while (bytesRead < 10):
- (readBytes, address) = csock.recvfrom_into( readArray, 10 )
- bytesRead += readBytes
- print "server: 10 bytes read"
- # Now we write a message on our own ...
- csock.send("0123456789")
- print "server: 10 bytes written"
- # And immediately close the connection
- csock.close()
- print "server: connection closed"
-
- try:
- with self.WebsockHarness(8998, closingServer_rw):
- self.btest('websockets_select_server_closes_connection_rw.c', expected='266')
- finally:
- self.clean_pids()
-
- def test_enet(self):
- try_delete(self.in_dir('enet'))
- shutil.copytree(path_from_root('tests', 'enet'), self.in_dir('enet'))
- pwd = os.getcwd()
- os.chdir(self.in_dir('enet'))
- Popen([PYTHON, path_from_root('emconfigure'), './configure']).communicate()
- Popen([PYTHON, path_from_root('emmake'), 'make']).communicate()
- enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I'+path_from_root('tests', 'enet', 'include')]
- os.chdir(pwd)
- Popen([PYTHON, EMCC, path_from_root('tests', 'enet_server.c'), '-o', 'server.html'] + enet).communicate()
-
- try:
- with self.WebsockHarness(1234, self.make_relay_server(1234, 1236)):
- with self.WebsockHarness(1236, no_server=True):
- self.btest('enet_client.c', expected='0', args=enet)
- finally:
- self.clean_pids()
-
-elif 'benchmark' in str(sys.argv):
- # Benchmarks. Run them with argument |benchmark|. To run a specific test, do
- # |benchmark.test_X|.
-
- fingerprint = [time.asctime()]
- try:
- fingerprint.append('em: ' + Popen(['git', 'show'], stdout=PIPE).communicate()[0].split('\n')[0])
- except:
- pass
- try:
- d = os.getcwd()
- os.chdir(os.path.expanduser('~/Dev/mozilla-central'))
- fingerprint.append('sm: ' + filter(lambda line: 'changeset' in line,
- Popen(['hg', 'tip'], stdout=PIPE).communicate()[0].split('\n'))[0])
- except:
- pass
- finally:
- os.chdir(d)
- fingerprint.append('llvm: ' + LLVM_ROOT)
- print 'Running Emscripten benchmarks... [ %s ]' % ' | '.join(fingerprint)
-
- sys.argv = filter(lambda x: x != 'benchmark', sys.argv)
+ def btest(self, filename, expected=None, reference=None, force_c=False, reference_slack=0,
+ args=[], outfile='test.html', message='.'): # TODO: use in all other tests
+ # if we are provided the source and not a path, use that
+ filename_is_src = '\n' in filename
+ src = filename if filename_is_src else ''
+ filepath = path_from_root('tests', filename) if not filename_is_src else ('main.c' if force_c else 'main.cpp')
+ temp_filepath = os.path.join(self.get_dir(), os.path.basename(filepath))
+ if filename_is_src:
+ with open(temp_filepath, 'w') as f: f.write(src)
+ if not reference:
+ if not src:
+ with open(filepath) as f: src = f.read()
+ with open(temp_filepath, 'w') as f: f.write(self.with_report_result(src))
+ else:
+ expected = [str(i) for i in range(0, reference_slack+1)]
+ shutil.copyfile(filepath, temp_filepath)
+ self.reftest(path_from_root('tests', reference))
+ args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1']
+ Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate()
+ assert os.path.exists(outfile)
+ if type(expected) is str: expected = [expected]
+ self.run_browser(outfile, message, ['/report_result?' + e for e in expected])
- assert(os.path.exists(CLOSURE_COMPILER))
+###################################################################################################
- try:
- index = SPIDERMONKEY_ENGINE.index("options('strict')")
- SPIDERMONKEY_ENGINE = SPIDERMONKEY_ENGINE[:index-1] + SPIDERMONKEY_ENGINE[index+1:] # closure generates non-strict
- except:
- pass
+if __name__ == '__main__':
+ # Sanity checks
+ total_engines = len(JS_ENGINES)
+ JS_ENGINES = filter(check_engine, JS_ENGINES)
+ if len(JS_ENGINES) == 0:
+ print 'WARNING: None of the JS engines in JS_ENGINES appears to work.'
+ elif len(JS_ENGINES) < total_engines:
+ print 'WARNING: Not all the JS engines in JS_ENGINES appears to work, ignoring those.'
- Building.COMPILER = CLANG
+ # Create a list of modules to load tests from
+ modules = []
+ for filename in glob.glob(os.path.join(os.path.dirname(__file__), 'test*.py')):
+ module_dir, module_file = os.path.split(filename)
+ module_name, module_ext = os.path.splitext(module_file)
+ __import__(module_name)
+ modules.append(sys.modules[module_name])
- # Pick the JS engine to benchmark. If you specify one, it will be picked. For example, python tests/runner.py benchmark SPIDERMONKEY_ENGINE
- JS_ENGINE = JS_ENGINES[0]
+ # Extract the JS engine override from the arguments (used by benchmarks)
for i in range(1, len(sys.argv)):
arg = sys.argv[i]
- if not arg.startswith('benchmark.test_'):
- JS_ENGINE = eval(arg)
+ if arg.isupper():
+ print 'Interpreting all capital argument "%s" as JS_ENGINE override' % arg
+ Building.JS_ENGINE_OVERRIDE = eval(arg)
sys.argv[i] = None
sys.argv = filter(lambda arg: arg is not None, sys.argv)
- print 'Benchmarking JS engine:', ' '.join(JS_ENGINE)
-
- Building.COMPILER_TEST_OPTS = []
-
- TEST_REPS = 2
- TOTAL_TESTS = 8
-
- # standard arguments for timing:
- # 0: no runtime, just startup
- # 1: very little runtime
- # 2: 0.5 seconds
- # 3: 1 second
- # 4: 5 seconds
- # 5: 10 seconds
- DEFAULT_ARG = '4'
-
- tests_done = 0
- total_times = map(lambda x: 0., range(TOTAL_TESTS))
- total_native_times = map(lambda x: 0., range(TOTAL_TESTS))
-
- class benchmark(RunnerCore):
- save_dir = True
-
- def print_stats(self, times, native_times, last=False, reps=TEST_REPS):
- if reps == 0:
- print '(no reps)'
- return
- mean = sum(times)/len(times)
- squared_times = map(lambda x: x*x, times)
- mean_of_squared = sum(squared_times)/len(times)
- std = math.sqrt(mean_of_squared - mean*mean)
- sorted_times = times[:]
- sorted_times.sort()
- median = sum(sorted_times[len(sorted_times)/2 - 1:len(sorted_times)/2 + 1])/2
-
- mean_native = sum(native_times)/len(native_times)
- squared_native_times = map(lambda x: x*x, native_times)
- mean_of_squared_native = sum(squared_native_times)/len(native_times)
- std_native = math.sqrt(mean_of_squared_native - mean_native*mean_native)
- sorted_native_times = native_times[:]
- sorted_native_times.sort()
- median_native = sum(sorted_native_times[len(sorted_native_times)/2 - 1:len(sorted_native_times)/2 + 1])/2
-
- final = mean / mean_native
-
- if last:
- norm = 0
- for i in range(len(times)):
- norm += times[i]/native_times[i]
- norm /= len(times)
- print
- print ' JavaScript: %.3f Native: %.3f Ratio: %.3f Normalized ratio: %.3f' % (mean, mean_native, final, norm)
- return
-
- print
- print ' JavaScript: mean: %.3f (+-%.3f) secs median: %.3f range: %.3f-%.3f (noise: %3.3f%%) (%d runs)' % (mean, std, median, min(times), max(times), 100*std/mean, reps)
- print ' Native : mean: %.3f (+-%.3f) secs median: %.3f range: %.3f-%.3f (noise: %3.3f%%) JS is %.2f X slower' % (mean_native, std_native, median_native, min(native_times), max(native_times), 100*std_native/mean_native, final)
- def do_benchmark(self, name, src, expected_output='FAIL', args=[], emcc_args=[], native_args=[], shared_args=[], force_c=False, reps=TEST_REPS, native_exec=None, output_parser=None, args_processor=None):
- args = args or [DEFAULT_ARG]
- if args_processor: args = args_processor(args)
+ # If an argument comes in as test_*, treat it as a test of the default suite
+ sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv)
- dirname = self.get_dir()
- filename = os.path.join(dirname, name + '.c' + ('' if force_c else 'pp'))
- f = open(filename, 'w')
- f.write(src)
- f.close()
- final_filename = os.path.join(dirname, name + '.js')
-
- open('hardcode.py', 'w').write('''
-def process(filename):
- js = open(filename).read()
- replaced = js.replace("run();", "run(%s.concat(Module[\\"arguments\\"]));")
- assert js != replaced
- open(filename, 'w').write(replaced)
-import sys
-process(sys.argv[1])
-''' % str(args[:-1]) # do not hardcode in the last argument, the default arg
-)
-
- try_delete(final_filename)
- output = Popen([PYTHON, EMCC, filename, #'-O3',
- '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
- '--llvm-lto', '3', '--memory-init-file', '0', '--js-transform', 'python hardcode.py',
- '-s', 'TOTAL_MEMORY=128*1024*1024',
- '--closure', '1',
- #'-g',
- '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate()
- assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0]
-
- # Run JS
- global total_times, tests_done
- times = []
- for i in range(reps):
- start = time.time()
- js_output = run_js(final_filename, engine=JS_ENGINE, args=args, stderr=PIPE, full_output=True)
-
- if i == 0 and 'uccessfully compiled asm.js code' in js_output:
- if 'asm.js link error' not in js_output:
- print "[%s was asm.js'ified]" % name
- if not output_parser:
- curr = time.time()-start
- else:
- curr = output_parser(js_output)
- times.append(curr)
- total_times[tests_done] += curr
- if i == 0:
- # Sanity check on output
- self.assertContained(expected_output, js_output)
+ # If a test (e.g. test_html) is specified as ALL.test_html, add an entry for each test_mode
+ if len(sys.argv) == 2 and sys.argv[1].startswith('ALL.'):
+ ignore, test = sys.argv[1].split('.')
+ print 'Running all test modes on test "%s"' % test
+ sys.argv = [sys.argv[0]] + map(lambda mode: mode+'.'+test, test_modes)
- # Run natively
- if not native_exec:
- self.build_native(filename, shared_args + native_args)
+ # Skip requested tests
+ for i in range(len(sys.argv)):
+ arg = sys.argv[i]
+ if arg.startswith('skip:'):
+ which = arg.split('skip:')[1]
+ if which.startswith('ALL.'):
+ ignore, test = which.split('.')
+ which = map(lambda mode: mode+'.'+test, test_modes)
else:
- shutil.copyfile(native_exec, filename + '.native')
- shutil.copymode(native_exec, filename + '.native')
- global total_native_times
- native_times = []
- for i in range(reps):
- start = time.time()
- native_output = self.run_native(filename, args)
- if i == 0:
- # Sanity check on output
- self.assertContained(expected_output, native_output)
- if not output_parser:
- curr = time.time()-start
- else:
- curr = output_parser(native_output)
- native_times.append(curr)
- total_native_times[tests_done] += curr
-
- self.print_stats(times, native_times, reps=reps)
-
- #tests_done += 1
- #if tests_done == TOTAL_TESTS:
- # print 'Total stats:',
- # self.print_stats(total_times, total_native_times, last=True)
-
- def test_primes(self):
- src = r'''
- #include<stdio.h>
- #include<math.h>
- int main(int argc, char **argv) {
- int arg = argc > 1 ? argv[1][0] - '0' : 3;
- switch(arg) {
- case 0: return 0; break;
- case 1: arg = 33000; break;
- case 2: arg = 130000; break;
- case 3: arg = 220000; break;
- case 4: arg = 610000; break;
- case 5: arg = 1010000; break;
- default: printf("error: %d\\n", arg); return -1;
- }
-
- int primes = 0, curri = 2;
- while (primes < arg) {
- int ok = true;
- for (int j = 2; j < sqrtf(curri); j++) {
- if (curri % j == 0) {
- ok = false;
- break;
- }
- }
- if (ok) {
- primes++;
- }
- curri++;
- }
- printf("lastprime: %d.\n", curri-1);
- return 0;
- }
- '''
- self.do_benchmark('primes', src, 'lastprime:')
-
- def test_memops(self):
- src = '''
- #include<stdio.h>
- #include<string.h>
- #include<stdlib.h>
- int main(int argc, char **argv) {
- int N, M;
- int arg = argc > 1 ? argv[1][0] - '0' : 3;
- switch(arg) {
- case 0: return 0; break;
- case 1: N = 1024*1024; M = 55; break;
- case 2: N = 1024*1024; M = 400; break;
- case 3: N = 1024*1024; M = 800; break;
- case 4: N = 1024*1024; M = 4000; break;
- case 5: N = 1024*1024; M = 8000; break;
- default: printf("error: %d\\n", arg); return -1;
- }
-
- int final = 0;
- char *buf = (char*)malloc(N);
- for (int t = 0; t < M; t++) {
- for (int i = 0; i < N; i++)
- buf[i] = (i + final)%256;
- for (int i = 0; i < N; i++)
- final += buf[i] & 1;
- final = final % 1000;
- }
- printf("final: %d.\\n", final);
- return 0;
- }
- '''
- self.do_benchmark('memops', src, 'final:')
-
- def zzztest_files(self):
- src = r'''
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- #include <unistd.h>
-
- int main() {
- int N = 100;
- int M = 1000;
- int K = 1000;
- unsigned char *k = (unsigned char*)malloc(K+1), *k2 = (unsigned char*)malloc(K+1);
- for (int i = 0; i < K; i++) {
- k[i] = (i % 250) + 1;
- }
- k[K] = 0;
- char buf[100];
- for (int i = 0; i < N; i++) {
- sprintf(buf, "/dev/shm/file-%d.dat", i);
- FILE *f = fopen(buf, "w");
- for (int j = 0; j < M; j++) {
- fwrite(k, 1, (j % K) + 1, f);
- }
- fclose(f);
- }
- for (int i = 0; i < N; i++) {
- sprintf(buf, "/dev/shm/file-%d.dat", i);
- FILE *f = fopen(buf, "r");
- for (int j = 0; j < M; j++) {
- fread(k2, 1, (j % K) + 1, f);
- }
- fclose(f);
- for (int j = 0; j < K; j++) {
- assert(k[j] == k2[j]);
- }
- unlink(buf);
- }
- printf("ok");
- return 0;
- }
- '''
- self.do_benchmark(src, 'ok')
-
- def test_copy(self):
- src = r'''
- #include<stdio.h>
- struct vec {
- int x, y, z;
- int r, g, b;
- vec(int x_, int y_, int z_, int r_, int g_, int b_) : x(x_), y(y_), z(z_), r(r_), g(g_), b(b_) {}
- static vec add(vec a, vec b) {
- return vec(a.x+b.x, a.y+b.y, a.z+b.z, a.r+b.r, a.g+b.g, a.b+b.b);
- }
- void norm() {
- x %= 1024;
- y %= 1024;
- z %= 1024;
- r %= 1024;
- b %= 1024;
- g %= 1024;
- }
- int sum() { return x + y + z + r + g + b; }
- };
- int main(int argc, char **argv) {
- int arg = argc > 1 ? argv[1][0] - '0' : 3;
- switch(arg) {
- case 0: return 0; break;
- case 1: arg = 75; break;
- case 2: arg = 625; break;
- case 3: arg = 1250; break;
- case 4: arg = 5*1250; break;
- case 5: arg = 10*1250; break;
- default: printf("error: %d\\n", arg); return -1;
- }
-
- int total = 0;
- for (int i = 0; i < arg; i++) {
- for (int j = 0; j < 50000; j++) {
- vec c(i, i+i%10, j*2, i%255, j%120, i%15);
- vec d(j+i%10, j*2, j%255, i%120, j%15, j);
- vec e = c;
- c.norm();
- d.norm();
- vec f = vec::add(c, d);
- f = vec::add(e, f);
- f.norm();
- f = vec::add(d, f);
- total += f.sum() % 100;
- total %= 10240;
- }
- }
- printf("sum:%d\n", total);
- return 0;
- }
- '''
- self.do_benchmark('copy', src, 'sum:')
-
- def test_fannkuch(self):
- src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read().replace(
- 'int n = argc > 1 ? atoi(argv[1]) : 0;',
- '''
- int n;
- int arg = argc > 1 ? argv[1][0] - '0' : 3;
- switch(arg) {
- case 0: return 0; break;
- case 1: n = 9; break;
- case 2: n = 10; break;
- case 3: n = 11; break;
- case 4: n = 11; break;
- case 5: n = 12; break;
- default: printf("error: %d\\n", arg); return -1;
- }
- '''
- )
- assert 'switch(arg)' in src
- self.do_benchmark('fannkuch', src, 'Pfannkuchen(')
-
- def test_corrections(self):
- src = r'''
- #include<stdio.h>
- #include<math.h>
- int main(int argc, char **argv) {
- int N, M;
- int arg = argc > 1 ? argv[1][0] - '0' : 3;
- switch(arg) {
- case 0: return 0; break;
- case 1: N = 20000; M = 550; break;
- case 2: N = 20000; M = 3500; break;
- case 3: N = 20000; M = 7000; break;
- case 4: N = 20000; M = 5*7000; break;
- case 5: N = 20000; M = 10*7000; break;
- default: printf("error: %d\\n", arg); return -1;
- }
-
- unsigned int f = 0;
- unsigned short s = 0;
- for (int t = 0; t < M; t++) {
- for (int i = 0; i < N; i++) {
- f += i / ((t % 5)+1);
- if (f > 1000) f /= (t % 3)+1;
- if (i % 4 == 0) f += i * (i % 8 == 0 ? 1 : -1);
- s += (short(f)*short(f)) % 256;
- }
- }
- printf("final: %d:%d.\n", f, s);
- return 0;
- }
- '''
- self.do_benchmark('corrections', src, 'final:', emcc_args=['-s', 'CORRECT_SIGNS=1', '-s', 'CORRECT_OVERFLOWS=1', '-s', 'CORRECT_ROUNDINGS=1'])
-
- def fasta(self, name, double_rep, emcc_args=[]):
- src = open(path_from_root('tests', 'fasta.cpp'), 'r').read().replace('double', double_rep)
- src = src.replace(' const size_t n = ( argc > 1 ) ? atoi( argv[1] ) : 512;', '''
- int n;
- int arg = argc > 1 ? argv[1][0] - '0' : 3;
- switch(arg) {
- case 0: return 0; break;
- case 1: n = 19000000/20; break;
- case 2: n = 19000000/2; break;
- case 3: n = 19000000; break;
- case 4: n = 19000000*5; break;
- case 5: n = 19000000*10; break;
- default: printf("error: %d\\n", arg); return -1;
- }
- ''')
- assert 'switch(arg)' in src
- self.do_benchmark('fasta', src, '')
-
- def test_fasta_float(self):
- self.fasta('fasta_float', 'float')
-
- def test_fasta_double(self):
- self.fasta('fasta_double', 'double')
-
- def test_fasta_double_full(self):
- self.fasta('fasta_double_full', 'double', emcc_args=['-s', 'DOUBLE_MODE=1'])
-
- def test_skinning(self):
- src = open(path_from_root('tests', 'skinning_test_no_simd.cpp'), 'r').read()
- self.do_benchmark('skinning', src, 'blah=0.000000')
-
- def test_life(self):
- src = open(path_from_root('tests', 'life.c'), 'r').read()
- self.do_benchmark('life', src, '''--------------------------------''', shared_args=['-std=c99'], force_c=True)
-
- def test_linpack(self):
- def output_parser(output):
- return 100.0/float(re.search('Unrolled Double Precision +([\d\.]+) Mflops', output).group(1))
- self.do_benchmark('linpack', open(path_from_root('tests', 'linpack.c')).read(), '''Unrolled Double Precision''', force_c=True, output_parser=output_parser)
-
- def test_zzz_java_nbody(self): # tests xmlvm compiled java, including bitcasts of doubles, i64 math, etc.
- args = [path_from_root('tests', 'nbody-java', x) for x in os.listdir(path_from_root('tests', 'nbody-java')) if x.endswith('.c')] + \
- ['-I' + path_from_root('tests', 'nbody-java')]
- self.do_benchmark('nbody_java', '', '''Time(s)''',
- force_c=True, emcc_args=args + ['-s', 'PRECISE_I64_MATH=1', '--llvm-lto', '2'], native_args=args + ['-lgc', '-std=c99', '-target', 'x86_64-pc-linux-gnu', '-lm'])
-
- def lua(self, benchmark, expected, output_parser=None, args_processor=None):
- shutil.copyfile(path_from_root('tests', 'lua', benchmark + '.lua'), benchmark + '.lua')
- #shutil.copyfile(path_from_root('tests', 'lua', 'binarytrees.lua'), 'binarytrees.lua')
- #shutil.copyfile(path_from_root('tests', 'lua', 'scimark.lua'), 'scimark.lua')
- emcc_args = self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None) + \
- ['--embed-file', benchmark + '.lua']
- #['--embed-file', 'binarytrees.lua', '--embed-file', 'scimark.lua'] + ['--minify', '0']
- shutil.copyfile(emcc_args[0], emcc_args[0] + '.bc')
- emcc_args[0] += '.bc'
- native_args = self.get_library('lua_native', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=True)
-
- self.do_benchmark('lua_' + benchmark, '', expected,
- force_c=True, args=[benchmark + '.lua', DEFAULT_ARG], emcc_args=emcc_args, native_args=native_args, native_exec=os.path.join('building', 'lua_native', 'src', 'lua'),
- output_parser=output_parser, args_processor=args_processor)
-
- def test_zzz_lua_scimark(self):
- def output_parser(output):
- return 100.0/float(re.search('\nSciMark +([\d\.]+) ', output).group(1))
-
- self.lua('scimark', '[small problem sizes]', output_parser=output_parser)
-
- def test_zzz_lua_binarytrees(self):
- # js version: ['binarytrees.lua', {0: 0, 1: 9.5, 2: 11.99, 3: 12.85, 4: 14.72, 5: 15.82}[arguments[0]]]
- self.lua('binarytrees', 'long lived tree of depth')
-
- def test_zzz_zlib(self):
- src = open(path_from_root('tests', 'zlib', 'benchmark.c'), 'r').read()
- emcc_args = self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']) + \
- ['-I' + path_from_root('tests', 'zlib')]
- native_args = self.get_library('zlib_native', os.path.join('libz.a'), make_args=['libz.a'], native=True) + \
- ['-I' + path_from_root('tests', 'zlib')]
- self.do_benchmark('zlib', src, '''ok.''',
- force_c=True, emcc_args=emcc_args, native_args=native_args)
-
- def test_zzz_box2d(self): # Called thus so it runs late in the alphabetical cycle... it is long
- src = open(path_from_root('tests', 'box2d', 'Benchmark.cpp'), 'r').read()
-
- js_lib = self.get_library('box2d', [os.path.join('box2d.a')], configure=None)
- native_lib = self.get_library('box2d_native', [os.path.join('box2d.a')], configure=None, native=True)
-
- emcc_args = js_lib + ['-I' + path_from_root('tests', 'box2d')]
- native_args = native_lib + ['-I' + path_from_root('tests', 'box2d')]
-
- self.do_benchmark('box2d', src, 'frame averages', emcc_args=emcc_args, native_args=native_args)
-
- def test_zzz_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
- src = open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'BenchmarkDemo.cpp'), 'r').read() + \
- open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'main.cpp'), 'r').read()
-
- js_lib = self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
- os.path.join('src', '.libs', 'libBulletCollision.a'),
- os.path.join('src', '.libs', 'libLinearMath.a')],
- configure_args=['--disable-demos','--disable-dependency-tracking'])
- native_lib = self.get_library('bullet_native', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
- os.path.join('src', '.libs', 'libBulletCollision.a'),
- os.path.join('src', '.libs', 'libLinearMath.a')],
- configure_args=['--disable-demos','--disable-dependency-tracking'],
- native=True)
-
- emcc_args = js_lib + ['-I' + path_from_root('tests', 'bullet', 'src'),
- '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks'),
- '-s', 'DEAD_FUNCTIONS=["__ZSt9terminatev"]']
- native_args = native_lib + ['-I' + path_from_root('tests', 'bullet', 'src'),
- '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks')]
-
- self.do_benchmark('bullet', src, '\nok.\n', emcc_args=emcc_args, native_args=native_args)
-
-elif 'sanity' in str(sys.argv):
-
- # Run some sanity checks on the test runner and emcc.
-
- sys.argv = filter(lambda x: x != 'sanity', sys.argv)
-
- print
- print 'Running sanity checks.'
- print 'WARNING: This will modify %s, and in theory can break it although it should be restored properly. A backup will be saved in %s_backup' % (EM_CONFIG, EM_CONFIG)
- print
-
- assert os.path.exists(CONFIG_FILE), 'To run these tests, we need a (working!) %s file to already exist' % EM_CONFIG
-
- assert not os.environ.get('EMCC_DEBUG'), 'do not run sanity checks in debug mode!'
-
- shutil.copyfile(CONFIG_FILE, CONFIG_FILE + '_backup')
- def restore():
- shutil.copyfile(CONFIG_FILE + '_backup', CONFIG_FILE)
-
- SANITY_FILE = CONFIG_FILE + '_sanity'
-
- def wipe():
- try_delete(CONFIG_FILE)
- try_delete(SANITY_FILE)
-
- commands = [[EMCC], [PYTHON, path_from_root('tests', 'runner.py'), 'blahblah']]
-
- def mtime(filename):
- return os.stat(filename).st_mtime
-
- class sanity(RunnerCore):
- def setUp(self):
- wipe()
-
- def tearDown(self):
- restore()
-
- def do(self, command):
- if type(command) is not list:
- command = [command]
- if command[0] == EMCC:
- command = [PYTHON] + command
-
- return Popen(command, stdout=PIPE, stderr=STDOUT).communicate()[0]
-
- def check_working(self, command, expected=None):
- if type(command) is not list:
- command = [command]
- if expected is None:
- if command[0] == EMCC:
- expected = 'no input files'
- else:
- expected = "has no attribute 'blahblah'"
-
- output = self.do(command)
- self.assertContained(expected, output)
- return output
-
- def test_aaa_normal(self): # this should be the very first thing that runs. if this fails, everything else is irrelevant!
- for command in commands:
- # Your existing EM_CONFIG should work!
- restore()
- self.check_working(command)
-
- def test_firstrun(self):
- for command in commands:
- wipe()
-
- def make_executable(name):
- with open(os.path.join(temp_bin, name), 'w') as f:
- os.fchmod(f.fileno(), stat.S_IRWXU)
-
- try:
- temp_bin = tempfile.mkdtemp()
- old_environ_path = os.environ['PATH']
- os.environ['PATH'] = temp_bin + os.pathsep + old_environ_path
- make_executable('llvm-dis')
- make_executable('node')
- make_executable('python2')
- output = self.do(command)
- finally:
- os.environ['PATH'] = old_environ_path
- shutil.rmtree(temp_bin)
-
- self.assertContained('Welcome to Emscripten!', output)
- self.assertContained('This is the first time any of the Emscripten tools has been run.', output)
- self.assertContained('A settings file has been copied to %s, at absolute path: %s' % (EM_CONFIG, CONFIG_FILE), output)
- self.assertContained('It contains our best guesses for the important paths, which are:', output)
- self.assertContained('LLVM_ROOT', output)
- self.assertContained('NODE_JS', output)
- self.assertContained('PYTHON', output)
- if platform.system() is not 'Windows':
- # os.chmod can't make files executable on Windows
- self.assertIdentical(temp_bin, re.search("^ *LLVM_ROOT *= (.*)$", output, re.M).group(1))
- self.assertIdentical(os.path.join(temp_bin, 'node'), re.search("^ *NODE_JS *= (.*)$", output, re.M).group(1))
- self.assertIdentical(os.path.join(temp_bin, 'python2'), re.search("^ *PYTHON *= (.*)$", output, re.M).group(1))
- self.assertContained('Please edit the file if any of those are incorrect', output)
- self.assertContained('This command will now exit. When you are done editing those paths, re-run it.', output)
- assert output.split()[-1].endswith('===='), 'We should have stopped: ' + output
- config_file = open(CONFIG_FILE).read()
- template_file = open(path_from_root('tools', 'settings_template_readonly.py')).read()
- self.assertNotContained('~/.emscripten', config_file)
- self.assertContained('~/.emscripten', template_file)
- self.assertNotContained('{{{', config_file)
- self.assertNotContained('}}}', config_file)
- self.assertContained('{{{', template_file)
- self.assertContained('}}}', template_file)
- for content in ['EMSCRIPTEN_ROOT', 'LLVM_ROOT', 'NODE_JS', 'TEMP_DIR', 'COMPILER_ENGINE', 'JS_ENGINES']:
- self.assertContained(content, config_file)
-
- # The guessed config should be ok XXX This depends on your local system! it is possible `which` guesses wrong
- #try_delete('a.out.js')
- #output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c')], stdout=PIPE, stderr=PIPE).communicate()
- #self.assertContained('hello, world!', run_js('a.out.js'), output)
-
- # Second run, with bad EM_CONFIG
- for settings in ['blah', 'LLVM_ROOT="blarg"; JS_ENGINES=[]; COMPILER_ENGINE=NODE_JS=SPIDERMONKEY_ENGINE=[]']:
- f = open(CONFIG_FILE, 'w')
- f.write(settings)
- f.close()
- output = self.do(command)
-
- if 'LLVM_ROOT' not in settings:
- self.assertContained('Error in evaluating %s' % EM_CONFIG, output)
- elif 'runner.py' not in ' '.join(command):
- self.assertContained('CRITICAL', output) # sanity check should fail
-
- def test_closure_compiler(self):
- CLOSURE_FATAL = 'fatal: Closure compiler'
- CLOSURE_WARNING = 'does not exist'
-
- # Sanity check should find closure
- restore()
- output = self.check_working(EMCC)
- self.assertNotContained(CLOSURE_FATAL, output)
- self.assertNotContained(CLOSURE_WARNING, output)
-
- # Append a bad path for closure, will warn
- f = open(CONFIG_FILE, 'a')
- f.write('CLOSURE_COMPILER = "/tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt"\n')
- f.close()
- output = self.check_working(EMCC, CLOSURE_WARNING)
-
- # And if you actually try to use the bad path, will be fatal
- f = open(CONFIG_FILE, 'a')
- f.write('CLOSURE_COMPILER = "/tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt"\n')
- f.close()
- output = self.check_working([EMCC, '-O2', '-s', 'ASM_JS=0', '--closure', '1', 'tests/hello_world.cpp'], CLOSURE_FATAL)
-
- # With a working path, all is well
- restore()
- try_delete('a.out.js')
- output = self.check_working([EMCC, '-O2', '-s', 'ASM_JS=0', '--closure', '1', 'tests/hello_world.cpp'], '')
- assert os.path.exists('a.out.js'), output
-
- def test_llvm(self):
- LLVM_WARNING = 'LLVM version appears incorrect'
-
- restore()
-
- # Clang should report the version number we expect, and emcc should not warn
- assert check_clang_version()
- output = self.check_working(EMCC)
- assert LLVM_WARNING not in output, output
-
- # Fake a different llvm version
- restore()
- f = open(CONFIG_FILE, 'a')
- f.write('LLVM_ROOT = "' + path_from_root('tests', 'fake') + '"')
- f.close()
-
- if not os.path.exists(path_from_root('tests', 'fake')):
- os.makedirs(path_from_root('tests', 'fake'))
-
- try:
- os.environ['EM_IGNORE_SANITY'] = '1'
- for x in range(-2, 3):
- for y in range(-2, 3):
- f = open(path_from_root('tests', 'fake', 'clang'), 'w')
- f.write('#!/bin/sh\n')
- f.write('echo "clang version %d.%d" 1>&2\n' % (EXPECTED_LLVM_VERSION[0] + x, EXPECTED_LLVM_VERSION[1] + y))
- f.close()
- shutil.copyfile(path_from_root('tests', 'fake', 'clang'), path_from_root('tests', 'fake', 'clang++'))
- os.chmod(path_from_root('tests', 'fake', 'clang'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
- os.chmod(path_from_root('tests', 'fake', 'clang++'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
- if x != 0 or y != 0:
- output = self.check_working(EMCC, LLVM_WARNING)
- else:
- output = self.check_working(EMCC)
- assert LLVM_WARNING not in output, output
- finally:
- del os.environ['EM_IGNORE_SANITY']
-
- def test_node(self):
- NODE_WARNING = 'node version appears too old'
- NODE_WARNING_2 = 'cannot check node version'
-
- restore()
-
- # Clang should report the version number we expect, and emcc should not warn
- assert check_node_version()
- output = self.check_working(EMCC)
- assert NODE_WARNING not in output, output
-
- # Fake a different node version
- restore()
- f = open(CONFIG_FILE, 'a')
- f.write('NODE_JS = "' + path_from_root('tests', 'fake', 'nodejs') + '"')
- f.close()
-
- if not os.path.exists(path_from_root('tests', 'fake')):
- os.makedirs(path_from_root('tests', 'fake'))
-
- try:
- os.environ['EM_IGNORE_SANITY'] = '1'
- for version, succeed in [('v0.7.9', False), ('v0.8.0', True), ('v0.8.1', True), ('cheez', False)]:
- f = open(path_from_root('tests', 'fake', 'nodejs'), 'w')
- f.write('#!/bin/sh\n')
- f.write('''if [ $1 = "--version" ]; then
- echo "%s"
-else
- %s $@
-fi
-''' % (version, NODE_JS))
- f.close()
- os.chmod(path_from_root('tests', 'fake', 'nodejs'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
- if not succeed:
- if version[0] == 'v':
- self.check_working(EMCC, NODE_WARNING)
- else:
- self.check_working(EMCC, NODE_WARNING_2)
- else:
- output = self.check_working(EMCC)
- assert NODE_WARNING not in output, output
- finally:
- del os.environ['EM_IGNORE_SANITY']
-
- def test_emcc(self):
- SANITY_MESSAGE = 'Emscripten: Running sanity checks'
- SANITY_FAIL_MESSAGE = 'sanity check failed to run'
-
- # emcc should check sanity if no ${EM_CONFIG}_sanity
- restore()
- time.sleep(0.1)
- assert not os.path.exists(SANITY_FILE) # restore is just the settings, not the sanity
- output = self.check_working(EMCC)
- self.assertContained(SANITY_MESSAGE, output)
- assert os.path.exists(SANITY_FILE) # EMCC should have checked sanity successfully
- assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
- assert generate_sanity() == open(SANITY_FILE).read()
- self.assertNotContained(SANITY_FAIL_MESSAGE, output)
-
- # emcc run again should not sanity check, because the sanity file is newer
- output = self.check_working(EMCC)
- self.assertNotContained(SANITY_MESSAGE, output)
- self.assertNotContained(SANITY_FAIL_MESSAGE, output)
-
- # correct sanity contents mean we need not check
- open(SANITY_FILE, 'w').write(generate_sanity())
- output = self.check_working(EMCC)
- self.assertNotContained(SANITY_MESSAGE, output)
-
- # incorrect sanity contents mean we *must* check
- open(SANITY_FILE, 'w').write('wakawaka')
- output = self.check_working(EMCC)
- self.assertContained(SANITY_MESSAGE, output)
-
- # but with EMCC_DEBUG=1 we should check
- try:
- os.environ['EMCC_DEBUG'] = '1'
- output = self.check_working(EMCC)
- finally:
- del os.environ['EMCC_DEBUG']
- self.assertContained(SANITY_MESSAGE, output)
- output = self.check_working(EMCC)
- self.assertNotContained(SANITY_MESSAGE, output)
-
- # Make sure the test runner didn't do anything to the setup
- output = self.check_working(EMCC)
- self.assertNotContained(SANITY_MESSAGE, output)
- self.assertNotContained(SANITY_FAIL_MESSAGE, output)
-
- # emcc should also check sanity if the file is outdated
- time.sleep(0.1)
- restore()
- assert mtime(SANITY_FILE) < mtime(CONFIG_FILE)
- output = self.check_working(EMCC)
- self.assertContained(SANITY_MESSAGE, output)
- assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
- self.assertNotContained(SANITY_FAIL_MESSAGE, output)
-
- # emcc should be configurable directly from EM_CONFIG without any config file
- restore()
- config = open(CONFIG_FILE, 'r').read()
- os.environ['EM_CONFIG'] = config
- wipe()
- dirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
- open(os.path.join(dirname, 'main.cpp'), 'w').write('''
- #include <stdio.h>
- int main() {
- printf("hello from emcc with no config file\\n");
- return 0;
- }
- ''')
- Popen([PYTHON, EMCC, os.path.join(dirname, 'main.cpp'), '-o', os.path.join(dirname, 'a.out.js')]).communicate()
- del os.environ['EM_CONFIG']
- old_dir = os.getcwd()
- try:
- os.chdir(dirname)
- self.assertContained('hello from emcc with no config file', run_js('a.out.js'))
- finally:
- os.chdir(old_dir)
- shutil.rmtree(dirname)
-
- try_delete(CANONICAL_TEMP_DIR)
-
- def test_emcc_caching(self):
- INCLUDING_MESSAGE = 'including X'
- BUILDING_MESSAGE = 'building X for cache'
- ERASING_MESSAGE = 'clearing cache'
-
- EMCC_CACHE = Cache.dirname
-
- for compiler in [EMCC, EMXX]:
- print compiler
-
- restore()
-
- Cache.erase()
- assert not os.path.exists(EMCC_CACHE)
-
- try:
- os.environ['EMCC_DEBUG'] ='1'
- self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
-
- # Building a file that doesn't need cached stuff should not trigger cache generation
- output = self.do([compiler, path_from_root('tests', 'hello_world.cpp')])
- assert INCLUDING_MESSAGE.replace('X', 'libc') not in output
- assert BUILDING_MESSAGE.replace('X', 'libc') not in output
- self.assertContained('hello, world!', run_js('a.out.js'))
- assert not os.path.exists(EMCC_CACHE)
- try_delete('a.out.js')
-
- basebc_name = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-0-basebc.bc')
- dcebc_name = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-1-linktime.bc')
- ll_names = [os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-X-ll.ll').replace('X', str(x)) for x in range(2,5)]
-
- # Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time
- for filename, libname in [('hello_malloc.cpp', 'libc'), ('hello_libcxx.cpp', 'libcxx')]:
- for i in range(3):
- print filename, libname, i
- self.clear()
- try_delete(basebc_name) # we might need to check this file later
- try_delete(dcebc_name) # we might need to check this file later
- for ll_name in ll_names: try_delete(ll_name)
- output = self.do([compiler, '-O' + str(i), '-s', 'RELOOP=0', '--llvm-lto', '0', path_from_root('tests', filename)])
- #print output
- assert INCLUDING_MESSAGE.replace('X', libname) in output
- if libname == 'libc':
- assert INCLUDING_MESSAGE.replace('X', 'libcxx') not in output # we don't need libcxx in this code
- else:
- assert INCLUDING_MESSAGE.replace('X', 'libc') in output # libcxx always forces inclusion of libc
- assert (BUILDING_MESSAGE.replace('X', libname) in output) == (i == 0), 'Must only build the first time'
- self.assertContained('hello, world!', run_js('a.out.js'))
- assert os.path.exists(EMCC_CACHE)
- assert os.path.exists(os.path.join(EMCC_CACHE, libname + '.bc'))
- if libname == 'libcxx':
- print os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size, os.stat(basebc_name).st_size, os.stat(dcebc_name).st_size
- assert os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size > 1000000, 'libc++ is big'
- assert os.stat(basebc_name).st_size > 1000000, 'libc++ is indeed big'
- assert os.stat(dcebc_name).st_size < 500000, 'Dead code elimination must remove most of libc++'
- # should only have metadata in -O0, not 1 and 2
- if i > 0:
- for ll_name in ll_names:
- ll = None
- try:
- ll = open(ll_name).read()
- break
- except:
- pass
- assert ll
- assert ll.count('\n!') < 10 # a few lines are left even in -O1 and -O2
- finally:
- del os.environ['EMCC_DEBUG']
-
- restore()
-
- def ensure_cache():
- self.do([EMCC, '-O2', path_from_root('tests', 'hello_world.c')])
-
- # Manual cache clearing
- ensure_cache()
- assert os.path.exists(EMCC_CACHE)
- output = self.do([EMCC, '--clear-cache'])
- assert ERASING_MESSAGE in output
- assert not os.path.exists(EMCC_CACHE)
-
- # Changing LLVM_ROOT, even without altering .emscripten, clears the cache
- ensure_cache()
- old = os.environ.get('LLVM')
- try:
- os.environ['LLVM'] = 'waka'
- assert os.path.exists(EMCC_CACHE)
- output = self.do([EMCC])
- assert ERASING_MESSAGE in output
- assert not os.path.exists(EMCC_CACHE)
- finally:
- if old: os.environ['LLVM'] = old
- else: del os.environ['LLVM']
-
- try_delete(CANONICAL_TEMP_DIR)
-
- def test_relooper(self):
- RELOOPER = Cache.get_path('relooper.js')
-
- restore()
- for phase in range(2): # 0: we wipe the relooper dir. 1: we have it, so should just update
- if phase == 0: Cache.erase()
- try_delete(RELOOPER)
-
- for i in range(4):
- print >> sys.stderr, phase, i
- opt = min(i, 2)
- try_delete('a.out.js')
- output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '-g'],
- stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('hello, world!', run_js('a.out.js'))
- output = '\n'.join(output)
- assert ('bootstrapping relooper succeeded' in output) == (i == 2), 'only bootstrap on first O2: ' + output
- assert os.path.exists(RELOOPER) == (i >= 2), 'have relooper on O2: ' + output
- src = open('a.out.js').read()
- main = src.split('function _main()')[1].split('\n}\n')[0]
- assert ('while (1) {' in main or 'while(1){' in main or '} while ($' in main or '}while($' in main) == (i >= 2), 'reloop code on O2: ' + main
- assert ('switch' not in main) == (i >= 2), 'reloop code on O2: ' + main
-
- def test_jcache(self):
- PRE_LOAD_MSG = 'loading pre from jcache'
- PRE_SAVE_MSG = 'saving pre to jcache'
- FUNC_CHUNKS_LOAD_MSG = ' funcchunks from jcache'
- FUNC_CHUNKS_SAVE_MSG = ' funcchunks to jcache'
- JSFUNC_CHUNKS_LOAD_MSG = 'jsfuncchunks from jcache'
- JSFUNC_CHUNKS_SAVE_MSG = 'jsfuncchunks to jcache'
+ which = [which]
- restore()
- Cache.erase()
+ print >> sys.stderr, ','.join(which)
+ for test in which:
+ print >> sys.stderr, 'will skip "%s"' % test
+ for m in modules:
+ try:
+ exec('m.' + test + ' = RunnerCore("skipme")')
+ break
+ except:
+ pass
+ sys.argv[i] = None
+ sys.argv = filter(lambda arg: arg is not None, sys.argv)
- try:
- os.environ['EMCC_DEBUG'] = '1'
- os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE'] = str(1024*512)
+ # If no tests were specified, run the core suite
+ if len(sys.argv) == 1:
+ sys.argv = [sys.argv[0]] + map(lambda mode: mode, test_modes)
+ print '''
+==============================================================================
+Running the main part of the test suite. Don't forget to run the other parts!
- self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
- if not os.path.exists(self.working_dir): os.makedirs(self.working_dir)
+ sanity - tests for first run, etc., modifies ~/.emscripten
+ benchmark - run before and after each set of changes before pushing to
+ master, verify no regressions
+ browser - runs pages in a web browser
+ sockets - runs websocket networking tests
- assert not os.path.exists(JCache.get_cachename('emscript_files'))
+There are also commands to run specific subsets of the test suite:
- srcs = {}
- used_jcache = False
+ browser.audio - runs audio tests in a web browser (requires human verification)
- for args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected in [
- ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
- (['--jcache'], 'hello_world_loop.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
- ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
- # new
- ([], 'hello_world.cpp', False, False, False, False, False, False, []),
- (['--jcache'], 'hello_world.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_world.cpp', False, True, False, True, False, True, []),
- ([], 'hello_world.cpp', False, False, False, False, False, False, []),
- # go back to old file, experience caching
- (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
- # new, large file
- ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
- (['--jcache'], 'hello_malloc.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_malloc.cpp', False, True, False, True, False, True, []),
- ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
- # new, huge file
- ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('3 chunks',)),
- (['--jcache'], 'hello_libcxx.cpp', True, False, True, False, True, False, []),
- (['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []),
- ([], 'hello_libcxx.cpp', False, False, False, False, False, False, []),
- # finally, build a file close to the previous, to see that some chunks are found in the cache and some not
- (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, True, []), # win on pre, mix on funcs, mix on jsfuncs
- (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, False, True, False, True, []),
- (None, None, None, None, None, None, None, None, None), # clear
- (['--jcache'], 'hello_libcxx_mod2.cpp', True, False, True, False, True, False, []), # load into cache
- (['--jcache'], 'hello_libcxx_mod2a.cpp', False, True, True, True, True, True, []) # add a printf, do not lose everything
- ]:
- self.clear()
- if args is None:
- Cache.erase()
- continue
+To run one of those parts, do something like
- print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected
+ python tests/runner.py sanity
- out, err = Popen([PYTHON, EMCC, '-O2', '-g', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
- errtail = err.split('emcc invocation')[-1]
- self.assertContained('hello, world!', run_js('a.out.js'), errtail)
- assert (PRE_SAVE_MSG in err) == expect_pre_save, errtail
- assert (PRE_LOAD_MSG in err) == expect_pre_load, errtail
- assert (FUNC_CHUNKS_SAVE_MSG in err) == expect_funcs_save, errtail
- assert (FUNC_CHUNKS_LOAD_MSG in err) == expect_funcs_load, errtail
- assert (JSFUNC_CHUNKS_SAVE_MSG in err) == expect_jsfuncs_save, errtail
- assert (JSFUNC_CHUNKS_LOAD_MSG in err) == expect_jsfuncs_load, errtail
- for expect in expected: assert expect in err, expect + ' ? ' + errtail
- curr = open('a.out.js').read()
- if input_file not in srcs:
- srcs[input_file] = curr
- else:
- #open('/home/alon/Dev/emscripten/a', 'w').write(srcs[input_file])
- #open('/home/alon/Dev/emscripten/b', 'w').write(curr)
- assert abs(len(curr)/float(len(srcs[input_file]))-1)<0.01, 'contents may shift in order, but must remain the same size %d vs %d' % (len(curr), len(srcs[input_file])) + '\n' + errtail
- used_jcache = used_jcache or ('--jcache' in args)
- assert used_jcache == os.path.exists(JCache.get_cachename('emscript_files'))
- #print >> sys.stderr, errtail
+To run a specific set of tests, you can do things like
- finally:
- del os.environ['EMCC_DEBUG']
- del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE']
+ python tests/runner.py o1
-else:
- raise Exception('Test runner is confused: ' + str(sys.argv))
+(that runs the o1 (-O1) tests). You can run individual tests with
-if __name__ == '__main__':
- # Sanity checks
+ python tests/runner.py test_hello_world
- total_engines = len(JS_ENGINES)
- JS_ENGINES = filter(check_engine, JS_ENGINES)
- if len(JS_ENGINES) == 0:
- print 'WARNING: None of the JS engines in JS_ENGINES appears to work.'
- elif len(JS_ENGINES) < total_engines:
- print 'WARNING: Not all the JS engines in JS_ENGINES appears to work, ignoring those.'
+Combinations work too, for example
- # Skip requested tests
+ python tests/runner.py browser.test_sdl_image
- for i in range(len(sys.argv)):
- arg = sys.argv[i]
- if arg.startswith('skip:'):
- which = arg.split('skip:')[1]
- if which.startswith('ALL.'):
- ignore, test = which.split('.')
- which = map(lambda mode: mode+'.'+test, test_modes)
- else:
- which = [which]
+In the main test suite, you can run all variations (O0, O1, O2, etc.) of
+an individual test with
- print >> sys.stderr, ','.join(which)
- for test in which:
- print >> sys.stderr, 'will skip "%s"' % test
- exec(test + ' = RunnerCore.skipme')
+ python tests/runner.py ALL.test_hello_world
- sys.argv[i] = ''
- sys.argv = filter(lambda arg: arg, sys.argv)
+==============================================================================
- # Go
+'''
+ time.sleep(2)
- unittest.main(verbosity=2)
+ # Filter and load tests from the discovered modules
+ loader = unittest.TestLoader()
+ names = sys.argv[1:]
+ suites = []
+ for m in modules:
+ try:
+ suites.append(loader.loadTestsFromNames(names, m))
+ except:
+ pass
+
+ numFailures = 0 # Keep count of the total number of failing tests.
+
+ # Run the discovered tests
+ if not len(suites):
+ print >> sys.stderr, 'No tests found for %s' % str(sys.argv[1:])
+ numFailures = 1
+ else:
+ testRunner = unittest.TextTestRunner(verbosity=2)
+ for suite in suites:
+ results = testRunner.run(suite)
+ numFailures += len(results.errors) + len(results.failures)
+
+ # Return the number of failures as the process exit code for automating success/failure reporting.
+ exit(numFailures)
diff --git a/tests/sdl_image.c b/tests/sdl_image.c
index 9d8c36f2..523f8903 100644
--- a/tests/sdl_image.c
+++ b/tests/sdl_image.c
@@ -3,6 +3,7 @@
#include <SDL/SDL_image.h>
#include <assert.h>
#include <emscripten.h>
+#include <unistd.h>
int testImage(SDL_Surface* screen, const char* fileName) {
SDL_Surface *image = IMG_Load(fileName);
@@ -27,9 +28,12 @@ int main() {
SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_SWSURFACE);
int result = 0;
- result = testImage(screen, "screenshot.jpg"); // relative path
+
+ result |= testImage(screen, SCREENSHOT_DIRNAME "/" SCREENSHOT_BASENAME); // absolute path
assert(result != 0);
- result |= testImage(screen, "/screenshot.jpg"); // absolute path
+
+ chdir(SCREENSHOT_DIRNAME);
+ result = testImage(screen, "./" SCREENSHOT_BASENAME); // relative path
assert(result != 0);
SDL_Flip(screen);
diff --git a/tests/sdl_image_jpeg.c b/tests/sdl_image_jpeg.c
deleted file mode 100644
index 10619dad..00000000
--- a/tests/sdl_image_jpeg.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdio.h>
-#include <SDL/SDL.h>
-#include <SDL/SDL_image.h>
-#include <assert.h>
-#include <emscripten.h>
-
-int testImage(SDL_Surface* screen, const char* fileName) {
- SDL_Surface *image = IMG_Load(fileName);
- if (!image)
- {
- printf("IMG_Load: %s\n", IMG_GetError());
- return 0;
- }
- assert(image->format->BitsPerPixel == 32);
- assert(image->format->BytesPerPixel == 4);
- assert(image->pitch == 4*image->w);
- int result = image->w;
-
- SDL_BlitSurface (image, NULL, screen, NULL);
- SDL_FreeSurface (image);
-
- return result;
-}
-
-int main() {
- SDL_Init(SDL_INIT_VIDEO);
- SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_SWSURFACE);
-
- int result = 0;
- result = testImage(screen, "screenshot.jpeg"); // relative path
- assert(result != 0);
- result |= testImage(screen, "/screenshot.jpeg"); // absolute path
- assert(result != 0);
-
- SDL_Flip(screen);
-
- printf("you should see an image.\n");
-
- SDL_Quit();
-
- REPORT_RESULT();
-
- return 0;
-}
-
diff --git a/tests/sdl_ogl_proc_alias.c b/tests/sdl_ogl_proc_alias.c
new file mode 100644
index 00000000..c96da81b
--- /dev/null
+++ b/tests/sdl_ogl_proc_alias.c
@@ -0,0 +1,180 @@
+/*******************************************************************
+ * *
+ * Using SDL With OpenGL *
+ * *
+ * Tutorial by Kyle Foley (sdw) *
+ * *
+ * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL *
+ * *
+ *******************************************************************/
+
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#include "SDL/SDL.h"
+#include "SDL/SDL_image.h"
+#include "SDL/SDL_opengl.h"
+
+#include <stdio.h>
+#include <string.h>
+
+void (*true_glGenTextures)(GLsizei, GLuint*) = NULL;
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+ printf("num? %d\n", n);
+ true_glGenTextures(n + 1, textures); // correct the error, ensures we are gone through
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+
+ // Slightly different SDL initialization
+ if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) {
+ printf("Unable to initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
+
+ screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed*
+ if ( !screen ) {
+ printf("Unable to set video mode: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ // Set the OpenGL state after creating the context with SDL_SetVideoMode
+
+ glClearColor( 0, 0, 0, 0 );
+
+ glEnable( GL_TEXTURE_2D ); // Needed when we're using the fixed-function pipeline.
+
+ glViewport( 0, 0, 640, 480 );
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix(); // just for testing
+ glLoadIdentity();
+
+ glOrtho( 0, 640, 480, 0, -1, 1 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ // Load the OpenGL texture
+
+ GLuint texture; // Texture object handle
+ SDL_Surface *surface; // Gives us the information to make the texture
+
+ if ( (surface = IMG_Load("screenshot.png")) ) {
+
+ // Check that the image's width is a power of 2
+ if ( (surface->w & (surface->w - 1)) != 0 ) {
+ printf("warning: image.bmp's width is not a power of 2\n");
+ }
+
+ // Also check if the height is a power of 2
+ if ( (surface->h & (surface->h - 1)) != 0 ) {
+ printf("warning: image.bmp's height is not a power of 2\n");
+ }
+
+ true_glGenTextures = SDL_GL_GetProcAddress("glGenTextures");
+
+ // Have OpenGL generate a texture object handle for us
+ glGenTextures( 0, &texture );
+
+ // Bind the texture object
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ // Set the texture's stretching properties
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ //SDL_LockSurface(surface);
+
+ // Add some greyness
+ memset(surface->pixels, 0x66, surface->w*surface->h);
+
+ // Edit the texture object's image data using the information SDL_Surface gives us
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );
+
+ //SDL_UnlockSurface(surface);
+ }
+ else {
+ printf("SDL could not load image.bmp: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 1;
+ }
+
+ // Free the SDL_Surface only if it was successfully created
+ if ( surface ) {
+ SDL_FreeSurface( surface );
+ }
+
+ // Clear the screen before drawing
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ // Bind the texture to which subsequent calls refer to
+ glBindTexture( GL_TEXTURE_2D, texture );
+
+ glBegin( GL_QUADS );
+ glTexCoord2i( 0, 0 ); glVertex3f( 10, 10, 0 );
+ glTexCoord2i( 1, 0 ); glVertex3f( 300, 10, 0 );
+ glTexCoord2i( 1, 1 ); glVertex3f( 300, 128, 0 );
+ glTexCoord2i( 0, 1 ); glVertex3f( 10, 128, 0 );
+
+ glTexCoord2f( 0, 0.5 ); glVertex3f( 410, 10, 0 );
+ glTexCoord2f( 1, 0.5 ); glVertex3f( 600, 10, 0 );
+ glTexCoord2f( 1, 1 ); glVertex3f( 630, 200, 0 );
+ glTexCoord2f( 0.5, 1 ); glVertex3f( 310, 250, 0 );
+ glEnd();
+
+ glBegin( GL_TRIANGLE_STRIP );
+ glTexCoord2i( 0, 0 ); glVertex3f( 100, 300, 0 );
+ glTexCoord2i( 1, 0 ); glVertex3f( 300, 300, 0 );
+ glTexCoord2i( 1, 1 ); glVertex3f( 300, 400, 0 );
+ glTexCoord2i( 0, 1 ); glVertex3f( 500, 410, 0 );
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+
+ glColor3ub(90, 255, 255);
+ glBegin( GL_QUADS );
+ glVertex3f( 10, 410, 0 );
+ glVertex3f( 300, 410, 0 );
+ glVertex3f( 300, 480, 0 );
+ glVertex3f( 10, 470, 0 );
+ glEnd();
+
+ glBegin( GL_QUADS );
+ glColor3f(1.0, 0, 1.0); glVertex3f( 410, 410, 0 );
+ glColor3f(0, 1.0, 0); glVertex3f( 600, 410, 0 );
+ glColor3f(0, 0, 1.0); glVertex3f( 600, 480, 0 );
+ glColor3f(1.0, 1.0, 1.0); glVertex3f( 410, 470, 0 );
+ glEnd();
+
+ SDL_GL_SwapBuffers();
+
+#if !EMSCRIPTEN
+ // Wait for 3 seconds to give us a chance to see the image
+ SDL_Delay(3000);
+#endif
+
+ // Now we can delete the OpenGL texture and close down SDL
+ glDeleteTextures( 1, &texture );
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/tests/sdl_pumpevents.c b/tests/sdl_pumpevents.c
new file mode 100644
index 00000000..64becaad
--- /dev/null
+++ b/tests/sdl_pumpevents.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <SDL/SDL.h>
+
+#include <emscripten.h>
+// bug - SDL_GetKeyboardState doesn't return scancodes, it returns keycodes, so acts exactly like
+// SDL_GetKeyState instead
+#define SDL_GetKeyState SDL_GetKeyboardState
+
+int result = 0;
+
+int loop1()
+{
+ unsigned i;
+ int r = 0;
+
+ // method 1: SDL_PollEvent loop
+ SDL_Event e;
+ while (SDL_PollEvent(&e));
+
+ const Uint8 *keys = SDL_GetKeyState(NULL);
+ if (keys[SDLK_LEFT])
+ r = 1;
+
+ return r;
+}
+
+int loop2()
+{
+ unsigned i;
+ int r = 0;
+
+ // method 2: SDL_PumpEvents
+ SDL_PumpEvents();
+
+ const Uint8 *keys = SDL_GetKeyState(NULL);
+ if (keys[SDLK_RIGHT])
+ r = 2;
+
+ return r;
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Init(SDL_INIT_EVERYTHING);
+ SDL_SetVideoMode(600, 400, 32, SDL_SWSURFACE);
+
+ emscripten_run_script("keydown(37);"); // left
+ result += loop1();
+ emscripten_run_script("keydown(39);"); // right
+ result += loop2();
+ REPORT_RESULT();
+ return 0;
+}
diff --git a/tests/socket_relay.py b/tests/sockets/socket_relay.py
index 5b6403f9..5b6403f9 100644
--- a/tests/socket_relay.py
+++ b/tests/sockets/socket_relay.py
diff --git a/tests/enet_client.c b/tests/sockets/test_enet_client.c
index 601b8769..bf14375c 100644
--- a/tests/enet_client.c
+++ b/tests/sockets/test_enet_client.c
@@ -1,20 +1,22 @@
#include <stdio.h>
-#include <emscripten.h>
-
+#include <string.h>
#include <enet/enet.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
ENetHost * host;
void main_loop() {
- static int counter = 0;
#if EMSCRIPTEN
+ static int counter = 0;
counter++;
-#endif
if (counter == 100) {
printf("stop!\n");
emscripten_cancel_main_loop();
return;
}
+#endif
ENetEvent event;
if (enet_host_service (host, & event, 0) == 0) return;
@@ -32,7 +34,11 @@ void main_loop() {
event.channelID);
int result = strcmp("packetfoo", event.packet->data);
+#if EMSCRIPTEN
REPORT_RESULT();
+#else
+ exit(EXIT_SUCCESS);
+#endif
/* Clean up the packet now that we're done using it. */
enet_packet_destroy (event.packet);
@@ -73,11 +79,7 @@ int main (int argc, char ** argv)
ENetAddress address;
enet_address_set_host (& address, "localhost");
-#if EMSCRIPTEN
- address.port = 1237;
-#else
- address.port = 1235;
-#endif
+ address.port = SOCKK;
printf("connecting to server...\n");
@@ -100,7 +102,11 @@ int main (int argc, char ** argv)
"console.log('added.');");
#endif
+#if EMSCRIPTEN
emscripten_set_main_loop(main_loop, 3, 1);
+#else
+ while (1) main_loop();
+#endif
return 1;
}
diff --git a/tests/enet_server.c b/tests/sockets/test_enet_server.c
index a8167e16..9a4518ac 100644
--- a/tests/enet_server.c
+++ b/tests/sockets/test_enet_server.c
@@ -1,10 +1,13 @@
// g++ -fpermissive ../enet_server.c -I/home/alon/Dev/emscripten/system/include/emscripten/ -Iinclude/ -fpermissive .libs/libenet.a -o enet_server ; g++ ../enet_client.c -I/home/alon/Dev/emscripten/system/include/emscripten/ -Iinclude/ -fpermissive .libs/libenet.a -o enet_client
#include <stdio.h>
-#include <emscripten.h>
-
+#include <string.h>
#include <enet/enet.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
ENetHost *host;
void send_msg(ENetPeer *peer) {
@@ -31,7 +34,9 @@ void main_loop() {
#endif
if (counter == 100) {
printf("stop!\n");
+#if EMSCRIPTEN
emscripten_cancel_main_loop();
+#endif
return;
}
@@ -82,7 +87,7 @@ int main (int argc, char ** argv)
ENetAddress address;
address.host = ENET_HOST_ANY;
- address.port = 1235;
+ address.port = SOCKK;
printf("create!\n");
host = enet_host_create (& address /* the address to bind the server host to */,
32 /* allow up to 32 clients and/or outgoing connections */,
@@ -96,7 +101,11 @@ int main (int argc, char ** argv)
exit (EXIT_FAILURE);
}
+#if EMSCRIPTEN
emscripten_set_main_loop(main_loop, 3, 1);
+#else
+ while (1) main_loop();
+#endif
return 1;
}
diff --git a/tests/sockets/test_sockets_echo_client.c b/tests/sockets/test_sockets_echo_client.c
new file mode 100644
index 00000000..6b3ccef3
--- /dev/null
+++ b/tests/sockets/test_sockets_echo_client.c
@@ -0,0 +1,148 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#include "test_sockets_msg.h"
+
+// message to send to the server
+#ifndef MESSAGE
+#define MESSAGE "pingtothepong"
+#endif
+
+typedef enum {
+ MSG_READ,
+ MSG_WRITE
+} msg_state_t;
+
+typedef struct {
+ int fd;
+ msg_t msg;
+ msg_state_t state;
+} server_t;
+
+server_t server;
+msg_t echo_msg;
+int echo_read;
+int echo_wrote;
+
+void finish(int result) {
+ close(server.fd);
+#if EMSCRIPTEN
+ REPORT_RESULT();
+#endif
+ exit(result);
+}
+
+void main_loop(void *arg) {
+ static char out[1024*2];
+ static int pos = 0;
+ fd_set fdr;
+ fd_set fdw;
+ int res;
+
+ // make sure that server.fd is ready to read / write
+ FD_ZERO(&fdr);
+ FD_ZERO(&fdw);
+ FD_SET(server.fd, &fdr);
+ FD_SET(server.fd, &fdw);
+ res = select(64, &fdr, &fdw, NULL, NULL);
+ if (res == -1) {
+ perror("select failed");
+ finish(EXIT_FAILURE);
+ }
+
+ if (server.state == MSG_READ) {
+ if (!FD_ISSET(server.fd, &fdr)) {
+ return;
+ }
+
+ // as a test, confirm with ioctl that we have data available
+ // after selecting
+ int available;
+ res = ioctl(server.fd, FIONREAD, &available);
+ assert(res != -1);
+ assert(available);
+
+ res = do_msg_read(server.fd, &server.msg, echo_read, 0, NULL, NULL);
+ if (res != -1) echo_read += res;
+
+ // once we've read the entire message, validate it
+ if (echo_read >= server.msg.length) {
+ assert(!strcmp(server.msg.buffer, MESSAGE));
+ finish(EXIT_SUCCESS);
+ }
+ } else {
+ if (!FD_ISSET(server.fd, &fdw)) {
+ return;
+ }
+
+ res = do_msg_write(server.fd, &echo_msg, echo_wrote, 0, NULL, 0);
+ if (res != -1) echo_wrote += res;
+
+ // once we're done writing the message, read it back
+ if (echo_wrote >= echo_msg.length) {
+ server.state = MSG_READ;
+ }
+ }
+}
+
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ memset(&server, 0, sizeof(server_t));
+ server.state = MSG_WRITE;
+
+ // setup the message we're going to echo
+ memset(&echo_msg, 0, sizeof(msg_t));
+ echo_msg.length = strlen(MESSAGE) + 1;
+ echo_msg.buffer = malloc(echo_msg.length);
+ strncpy(echo_msg.buffer, MESSAGE, echo_msg.length);
+
+ // create the socket and set to non-blocking
+#if !USE_UDP
+ server.fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+#else
+ server.fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#endif
+ if (server.fd == -1) {
+ perror("cannot create socket");
+ finish(EXIT_FAILURE);
+ }
+ fcntl(server.fd, F_SETFL, O_NONBLOCK);
+
+ // connect the socket
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ finish(EXIT_FAILURE);
+ }
+
+ res = connect(server.fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1 && errno != EINPROGRESS) {
+ perror("connect failed");
+ finish(EXIT_FAILURE);
+ }
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(main_loop, 0, 0);
+#else
+ while (1) main_loop(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/sockets/test_sockets_echo_server.c b/tests/sockets/test_sockets_echo_server.c
new file mode 100644
index 00000000..38e27cac
--- /dev/null
+++ b/tests/sockets/test_sockets_echo_server.c
@@ -0,0 +1,160 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#include "test_sockets_msg.h"
+
+typedef enum {
+ MSG_READ,
+ MSG_WRITE
+} msg_state_t;
+
+typedef struct {
+ int fd;
+} server_t;
+
+typedef struct {
+ int fd;
+ struct sockaddr_in addr;
+ msg_t msg;
+ msg_state_t state;
+ int read;
+ int wrote;
+} client_t;
+
+server_t server;
+client_t client;
+
+void cleanup() {
+ if (server.fd) close(server.fd);
+ if (client.fd) close(client.fd);
+}
+
+void main_loop(void *arg) {
+ int res;
+ fd_set fdr;
+ fd_set fdw;
+
+ // see if there are any connections to accept or read / write from
+ FD_ZERO(&fdr);
+ FD_ZERO(&fdw);
+ FD_SET(server.fd, &fdr);
+ FD_SET(server.fd, &fdw);
+#if !USE_UDP
+ if (client.fd) FD_SET(client.fd, &fdr);
+ if (client.fd) FD_SET(client.fd, &fdw);
+#endif
+ res = select(64, &fdr, &fdw, NULL, NULL);
+ if (res == -1) {
+ perror("select failed");
+ exit(EXIT_SUCCESS);
+ }
+
+#if !USE_UDP
+ // for TCP sockets, we may need to accept a connection
+ if (FD_ISSET(server.fd, &fdr)) {
+ client.fd = accept(server.fd, NULL, NULL);
+ assert(client.fd != -1);
+ }
+#endif
+
+#if !USE_UDP
+ int fd = client.fd;
+#else
+ int fd = server.fd;
+#endif
+ if (client.state == MSG_READ) {
+ socklen_t addrlen;
+
+ if (!FD_ISSET(fd, &fdr)) {
+ return;
+ }
+
+ res = do_msg_read(fd, &client.msg, client.read, 0, (struct sockaddr *)&client.addr, &addrlen);
+ if (res != -1) client.read += res;
+
+ // once we've read the entire message, echo it back
+ if (client.read >= client.msg.length) {
+ client.read = 0;
+ client.state = MSG_WRITE;
+ }
+ } else {
+ if (!FD_ISSET(fd, &fdw)) {
+ return;
+ }
+
+ res = do_msg_write(fd, &client.msg, client.wrote, 0, (struct sockaddr *)&client.addr, sizeof(client.addr));
+ if (res != -1) client.wrote += res;
+
+ // close the client once we've echo'd back the entire message
+ if (client.wrote >= client.msg.length) {
+ close(client.fd);
+ memset(&client, 0, sizeof(client_t));
+ }
+ }
+}
+
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ atexit(cleanup);
+ signal(SIGTERM, cleanup);
+
+ memset(&server, 0, sizeof(server_t));
+ memset(&client, 0, sizeof(client_t));
+
+ // create the socket and set to non-blocking
+#if !USE_UDP
+ server.fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+#else
+ server.fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#endif
+ if (server.fd == -1) {
+ perror("cannot create socket");
+ exit(EXIT_FAILURE);
+ }
+ fcntl(server.fd, F_SETFL, O_NONBLOCK);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ exit(EXIT_FAILURE);
+ }
+
+ res = bind(server.fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1) {
+ perror("bind failed");
+ exit(EXIT_FAILURE);
+ }
+
+#if !USE_UDP
+ res = listen(server.fd, 50);
+ if (res == -1) {
+ perror("listen failed");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(main_loop, 60, 0);
+#else
+ while (1) main_loop(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/sockets/test_sockets_gethostbyname.c b/tests/sockets/test_sockets_gethostbyname.c
new file mode 100644
index 00000000..12fc6d9d
--- /dev/null
+++ b/tests/sockets/test_sockets_gethostbyname.c
@@ -0,0 +1,49 @@
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+int sockfd;
+
+void finish(int result) {
+ close(sockfd);
+#if EMSCRIPTEN
+ REPORT_RESULT();
+#endif
+ exit(result);
+}
+
+int main() {
+ char str[INET_ADDRSTRLEN];
+ struct in_addr addr;
+ const char *res;
+ int err;
+
+ // resolve the hostname ot an actual address
+ struct hostent *host = gethostbyname("slashdot.org");
+
+ // convert the raw address to a string
+ char **raw_addr_list = host->h_addr_list;
+ int *raw_addr = (int*)*raw_addr_list;
+ res = inet_ntop(host->h_addrtype, raw_addr, str, INET_ADDRSTRLEN);
+ assert(res);
+
+ // convert the string to an in_addr structure
+ err = inet_pton(AF_INET, str, &addr);
+ assert(err == 1);
+
+ // do a reverse lookup on the ip address
+ struct hostent *host1 = gethostbyaddr(&addr, sizeof(addr), host->h_addrtype);
+ assert(strstr(host1->h_name, "slashdot.org"));
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tests/sockets/test_sockets_msg.h b/tests/sockets/test_sockets_msg.h
new file mode 100644
index 00000000..30094d65
--- /dev/null
+++ b/tests/sockets/test_sockets_msg.h
@@ -0,0 +1,78 @@
+#ifndef __TEST_SOCKETS_MSG_H__
+#define __TEST_SOCKETS_MSG_H__
+
+typedef struct {
+ char *buffer;
+ int length;
+} msg_t;
+
+int do_msg_read(int sockfd, msg_t *msg, int offset, int length, struct sockaddr *addr, socklen_t *addrlen) {
+ int res;
+
+ if (!msg->length) {
+ // read the message length
+ res = recvfrom(sockfd, &msg->length, sizeof(int), 0, (struct sockaddr *)addr, addrlen);
+ if (res == -1) {
+ assert(errno == EAGAIN);
+ return res;
+ }
+ assert(res != 0);
+ msg->buffer = malloc(msg->length);
+
+ printf("do_msg_read: allocating %d bytes for message\n", msg->length);
+ }
+
+ // read the actual message
+ int max = msg->length - offset;
+ if (length && max > length) {
+ max = length;
+ }
+ res = recvfrom(sockfd, msg->buffer + offset, max, 0, (struct sockaddr *)addr, addrlen);
+ if (res == -1) {
+ assert(errno == EAGAIN);
+ return res;
+ }
+
+ printf("do_msg_read: read %d bytes\n", res);
+
+ return res;
+}
+
+int do_msg_write(int sockfd, msg_t *msg, int offset, int length, struct sockaddr *addr, socklen_t addrlen) {
+ int res;
+
+ // send the message length first
+ if (!offset) {
+ if (addr) {
+ res = sendto(sockfd, &msg->length, sizeof(int), 0, addr, addrlen);
+ } else {
+ res = send(sockfd, &msg->length, sizeof(int), 0);
+ }
+ if (res == -1) {
+ assert(errno == EAGAIN);
+ return res;
+ }
+ assert(res == sizeof(int));
+ }
+
+ // then the actual message
+ int max = msg->length - offset;
+ if (length && max > length) {
+ max = length;
+ }
+ if (addr) {
+ res = sendto(sockfd, msg->buffer + offset, max, 0, addr, addrlen);
+ } else {
+ res = send(sockfd, msg->buffer + offset, max, 0);
+ }
+ if (res == -1) {
+ assert(errno == EAGAIN);
+ return res;
+ }
+
+ printf("do_msg_write: wrote %d bytes %d\n", res, msg->length);
+
+ return res;
+}
+
+#endif \ No newline at end of file
diff --git a/tests/sockets/test_sockets_partial_client.c b/tests/sockets/test_sockets_partial_client.c
new file mode 100644
index 00000000..dcf90f19
--- /dev/null
+++ b/tests/sockets/test_sockets_partial_client.c
@@ -0,0 +1,119 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+int sockfd = -1;
+int sum = 0;
+
+void finish(int result) {
+ close(sockfd);
+#if EMSCRIPTEN
+ REPORT_RESULT();
+#endif
+ exit(result);
+}
+
+void iter(void *arg) {
+ char buffer[1024];
+ char packetLength;
+ fd_set fdr;
+ int i;
+ int res;
+
+ // make sure that sockfd is ready to read
+ FD_ZERO(&fdr);
+ FD_SET(sockfd, &fdr);
+ res = select(64, &fdr, NULL, NULL, NULL);
+ if (res == -1) {
+ perror("select failed");
+ finish(EXIT_FAILURE);
+ } else if (!FD_ISSET(sockfd, &fdr)) {
+ return;
+ }
+
+ res = recv(sockfd, buffer, 1, 0);
+ if (res == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return; //try again
+ }
+
+ perror("unexcepted end of data");
+ finish(EXIT_FAILURE);
+ }
+
+ if (res != 1) {
+ perror("should read 1 byte");
+ finish(EXIT_FAILURE);
+ }
+
+ packetLength = buffer[0];
+ res = recv(sockfd, buffer, packetLength, 0);
+
+ printf("got %d,%d\n", res, packetLength);
+
+ if (res != packetLength) {
+ fprintf(stderr, "lost packet data, expected: %d readed: %d", packetLength, res);
+ finish(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < packetLength; ++i) {
+ if (buffer[i] != i+1) {
+ fprintf(stderr, "packet corrupted, expected: %d, actual: %d", i+1, buffer[i]);
+ finish(EXIT_FAILURE);
+ }
+
+ sum += buffer[i];
+ }
+
+ if (packetLength == buffer[0]) { // \x01\x01 - end marker
+ printf("sum: %d\n", sum);
+ finish(sum);
+ }
+}
+
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd == -1) {
+ perror("cannot create socket");
+ exit(EXIT_FAILURE);
+ }
+ fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ finish(EXIT_FAILURE);
+ }
+
+ res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1 && errno != EINPROGRESS) {
+ perror("connect failed");
+ finish(EXIT_FAILURE);
+ }
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(iter, 0, 0);
+#else
+ while (1) iter(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tests/sockets/test_sockets_partial_server.c b/tests/sockets/test_sockets_partial_server.c
new file mode 100644
index 00000000..dfe0e249
--- /dev/null
+++ b/tests/sockets/test_sockets_partial_server.c
@@ -0,0 +1,128 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+int serverfd = 0;
+int clientfd = 0;
+
+void cleanup() {
+ if (serverfd) close(serverfd);
+ if (clientfd) close(clientfd);
+}
+
+void do_send(int sockfd) {
+ static char* buffers[] = {
+ "\x09\x01\x02\x03\x04\x05\x06\x07\x08\x09\0",
+ "\x08\x01\x02\x03\x04\x05\x06\x07\x08\0",
+ "\x07\x01\x02\x03\x04\x05\x06\x07\0",
+ "\x06\x01\x02\x03\x04\x05\x06\0",
+ "\x05\x01\x02\x03\x04\x05\0",
+ "\x04\x01\x02\x03\x04\0",
+ "\x03\x01\x02\x03\0",
+ "\x02\x01\x02\0",
+ "\x01\x01\0"
+ };
+
+ int i;
+ int res;
+ char *buffer;
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+
+ for (i = 0; i < sizeof(buffers) / sizeof(char*); i++) {
+ buffer = buffers[i];
+
+ res = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1) {
+ perror("send failed");
+ exit(EXIT_FAILURE);
+ }
+ printf("sent \"%s\" (%d bytes)\n", buffer, res);
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+void iter(void *arg) {
+ int res;
+ fd_set fdr;
+ fd_set fdw;
+
+ // see if there are any connections to accept / write to
+ FD_ZERO(&fdr);
+ FD_ZERO(&fdw);
+ FD_SET(serverfd, &fdr);
+ if (clientfd) FD_SET(clientfd, &fdw);
+ res = select(64, &fdr, &fdw, NULL, NULL);
+ if (res == -1) {
+ perror("select failed");
+ exit(EXIT_SUCCESS);
+ }
+
+ if (FD_ISSET(serverfd, &fdr)) {
+ printf("accepted someone\n");
+ clientfd = accept(serverfd, NULL, NULL);
+ assert(clientfd != -1);
+ }
+
+ if (FD_ISSET(clientfd, &fdw)) {
+ do_send(clientfd);
+ }
+}
+
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ atexit(cleanup);
+ signal(SIGTERM, cleanup);
+
+ // create the socket
+ serverfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (serverfd == -1) {
+ perror("cannot create socket");
+ exit(EXIT_FAILURE);
+ }
+ fcntl(serverfd, F_SETFL, O_NONBLOCK);
+
+ // bind and listen to the supplied port
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ exit(EXIT_FAILURE);
+ }
+
+ res = bind(serverfd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1) {
+ perror("bind failed");
+ exit(EXIT_FAILURE);
+ }
+
+ res = listen(serverfd, 50);
+ if (res == -1) {
+ perror("listen failed");
+ exit(EXIT_FAILURE);
+ }
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(iter, 60, 0);
+#else
+ while (1) iter(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/sockets/test_sockets_select_server_closes_connection_client_rw.c b/tests/sockets/test_sockets_select_server_closes_connection_client_rw.c
new file mode 100644
index 00000000..198ad232
--- /dev/null
+++ b/tests/sockets/test_sockets_select_server_closes_connection_client_rw.c
@@ -0,0 +1,217 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#include "test_sockets_msg.h"
+
+#define MESSAGE "0123456789"
+
+int sockfd;
+msg_t readmsg;
+msg_t writemsg;
+
+void finish(int result) {
+ close(sockfd);
+#if EMSCRIPTEN
+ REPORT_RESULT();
+#endif
+ exit(result);
+}
+
+void main_loop(void *arg) {
+ static int state = 0;
+ static int readPos = 0;
+ static int writePos = 0;
+ int selectRes;
+ ssize_t transferAmount;
+ fd_set sett;
+
+ switch (state) {
+ case 0:
+ // writing 10 bytes to the server
+
+ // since the socket in the read file descriptors has no available data,
+ // select should tell us 0 handles are ready
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+ selectRes = select(64, &sett, NULL, NULL, NULL);
+ if (selectRes != 0) {
+ printf("case 0: read select != 0 (%d)\n", selectRes);
+ finish(EXIT_FAILURE);
+ }
+
+ // the socket in the write file descriptors has to result in either a 0 or 1
+ // the connection either is setting up or is established and writing is possible
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+ selectRes = select(64, NULL, &sett, NULL, NULL);
+ if (selectRes == -1) {
+ printf("case 0: write select == -1\n");
+ finish(EXIT_FAILURE);
+ } else if (selectRes == 0) {
+ return;
+ }
+
+ // send a single byte
+ transferAmount = do_msg_write(sockfd, &writemsg, writePos, 1, NULL, 0);
+ if (transferAmount != -1) writePos += transferAmount;
+
+ // after 10 bytes switch to next state
+ if (writePos >= writemsg.length) {
+ state = 1;
+ }
+ break;
+
+ case 1:
+ // wait until we can read one byte to make sure the server
+ // has sent the data and then closed the connection
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+ selectRes = select(64, &sett, NULL, NULL, NULL);
+ if (selectRes == -1) {
+ printf("case 1: read selectRes == -1\n");
+ finish(EXIT_FAILURE);
+ } else if (selectRes == 0) {
+ return;
+ }
+
+ // read a single byte
+ transferAmount = do_msg_read(sockfd, &readmsg, readPos, 1, NULL, NULL);
+ if (transferAmount != -1) readPos += transferAmount;
+
+ // if successfully reading 1 byte, switch to next state
+ if (readPos >= 1) {
+ state = 2;
+ }
+ break;
+
+ case 2:
+ // calling select with the socket in the write file descriptors should
+ // succeed, but the socket should not set in the set.
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+ selectRes = select(64, NULL, &sett, NULL, NULL);
+ if (selectRes != 0 || FD_ISSET(sockfd, &sett)) {
+ printf("case 2: write selectRes != 0 || FD_ISSET(sockfd, &sett)\n");
+ finish(EXIT_FAILURE);
+ }
+
+ // calling select with the socket in the read file descriptors
+ // has to succeed because there is still data in the inQueue
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+ selectRes = select(64, &sett, NULL, NULL, NULL);
+ if (selectRes != 1) {
+ printf("case 2: read selectRes != 1\n");
+ finish(EXIT_FAILURE);
+ } else if (selectRes == 0) {
+ return;
+ }
+
+ // read a single byte
+ transferAmount = do_msg_read(sockfd, &readmsg, readPos, 1, NULL, NULL);
+ if (transferAmount != -1) readPos += transferAmount;
+
+ // with 10 bytes read the inQueue is empty => switch state
+ if (readPos >= readmsg.length) {
+ state = 3;
+ }
+ break;
+
+ case 3:
+ // calling select with the socket in the read file descriptors
+ // should succeed
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+ selectRes = select(64, &sett, NULL, NULL, NULL);
+ if (selectRes != 1) {
+ printf("case 3: read selectRes != 1\n");
+ finish(EXIT_FAILURE);
+ }
+
+ // but recv should return 0 signaling the remote
+ // end has closed the connection.
+ transferAmount = do_msg_read(sockfd, &readmsg, readPos, 0, NULL, NULL);
+ if (transferAmount) {
+ printf("case 3: read != 0\n");
+ finish(EXIT_FAILURE);
+ }
+
+ // report back success, the 266 is just an arbitrary value without
+ // deeper meaning
+ finish(266);
+ break;
+
+ default:
+ printf("Impossible state!\n");
+ finish(EXIT_FAILURE);
+ break;
+ }
+
+ return;
+}
+
+// This test checks for an intended asymmetry in the behavior of the select function.
+// Scenario: the client sends data to the server. After 10 received bytes the
+// server sends 10 bytes on its own and immediately afterwards closes the connection.
+// This mimics a typical connect-request-response-disconnect situation.
+// After the server closed the connection select calls with the socket in the write file
+// descriptors have to fail as the tcp connection is already down and there is no way
+// anymore to send data.
+// Select calls with the socket in the read file descriptor list still have to succeed
+// as there are still 10 bytes to read from the inQueue. So, for the same socket the
+// select call behaves differently depending on whether the socket is listed in the
+// read or write file descriptors.
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ memset(&readmsg, 0, sizeof(msg_t));
+ memset(&writemsg, 0, sizeof(msg_t));
+ writemsg.length = strlen(MESSAGE) + 1;
+ writemsg.buffer = malloc(writemsg.length);
+ strncpy(writemsg.buffer, MESSAGE, writemsg.length);
+
+ sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd == -1) {
+ perror("cannot create socket");
+ finish(EXIT_FAILURE);
+ }
+ fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ finish(EXIT_FAILURE);
+ }
+
+ // This call should succeed (even if the server port is closed)
+ res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1 && errno != EINPROGRESS) {
+ perror("connect failed");
+ finish(EXIT_FAILURE);
+ }
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(main_loop, 0, 0);
+#else
+ while (1) main_loop(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tests/sockets/test_sockets_select_server_no_accept_client.c b/tests/sockets/test_sockets_select_server_no_accept_client.c
new file mode 100644
index 00000000..e05bd4c8
--- /dev/null
+++ b/tests/sockets/test_sockets_select_server_no_accept_client.c
@@ -0,0 +1,98 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#define EXPECTED_BYTES 5
+
+int sockfd = -1;
+
+void finish(int result) {
+ close(sockfd);
+#if EMSCRIPTEN
+ REPORT_RESULT();
+#endif
+ exit(result);
+}
+
+void iter(void *arg) {
+ static int retries = 0;
+
+ fd_set sett;
+ FD_ZERO(&sett);
+ FD_SET(sockfd, &sett);
+
+ // currently, we've connected to a closed server port.
+ // the initial async connect "succeeded" and select
+ // should say that the socket is ready for a non-blocking
+ // read, however, the read should be 0 sized signalling
+ // that the remote end has closed.
+ int handles = select(64, &sett, NULL, NULL, NULL);
+ if (handles == -1) {
+ perror("select failed");
+ finish(EXIT_FAILURE);
+ }
+
+ if (FD_ISSET(sockfd, &sett)) {
+ char buffer[1024];
+ int n = recv(sockfd, buffer, sizeof(buffer), 0);
+ if (n == -1 && retries++ > 10) {
+ perror("revv failed");
+ finish(EXIT_FAILURE);
+ } else if (!n) {
+ perror("Connection to websocket server failed as expected.");
+ finish(266);
+ }
+ }
+}
+
+// This is for testing a websocket connection to a closed server port.
+// The connect call will succeed (due to the asynchronous websocket
+// behavior) but once the underlying websocket system realized that
+// the connection cannot be established, the next select call will fail.
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd == -1) {
+ perror("cannot create socket");
+ finish(EXIT_FAILURE);
+ }
+ fcntl(sockfd, F_SETFL, O_NONBLOCK);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ finish(EXIT_FAILURE);
+ }
+
+ // This call should succeed (even if the server port is closed)
+ res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1 && errno != EINPROGRESS) {
+ perror("connect failed");
+ finish(EXIT_FAILURE);
+ }
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(iter, 0, 0);
+#else
+ while (1) iter(NULL);
+#endif
+
+ return EXIT_FAILURE;
+}
+
diff --git a/tests/sockets/test_sockets_select_server_no_accept_server.c b/tests/sockets/test_sockets_select_server_no_accept_server.c
new file mode 100644
index 00000000..4a399ed1
--- /dev/null
+++ b/tests/sockets/test_sockets_select_server_no_accept_server.c
@@ -0,0 +1,86 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+int serverfd = -1;
+
+void iter(void *arg) {
+ int res;
+ fd_set fdr;
+ fd_set fdw;
+
+ // see if there are any connections to accept / write to
+ FD_ZERO(&fdr);
+ FD_ZERO(&fdw);
+ FD_SET(serverfd, &fdr);
+ if (clientfd != -1) FD_SET(clientfd, &fdw);
+ res = select(64, &fdr, &fdw, NULL, NULL);
+ if (res == -1) {
+ perror("select failed");
+ exit(EXIT_SUCCESS);
+ }
+
+ if (FD_ISSET(serverfd, &fdr)) {
+ printf("accepted someone\n");
+ clientfd = accept(serverfd, NULL, NULL);
+ assert(clientfd != -1);
+ }
+
+ if (FD_ISSET(clientfd, &fdw)) {
+ do_send(clientfd);
+ }
+}
+
+int main() {
+ struct sockaddr_in addr;
+ int res;
+
+ // create the socket
+ serverfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (serverfd == -1) {
+ perror("cannot create socket");
+ exit(EXIT_FAILURE);
+ }
+ fcntl(serverfd, F_SETFL, O_NONBLOCK);
+
+ // bind and listen to the supplied port
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(SOCKK);
+ if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
+ perror("inet_pton failed");
+ exit(EXIT_FAILURE);
+ }
+
+ res = bind(serverfd, (struct sockaddr *)&addr, sizeof(addr));
+ if (res == -1) {
+ perror("bind failed");
+ exit(EXIT_FAILURE);
+ }
+
+ res = listen(serverfd, 50);
+ if (res == -1) {
+ perror("listen failed");
+ exit(EXIT_FAILURE);
+ }
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(iter, 60, 0);
+#else
+ while (1) iter(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/sockets/webrtc_host.c b/tests/sockets/webrtc_host.c
new file mode 100644
index 00000000..770e59e0
--- /dev/null
+++ b/tests/sockets/webrtc_host.c
@@ -0,0 +1,89 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#define EXPECTED_BYTES 5
+#define BUFLEN 16
+
+int result = 0;
+int sock;
+char buf[BUFLEN];
+char expected[] = "emscripten";
+struct sockaddr_in si_host,
+ si_peer;
+struct iovec iov[1];
+struct msghdr hdr;
+int done = 0;
+
+void iter(void* arg) {
+ int n;
+ n = recvmsg(sock, &hdr, 0);
+
+ if(0 < n) {
+ done = 1;
+ fprintf(stderr, "received %d bytes: %s", n, (char*)hdr.msg_iov[0].iov_base);
+
+ shutdown(sock, SHUT_RDWR);
+ close(sock);
+
+#if EMSCRIPTEN
+ int result = 1;
+ REPORT_RESULT();
+ exit(EXIT_SUCCESS);
+ emscripten_cancel_main_loop();
+#endif
+ } else if(EWOULDBLOCK != errno) {
+ perror("recvmsg failed");
+ exit(EXIT_FAILURE);
+ emscripten_cancel_main_loop();
+ }
+}
+
+int main(void)
+{
+ memset(&si_host, 0, sizeof(struct sockaddr_in));
+ memset(&si_peer, 0, sizeof(struct sockaddr_in));
+
+ si_host.sin_family = AF_INET;
+ si_host.sin_port = htons(8991);
+ si_host.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if(-1 == (sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))) {
+ perror("cannot create host socket");
+ exit(EXIT_FAILURE);
+ }
+
+ if(-1 == bind(sock, (struct sockaddr*)&si_host, sizeof(struct sockaddr))) {
+ perror("cannot bind host socket");
+ exit(EXIT_FAILURE);
+ }
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof(buf);
+
+ memset (&hdr, 0, sizeof (struct msghdr));
+
+ hdr.msg_name = &si_peer;
+ hdr.msg_namelen = sizeof(struct sockaddr_in);
+ hdr.msg_iov = iov;
+ hdr.msg_iovlen = 1;
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(iter, 0, 0);
+#else
+ while (!done) iter(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/sockets/webrtc_peer.c b/tests/sockets/webrtc_peer.c
new file mode 100644
index 00000000..d24979e7
--- /dev/null
+++ b/tests/sockets/webrtc_peer.c
@@ -0,0 +1,81 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <assert.h>
+#if EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#define EXPECTED_BYTES 5
+#define BUFLEN 16
+#define HOST_ADDR "10.0.0.1"
+
+int result = 0;
+int sock;
+char buf[16] = "emscripten";
+struct sockaddr_in si_host;
+struct iovec iov[1];
+struct msghdr hdr;
+int done = 0;
+
+void iter(void* arg) {
+ int n;
+ n = sendmsg(sock, &hdr, 0);
+
+ if(0 < n) {
+ done = 1;
+ fprintf(stderr, "sent %d bytes: %s", n, (char*)hdr.msg_iov[0].iov_base);
+
+ shutdown(sock, SHUT_RDWR);
+ close(sock);
+
+ exit(EXIT_SUCCESS);
+ emscripten_cancel_main_loop();
+ } else if(EWOULDBLOCK != errno) {
+ perror("sendmsg failed");
+ exit(EXIT_FAILURE);
+ emscripten_cancel_main_loop();
+ }
+}
+
+int main(void)
+{
+ memset(&si_host, 0, sizeof(struct sockaddr_in));
+
+ si_host.sin_family = AF_INET;
+ si_host.sin_port = htons(8991);
+ if(0 == inet_pton(AF_INET, HOST_ADDR, &si_host.sin_addr)) {
+ perror("inet_aton failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if(-1 == (sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP))) {
+ perror("cannot create socket");
+ exit(EXIT_FAILURE);
+ }
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof(buf);
+
+ memset (&hdr, 0, sizeof (struct msghdr));
+
+ hdr.msg_name = &si_host;
+ hdr.msg_namelen = sizeof(struct sockaddr_in);
+ hdr.msg_iov = iov;
+ hdr.msg_iovlen = 1;
+
+#if EMSCRIPTEN
+ emscripten_set_main_loop(iter, 0, 0);
+#else
+ while (!done) iter(NULL);
+#endif
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/stdio/test_rename.c b/tests/stdio/test_rename.c
index 20ffb513..f15c8140 100644
--- a/tests/stdio/test_rename.c
+++ b/tests/stdio/test_rename.c
@@ -1,6 +1,7 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -104,4 +105,4 @@ int main() {
setup();
test();
return EXIT_SUCCESS;
-} \ No newline at end of file
+}
diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py
new file mode 100644
index 00000000..e9cfee52
--- /dev/null
+++ b/tests/test_benchmark.py
@@ -0,0 +1,507 @@
+import math, os, shutil, subprocess
+import runner
+from runner import RunnerCore, path_from_root
+from tools.shared import *
+
+# standard arguments for timing:
+# 0: no runtime, just startup
+# 1: very little runtime
+# 2: 0.5 seconds
+# 3: 1 second
+# 4: 5 seconds
+# 5: 10 seconds
+DEFAULT_ARG = '4'
+
+TEST_REPS = 2
+TOTAL_TESTS = 8
+
+tests_done = 0
+total_times = map(lambda x: 0., range(TOTAL_TESTS))
+total_native_times = map(lambda x: 0., range(TOTAL_TESTS))
+
+class benchmark(RunnerCore):
+ save_dir = True
+
+ @classmethod
+ def setUpClass(self):
+ super(benchmark, self).setUpClass()
+
+ fingerprint = [time.asctime()]
+ try:
+ fingerprint.append('em: ' + Popen(['git', 'show'], stdout=PIPE).communicate()[0].split('\n')[0])
+ except:
+ pass
+ try:
+ d = os.getcwd()
+ os.chdir(os.path.expanduser('~/Dev/mozilla-central'))
+ fingerprint.append('sm: ' + filter(lambda line: 'changeset' in line,
+ Popen(['hg', 'tip'], stdout=PIPE).communicate()[0].split('\n'))[0])
+ except:
+ pass
+ finally:
+ os.chdir(d)
+ fingerprint.append('llvm: ' + LLVM_ROOT)
+ print 'Running Emscripten benchmarks... [ %s ]' % ' | '.join(fingerprint)
+
+ assert(os.path.exists(CLOSURE_COMPILER))
+
+ try:
+ index = SPIDERMONKEY_ENGINE.index("options('strict')")
+ SPIDERMONKEY_ENGINE = SPIDERMONKEY_ENGINE[:index-1] + SPIDERMONKEY_ENGINE[index+1:] # closure generates non-strict
+ except:
+ pass
+
+ Building.COMPILER = CLANG
+ Building.COMPILER_TEST_OPTS = []
+
+ # Pick the JS engine to benchmark. If you specify one, it will be picked. For example, python tests/runner.py benchmark SPIDERMONKEY_ENGINE
+ global JS_ENGINE
+ JS_ENGINE = Building.JS_ENGINE_OVERRIDE if Building.JS_ENGINE_OVERRIDE is not None else JS_ENGINES[0]
+ print 'Benchmarking JS engine: %s' % JS_ENGINE
+
+ def print_stats(self, times, native_times, last=False, reps=TEST_REPS):
+ if reps == 0:
+ print '(no reps)'
+ return
+ mean = sum(times)/len(times)
+ squared_times = map(lambda x: x*x, times)
+ mean_of_squared = sum(squared_times)/len(times)
+ std = math.sqrt(mean_of_squared - mean*mean)
+ sorted_times = times[:]
+ sorted_times.sort()
+ median = sum(sorted_times[len(sorted_times)/2 - 1:len(sorted_times)/2 + 1])/2
+
+ mean_native = sum(native_times)/len(native_times)
+ squared_native_times = map(lambda x: x*x, native_times)
+ mean_of_squared_native = sum(squared_native_times)/len(native_times)
+ std_native = math.sqrt(mean_of_squared_native - mean_native*mean_native)
+ sorted_native_times = native_times[:]
+ sorted_native_times.sort()
+ median_native = sum(sorted_native_times[len(sorted_native_times)/2 - 1:len(sorted_native_times)/2 + 1])/2
+
+ final = mean / mean_native
+
+ if last:
+ norm = 0
+ for i in range(len(times)):
+ norm += times[i]/native_times[i]
+ norm /= len(times)
+ print
+ print ' JavaScript: %.3f Native: %.3f Ratio: %.3f Normalized ratio: %.3f' % (mean, mean_native, final, norm)
+ return
+
+ print
+ print ' JavaScript: mean: %.3f (+-%.3f) secs median: %.3f range: %.3f-%.3f (noise: %3.3f%%) (%d runs)' % (mean, std, median, min(times), max(times), 100*std/mean, reps)
+ print ' Native : mean: %.3f (+-%.3f) secs median: %.3f range: %.3f-%.3f (noise: %3.3f%%) JS is %.2f X slower' % (mean_native, std_native, median_native, min(native_times), max(native_times), 100*std_native/mean_native, final)
+
+ def do_benchmark(self, name, src, expected_output='FAIL', args=[], emcc_args=[], native_args=[], shared_args=[], force_c=False, reps=TEST_REPS, native_exec=None, output_parser=None, args_processor=None):
+ args = args or [DEFAULT_ARG]
+ if args_processor: args = args_processor(args)
+
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, name + '.c' + ('' if force_c else 'pp'))
+ f = open(filename, 'w')
+ f.write(src)
+ f.close()
+ final_filename = os.path.join(dirname, name + '.js')
+
+ open('hardcode.py', 'w').write('''
+def process(filename):
+ js = open(filename).read()
+ replaced = js.replace("run();", "run(%s.concat(Module[\\"arguments\\"]));")
+ assert js != replaced
+ open(filename, 'w').write(replaced)
+import sys
+process(sys.argv[1])
+''' % str(args[:-1]) # do not hardcode in the last argument, the default arg
+)
+
+ try_delete(final_filename)
+ output = Popen([PYTHON, EMCC, filename, #'-O3',
+ '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
+ '--llvm-lto', '3', '--memory-init-file', '0', '--js-transform', 'python hardcode.py',
+ '-s', 'TOTAL_MEMORY=128*1024*1024',
+ '--closure', '1',
+ #'-g',
+ '-o', final_filename] + shared_args + emcc_args, stdout=PIPE, stderr=self.stderr_redirect).communicate()
+ assert os.path.exists(final_filename), 'Failed to compile file: ' + output[0]
+
+ # Run JS
+ global total_times, tests_done
+ times = []
+ for i in range(reps):
+ start = time.time()
+ js_output = run_js(final_filename, engine=JS_ENGINE, args=args, stderr=PIPE, full_output=True)
+
+ if i == 0 and 'uccessfully compiled asm.js code' in js_output:
+ if 'asm.js link error' not in js_output:
+ print "[%s was asm.js'ified]" % name
+ if not output_parser:
+ curr = time.time()-start
+ else:
+ curr = output_parser(js_output)
+ times.append(curr)
+ total_times[tests_done] += curr
+ if i == 0:
+ # Sanity check on output
+ self.assertContained(expected_output, js_output)
+
+ # Run natively
+ if not native_exec:
+ self.build_native(filename, shared_args + native_args)
+ else:
+ shutil.copyfile(native_exec, filename + '.native')
+ shutil.copymode(native_exec, filename + '.native')
+ global total_native_times
+ native_times = []
+ for i in range(reps):
+ start = time.time()
+ native_output = self.run_native(filename, args)
+ if i == 0:
+ # Sanity check on output
+ self.assertContained(expected_output, native_output)
+ if not output_parser:
+ curr = time.time()-start
+ else:
+ curr = output_parser(native_output)
+ native_times.append(curr)
+ total_native_times[tests_done] += curr
+
+ self.print_stats(times, native_times, reps=reps)
+
+ #tests_done += 1
+ #if tests_done == TOTAL_TESTS:
+ # print 'Total stats:',
+ # self.print_stats(total_times, total_native_times, last=True)
+
+ def test_primes(self):
+ src = r'''
+ #include<stdio.h>
+ #include<math.h>
+ int main(int argc, char **argv) {
+ int arg = argc > 1 ? argv[1][0] - '0' : 3;
+ switch(arg) {
+ case 0: return 0; break;
+ case 1: arg = 33000; break;
+ case 2: arg = 130000; break;
+ case 3: arg = 220000; break;
+ case 4: arg = 610000; break;
+ case 5: arg = 1010000; break;
+ default: printf("error: %d\\n", arg); return -1;
+ }
+
+ int primes = 0, curri = 2;
+ while (primes < arg) {
+ int ok = true;
+ for (int j = 2; j < sqrtf(curri); j++) {
+ if (curri % j == 0) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ primes++;
+ }
+ curri++;
+ }
+ printf("lastprime: %d.\n", curri-1);
+ return 0;
+ }
+ '''
+ self.do_benchmark('primes', src, 'lastprime:')
+
+ def test_memops(self):
+ src = '''
+ #include<stdio.h>
+ #include<string.h>
+ #include<stdlib.h>
+ int main(int argc, char **argv) {
+ int N, M;
+ int arg = argc > 1 ? argv[1][0] - '0' : 3;
+ switch(arg) {
+ case 0: return 0; break;
+ case 1: N = 1024*1024; M = 55; break;
+ case 2: N = 1024*1024; M = 400; break;
+ case 3: N = 1024*1024; M = 800; break;
+ case 4: N = 1024*1024; M = 4000; break;
+ case 5: N = 1024*1024; M = 8000; break;
+ default: printf("error: %d\\n", arg); return -1;
+ }
+
+ int final = 0;
+ char *buf = (char*)malloc(N);
+ for (int t = 0; t < M; t++) {
+ for (int i = 0; i < N; i++)
+ buf[i] = (i + final)%256;
+ for (int i = 0; i < N; i++)
+ final += buf[i] & 1;
+ final = final % 1000;
+ }
+ printf("final: %d.\\n", final);
+ return 0;
+ }
+ '''
+ self.do_benchmark('memops', src, 'final:')
+
+ def zzztest_files(self):
+ src = r'''
+ #include<stdio.h>
+ #include<stdlib.h>
+ #include<assert.h>
+ #include <unistd.h>
+
+ int main() {
+ int N = 100;
+ int M = 1000;
+ int K = 1000;
+ unsigned char *k = (unsigned char*)malloc(K+1), *k2 = (unsigned char*)malloc(K+1);
+ for (int i = 0; i < K; i++) {
+ k[i] = (i % 250) + 1;
+ }
+ k[K] = 0;
+ char buf[100];
+ for (int i = 0; i < N; i++) {
+ sprintf(buf, "/dev/shm/file-%d.dat", i);
+ FILE *f = fopen(buf, "w");
+ for (int j = 0; j < M; j++) {
+ fwrite(k, 1, (j % K) + 1, f);
+ }
+ fclose(f);
+ }
+ for (int i = 0; i < N; i++) {
+ sprintf(buf, "/dev/shm/file-%d.dat", i);
+ FILE *f = fopen(buf, "r");
+ for (int j = 0; j < M; j++) {
+ fread(k2, 1, (j % K) + 1, f);
+ }
+ fclose(f);
+ for (int j = 0; j < K; j++) {
+ assert(k[j] == k2[j]);
+ }
+ unlink(buf);
+ }
+ printf("ok");
+ return 0;
+ }
+ '''
+ self.do_benchmark(src, 'ok')
+
+ def test_copy(self):
+ src = r'''
+ #include<stdio.h>
+ struct vec {
+ int x, y, z;
+ int r, g, b;
+ vec(int x_, int y_, int z_, int r_, int g_, int b_) : x(x_), y(y_), z(z_), r(r_), g(g_), b(b_) {}
+ static vec add(vec a, vec b) {
+ return vec(a.x+b.x, a.y+b.y, a.z+b.z, a.r+b.r, a.g+b.g, a.b+b.b);
+ }
+ void norm() {
+ x %= 1024;
+ y %= 1024;
+ z %= 1024;
+ r %= 1024;
+ b %= 1024;
+ g %= 1024;
+ }
+ int sum() { return x + y + z + r + g + b; }
+ };
+ int main(int argc, char **argv) {
+ int arg = argc > 1 ? argv[1][0] - '0' : 3;
+ switch(arg) {
+ case 0: return 0; break;
+ case 1: arg = 75; break;
+ case 2: arg = 625; break;
+ case 3: arg = 1250; break;
+ case 4: arg = 5*1250; break;
+ case 5: arg = 10*1250; break;
+ default: printf("error: %d\\n", arg); return -1;
+ }
+
+ int total = 0;
+ for (int i = 0; i < arg; i++) {
+ for (int j = 0; j < 50000; j++) {
+ vec c(i, i+i%10, j*2, i%255, j%120, i%15);
+ vec d(j+i%10, j*2, j%255, i%120, j%15, j);
+ vec e = c;
+ c.norm();
+ d.norm();
+ vec f = vec::add(c, d);
+ f = vec::add(e, f);
+ f.norm();
+ f = vec::add(d, f);
+ total += f.sum() % 100;
+ total %= 10240;
+ }
+ }
+ printf("sum:%d\n", total);
+ return 0;
+ }
+ '''
+ self.do_benchmark('copy', src, 'sum:')
+
+ def test_fannkuch(self):
+ src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read().replace(
+ 'int n = argc > 1 ? atoi(argv[1]) : 0;',
+ '''
+ int n;
+ int arg = argc > 1 ? argv[1][0] - '0' : 3;
+ switch(arg) {
+ case 0: return 0; break;
+ case 1: n = 9; break;
+ case 2: n = 10; break;
+ case 3: n = 11; break;
+ case 4: n = 11; break;
+ case 5: n = 12; break;
+ default: printf("error: %d\\n", arg); return -1;
+ }
+ '''
+ )
+ assert 'switch(arg)' in src
+ self.do_benchmark('fannkuch', src, 'Pfannkuchen(')
+
+ def test_corrections(self):
+ src = r'''
+ #include<stdio.h>
+ #include<math.h>
+ int main(int argc, char **argv) {
+ int N, M;
+ int arg = argc > 1 ? argv[1][0] - '0' : 3;
+ switch(arg) {
+ case 0: return 0; break;
+ case 1: N = 20000; M = 550; break;
+ case 2: N = 20000; M = 3500; break;
+ case 3: N = 20000; M = 7000; break;
+ case 4: N = 20000; M = 5*7000; break;
+ case 5: N = 20000; M = 10*7000; break;
+ default: printf("error: %d\\n", arg); return -1;
+ }
+
+ unsigned int f = 0;
+ unsigned short s = 0;
+ for (int t = 0; t < M; t++) {
+ for (int i = 0; i < N; i++) {
+ f += i / ((t % 5)+1);
+ if (f > 1000) f /= (t % 3)+1;
+ if (i % 4 == 0) f += i * (i % 8 == 0 ? 1 : -1);
+ s += (short(f)*short(f)) % 256;
+ }
+ }
+ printf("final: %d:%d.\n", f, s);
+ return 0;
+ }
+ '''
+ self.do_benchmark('corrections', src, 'final:', emcc_args=['-s', 'CORRECT_SIGNS=1', '-s', 'CORRECT_OVERFLOWS=1', '-s', 'CORRECT_ROUNDINGS=1'])
+
+ def fasta(self, name, double_rep, emcc_args=[]):
+ src = open(path_from_root('tests', 'fasta.cpp'), 'r').read().replace('double', double_rep)
+ src = src.replace(' const size_t n = ( argc > 1 ) ? atoi( argv[1] ) : 512;', '''
+ int n;
+ int arg = argc > 1 ? argv[1][0] - '0' : 3;
+ switch(arg) {
+ case 0: return 0; break;
+ case 1: n = 19000000/20; break;
+ case 2: n = 19000000/2; break;
+ case 3: n = 19000000; break;
+ case 4: n = 19000000*5; break;
+ case 5: n = 19000000*10; break;
+ default: printf("error: %d\\n", arg); return -1;
+ }
+ ''')
+ assert 'switch(arg)' in src
+ self.do_benchmark('fasta', src, '')
+
+ def test_fasta_float(self):
+ self.fasta('fasta_float', 'float')
+
+ def test_fasta_double(self):
+ self.fasta('fasta_double', 'double')
+
+ def test_fasta_double_full(self):
+ self.fasta('fasta_double_full', 'double', emcc_args=['-s', 'DOUBLE_MODE=1'])
+
+ def test_skinning(self):
+ src = open(path_from_root('tests', 'skinning_test_no_simd.cpp'), 'r').read()
+ self.do_benchmark('skinning', src, 'blah=0.000000')
+
+ def test_life(self):
+ src = open(path_from_root('tests', 'life.c'), 'r').read()
+ self.do_benchmark('life', src, '''--------------------------------''', shared_args=['-std=c99'], force_c=True)
+
+ def test_linpack(self):
+ def output_parser(output):
+ return 100.0/float(re.search('Unrolled Double Precision +([\d\.]+) Mflops', output).group(1))
+ self.do_benchmark('linpack', open(path_from_root('tests', 'linpack.c')).read(), '''Unrolled Double Precision''', force_c=True, output_parser=output_parser)
+
+ def test_zzz_java_nbody(self): # tests xmlvm compiled java, including bitcasts of doubles, i64 math, etc.
+ args = [path_from_root('tests', 'nbody-java', x) for x in os.listdir(path_from_root('tests', 'nbody-java')) if x.endswith('.c')] + \
+ ['-I' + path_from_root('tests', 'nbody-java')]
+ self.do_benchmark('nbody_java', '', '''Time(s)''',
+ force_c=True, emcc_args=args + ['-s', 'PRECISE_I64_MATH=1', '--llvm-lto', '2'], native_args=args + ['-lgc', '-std=c99', '-target', 'x86_64-pc-linux-gnu', '-lm'])
+
+ def lua(self, benchmark, expected, output_parser=None, args_processor=None):
+ shutil.copyfile(path_from_root('tests', 'lua', benchmark + '.lua'), benchmark + '.lua')
+ #shutil.copyfile(path_from_root('tests', 'lua', 'binarytrees.lua'), 'binarytrees.lua')
+ #shutil.copyfile(path_from_root('tests', 'lua', 'scimark.lua'), 'scimark.lua')
+ emcc_args = self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None) + \
+ ['--embed-file', benchmark + '.lua']
+ #['--embed-file', 'binarytrees.lua', '--embed-file', 'scimark.lua'] + ['--minify', '0']
+ shutil.copyfile(emcc_args[0], emcc_args[0] + '.bc')
+ emcc_args[0] += '.bc'
+ native_args = self.get_library('lua_native', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=True)
+
+ self.do_benchmark('lua_' + benchmark, '', expected,
+ force_c=True, args=[benchmark + '.lua', DEFAULT_ARG], emcc_args=emcc_args, native_args=native_args, native_exec=os.path.join('building', 'lua_native', 'src', 'lua'),
+ output_parser=output_parser, args_processor=args_processor)
+
+ def test_zzz_lua_scimark(self):
+ def output_parser(output):
+ return 100.0/float(re.search('\nSciMark +([\d\.]+) ', output).group(1))
+
+ self.lua('scimark', '[small problem sizes]', output_parser=output_parser)
+
+ def test_zzz_lua_binarytrees(self):
+ # js version: ['binarytrees.lua', {0: 0, 1: 9.5, 2: 11.99, 3: 12.85, 4: 14.72, 5: 15.82}[arguments[0]]]
+ self.lua('binarytrees', 'long lived tree of depth')
+
+ def test_zzz_zlib(self):
+ src = open(path_from_root('tests', 'zlib', 'benchmark.c'), 'r').read()
+ emcc_args = self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']) + \
+ ['-I' + path_from_root('tests', 'zlib')]
+ native_args = self.get_library('zlib_native', os.path.join('libz.a'), make_args=['libz.a'], native=True) + \
+ ['-I' + path_from_root('tests', 'zlib')]
+ self.do_benchmark('zlib', src, '''ok.''',
+ force_c=True, emcc_args=emcc_args, native_args=native_args)
+
+ def test_zzz_box2d(self): # Called thus so it runs late in the alphabetical cycle... it is long
+ src = open(path_from_root('tests', 'box2d', 'Benchmark.cpp'), 'r').read()
+
+ js_lib = self.get_library('box2d', [os.path.join('box2d.a')], configure=None)
+ native_lib = self.get_library('box2d_native', [os.path.join('box2d.a')], configure=None, native=True)
+
+ emcc_args = js_lib + ['-I' + path_from_root('tests', 'box2d')]
+ native_args = native_lib + ['-I' + path_from_root('tests', 'box2d')]
+
+ self.do_benchmark('box2d', src, 'frame averages', emcc_args=emcc_args, native_args=native_args)
+
+ def test_zzz_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
+ src = open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'BenchmarkDemo.cpp'), 'r').read() + \
+ open(path_from_root('tests', 'bullet', 'Demos', 'Benchmarks', 'main.cpp'), 'r').read()
+
+ js_lib = self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
+ os.path.join('src', '.libs', 'libBulletCollision.a'),
+ os.path.join('src', '.libs', 'libLinearMath.a')],
+ configure_args=['--disable-demos','--disable-dependency-tracking'])
+ native_lib = self.get_library('bullet_native', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
+ os.path.join('src', '.libs', 'libBulletCollision.a'),
+ os.path.join('src', '.libs', 'libLinearMath.a')],
+ configure_args=['--disable-demos','--disable-dependency-tracking'],
+ native=True)
+
+ emcc_args = js_lib + ['-I' + path_from_root('tests', 'bullet', 'src'),
+ '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks'),
+ '-s', 'DEAD_FUNCTIONS=["__ZSt9terminatev"]']
+ native_args = native_lib + ['-I' + path_from_root('tests', 'bullet', 'src'),
+ '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks')]
+
+ self.do_benchmark('bullet', src, '\nok.\n', emcc_args=emcc_args, native_args=native_args) \ No newline at end of file
diff --git a/tests/test_browser.py b/tests/test_browser.py
new file mode 100644
index 00000000..2c5d65ee
--- /dev/null
+++ b/tests/test_browser.py
@@ -0,0 +1,1385 @@
+import BaseHTTPServer, multiprocessing, os, shutil, subprocess, unittest
+from runner import BrowserCore, path_from_root
+from tools.shared import *
+
+''' Enable this code to run in another browser than webbrowser detects as default
+def run_in_other_browser(url):
+ execute(['yourbrowser', url])
+webbrowser.open_new = run_in_other_browser
+'''
+
+class browser(BrowserCore):
+ @staticmethod
+ def audio():
+ print
+ print 'Running the browser audio tests. Make sure to listen to hear the correct results!'
+ print
+ audio_test_cases = [
+ 'test_sdl_audio',
+ 'test_sdl_audio_mix_channels',
+ 'test_sdl_audio_mix',
+ 'test_sdl_audio_quickload',
+ 'test_openal_playback',
+ 'test_openal_buffers',
+ 'test_freealut'
+ ]
+ return unittest.TestSuite(map(browser, audio_test_cases))
+
+ @classmethod
+ def setUpClass(self):
+ super(browser, self).setUpClass()
+ print
+ print 'Running the browser tests. Make sure the browser allows popups from localhost.'
+ print
+
+ def test_html(self):
+ # test HTML generation.
+ self.btest('hello_world_sdl.cpp', reference='htmltest.png',
+ message='You should see "hello, world!" and a colored cube.')
+
+ def test_html_source_map(self):
+ if 'test_html_source_map' not in str(sys.argv): return self.skip('''This test
+requires manual intervention; will not be run unless explicitly requested''')
+ cpp_file = os.path.join(self.get_dir(), 'src.cpp')
+ html_file = os.path.join(self.get_dir(), 'src.html')
+ # browsers will try to 'guess' the corresponding original line if a
+ # generated line is unmapped, so if we want to make sure that our
+ # numbering is correct, we need to provide a couple of 'possible wrong
+ # answers'. thus, we add some printf calls so that the cpp file gets
+ # multiple mapped lines. in other words, if the program consists of a
+ # single 'throw' statement, browsers may just map any thrown exception to
+ # that line, because it will be the only mapped line.
+ with open(cpp_file, 'w') as f:
+ f.write(r'''
+ #include <cstdio>
+
+ int main() {
+ printf("Starting test\n");
+ try {
+ throw 42; // line 8
+ } catch (int e) { }
+ printf("done\n");
+ return 0;
+ }
+ ''')
+ # use relative paths when calling emcc, because file:// URIs can only load
+ # sourceContent when the maps are relative paths
+ Popen([PYTHON, EMCC, 'src.cpp', '-o', 'src.html', '-g4'],
+ cwd=self.get_dir()).communicate()
+ webbrowser.open_new('file://' + html_file)
+ print '''
+Set the debugger to pause on exceptions
+You should see an exception thrown at src.cpp:7.
+Press any key to continue.'''
+ raw_input()
+
+ def build_native_lzma(self):
+ lzma_native = path_from_root('third_party', 'lzma.js', 'lzma-native')
+ if os.path.isfile(lzma_native) and os.access(lzma_native, os.X_OK): return
+
+ cwd = os.getcwd()
+ try:
+ os.chdir(path_from_root('third_party', 'lzma.js'))
+ Popen(['sh', './doit.sh']).communicate()
+ finally:
+ os.chdir(cwd)
+
+ def test_split(self):
+ # test HTML generation.
+ self.reftest(path_from_root('tests', 'htmltest.png'))
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '--split', '100', '--pre-js', 'reftest.js']).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something_functions.js')), 'must be functions js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
+
+ open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
+
+ <!doctype html>
+ <html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Emscripten-Generated Code</title>
+ <style>
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+ canvas.emscripten { border: 1px solid black; }
+ textarea.emscripten { font-family: monospace; width: 80%; }
+ div.emscripten { text-align: center; }
+ </style>
+ </head>
+ <body>
+ <hr/>
+ <div class="emscripten" id="status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="progress" hidden=1></progress>
+ </div>
+ <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+ <hr/>
+ <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
+ <hr/>
+ <textarea class="emscripten" id="output" rows="8"></textarea>
+ <hr>
+ <script type='text/javascript'>
+ // connect to canvas
+ var Module = {
+ preRun: [],
+ postRun: [],
+ print: (function() {
+ var element = document.getElementById('output');
+ element.value = ''; // clear browser cache
+ return function(text) {
+ // These replacements are necessary if you render to raw HTML
+ //text = text.replace(/&/g, "&amp;");
+ //text = text.replace(/</g, "&lt;");
+ //text = text.replace(/>/g, "&gt;");
+ //text = text.replace('\\n', '<br>', 'g');
+ element.value += text + "\\n";
+ element.scrollTop = 99999; // focus on bottom
+ };
+ })(),
+ printErr: function(text) {
+ if (0) { // XXX disabled for safety typeof dump == 'function') {
+ dump(text + '\\n'); // fast, straight to the real console
+ } else {
+ console.log(text);
+ }
+ },
+ canvas: document.getElementById('canvas'),
+ setStatus: function(text) {
+ if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var statusElement = document.getElementById('status');
+ var progressElement = document.getElementById('progress');
+ if (m) {
+ text = m[1];
+ progressElement.value = parseInt(m[2])*100;
+ progressElement.max = parseInt(m[4])*100;
+ progressElement.hidden = false;
+ } else {
+ progressElement.value = null;
+ progressElement.max = null;
+ progressElement.hidden = true;
+ }
+ statusElement.innerHTML = text;
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
+ }
+ };
+ Module.setStatus('Downloading...');
+ </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
+ </body>
+ </html>
+ ''')
+
+ self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
+
+ def test_split_in_source_filenames(self):
+ self.reftest(path_from_root('tests', 'htmltest.png'))
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_sdl.cpp'), '-o', 'something.js', '-g', '--split', '100', '--pre-js', 'reftest.js']).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
+ assert os.path.exists(self.get_dir() + '/something/' + path_from_root('tests', 'hello_world_sdl.cpp.js')), 'must be functions js file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
+
+ open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
+
+ <!doctype html>
+ <html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Emscripten-Generated Code</title>
+ <style>
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+ canvas.emscripten { border: 1px solid black; }
+ textarea.emscripten { font-family: monospace; width: 80%; }
+ div.emscripten { text-align: center; }
+ </style>
+ </head>
+ <body>
+ <hr/>
+ <div class="emscripten" id="status">Downloading...</div>
+ <div class="emscripten">
+ <progress value="0" max="100" id="progress" hidden=1></progress>
+ </div>
+ <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+ <hr/>
+ <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
+ <hr/>
+ <textarea class="emscripten" id="output" rows="8"></textarea>
+ <hr>
+ <script type='text/javascript'>
+ // connect to canvas
+ var Module = {
+ preRun: [],
+ postRun: [],
+ print: (function() {
+ var element = document.getElementById('output');
+ element.value = ''; // clear browser cache
+ return function(text) {
+ // These replacements are necessary if you render to raw HTML
+ //text = text.replace(/&/g, "&amp;");
+ //text = text.replace(/</g, "&lt;");
+ //text = text.replace(/>/g, "&gt;");
+ //text = text.replace('\\n', '<br>', 'g');
+ element.value += text + "\\n";
+ element.scrollTop = 99999; // focus on bottom
+ };
+ })(),
+ printErr: function(text) {
+ if (0) { // XXX disabled for safety typeof dump == 'function') {
+ dump(text + '\\n'); // fast, straight to the real console
+ } else {
+ console.log(text);
+ }
+ },
+ canvas: document.getElementById('canvas'),
+ setStatus: function(text) {
+ if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var statusElement = document.getElementById('status');
+ var progressElement = document.getElementById('progress');
+ if (m) {
+ text = m[1];
+ progressElement.value = parseInt(m[2])*100;
+ progressElement.max = parseInt(m[4])*100;
+ progressElement.hidden = false;
+ } else {
+ progressElement.value = null;
+ progressElement.max = null;
+ progressElement.hidden = true;
+ }
+ statusElement.innerHTML = text;
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
+ }
+ };
+ Module.setStatus('Downloading...');
+ </script>''' + open(os.path.join(self.get_dir(), 'something.include.html')).read() + '''
+ </body>
+ </html>
+ ''')
+
+ self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
+
+ def test_compression(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
+ #include <stdio.h>
+ #include <emscripten.h>
+ int main() {
+ printf("hello compressed world\n");
+ int result = 1;
+ REPORT_RESULT();
+ return 0;
+ }
+ '''))
+
+ self.build_native_lzma()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'page.html',
+ '--compression', '%s,%s,%s' % (path_from_root('third_party', 'lzma.js', 'lzma-native'),
+ path_from_root('third_party', 'lzma.js', 'lzma-decoder.js'),
+ 'LZMA.decompress')]).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'page.js')), 'must be side js'
+ assert os.path.exists(os.path.join(self.get_dir(), 'page.js.compress')), 'must be side compressed js'
+ assert os.stat(os.path.join(self.get_dir(), 'page.js')).st_size > os.stat(os.path.join(self.get_dir(), 'page.js.compress')).st_size, 'compressed file must be smaller'
+ shutil.move(os.path.join(self.get_dir(), 'page.js'), 'page.js.renamedsoitcannotbefound');
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_preload_file(self):
+ absolute_src_path = os.path.join(self.get_dir(), 'somefile.txt').replace('\\', '/')
+ open(absolute_src_path, 'w').write('''load me right before running the code please''')
+
+ absolute_src_path2 = os.path.join(self.get_dir(), '.somefile.txt').replace('\\', '/')
+ open(absolute_src_path2, 'w').write('''load me right before running the code please''')
+
+ def make_main(path):
+ print 'make main at', path
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <emscripten.h>
+ int main() {
+ FILE *f = fopen("%s", "r");
+ char buf[100];
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("|%%s|\n", buf);
+
+ int result = !strcmp("load me right before", buf);
+ REPORT_RESULT();
+ return 0;
+ }
+ ''' % path))
+
+ test_cases = [
+ # (source preload-file string, file on target FS to load)
+ ("somefile.txt", "somefile.txt"),
+ (".somefile.txt@somefile.txt", "somefile.txt"),
+ ("./somefile.txt", "somefile.txt"),
+ ("somefile.txt@file.txt", "file.txt"),
+ ("./somefile.txt@file.txt", "file.txt"),
+ ("./somefile.txt@./file.txt", "file.txt"),
+ ("somefile.txt@/file.txt", "file.txt"),
+ ("somefile.txt@/", "somefile.txt"),
+ (absolute_src_path + "@file.txt", "file.txt"),
+ (absolute_src_path + "@/file.txt", "file.txt"),
+ (absolute_src_path + "@/", "somefile.txt"),
+ ("somefile.txt@/directory/file.txt", "/directory/file.txt"),
+ ("somefile.txt@/directory/file.txt", "directory/file.txt"),
+ (absolute_src_path + "@/directory/file.txt", "directory/file.txt")]
+
+ for test in test_cases:
+ (srcpath, dstpath) = test
+ print 'Testing', srcpath, dstpath
+ make_main(dstpath)
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', srcpath, '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
+
+ # By absolute path
+
+ make_main('somefile.txt') # absolute becomes relative
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', absolute_src_path, '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
+
+ # Test subdirectory handling with asset packaging.
+ os.makedirs(os.path.join(self.get_dir(), 'assets/sub/asset1/').replace('\\', '/'))
+ os.makedirs(os.path.join(self.get_dir(), 'assets/sub/asset1/.git').replace('\\', '/')) # Test adding directory that shouldn't exist.
+ os.makedirs(os.path.join(self.get_dir(), 'assets/sub/asset2/').replace('\\', '/'))
+ open(os.path.join(self.get_dir(), 'assets/sub/asset1/file1.txt'), 'w').write('''load me right before running the code please''')
+ open(os.path.join(self.get_dir(), 'assets/sub/asset1/.git/shouldnt_be_embedded.txt'), 'w').write('''this file should not get embedded''')
+ open(os.path.join(self.get_dir(), 'assets/sub/asset2/file2.txt'), 'w').write('''load me right before running the code please''')
+ absolute_assets_src_path = os.path.join(self.get_dir(), 'assets').replace('\\', '/')
+ def make_main_two_files(path1, path2, nonexistingpath):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <emscripten.h>
+ int main() {
+ FILE *f = fopen("%s", "r");
+ char buf[100];
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("|%%s|\n", buf);
+
+ int result = !strcmp("load me right before", buf);
+
+ f = fopen("%s", "r");
+ if (f == NULL)
+ result = 0;
+ fclose(f);
+
+ f = fopen("%s", "r");
+ if (f != NULL)
+ result = 0;
+
+ REPORT_RESULT();
+ return 0;
+ }
+ ''' % (path1, path2, nonexistingpath)))
+
+ test_cases = [
+ # (source directory to embed, file1 on target FS to load, file2 on target FS to load, name of a file that *shouldn't* exist on VFS)
+ ("assets", "assets/sub/asset1/file1.txt", "assets/sub/asset2/file2.txt", "assets/sub/asset1/.git/shouldnt_be_embedded.txt"),
+ ("assets/", "assets/sub/asset1/file1.txt", "assets/sub/asset2/file2.txt", "assets/sub/asset1/.git/shouldnt_be_embedded.txt"),
+ ("assets@/", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
+ ("assets/@/", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
+ ("assets@./", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
+ (absolute_assets_src_path + "@/", "/sub/asset1/file1.txt", "/sub/asset2/file2.txt", "/sub/asset1/.git/shouldnt_be_embedded.txt"),
+ (absolute_assets_src_path + "@/assets", "/assets/sub/asset1/file1.txt", "/assets/sub/asset2/file2.txt", "assets/sub/asset1/.git/shouldnt_be_embedded.txt")]
+
+ for test in test_cases:
+ (srcpath, dstpath1, dstpath2, nonexistingpath) = test
+ make_main_two_files(dstpath1, dstpath2, nonexistingpath)
+ print srcpath
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', srcpath, '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
+
+ # Should still work with -o subdir/..
+
+ make_main('somefile.txt') # absolute becomes relative
+ try:
+ os.mkdir(os.path.join(self.get_dir(), 'dirrey'))
+ except:
+ pass
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', absolute_src_path, '-o', 'dirrey/page.html']).communicate()
+ self.run_browser('dirrey/page.html', 'You should see |load me right before|.', '/report_result?1')
+
+ # With FS.preloadFile
+
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ Module.preRun = function() {
+ FS.createPreloadedFile('/', 'someotherfile.txt', 'somefile.txt', true, false);
+ };
+ ''')
+ make_main('someotherfile.txt')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
+
+ def test_preload_caching(self):
+ open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''load me right before running the code please''')
+ def make_main(path):
+ print path
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <emscripten.h>
+
+ extern "C" {
+ extern int checkPreloadResults();
+ }
+
+ int main(int argc, char** argv) {
+ FILE *f = fopen("%s", "r");
+ char buf[100];
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("|%%s|\n", buf);
+
+ int result = 0;
+
+ result += !strcmp("load me right before", buf);
+ result += checkPreloadResults();
+
+ REPORT_RESULT();
+ return 0;
+ }
+ ''' % path))
+
+ open(os.path.join(self.get_dir(), 'test.js'), 'w').write('''
+ mergeInto(LibraryManager.library, {
+ checkPreloadResults: function() {
+ var cached = 0;
+ var packages = Object.keys(Module['preloadResults']);
+ packages.forEach(function(package) {
+ var fromCache = Module['preloadResults'][package]['fromCache'];
+ if (fromCache)
+ ++ cached;
+ });
+ return cached;
+ }
+ });
+ ''')
+
+ make_main('somefile.txt')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--use-preload-cache', '--js-library', os.path.join(self.get_dir(), 'test.js'), '--preload-file', 'somefile.txt', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
+ self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?2')
+
+ def test_multifile(self):
+ # a few files inside a directory
+ self.clear()
+ os.makedirs(os.path.join(self.get_dir(), 'subdirr'));
+ os.makedirs(os.path.join(self.get_dir(), 'subdirr', 'moar'));
+ open(os.path.join(self.get_dir(), 'subdirr', 'data1.txt'), 'w').write('''1214141516171819''')
+ open(os.path.join(self.get_dir(), 'subdirr', 'moar', 'data2.txt'), 'w').write('''3.14159265358979''')
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <emscripten.h>
+ int main() {
+ char buf[17];
+
+ FILE *f = fopen("subdirr/data1.txt", "r");
+ fread(buf, 1, 16, f);
+ buf[16] = 0;
+ fclose(f);
+ printf("|%s|\n", buf);
+ int result = !strcmp("1214141516171819", buf);
+
+ FILE *f2 = fopen("subdirr/moar/data2.txt", "r");
+ fread(buf, 1, 16, f2);
+ buf[16] = 0;
+ fclose(f2);
+ printf("|%s|\n", buf);
+ result = result && !strcmp("3.14159265358979", buf);
+
+ REPORT_RESULT();
+ return 0;
+ }
+ '''))
+
+ # by individual files
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', 'subdirr/data1.txt', '--preload-file', 'subdirr/moar/data2.txt', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should see two cool numbers', '/report_result?1')
+ os.remove('page.html')
+
+ # by directory, and remove files to make sure
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', 'subdirr', '-o', 'page.html']).communicate()
+ shutil.rmtree(os.path.join(self.get_dir(), 'subdirr'))
+ self.run_browser('page.html', 'You should see two cool numbers', '/report_result?1')
+
+ def test_compressed_file(self):
+ open(os.path.join(self.get_dir(), 'datafile.txt'), 'w').write('compress this please' + (2000*'.'))
+ open(os.path.join(self.get_dir(), 'datafile2.txt'), 'w').write('moar' + (100*'!'))
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <emscripten.h>
+ int main() {
+ char buf[21];
+ FILE *f = fopen("datafile.txt", "r");
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("file says: |%s|\n", buf);
+ int result = !strcmp("compress this please", buf);
+ FILE *f2 = fopen("datafile2.txt", "r");
+ fread(buf, 1, 5, f2);
+ buf[5] = 0;
+ fclose(f2);
+ result = result && !strcmp("moar!", buf);
+ printf("file 2 says: |%s|\n", buf);
+ REPORT_RESULT();
+ return 0;
+ }
+ '''))
+
+ self.build_native_lzma()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'page.html', '--preload-file', 'datafile.txt', '--preload-file', 'datafile2.txt',
+ '--compression', '%s,%s,%s' % (path_from_root('third_party', 'lzma.js', 'lzma-native'),
+ path_from_root('third_party', 'lzma.js', 'lzma-decoder.js'),
+ 'LZMA.decompress')]).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'datafile.txt')), 'must be data file'
+ assert os.path.exists(os.path.join(self.get_dir(), 'page.data.compress')), 'must be data file in compressed form'
+ assert os.stat(os.path.join(self.get_dir(), 'page.js')).st_size != os.stat(os.path.join(self.get_dir(), 'page.js.compress')).st_size, 'compressed file must be different'
+ shutil.move(os.path.join(self.get_dir(), 'datafile.txt'), 'datafile.txt.renamedsoitcannotbefound');
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_image(self):
+ # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpg'))
+ open(os.path.join(self.get_dir(), 'sdl_image.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read()))
+
+ for mem in [0, 1]:
+ for dest, dirname, basename in [('screenshot.jpg', '/', 'screenshot.jpg'),
+ ('screenshot.jpg@/assets/screenshot.jpg', '/assets', 'screenshot.jpg')]:
+ Popen([
+ PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-o', 'page.html', '-O2', '--memory-init-file', str(mem),
+ '--preload-file', dest, '-DSCREENSHOT_DIRNAME="' + dirname + '"', '-DSCREENSHOT_BASENAME="' + basename + '"'
+ ]).communicate()
+ self.run_browser('page.html', '', '/report_result?600')
+
+ def test_sdl_image_jpeg(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.jpeg'))
+ open(os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read()))
+ Popen([
+ PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image_jpeg.c'), '-o', 'page.html',
+ '--preload-file', 'screenshot.jpeg', '-DSCREENSHOT_DIRNAME="/"', '-DSCREENSHOT_BASENAME="screenshot.jpeg"'
+ ]).communicate()
+ self.run_browser('page.html', '', '/report_result?600')
+
+ def test_sdl_image_compressed(self):
+ for image, width in [(path_from_root('tests', 'screenshot2.png'), 300),
+ (path_from_root('tests', 'screenshot.jpg'), 600)]:
+ self.clear()
+ print image
+
+ basename = os.path.basename(image)
+ shutil.copyfile(image, os.path.join(self.get_dir(), basename))
+ open(os.path.join(self.get_dir(), 'sdl_image.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_image.c')).read()))
+
+ self.build_native_lzma()
+ Popen([
+ PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_image.c'), '-o', 'page.html',
+ '--preload-file', basename, '-DSCREENSHOT_DIRNAME="/"', '-DSCREENSHOT_BASENAME="' + basename + '"',
+ '--compression', '%s,%s,%s' % (path_from_root('third_party', 'lzma.js', 'lzma-native'),
+ path_from_root('third_party', 'lzma.js', 'lzma-decoder.js'),
+ 'LZMA.decompress')
+ ]).communicate()
+ shutil.move(os.path.join(self.get_dir(), basename), basename + '.renamedsoitcannotbefound');
+ self.run_browser('page.html', '', '/report_result?' + str(width))
+
+ def test_sdl_image_prepare(self):
+ # load an image file, get pixel data.
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
+ self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
+
+ def test_sdl_image_prepare_data(self):
+ # load an image file, get pixel data.
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
+ self.btest('sdl_image_prepare_data.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
+
+ def test_sdl_stb_image(self):
+ # load an image file, get pixel data.
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
+ self.btest('sdl_stb_image.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not'])
+
+ def test_sdl_stb_image_data(self):
+ # load an image file, get pixel data.
+ shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
+ self.btest('sdl_stb_image_data.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not'])
+
+ def test_sdl_canvas(self):
+ open(os.path.join(self.get_dir(), 'sdl_canvas.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas.c')).read()))
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_key(self):
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ Module.postRun = function() {
+ function doOne() {
+ Module._one();
+ setTimeout(doOne, 1000/60);
+ }
+ setTimeout(doOne, 1000/60);
+ }
+
+ function keydown(c) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keydown", true, true, window,
+ 0, 0, 0, 0,
+ c, c);
+ document.dispatchEvent(event);
+ }
+
+ function keyup(c) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keyup", true, true, window,
+ 0, 0, 0, 0,
+ c, c);
+ document.dispatchEvent(event);
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'sdl_key.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_key.c')).read()))
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''']).communicate()
+ self.run_browser('page.html', '', '/report_result?223092870')
+
+ def test_sdl_text(self):
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ Module.postRun = function() {
+ function doOne() {
+ Module._one();
+ setTimeout(doOne, 1000/60);
+ }
+ setTimeout(doOne, 1000/60);
+ }
+
+ function simulateKeyEvent(charCode) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keypress", true, true, window,
+ 0, 0, 0, 0, 0, charCode);
+ document.body.dispatchEvent(event);
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'sdl_text.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_text.c')).read()))
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_text.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_mouse(self):
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ function simulateMouseEvent(x, y, button) {
+ var event = document.createEvent("MouseEvents");
+ if (button >= 0) {
+ var event1 = document.createEvent("MouseEvents");
+ event1.initMouseEvent('mousedown', true, true, window,
+ 1, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y,
+ 0, 0, 0, 0,
+ button, null);
+ Module['canvas'].dispatchEvent(event1);
+ var event2 = document.createEvent("MouseEvents");
+ event2.initMouseEvent('mouseup', true, true, window,
+ 1, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y,
+ 0, 0, 0, 0,
+ button, null);
+ Module['canvas'].dispatchEvent(event2);
+ } else {
+ var event1 = document.createEvent("MouseEvents");
+ event1.initMouseEvent('mousemove', true, true, window,
+ 0, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y, Module['canvas'].offsetLeft + x, Module['canvas'].offsetTop + y,
+ 0, 0, 0, 0,
+ 0, null);
+ Module['canvas'].dispatchEvent(event1);
+ }
+ }
+ window['simulateMouseEvent'] = simulateMouseEvent;
+ ''')
+ open(os.path.join(self.get_dir(), 'sdl_mouse.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_mouse.c')).read()))
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'page.html', '--pre-js', 'pre.js']).communicate()
+ self.run_browser('page.html', '', '/report_result?740')
+
+ def test_sdl_mouse_offsets(self):
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ function simulateMouseEvent(x, y, button) {
+ var event = document.createEvent("MouseEvents");
+ if (button >= 0) {
+ var event1 = document.createEvent("MouseEvents");
+ event1.initMouseEvent('mousedown', true, true, window,
+ 1, x, y, x, y,
+ 0, 0, 0, 0,
+ button, null);
+ Module['canvas'].dispatchEvent(event1);
+ var event2 = document.createEvent("MouseEvents");
+ event2.initMouseEvent('mouseup', true, true, window,
+ 1, x, y, x, y,
+ 0, 0, 0, 0,
+ button, null);
+ Module['canvas'].dispatchEvent(event2);
+ } else {
+ var event1 = document.createEvent("MouseEvents");
+ event1.initMouseEvent('mousemove', true, true, window,
+ 0, x, y, x, y,
+ 0, 0, 0, 0,
+ 0, null);
+ Module['canvas'].dispatchEvent(event1);
+ }
+ }
+ window['simulateMouseEvent'] = simulateMouseEvent;
+ ''')
+ open(os.path.join(self.get_dir(), 'page.html'), 'w').write('''
+ <html>
+ <head>
+ <style type="text/css">
+ html, body { margin: 0; padding: 0; }
+ #container {
+ position: absolute;
+ left: 5px; right: 0;
+ top: 5px; bottom: 0;
+ }
+ #canvas {
+ position: absolute;
+ left: 0; width: 600px;
+ top: 0; height: 450px;
+ }
+ textarea {
+ margin-top: 500px;
+ margin-left: 5px;
+ width: 600px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="container">
+ <canvas id="canvas"></canvas>
+ </div>
+ <textarea id="output" rows="8"></textarea>
+ <script type="text/javascript">
+ var Module = {
+ canvas: document.getElementById('canvas'),
+ print: (function() {
+ var element = document.getElementById('output');
+ element.value = ''; // clear browser cache
+ return function(text) {
+ text = Array.prototype.slice.call(arguments).join(' ');
+ element.value += text + "\\n";
+ element.scrollTop = 99999; // focus on bottom
+ };
+ })()
+ };
+ </script>
+ <script type="text/javascript" src="sdl_mouse.js"></script>
+ </body>
+ </html>
+ ''')
+ open(os.path.join(self.get_dir(), 'sdl_mouse.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_mouse.c')).read()))
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_mouse.c'), '-O2', '--minify', '0', '-o', 'sdl_mouse.js', '--pre-js', 'pre.js']).communicate()
+ self.run_browser('page.html', '', '/report_result?600')
+
+ def test_sdl_pumpevents(self):
+ # key events should be detected using SDL_PumpEvents
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ function keydown(c) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keydown", true, true, window,
+ 0, 0, 0, 0,
+ c, c);
+ document.dispatchEvent(event);
+ }
+ ''')
+ self.btest('sdl_pumpevents.c', expected='3', args=['--pre-js', 'pre.js'])
+
+ def test_sdl_audio(self):
+ shutil.copyfile(path_from_root('tests', 'sounds', 'alarmvictory_1.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'alarmcreatemiltaryfoot_1.wav'), os.path.join(self.get_dir(), 'sound2.wav'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'noise.ogg'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'the_entertainer.ogg'))
+ open(os.path.join(self.get_dir(), 'bad.ogg'), 'w').write('I claim to be audio, but am lying')
+ open(os.path.join(self.get_dir(), 'sdl_audio.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio.c')).read()))
+
+ # use closure to check for a possible bug with closure minifying away newer Audio() attributes
+ Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--embed-file', 'the_entertainer.ogg', '--preload-file', 'noise.ogg', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_audio_mix_channels(self):
+ shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
+ open(os.path.join(self.get_dir(), 'sdl_audio_mix_channels.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_mix_channels.c')).read()))
+
+ Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_mix_channels.c'), '--preload-file', 'sound.ogg', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_audio_mix(self):
+ shutil.copyfile(path_from_root('tests', 'sounds', 'pluck.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'music.ogg'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'noise.ogg'))
+ open(os.path.join(self.get_dir(), 'sdl_audio_mix.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_mix.c')).read()))
+
+ Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_mix.c'), '--preload-file', 'sound.ogg', '--preload-file', 'music.ogg', '--preload-file', 'noise.ogg', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_audio_quickload(self):
+ open(os.path.join(self.get_dir(), 'sdl_audio_quickload.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_quickload.c')).read()))
+
+ Popen([PYTHON, EMCC, '-O2', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio_quickload.c'), '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play"]']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_sdl_gl_read(self):
+ # SDL, OpenGL, readPixels
+ open(os.path.join(self.get_dir(), 'sdl_gl_read.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_gl_read.c')).read()))
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_gl_read.c'), '-o', 'something.html']).communicate()
+ self.run_browser('something.html', '.', '/report_result?1')
+
+ def test_sdl_ogl(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_ogl.c', reference='screenshot-gray-purple.png', reference_slack=1,
+ args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with gray at the top.')
+
+ def test_sdl_ogl_defaultmatrixmode(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_ogl_defaultMatrixMode.c', reference='screenshot-gray-purple.png', reference_slack=1,
+ args=['--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with gray at the top.')
+
+ def test_sdl_ogl_p(self):
+ # Immediate mode with pointers
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_ogl_p.c', reference='screenshot-gray.png', reference_slack=1,
+ args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with gray at the top.')
+
+ def test_sdl_ogl_proc_alias(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_ogl_proc_alias.c', reference='screenshot-gray-purple.png', reference_slack=1,
+ args=['-O2', '-g2', '-s', 'INLINING_LIMIT=1', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1', '-s', 'VERBOSE=1'])
+
+ def test_sdl_fog_simple(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_fog_simple.c', reference='screenshot-fog-simple.png',
+ args=['-O2', '--minify', '0', '--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with fog.')
+
+ def test_sdl_fog_negative(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_fog_negative.c', reference='screenshot-fog-negative.png',
+ args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with fog.')
+
+ def test_sdl_fog_density(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_fog_density.c', reference='screenshot-fog-density.png',
+ args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with fog.')
+
+ def test_sdl_fog_exp2(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_fog_exp2.c', reference='screenshot-fog-exp2.png',
+ args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with fog.')
+
+ def test_sdl_fog_linear(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_fog_linear.c', reference='screenshot-fog-linear.png', reference_slack=1,
+ args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'],
+ message='You should see an image with fog.')
+
+ def test_openal_playback(self):
+ shutil.copyfile(path_from_root('tests', 'sounds', 'audio.wav'), os.path.join(self.get_dir(), 'audio.wav'))
+ open(os.path.join(self.get_dir(), 'openal_playback.cpp'), 'w').write(self.with_report_result(open(path_from_root('tests', 'openal_playback.cpp')).read()))
+
+ Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'openal_playback.cpp'), '--preload-file', 'audio.wav', '-o', 'page.html']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_openal_buffers(self):
+ shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.wav'), os.path.join(self.get_dir(), 'the_entertainer.wav'))
+ self.btest('openal_buffers.c', '0', args=['--preload-file', 'the_entertainer.wav'],)
+
+ def test_glfw(self):
+ open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read()))
+
+ Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
+ self.run_browser('page.html', '', '/report_result?1')
+
+ def test_egl_width_height(self):
+ open(os.path.join(self.get_dir(), 'test_egl_width_height.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl_width_height.c')).read()))
+
+ Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl_width_height.c'), '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'Should print "(300, 150)" -- the size of the canvas in pixels', '/report_result?1')
+
+ def test_freealut(self):
+ programs = self.get_library('freealut', os.path.join('examples', '.libs', 'hello_world.bc'), make_args=['EXEEXT=.bc'])
+ for program in programs:
+ assert os.path.exists(program)
+ Popen([PYTHON, EMCC, '-O2', program, '-o', 'page.html']).communicate()
+ self.run_browser('page.html', 'You should hear "Hello World!"')
+
+ def test_worker(self):
+ # Test running in a web worker
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'], stdout=PIPE, stderr=PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists('worker.js'), output
+ self.assertContained('you should not see this text when in a worker!', run_js('worker.js')) # code should run standalone
+ html_file = open('main.html', 'w')
+ html_file.write('''
+ <html>
+ <body>
+ Worker Test
+ <script>
+ var worker = new Worker('worker.js');
+ worker.onmessage = function(event) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?' + event.data);
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
+ };
+ </script>
+ </body>
+ </html>
+ ''')
+ html_file.close()
+ self.run_browser('main.html', 'You should see that the worker was called, and said "hello from worker!"', '/report_result?hello%20from%20worker!')
+
+ def test_chunked_synchronous_xhr(self):
+ main = 'chunked_sync_xhr.html'
+ worker_filename = "download_and_checksum_worker.js"
+
+ html_file = open(main, 'w')
+ html_file.write(r"""
+ <!doctype html>
+ <html>
+ <head><meta charset="utf-8"><title>Chunked XHR</title></head>
+ <html>
+ <body>
+ Chunked XHR Web Worker Test
+ <script>
+ var worker = new Worker(""" + json.dumps(worker_filename) + r""");
+ var buffer = [];
+ worker.onmessage = function(event) {
+ if (event.data.channel === "stdout") {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?' + event.data.line);
+ xhr.send();
+ setTimeout(function() { window.close() }, 1000);
+ } else {
+ if (event.data.trace) event.data.trace.split("\n").map(function(v) { console.error(v); });
+ if (event.data.line) {
+ console.error(event.data.line);
+ } else {
+ var v = event.data.char;
+ if (v == 10) {
+ var line = buffer.splice(0);
+ console.error(line = line.map(function(charCode){return String.fromCharCode(charCode);}).join(''));
+ } else {
+ buffer.push(v);
+ }
+ }
+ }
+ };
+ </script>
+ </body>
+ </html>
+ """)
+ html_file.close()
+
+ c_source_filename = "checksummer.c"
+
+ prejs_filename = "worker_prejs.js"
+ prejs_file = open(prejs_filename, 'w')
+ prejs_file.write(r"""
+ if (typeof(Module) === "undefined") Module = {};
+ Module["arguments"] = ["/bigfile"];
+ Module["preInit"] = function() {
+ FS.createLazyFile('/', "bigfile", "http://localhost:11111/bogus_file_path", true, false);
+ };
+ var doTrace = true;
+ Module["print"] = function(s) { self.postMessage({channel: "stdout", line: s}); };
+ Module["stderr"] = function(s) { self.postMessage({channel: "stderr", char: s, trace: ((doTrace && s === 10) ? new Error().stack : null)}); doTrace = false; };
+ """)
+ prejs_file.close()
+ # vs. os.path.join(self.get_dir(), filename)
+ # vs. path_from_root('tests', 'hello_world_gles.c')
+ Popen([PYTHON, EMCC, path_from_root('tests', c_source_filename), '-g', '-s', 'SMALL_CHUNKS=1', '-o', worker_filename,
+ '--pre-js', prejs_filename]).communicate()
+
+ chunkSize = 1024
+ data = os.urandom(10*chunkSize+1) # 10 full chunks and one 1 byte chunk
+ expectedConns = 11
+ import zlib
+ checksum = zlib.adler32(data)
+
+ def chunked_server(support_byte_ranges):
+ class ChunkedServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def sendheaders(s, extra=[], length=len(data)):
+ s.send_response(200)
+ s.send_header("Content-Length", str(length))
+ s.send_header("Access-Control-Allow-Origin", "http://localhost:8888")
+ s.send_header("Access-Control-Expose-Headers", "Content-Length, Accept-Ranges")
+ s.send_header("Content-type", "application/octet-stream")
+ if support_byte_ranges:
+ s.send_header("Accept-Ranges", "bytes")
+ for i in extra:
+ s.send_header(i[0], i[1])
+ s.end_headers()
+
+ def do_HEAD(s):
+ s.sendheaders()
+
+ def do_OPTIONS(s):
+ s.sendheaders([("Access-Control-Allow-Headers", "Range")], 0)
+
+ def do_GET(s):
+ if not support_byte_ranges:
+ s.sendheaders()
+ s.wfile.write(data)
+ else:
+ (start, end) = s.headers.get("range").split("=")[1].split("-")
+ start = int(start)
+ end = int(end)
+ end = min(len(data)-1, end)
+ length = end-start+1
+ s.sendheaders([],length)
+ s.wfile.write(data[start:end+1])
+ s.wfile.close()
+ httpd = BaseHTTPServer.HTTPServer(('localhost', 11111), ChunkedServerHandler)
+ for i in range(expectedConns+1):
+ httpd.handle_request()
+
+ server = multiprocessing.Process(target=chunked_server, args=(True,))
+ server.start()
+ self.run_browser(main, 'Chunked binary synchronous XHR in Web Workers!', '/report_result?' + str(checksum))
+ server.terminate()
+
+ def test_glgears(self):
+ self.btest('hello_world_gles.c', reference='gears.png', reference_slack=1,
+ args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html',
+ message='You should see animating gears.')
+
+ def test_glgears_animation(self):
+ es2_suffix = ['', '_full', '_full_944']
+ for full_es2 in [0, 1, 2]:
+ print full_es2
+ Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles%s.c' % es2_suffix[full_es2]), '-o', 'something.html',
+ '-DHAVE_BUILTIN_SINCOS', '-s', 'GL_TESTING=1',
+ '--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')] +
+ (['-s', 'FULL_ES2=1'] if full_es2 else []),
+ ).communicate()
+ self.run_browser('something.html', 'You should see animating gears.', '/report_gl_result?true')
+
+ def test_fulles2_sdlproc(self):
+ self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1'])
+
+ def test_glgears_deriv(self):
+ self.btest('hello_world_gles_deriv.c', reference='gears.png', reference_slack=1,
+ args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html',
+ message='You should see animating gears.')
+ with open('something.html') as f:
+ assert 'gl-matrix' not in f.read(), 'Should not include glMatrix when not needed'
+
+ def test_glbook(self):
+ programs = self.get_library('glbook', [
+ os.path.join('Chapter_2', 'Hello_Triangle', 'CH02_HelloTriangle.bc'),
+ os.path.join('Chapter_8', 'Simple_VertexShader', 'CH08_SimpleVertexShader.bc'),
+ os.path.join('Chapter_9', 'Simple_Texture2D', 'CH09_SimpleTexture2D.bc'),
+ os.path.join('Chapter_9', 'Simple_TextureCubemap', 'CH09_TextureCubemap.bc'),
+ os.path.join('Chapter_9', 'TextureWrap', 'CH09_TextureWrap.bc'),
+ os.path.join('Chapter_10', 'MultiTexture', 'CH10_MultiTexture.bc'),
+ os.path.join('Chapter_13', 'ParticleSystem', 'CH13_ParticleSystem.bc'),
+ ], configure=None)
+ def book_path(*pathelems):
+ return path_from_root('tests', 'glbook', *pathelems)
+ for program in programs:
+ print program
+ basename = os.path.basename(program)
+ args = []
+ if basename == 'CH10_MultiTexture.bc':
+ shutil.copyfile(book_path('Chapter_10', 'MultiTexture', 'basemap.tga'), os.path.join(self.get_dir(), 'basemap.tga'))
+ shutil.copyfile(book_path('Chapter_10', 'MultiTexture', 'lightmap.tga'), os.path.join(self.get_dir(), 'lightmap.tga'))
+ args = ['--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga']
+ elif basename == 'CH13_ParticleSystem.bc':
+ shutil.copyfile(book_path('Chapter_13', 'ParticleSystem', 'smoke.tga'), os.path.join(self.get_dir(), 'smoke.tga'))
+ args = ['--preload-file', 'smoke.tga', '-O2'] # test optimizations and closure here as well for more coverage
+
+ self.btest(program,
+ reference=book_path(basename.replace('.bc', '.png')), args=args)
+
+ def test_gles2_emulation(self):
+ shutil.copyfile(path_from_root('tests', 'glbook', 'Chapter_10', 'MultiTexture', 'basemap.tga'), self.in_dir('basemap.tga'))
+ shutil.copyfile(path_from_root('tests', 'glbook', 'Chapter_10', 'MultiTexture', 'lightmap.tga'), self.in_dir('lightmap.tga'))
+ shutil.copyfile(path_from_root('tests', 'glbook', 'Chapter_13', 'ParticleSystem', 'smoke.tga'), self.in_dir('smoke.tga'))
+
+ for source, reference in [
+ (os.path.join('glbook', 'Chapter_2', 'Hello_Triangle', 'Hello_Triangle_orig.c'), path_from_root('tests', 'glbook', 'CH02_HelloTriangle.png')),
+ #(os.path.join('glbook', 'Chapter_8', 'Simple_VertexShader', 'Simple_VertexShader_orig.c'), path_from_root('tests', 'glbook', 'CH08_SimpleVertexShader.png')), # XXX needs INT extension in WebGL
+ (os.path.join('glbook', 'Chapter_9', 'TextureWrap', 'TextureWrap_orig.c'), path_from_root('tests', 'glbook', 'CH09_TextureWrap.png')),
+ #(os.path.join('glbook', 'Chapter_9', 'Simple_TextureCubemap', 'Simple_TextureCubemap_orig.c'), path_from_root('tests', 'glbook', 'CH09_TextureCubemap.png')), # XXX needs INT extension in WebGL
+ (os.path.join('glbook', 'Chapter_9', 'Simple_Texture2D', 'Simple_Texture2D_orig.c'), path_from_root('tests', 'glbook', 'CH09_SimpleTexture2D.png')),
+ (os.path.join('glbook', 'Chapter_10', 'MultiTexture', 'MultiTexture_orig.c'), path_from_root('tests', 'glbook', 'CH10_MultiTexture.png')),
+ (os.path.join('glbook', 'Chapter_13', 'ParticleSystem', 'ParticleSystem_orig.c'), path_from_root('tests', 'glbook', 'CH13_ParticleSystem.png')),
+ ]:
+ print source
+ self.btest(source,
+ reference=reference,
+ args=['-I' + path_from_root('tests', 'glbook', 'Common'),
+ path_from_root('tests', 'glbook', 'Common', 'esUtil.c'),
+ path_from_root('tests', 'glbook', 'Common', 'esShader.c'),
+ path_from_root('tests', 'glbook', 'Common', 'esShapes.c'),
+ path_from_root('tests', 'glbook', 'Common', 'esTransform.c'),
+ '-s', 'FULL_ES2=1',
+ '--preload-file', 'basemap.tga', '--preload-file', 'lightmap.tga', '--preload-file', 'smoke.tga'])
+
+ def test_emscripten_api(self):
+ self.btest('emscripten_api_browser.cpp', '1', args=['-s', '''EXPORTED_FUNCTIONS=['_main', '_third']'''])
+
+ def test_emscripten_api_infloop(self):
+ self.btest('emscripten_api_browser_infloop.cpp', '7')
+
+ def test_emscripten_fs_api(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) # preloaded *after* run
+ self.btest('emscripten_fs_api_browser.cpp', '1')
+
+ def test_sdl_quit(self):
+ self.btest('sdl_quit.c', '1')
+
+ def test_sdl_resize(self):
+ self.btest('sdl_resize.c', '1')
+
+ def test_gc(self):
+ self.btest('browser_gc.cpp', '1')
+
+ def test_glshaderinfo(self):
+ self.btest('glshaderinfo.cpp', '1')
+
+ def test_glgetattachedshaders(self):
+ self.btest('glgetattachedshaders.c', '1')
+
+ def test_sdlglshader(self):
+ self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_gl_ps(self):
+ # pointers and a shader
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('gl_ps.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1)
+
+ def test_gl_ps_packed(self):
+ # packed data that needs to be strided
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('gl_ps_packed.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1)
+
+ def test_gl_ps_strides(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_gl_renderers(self):
+ self.btest('gl_renderers.c', reference='gl_renderers.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_gl_stride(self):
+ self.btest('gl_stride.c', reference='gl_stride.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_matrix_identity(self):
+ self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840'], args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_pre(self):
+ self.btest('cubegeom_pre.c', reference='cubegeom_pre.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_pre2(self):
+ self.btest('cubegeom_pre2.c', reference='cubegeom_pre2.png', args=['-s', 'GL_DEBUG=1', '-s', 'LEGACY_GL_EMULATION=1']) # some coverage for GL_DEBUG not breaking the build
+
+ def test_cubegeom_pre3(self):
+ self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom(self):
+ self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_glew(self):
+ self.btest('cubegeom_glew.c', reference='cubegeom.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_color(self):
+ self.btest('cubegeom_color.c', reference='cubegeom_color.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_normal(self):
+ self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_normal_dap(self): # draw is given a direct pointer to clientside memory, no element array buffer
+ self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_normal_dap_far(self): # indices do nto start from 0
+ self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_normal_dap_far_range(self): # glDrawRangeElements
+ self.btest('cubegeom_normal_dap_far_range.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_normal_dap_far_glda(self): # use glDrawArrays
+ self.btest('cubegeom_normal_dap_far_glda.c', reference='cubegeom_normal_dap_far_glda.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_normal_dap_far_glda_quad(self): # with quad
+ self.btest('cubegeom_normal_dap_far_glda_quad.c', reference='cubegeom_normal_dap_far_glda_quad.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_mt(self):
+ self.btest('cubegeom_mt.c', reference='cubegeom_mt.png', args=['-s', 'LEGACY_GL_EMULATION=1']) # multitexture
+
+ def test_cubegeom_color2(self):
+ self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_texturematrix(self):
+ self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_fog(self):
+ self.btest('cubegeom_fog.c', reference='cubegeom_fog.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_pre_vao(self):
+ self.btest('cubegeom_pre_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_pre2_vao(self):
+ self.btest('cubegeom_pre2_vao.c', reference='cubegeom_pre_vao.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cubegeom_pre2_vao2(self):
+ self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_cube_explosion(self):
+ self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_sdl_canvas_blank(self):
+ self.btest('sdl_canvas_blank.c', reference='sdl_canvas_blank.png')
+
+ def test_sdl_canvas_palette(self):
+ self.btest('sdl_canvas_palette.c', reference='sdl_canvas_palette.png')
+
+ def test_sdl_canvas_twice(self):
+ self.btest('sdl_canvas_twice.c', reference='sdl_canvas_twice.png')
+
+ def test_sdl_maprgba(self):
+ self.btest('sdl_maprgba.c', reference='sdl_maprgba.png', reference_slack=3)
+
+ def test_sdl_rotozoom(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('sdl_rotozoom.c', reference='sdl_rotozoom.png', args=['--preload-file', 'screenshot.png'], reference_slack=5)
+
+ def test_sdl_gfx_primitives(self):
+ self.btest('sdl_gfx_primitives.c', reference='sdl_gfx_primitives.png', reference_slack=1)
+
+ def test_sdl_canvas_palette_2(self):
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ Module['preRun'].push(function() {
+ SDL.defaults.copyOnLock = false;
+ });
+ ''')
+
+ open(os.path.join(self.get_dir(), 'args-r.js'), 'w').write('''
+ Module['arguments'] = ['-r'];
+ ''')
+
+ open(os.path.join(self.get_dir(), 'args-g.js'), 'w').write('''
+ Module['arguments'] = ['-g'];
+ ''')
+
+ open(os.path.join(self.get_dir(), 'args-b.js'), 'w').write('''
+ Module['arguments'] = ['-b'];
+ ''')
+
+ self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_r.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-r.js'])
+ self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_g.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-g.js'])
+ self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_b.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-b.js'])
+
+ def test_sdl_alloctext(self):
+ self.btest('sdl_alloctext.c', expected='1', args=['-O2', '-s', 'TOTAL_MEMORY=' + str(1024*1024*8)])
+
+ def test_sdl_surface_refcount(self):
+ self.btest('sdl_surface_refcount.c', expected='1')
+
+ def test_glbegin_points(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
+ self.btest('glbegin_points.c', reference='glbegin_points.png', args=['--preload-file', 'screenshot.png', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_s3tc(self):
+ shutil.copyfile(path_from_root('tests', 'screenshot.dds'), os.path.join(self.get_dir(), 'screenshot.dds'))
+ self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_s3tc_crunch(self):
+ shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds')
+ shutil.copyfile(path_from_root('tests', 'bloom.dds'), 'bloom.dds')
+ shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
+ Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch', '--preload', 'ship.dds', 'bloom.dds', 'water.dds'], stdout=open('pre.js', 'w')).communicate()
+ assert os.stat('test.data').st_size < 0.5*(os.stat('ship.dds').st_size+os.stat('bloom.dds').st_size+os.stat('water.dds').st_size), 'Compressed should be smaller than dds'
+ shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed
+ shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed
+ shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed
+ self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'pre.js', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_s3tc_crunch_split(self): # load several datafiles/outputs of file packager
+ shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds')
+ shutil.copyfile(path_from_root('tests', 'bloom.dds'), 'bloom.dds')
+ shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
+ Popen([PYTHON, FILE_PACKAGER, 'asset_a.data', '--pre-run', '--crunch', '--preload', 'ship.dds', 'bloom.dds'], stdout=open('asset_a.js', 'w')).communicate()
+ Popen([PYTHON, FILE_PACKAGER, 'asset_b.data', '--pre-run', '--crunch', '--preload', 'water.dds'], stdout=open('asset_b.js', 'w')).communicate()
+ shutil.move('ship.dds', 'ship.donotfindme.dds') # make sure we load from the compressed
+ shutil.move('bloom.dds', 'bloom.donotfindme.dds') # make sure we load from the compressed
+ shutil.move('water.dds', 'water.donotfindme.dds') # make sure we load from the compressed
+ self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_aniso(self):
+ if SPIDERMONKEY_ENGINE in JS_ENGINES:
+ # asm.js-ification check
+ Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
+ Settings.ASM_JS = 1
+ self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js')
+
+ shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
+ self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_tex_nonbyte(self):
+ self.btest('tex_nonbyte.c', reference='tex_nonbyte.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_float_tex(self):
+ self.btest('float_tex.cpp', reference='float_tex.png')
+
+ def test_subdata(self):
+ self.btest('gl_subdata.cpp', reference='float_tex.png')
+
+ def test_perspective(self):
+ self.btest('perspective.c', reference='perspective.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+
+ def test_runtimelink(self):
+ return self.skip('BUILD_AS_SHARED_LIB=2 is deprecated')
+ main, supp = self.setup_runtimelink_test()
+
+ open(self.in_dir('supp.cpp'), 'w').write(supp)
+ Popen([PYTHON, EMCC, self.in_dir('supp.cpp'), '-o', 'supp.js', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'BUILD_AS_SHARED_LIB=2', '-O2', '-s', 'ASM_JS=0']).communicate()
+ shutil.move(self.in_dir('supp.js'), self.in_dir('supp.so'))
+
+ self.btest(main, args=['-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-s', 'RUNTIME_LINKED_LIBS=["supp.so"]', '-DBROWSER=1', '-O2', '-s', 'ASM_JS=0'], expected='76')
+
+ def test_pre_run_deps(self):
+ # Adding a dependency in preRun will delay run
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ Module.preRun = function() {
+ addRunDependency();
+ Module.print('preRun called, added a dependency...');
+ setTimeout(function() {
+ Module.okk = 10;
+ removeRunDependency()
+ }, 2000);
+ };
+ ''')
+ self.btest('pre_run_deps.cpp', expected='10', args=['--pre-js', 'pre.js'])
+
+ def test_worker_api(self):
+ Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate()
+ self.btest('worker_api_main.cpp', expected='566')
+
+ def test_worker_api_2(self):
+ Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_2_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-O2', '--minify', '0', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two", "_three", "_four"]']).communicate()
+ self.btest('worker_api_2_main.cpp', args=['-O2', '--minify', '0'], expected='11')
+
+ def test_emscripten_async_wget2(self):
+ self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')])
diff --git a/tests/test_core.py b/tests/test_core.py
new file mode 100644
index 00000000..35f5f0f9
--- /dev/null
+++ b/tests/test_core.py
@@ -0,0 +1,10069 @@
+# coding=utf-8
+
+import glob, hashlib, os, re, shutil, subprocess, sys
+import tools.shared
+from tools.shared import *
+from runner import RunnerCore, path_from_root, checked_sanity, test_modes
+
+class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
+ def is_le32(self):
+ return not ('i386-pc-linux-gnu' in COMPILER_OPTS or self.env.get('EMCC_LLVM_TARGET') == 'i386-pc-linux-gnu')
+
+ def test_hello_world(self):
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ printf("hello, world!\\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'hello, world!')
+
+ assert 'EMSCRIPTEN_GENERATED_FUNCTIONS' not in open(self.in_dir('src.cpp.o.js')).read(), 'must not emit this unneeded internal thing'
+
+ def test_intvars(self):
+ if self.emcc_args == None: return self.skip('needs ta2')
+
+ src = '''
+ #include <stdio.h>
+ int global = 20;
+ int *far;
+ int main()
+ {
+ int x = 5;
+ int y = x+17;
+ int z = (y-1)/2; // Should stay an integer after division!
+ y += 1;
+ int w = x*3+4;
+ int k = w < 15 ? 99 : 101;
+ far = &k;
+ *far += global;
+ int i = k > 100; // Should be an int, not a bool!
+ int j = i << 6;
+ j >>= 1;
+ j = j ^ 5;
+ int h = 1;
+ h |= 0;
+ int p = h;
+ p &= 0;
+ printf("*%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n", x, y, z, w, k, i, j, h, p);
+
+ long hash = -1;
+ size_t perturb;
+ int ii = 0;
+ for (perturb = hash; ; perturb >>= 5) {
+ printf("%d:%d", ii, perturb);
+ ii++;
+ if (ii == 9) break;
+ printf(",");
+ }
+ printf("*\\n");
+ printf("*%.1d,%.2d*\\n", 56, 9);
+
+ // Fixed-point math on 64-bit ints. Tricky to support since we have no 64-bit shifts in JS
+ {
+ struct Fixed {
+ static int Mult(int a, int b) {
+ return ((long long)a * (long long)b) >> 16;
+ }
+ };
+ printf("fixed:%d\\n", Fixed::Mult(150000, 140000));
+ }
+
+ printf("*%ld*%p\\n", (long)21, &hash); // The %p should not enter an infinite loop!
+ return 0;
+ }
+ '''
+ self.do_run(src, '*5,23,10,19,121,1,37,1,0*\n0:-1,1:134217727,2:4194303,3:131071,4:4095,5:127,6:3,7:0,8:0*\n*56,09*\nfixed:320434\n*21*')
+
+ def test_sintvars(self):
+ Settings.CORRECT_SIGNS = 1 # Relevant to this test
+ src = '''
+ #include <stdio.h>
+ struct S {
+ char *match_start;
+ char *strstart;
+ };
+ int main()
+ {
+ struct S _s;
+ struct S *s = &_s;
+ unsigned short int sh;
+
+ s->match_start = (char*)32522;
+ s->strstart = (char*)(32780);
+ printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start));
+ sh = s->strstart - s->match_start;
+ printf("*%d,%d*\\n", sh, sh>>7);
+
+ s->match_start = (char*)32999;
+ s->strstart = (char*)(32780);
+ printf("*%d,%d,%d*\\n", (int)s->strstart, (int)s->match_start, (int)(s->strstart - s->match_start));
+ sh = s->strstart - s->match_start;
+ printf("*%d,%d*\\n", sh, sh>>7);
+ }
+ '''
+ output = '*32780,32522,258*\n*258,2*\n*32780,32999,-219*\n*65317,510*'
+ Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right
+ self.do_run(src, output, force_c=True)
+
+ def test_i64(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
+
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ long long a = 0x2b00505c10;
+ long long b = a >> 29;
+ long long c = a >> 32;
+ long long d = a >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\\n", a, b, c, d);
+ unsigned long long ua = 0x2b00505c10;
+ unsigned long long ub = ua >> 29;
+ unsigned long long uc = ua >> 32;
+ unsigned long long ud = ua >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\\n", ua, ub, uc, ud);
+
+ long long x = 0x0000def123450789ULL; // any bigger than this, and we
+ long long y = 0x00020ef123456089ULL; // start to run into the double precision limit!
+ printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2);
+
+ printf("*");
+ long long z = 13;
+ int n = 0;
+ while (z > 1) {
+ printf("%.2f,", (float)z); // these must be integers!
+ z = z >> 1;
+ n++;
+ }
+ printf("*%d*\\n", n);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*184688860176,344,43,10*\n*184688860176,344,43,10*\n*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*')
+
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <stdint.h>
+
+ int64_t returner1() { return 0x0000def123450789ULL; }
+ int64_t returner2(int test) {
+ while (test > 10) test /= 2; // confuse the compiler so it doesn't eliminate this function
+ return test > 5 ? 0x0000def123450123ULL : 0ULL;
+ }
+
+ void modifier1(int64_t t) {
+ t |= 12;
+ printf("m1: %Ld\n", t);
+ }
+ void modifier2(int64_t &t) {
+ t |= 12;
+ }
+
+ int truthy() {
+ int x = time(0);
+ while (x > 10) {
+ x |= 7;
+ x /= 2;
+ }
+ return x < 3;
+ }
+
+ struct IUB {
+ int c;
+ long long d;
+ };
+
+ IUB iub[] = {
+ { 55, 17179869201 },
+ { 122, 25769803837 },
+ };
+
+ int main(int argc, char **argv)
+ {
+ int64_t x1 = 0x1234def123450789ULL;
+ int64_t x2 = 0x1234def123450788ULL;
+ int64_t x3 = 0x1234def123450789ULL;
+ printf("*%Ld\n%d,%d,%d,%d,%d\n%d,%d,%d,%d,%d*\n", x1, x1==x2, x1<x2, x1<=x2, x1>x2, x1>=x2, // note: some rounding in the printing!
+ x1==x3, x1<x3, x1<=x3, x1>x3, x1>=x3);
+ printf("*%Ld*\n", returner1());
+ printf("*%Ld*\n", returner2(30));
+
+ uint64_t maxx = -1ULL;
+ printf("*%Lu*\n*%Lu*\n", maxx, maxx >> 5);
+
+ // Make sure params are not modified if they shouldn't be
+ int64_t t = 123;
+ modifier1(t);
+ printf("*%Ld*\n", t);
+ modifier2(t);
+ printf("*%Ld*\n", t);
+
+ // global structs with i64s
+ printf("*%d,%Ld*\n*%d,%Ld*\n", iub[0].c, iub[0].d, iub[1].c, iub[1].d);
+
+ // Bitshifts
+ {
+ int64_t a = -1;
+ int64_t b = a >> 29;
+ int64_t c = a >> 32;
+ int64_t d = a >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d);
+ uint64_t ua = -1;
+ int64_t ub = ua >> 29;
+ int64_t uc = ua >> 32;
+ int64_t ud = ua >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud);
+ }
+
+ // Nonconstant bitshifts
+ {
+ int64_t a = -1;
+ int64_t b = a >> (29 - argc + 1);
+ int64_t c = a >> (32 - argc + 1);
+ int64_t d = a >> (34 - argc + 1);
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", a, b, c, d);
+ uint64_t ua = -1;
+ int64_t ub = ua >> (29 - argc + 1);
+ int64_t uc = ua >> (32 - argc + 1);
+ int64_t ud = ua >> (34 - argc + 1);
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", ua, ub, uc, ud);
+ }
+
+ // Math mixtures with doubles
+ {
+ uint64_t a = 5;
+ double b = 6.8;
+ uint64_t c = a * b;
+ if (truthy()) printf("*%d,%d,%d*\n", (int)&a, (int)&b, (int)&c); // printing addresses prevents optimizations
+ printf("*prod:%llu*\n", c);
+ }
+
+ // Basic (rounded, for now) math. Just check compilation.
+ int64_t a = 0x1234def123450789ULL;
+ a--; if (truthy()) a--; // confuse optimizer
+ int64_t b = 0x1234000000450789ULL;
+ b++; if (truthy()) b--; // confuse optimizer
+ printf("*%Ld,%Ld,%Ld,%Ld*\n", (a+b)/5000, (a-b)/5000, (a*3)/5000, (a/5)/5000);
+
+ a -= 17; if (truthy()) a += 5; // confuse optimizer
+ b -= 17; if (truthy()) b += 121; // confuse optimizer
+ printf("*%Lx,%Lx,%Lx,%Lx*\n", b - a, b - a/2, b/2 - a, b - 20);
+
+ if (truthy()) a += 5/b; // confuse optimizer
+ if (truthy()) b += 121*(3+a/b); // confuse optimizer
+ printf("*%Lx,%Lx,%Lx,%Lx*\n", a - b, a - b/2, a/2 - b, a - 20);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*1311918518731868041\n' +
+ '0,0,0,1,1\n' +
+ '1,0,1,0,1*\n' +
+ '*245127260211081*\n' +
+ '*245127260209443*\n' +
+ '*18446744073709551615*\n' +
+ '*576460752303423487*\n' +
+ 'm1: 127\n' +
+ '*123*\n' +
+ '*127*\n' +
+ '*55,17179869201*\n' +
+ '*122,25769803837*\n' +
+ '*-1,-1,-1,-1*\n' +
+ '*-1,34359738367,4294967295,1073741823*\n' +
+ '*-1,-1,-1,-1*\n' +
+ '*-1,34359738367,4294967295,1073741823*\n' +
+ '*prod:34*\n' +
+ '*524718382041609,49025451137,787151111239120,52476740749274*\n' +
+ '*ffff210edd000002,91990876ea283be,f6e5210edcdd7c45,1234000000450765*\n' +
+ '*def122fffffe,91adef1232283bb,f6e66f78915d7c42,1234def123450763*\n')
+
+ src = r'''
+ #include <stdio.h>
+ #include <limits>
+
+ int main()
+ {
+ long long i,j,k;
+
+ i = 0;
+ j = -1,
+ k = 1;
+
+ printf( "*\n" );
+ printf( "%s\n", i > j ? "Ok": "Fail" );
+ printf( "%s\n", k > i ? "Ok": "Fail" );
+ printf( "%s\n", k > j ? "Ok": "Fail" );
+ printf( "%s\n", i < j ? "Fail": "Ok" );
+ printf( "%s\n", k < i ? "Fail": "Ok" );
+ printf( "%s\n", k < j ? "Fail": "Ok" );
+ printf( "%s\n", (i-j) >= k ? "Ok": "Fail" );
+ printf( "%s\n", (i-j) <= k ? "Ok": "Fail" );
+ printf( "%s\n", i > std::numeric_limits<long long>::min() ? "Ok": "Fail" );
+ printf( "%s\n", i < std::numeric_limits<long long>::max() ? "Ok": "Fail" );
+ printf( "*\n" );
+ }
+ '''
+
+ self.do_run(src, '*\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\nOk\n*')
+
+ # stuff that also needs sign corrections
+
+ Settings.CORRECT_SIGNS = 1
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdint.h>
+
+ int main()
+ {
+ // i32 vs i64
+ int32_t small = -1;
+ int64_t large = -1;
+ printf("*%d*\n", small == large);
+ small++;
+ printf("*%d*\n", small == large);
+ uint32_t usmall = -1;
+ uint64_t ularge = -1;
+ printf("*%d*\n", usmall == ularge);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1*\n*0*\n*0*\n')
+
+ def test_i64_b(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <sys/time.h>
+
+ typedef long long int64;
+
+ #define PRMJ_USEC_PER_SEC 1000000L
+
+ int main(int argc, char * argv[]) {
+ int64 sec = 1329409675 + argc;
+ int64 usec = 2329509675;
+ int64 mul = int64(sec) * PRMJ_USEC_PER_SEC;
+ int64 add = mul + int64(usec);
+ int add_low = add;
+ int add_high = add >> 32;
+ printf("*%lld,%lld,%u,%u*\n", mul, add, add_low, add_high);
+ int64 x = sec + (usec << 25);
+ x >>= argc*3;
+ printf("*%llu*\n", x);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n*9770671914067409*\n')
+
+ def test_i64_cmp(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+
+ typedef long long int64;
+
+ bool compare(int64 val) {
+ return val == -12;
+ }
+
+ bool compare2(int64 val) {
+ return val < -12;
+ }
+
+ int main(int argc, char * argv[]) {
+ printf("*%d,%d,%d,%d,%d,%d*\n", argc, compare(argc-1-12), compare(1000+argc), compare2(argc-1-10), compare2(argc-1-14), compare2(argc+1000));
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1,1,0,0,1,0*\n')
+
+ def test_i64_cmp2(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ typedef int32_t INT32;
+ typedef int64_t INT64;
+ typedef uint8_t UINT8;
+
+ void interface_clock_changed()
+ {
+ UINT8 m_divshift;
+ INT32 m_divisor;
+
+ //INT64 attos = m_attoseconds_per_cycle;
+ INT64 attos = 279365114840;
+ m_divshift = 0;
+ while (attos >= (1UL << 31))
+ {
+ m_divshift++;
+ printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31);
+ attos >>= 1;
+ }
+ m_divisor = attos;
+
+ printf("m_divisor is %i\n",m_divisor);
+ }
+
+ int main() {
+ interface_clock_changed();
+ return 0;
+ }
+ '''
+ self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648
+m_divshift is 2, on 139682557420 >?= 2147483648
+m_divshift is 3, on 69841278710 >?= 2147483648
+m_divshift is 4, on 34920639355 >?= 2147483648
+m_divshift is 5, on 17460319677 >?= 2147483648
+m_divshift is 6, on 8730159838 >?= 2147483648
+m_divshift is 7, on 4365079919 >?= 2147483648
+m_divshift is 8, on 2182539959 >?= 2147483648
+m_divisor is 1091269979
+''')
+
+ def test_i64_double(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+
+ src = r'''
+ #include <stdio.h>
+
+ typedef long long int64;
+ #define JSDOUBLE_HI32_SIGNBIT 0x80000000
+
+ bool JSDOUBLE_IS_NEGZERO(double d)
+ {
+ union {
+ struct {
+ unsigned int lo, hi;
+ } s;
+ double d;
+ } x;
+ if (d != 0)
+ return false;
+ x.d = d;
+ return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
+ }
+
+ bool JSINT64_IS_NEGZERO(int64 l)
+ {
+ union {
+ int64 i;
+ double d;
+ } x;
+ if (l != 0)
+ return false;
+ x.i = l;
+ return x.d == -0;
+ }
+
+ int main(int argc, char * argv[]) {
+ printf("*%d,%d,%d,%d*\n", JSDOUBLE_IS_NEGZERO(0), JSDOUBLE_IS_NEGZERO(-0), JSDOUBLE_IS_NEGZERO(-1), JSDOUBLE_IS_NEGZERO(+1));
+ printf("*%d,%d,%d,%d*\n", JSINT64_IS_NEGZERO(0), JSINT64_IS_NEGZERO(-0), JSINT64_IS_NEGZERO(-1), JSINT64_IS_NEGZERO(+1));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0,0,0,0*\n*1,1,0,0*\n') # same as gcc
+
+ def test_i64_umul(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ typedef uint32_t UINT32;
+ typedef uint64_t UINT64;
+
+ int main() {
+ volatile UINT32 testu32a = 2375724032U;
+ UINT32 bigu32 = 0xffffffffU;
+ volatile UINT64 testu64a = 14746250828952703000U;
+
+ while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) {
+ printf("testu64a is %llu\n", testu64a);
+ testu64a /= 2;
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'testu64a is 14746250828952703000\n')
+
+ def test_i64_precise(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ int main() {
+ uint64_t x = 0, y = 0;
+ for (int i = 0; i < 64; i++) {
+ x += 1ULL << i;
+ y += x;
+ x /= 3;
+ y *= 5;
+ printf("unsigned %d: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n", i, x, y, x+y, x-y, x*y, y ? x/y : 0, x ? y/x : 0, y ? x%y : 0, x ? y%x : 0);
+ }
+ int64_t x2 = 0, y2 = 0;
+ for (int i = 0; i < 64; i++) {
+ x2 += 1LL << i;
+ y2 += x2;
+ x2 /= 3 * (i % 7 ? -1 : 1);
+ y2 *= 5 * (i % 2 ? -1 : 1);
+ printf("signed %d: %lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld\n", i, x2, y2, x2+y2, x2-y2, x2*y2, y2 ? x2/y2 : 0, x2 ? y2/x2 : 0, y2 ? x2%y2 : 0, x2 ? y2%x2 : 0);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, open(path_from_root('tests', 'i64_precise.txt')).read())
+
+ # Verify that even if we ask for precision, if it is not needed it is not included
+ Settings.PRECISE_I64_MATH = 1
+ src = '''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ int main(int argc, char **argv) {
+ uint64_t x = 2125299906845564, y = 1225891506842664;
+ if (argc == 12) {
+ x = x >> 1;
+ y = y >> 1;
+ }
+ x = x & 12ULL;
+ y = y | 12ULL;
+ x = x ^ y;
+ x <<= 2;
+ y >>= 3;
+ printf("*%llu, %llu*\\n", x, y);
+ }
+ '''
+ self.do_run(src, '*4903566027370624, 153236438355333*')
+ code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
+ assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not actually used'
+
+ # But if we force it to be included, it is. First, a case where we don't need it
+ Settings.PRECISE_I64_MATH = 2
+ self.do_run(open(path_from_root('tests', 'hello_world.c')).read(), 'hello')
+ code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
+ assert 'goog.math.Long' in code, 'i64 precise math should be included if forced'
+
+ # and now one where we do
+ self.do_run(r'''
+ #include <stdio.h>
+
+ int main( int argc, char ** argv )
+ {
+ unsigned long a = 0x60DD1695U;
+ unsigned long b = 0xCA8C4E7BU;
+ unsigned long long c = (unsigned long long)a * b;
+ printf( "c = %016llx\n", c );
+
+ return 0;
+ }
+ ''', 'c = 4ca38a6bd2973f97')
+
+ def test_i64_llabs(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+ Settings.PRECISE_I64_MATH = 2
+ self.do_run(r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main(int argc, char ** argv) {
+ printf("%lld,%lld\n", llabs(-576460752303423489), llabs(576460752303423489));
+ return 0;
+ }
+ ''', '576460752303423489,576460752303423489')
+
+ def test_i64_zextneg(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+
+ int main(int argc, char *argv[])
+ {
+ uint8_t byte = 0x80;
+ uint16_t two = byte;
+ uint32_t four = byte;
+ uint64_t eight = byte;
+
+ printf("value: %d,%d,%d,%lld.\n", byte, two, four, eight);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'value: 128,128,128,128.')
+
+ def test_i64_7z(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+ uint64_t a, b;
+ int main(int argc, char *argv[])
+ {
+ a = argc;
+ b = argv[1][0];
+ printf("%d,%d\n", a, b);
+ if (a > a + b || a > a + b + 1) {
+ printf("one %lld, %lld", a, b);
+ return 0;
+ }
+ printf("zero %lld, %lld", a, b);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'zero 2, 104', ['hallo'])
+
+ def test_i64_i16(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+ int main(int argc, char ** argv){
+ int y=-133;
+ int64_t x= ((int64_t)((short)(y)))*(100 + argc);
+ if(x>0)
+ printf(">0\n");
+ else
+ printf("<=0\n");
+ }
+ '''
+ self.do_run(src, '<=0')
+
+ def test_i64_qdouble(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ typedef long long qint64; /* 64 bit signed */
+ typedef double qreal;
+
+
+ int main(int argc, char **argv)
+ {
+ qreal c = 111;
+ qint64 d = -111 + (argc - 1);
+ c += d;
+ if (c < -1 || c > 1)
+ {
+ printf("Failed!\n");
+ }
+ else
+ {
+ printf("Succeeded!\n");
+ }
+ };
+ '''
+ self.do_run(src, 'Succeeded!')
+
+ def test_i64_varargs(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <stdarg.h>
+
+ int64_t ccv_cache_generate_signature(char *msg, int len, int64_t sig_start, ...) {
+ if (sig_start < 10123)
+ printf("%s\n", msg+len);
+ va_list v;
+ va_start(v, sig_start);
+ if (sig_start > 1413)
+ printf("%d\n", va_arg(v, int));
+ else
+ printf("nada\n");
+ va_end(v);
+ return len*sig_start*(msg[0]+1);
+ }
+
+ int main(int argc, char **argv)
+ {
+ for (int i = 0; i < argc; i++) {
+ int64_t x;
+ if (i % 123123 == 0)
+ x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 54.111);
+ else
+ x = ccv_cache_generate_signature(argv[i], i+2, (int64_t)argc*argc, 13);
+ printf("%lld\n", x);
+ }
+ };
+ '''
+ self.do_run(src, '''in/this.program
+nada
+1536
+a
+nada
+5760
+fl
+nada
+6592
+sdfasdfasdf
+nada
+7840
+''', 'waka fleefl asdfasdfasdfasdf'.split(' '))
+
+ def test_i32_mul_precise(self):
+ if self.emcc_args == None: return self.skip('needs ta2')
+
+ src = r'''
+ #include <stdio.h>
+
+ int main(int argc, char **argv) {
+ unsigned long d1 = 0x847c9b5d;
+ unsigned long q = 0x549530e1;
+ if (argc > 1000) { q += argc; d1 -= argc; } // confuse optimizer
+ printf("%lu\n", d1*q);
+ return 0;
+ }
+ '''
+ self.do_run(src, '3217489085')
+
+ def test_i32_mul_semiprecise(self):
+ if Settings.ASM_JS: return self.skip('asm is always fully precise')
+
+ Settings.PRECISE_I32_MUL = 0 # we want semiprecise here
+
+ src = r'''
+ #include <stdio.h>
+
+ typedef unsigned int uint;
+
+ // from cube2, zlib licensed
+
+ #define N (624)
+ #define M (397)
+ #define K (0x9908B0DFU)
+
+ static uint state[N];
+ static int next = N;
+
+ void seedMT(uint seed)
+ {
+ state[0] = seed;
+ for(uint i = 1; i < N; i++) // if we do not do this precisely, at least we should coerce to int immediately, not wait
+ state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i;
+ next = 0;
+ }
+
+ int main() {
+ seedMT(5497);
+ for (int i = 0; i < 10; i++) printf("%d: %u\n", i, state[i]);
+ return 0;
+ }
+ '''
+ self.do_run(src, '''0: 5497
+1: 2916432318
+2: 2502517762
+3: 3151524867
+4: 2323729668
+5: 2053478917
+6: 2409490438
+7: 848473607
+8: 691103752
+9: 3915535113
+''')
+
+ def test_i16_emcc_intrinsic(self):
+ Settings.CORRECT_SIGNS = 1 # Relevant to this test
+
+ src = r'''
+ #include <stdio.h>
+
+ int test(unsigned short a, unsigned short b) {
+ unsigned short result = a;
+ result += b;
+ if (result < b) printf("C!");
+ return result;
+ }
+
+ int main(void) {
+ printf(",%d,", test(0, 0));
+ printf(",%d,", test(1, 1));
+ printf(",%d,", test(65535, 1));
+ printf(",%d,", test(1, 65535));
+ printf(",%d,", test(32768, 32767));
+ printf(",%d,", test(32768, 32768));
+ return 0;
+ }
+ '''
+ self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,')
+
+ def test_negative_zero(self):
+ src = r'''
+ #include <stdio.h>
+ #include <math.h>
+
+ int main() {
+ #define TEST(x, y) \
+ printf("%.2f, %.2f ==> %.2f\n", x, y, copysign(x, y));
+ TEST( 5.0f, 5.0f);
+ TEST( 5.0f, -5.0f);
+ TEST(-5.0f, 5.0f);
+ TEST(-5.0f, -5.0f);
+ TEST( 5.0f, 4.0f);
+ TEST( 5.0f, -4.0f);
+ TEST(-5.0f, 4.0f);
+ TEST(-5.0f, -4.0f);
+ TEST( 0.0f, 5.0f);
+ TEST( 0.0f, -5.0f);
+ TEST(-0.0f, 5.0f);
+ TEST(-0.0f, -5.0f);
+ TEST( 5.0f, 0.0f);
+ TEST( 5.0f, -0.0f);
+ TEST(-5.0f, 0.0f);
+ TEST(-5.0f, -0.0f);
+ TEST( 0.0f, 0.0f);
+ TEST( 0.0f, -0.0f);
+ TEST(-0.0f, 0.0f);
+ TEST(-0.0f, -0.0f);
+ return 0;
+ }
+ '''
+ self.do_run(src, '''5.00, 5.00 ==> 5.00
+5.00, -5.00 ==> -5.00
+-5.00, 5.00 ==> 5.00
+-5.00, -5.00 ==> -5.00
+5.00, 4.00 ==> 5.00
+5.00, -4.00 ==> -5.00
+-5.00, 4.00 ==> 5.00
+-5.00, -4.00 ==> -5.00
+0.00, 5.00 ==> 0.00
+0.00, -5.00 ==> -0.00
+-0.00, 5.00 ==> 0.00
+-0.00, -5.00 ==> -0.00
+5.00, 0.00 ==> 5.00
+5.00, -0.00 ==> -5.00
+-5.00, 0.00 ==> 5.00
+-5.00, -0.00 ==> -5.00
+0.00, 0.00 ==> 0.00
+0.00, -0.00 ==> -0.00
+-0.00, 0.00 ==> 0.00
+-0.00, -0.00 ==> -0.00
+''')
+
+ def test_llvm_intrinsics(self):
+ if self.emcc_args == None: return self.skip('needs ta2')
+
+ Settings.PRECISE_I64_MATH = 2 # for bswap64
+
+ src = r'''
+ #include <stdio.h>
+ #include <sys/types.h>
+
+ extern "C" {
+ extern unsigned short llvm_bswap_i16(unsigned short x);
+ extern unsigned int llvm_bswap_i32(unsigned int x);
+ extern int32_t llvm_ctlz_i32(int32_t x);
+ extern int64_t llvm_ctlz_i64(int64_t x);
+ extern int32_t llvm_cttz_i32(int32_t x);
+ extern int64_t llvm_cttz_i64(int64_t x);
+ extern int32_t llvm_ctpop_i32(int32_t x);
+ extern int64_t llvm_ctpop_i64(int64_t x);
+ extern int llvm_expect_i32(int x, int y);
+ }
+
+ int main(void) {
+ unsigned short x = 0xc8ef;
+ printf("%x,%x\n", x&0xff, x >> 8);
+ x = llvm_bswap_i16(x);
+ printf("%x,%x\n", x&0xff, x >> 8);
+
+ unsigned int y = 0xc5de158a;
+ printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff);
+ y = llvm_bswap_i32(y);
+ printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff);
+
+ printf("%d,%d\n", (int)llvm_ctlz_i64(((int64_t)1) << 40), llvm_ctlz_i32(1<<10));
+ printf("%d,%d\n", (int)llvm_cttz_i64(((int64_t)1) << 40), llvm_cttz_i32(1<<10));
+ printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1), llvm_ctpop_i32(0x3101));
+ printf("%d\n", (int)llvm_ctpop_i32(-594093059));
+
+ printf("%d\n", llvm_expect_i32(x % 27, 3));
+
+ int64_t a = 1;
+ a = __builtin_bswap64(a);
+ printf("%lld\n", a);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''ef,c8
+c8,ef
+8a,15,de,c5
+c5,de,15,8a
+23,21
+40,10
+5,4
+22
+13
+72057594037927936
+''')
+
+ def test_bswap64(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ #include <iostream>
+ #include <string>
+ #include <sstream>
+
+ typedef unsigned long long quint64;
+
+ using namespace std;
+
+ inline quint64 qbswap(quint64 source)
+ {
+ return 0
+ | ((source & quint64(0x00000000000000ffLL)) << 56)
+ | ((source & quint64(0x000000000000ff00LL)) << 40)
+ | ((source & quint64(0x0000000000ff0000LL)) << 24)
+ | ((source & quint64(0x00000000ff000000LL)) << 8)
+ | ((source & quint64(0x000000ff00000000LL)) >> 8)
+ | ((source & quint64(0x0000ff0000000000LL)) >> 24)
+ | ((source & quint64(0x00ff000000000000LL)) >> 40)
+ | ((source & quint64(0xff00000000000000LL)) >> 56);
+ }
+
+ int main()
+ {
+ quint64 v = strtoull("4433ffeeddccbb00", NULL, 16);
+ printf("%lld\n", v);
+
+ const string string64bitInt = "4433ffeeddccbb00";
+ stringstream s(string64bitInt);
+ quint64 int64bitInt = 0;
+ printf("1\n");
+ s >> hex >> int64bitInt;
+ printf("2\n");
+
+ stringstream out;
+ out << hex << qbswap(int64bitInt);
+
+ cout << out.str() << endl;
+ cout << hex << int64bitInt << endl;
+ cout << string64bitInt << endl;
+
+ if (out.str() != "bbccddeeff3344")
+ {
+ cout << "Failed!" << endl;
+ }
+ else
+ {
+ cout << "Succeeded!" << endl;
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''4914553019779824384
+1
+2
+bbccddeeff3344
+4433ffeeddccbb00
+4433ffeeddccbb00
+Succeeded!
+''')
+
+ def test_sha1(self):
+ if self.emcc_args == None: return self.skip('needs ta2')
+
+ self.do_run(open(path_from_root('tests', 'sha1.c')).read(), 'SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6')
+
+ def test_cube2md5(self):
+ if self.emcc_args == None: return self.skip('needs emcc')
+ self.emcc_args += ['--embed-file', 'cube2md5.txt']
+ shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt'))
+ self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read())
+
+ def test_cube2hash(self):
+
+ try:
+ old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = '1' # test splitting out each function to a chunk in emscripten.py (21 functions here)
+
+ # A good test of i64 math
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
+ self.do_run('', 'Usage: hashstring <seed>',
+ libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None),
+ includes=[path_from_root('tests', 'cube2hash')])
+
+ for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
+ ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
+ ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
+ self.do_run('', 'hash value: ' + output, [text], no_build=True)
+ finally:
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
+
+ def test_unaligned(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
+
+ src = r'''
+ #include<stdio.h>
+
+ struct S {
+ double x;
+ int y;
+ };
+
+ int main() {
+ // the 64-bit value here will not be 8-byte aligned
+ S s0[3] = { {0x12a751f430142, 22}, {0x17a5c85bad144, 98}, {1, 1}};
+ char buffer[10*sizeof(S)];
+ int b = int(buffer);
+ S *s = (S*)(b + 4-b%8);
+ s[0] = s0[0];
+ s[1] = s0[1];
+ s[2] = s0[2];
+
+ printf("*%d : %d : %d\n", sizeof(S), ((unsigned int)&s[0]) % 8 != ((unsigned int)&s[1]) % 8,
+ ((unsigned int)&s[1]) - ((unsigned int)&s[0]));
+ s[0].x++;
+ s[0].y++;
+ s[1].x++;
+ s[1].y++;
+ printf("%.1f,%d,%.1f,%d\n", s[0].x, s[0].y, s[1].x, s[1].y);
+ return 0;
+ }
+ '''
+
+ # TODO: A version of this with int64s as well
+
+ if self.is_le32():
+ return self.skip('LLVM marks the reads of s as fully aligned, making this test invalid')
+ else:
+ self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n')
+
+ return # TODO: continue to the next part here
+
+ # Test for undefined behavior in C. This is not legitimate code, but does exist
+
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('No meaning to unaligned addresses without t2')
+
+ src = r'''
+ #include <stdio.h>
+
+ int main()
+ {
+ int x[10];
+ char *p = (char*)&x[0];
+ p++;
+ short *q = (short*)p;
+ *q = 300;
+ printf("*%d:%d*\n", *q, ((int)q)%2);
+ int *r = (int*)p;
+ *r = 515559;
+ printf("*%d*\n", *r);
+ long long *t = (long long*)p;
+ *t = 42949672960;
+ printf("*%Ld*\n", *t);
+ return 0;
+ }
+ '''
+
+ try:
+ self.do_run(src, '*300:1*\n*515559*\n*42949672960*\n')
+ except Exception, e:
+ assert 'must be aligned' in str(e), e # expected to fail without emulation
+
+ def test_align64(self):
+ src = r'''
+ #include <stdio.h>
+
+ // inspired by poppler
+
+ enum Type {
+ A = 10,
+ B = 20
+ };
+
+ struct Object {
+ Type type;
+ union {
+ int intg;
+ double real;
+ char *name;
+ };
+ };
+
+ struct Principal {
+ double x;
+ Object a;
+ double y;
+ };
+
+ int main(int argc, char **argv)
+ {
+ int base = argc-1;
+ Object *o = NULL;
+ printf("%d,%d\n", sizeof(Object), sizeof(Principal));
+ printf("%d,%d,%d,%d\n", (int)&o[base].type, (int)&o[base].intg, (int)&o[base].real, (int)&o[base].name);
+ printf("%d,%d,%d,%d\n", (int)&o[base+1].type, (int)&o[base+1].intg, (int)&o[base+1].real, (int)&o[base+1].name);
+ Principal p, q;
+ p.x = p.y = q.x = q.y = 0;
+ p.a.type = A;
+ p.a.real = 123.456;
+ *(&q.a) = p.a;
+ printf("%.2f,%d,%.2f,%.2f : %.2f,%d,%.2f,%.2f\n", p.x, p.a.type, p.a.real, p.y, q.x, q.a.type, q.a.real, q.y);
+ return 0;
+ }
+ '''
+
+ if self.is_le32():
+ self.do_run(src, '''16,32
+0,8,8,8
+16,24,24,24
+0.00,10,123.46,0.00 : 0.00,10,123.46,0.00
+''')
+ else:
+ self.do_run(src, '''12,28
+0,4,4,4
+12,16,16,16
+0.00,10,123.46,0.00 : 0.00,10,123.46,0.00
+''')
+
+ def test_unsigned(self):
+ Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here
+ Settings.CHECK_SIGNS = 0
+ src = '''
+ #include <stdio.h>
+ const signed char cvals[2] = { -1, -2 }; // compiler can store this is a string, so -1 becomes \FF, and needs re-signing
+ int main()
+ {
+ {
+ unsigned char x = 200;
+ printf("*%d*\\n", x);
+ unsigned char y = -22;
+ printf("*%d*\\n", y);
+ }
+
+ int varey = 100;
+ unsigned int MAXEY = -1, MAXEY2 = -77;
+ printf("*%u,%d,%u*\\n", MAXEY, varey >= MAXEY, MAXEY2); // 100 >= -1? not in unsigned!
+
+ int y = cvals[0];
+ printf("*%d,%d,%d,%d*\\n", cvals[0], cvals[0] < 0, y, y < 0);
+ y = cvals[1];
+ printf("*%d,%d,%d,%d*\\n", cvals[1], cvals[1] < 0, y, y < 0);
+
+ // zext issue - see mathop in jsifier
+ unsigned char x8 = -10;
+ unsigned long hold = 0;
+ hold += x8;
+ int y32 = hold+50;
+ printf("*%u,%u*\\n", hold, y32);
+
+ // Comparisons
+ x8 = 0;
+ for (int i = 0; i < 254; i++) x8++; // make it an actual 254 in JS - not a -2
+ printf("*%d,%d*\\n", x8+1 == 0xff, x8+1 != 0xff); // 0xff may be '-1' in the bitcode
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*')
+
+ # Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires
+ # corrections otherwise
+ if Settings.USE_TYPED_ARRAYS == 2:
+ Settings.CORRECT_SIGNS = 0
+ Settings.CHECK_SIGNS = 1 if not Settings.ASM_JS else 0
+ else:
+ Settings.CORRECT_SIGNS = 1
+ Settings.CHECK_SIGNS = 0
+
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ {
+ unsigned char x;
+ unsigned char *y = &x;
+ *y = -1;
+ printf("*%d*\\n", x);
+ }
+ {
+ unsigned short x;
+ unsigned short *y = &x;
+ *y = -1;
+ printf("*%d*\\n", x);
+ }
+ /*{ // This case is not checked. The hint for unsignedness is just the %u in printf, and we do not analyze that
+ unsigned int x;
+ unsigned int *y = &x;
+ *y = -1;
+ printf("*%u*\\n", x);
+ }*/
+ {
+ char x;
+ char *y = &x;
+ *y = 255;
+ printf("*%d*\\n", x);
+ }
+ {
+ char x;
+ char *y = &x;
+ *y = 65535;
+ printf("*%d*\\n", x);
+ }
+ {
+ char x;
+ char *y = &x;
+ *y = 0xffffffff;
+ printf("*%d*\\n", x);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, '*255*\n*65535*\n*-1*\n*-1*\n*-1*')
+
+ def test_bitfields(self):
+ if self.emcc_args is None: Settings.SAFE_HEAP = 0 # bitfields do loads on invalid areas, by design
+ src = '''
+ #include <stdio.h>
+ struct bitty {
+ unsigned x : 1;
+ unsigned y : 1;
+ unsigned z : 1;
+ };
+ int main()
+ {
+ bitty b;
+ printf("*");
+ for (int i = 0; i <= 1; i++)
+ for (int j = 0; j <= 1; j++)
+ for (int k = 0; k <= 1; k++) {
+ b.x = i;
+ b.y = j;
+ b.z = k;
+ printf("%d,%d,%d,", b.x, b.y, b.z);
+ }
+ printf("*\\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,1,0,1,1,1,0,1,1,1,*')
+
+ def test_floatvars(self):
+ src = '''
+ #include <stdio.h>
+
+ // headers test, see issue #1013
+ #include<cfloat>
+ #include<cmath>
+
+ int main(int argc, char **argv)
+ {
+ float x = 1.234, y = 3.5, q = 0.00000001;
+ y *= 3;
+ int z = x < y;
+ printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q);
+
+ printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3));
+
+ printf("small: %.10f\\n", argc * 0.000001);
+
+ /*
+ // Rounding behavior
+ float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
+ double ds[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
+ for (int i = 0; i < 6; i++)
+ printf("*int(%.2f)=%d,%d*\\n", fs[i], int(fs[i]), int(ds[i]));
+ */
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\nsmall: 0.0000010000\n')
+
+ def test_isnan(self):
+ src = r'''
+ #include <stdio.h>
+
+ int IsNaN(double x){
+ int rc; /* The value return */
+ volatile double y = x;
+ volatile double z = y;
+ rc = (y!=z);
+ return rc;
+ }
+
+ int main() {
+ double tests[] = { 1.0, 3.333, 1.0/0.0, 0.0/0.0, -1.0/0.0, -0, 0, -123123123, 12.0E200 };
+ for (int i = 0; i < sizeof(tests)/sizeof(double); i++)
+ printf("%d - %f - %d\n", i, tests[i], IsNaN(tests[i]));
+ }
+ '''
+ self.do_run(src, '''0 - 1.000000 - 0
+1 - 3.333000 - 0
+2 - inf - 0
+3 - nan - 1
+4 - -inf - 0
+5 - 0.000000 - 0
+6 - 0.000000 - 0
+7 - -123123123.000000 - 0
+8 - 1.2e+201 - 0
+''')
+
+ def test_globaldoubles(self):
+ src = r'''
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ double testVu, testVv, testWu, testWv;
+
+ void Test(double _testVu, double _testVv, double _testWu, double _testWv)
+ {
+ testVu = _testVu;
+ testVv = _testVv;
+ testWu = _testWu;
+ testWv = _testWv;
+ printf("BUG?\n");
+ printf("Display: Vu=%f Vv=%f Wu=%f Wv=%f\n", testVu, testVv, testWu, testWv);
+ }
+
+ int main(void)
+ {
+ double v1 = 465.1;
+ double v2 = 465.2;
+ double v3 = 160.3;
+ double v4 = 111.4;
+ Test(v1, v2, v3, v4);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'BUG?\nDisplay: Vu=465.100000 Vv=465.200000 Wu=160.300000 Wv=111.400000')
+
+ def test_math(self):
+ src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <cmath>
+ int main()
+ {
+ printf("*%.2f,%.2f,%d", M_PI, -M_PI, (1/0.0) > 1e300); // could end up as infinity, or just a very very big number
+ printf(",%d", isfinite(NAN) != 0);
+ printf(",%d", isfinite(INFINITY) != 0);
+ printf(",%d", isfinite(-INFINITY) != 0);
+ printf(",%d", isfinite(12.3) != 0);
+ printf(",%d", isinf(NAN) != 0);
+ printf(",%d", isinf(INFINITY) != 0);
+ printf(",%d", isinf(-INFINITY) != 0);
+ printf(",%d", isinf(12.3) != 0);
+ div_t div_result = div(23, 10);
+ printf(",%d", div_result.quot);
+ printf(",%d", div_result.rem);
+ double sine = -1.0, cosine = -1.0;
+ sincos(0.0, &sine, &cosine);
+ printf(",%1.1lf", sine);
+ printf(",%1.1lf", cosine);
+ float fsine = -1.0f, fcosine = -1.0f;
+ sincosf(0.0, &fsine, &fcosine);
+ printf(",%1.1f", fsine);
+ printf(",%1.1f", fcosine);
+ printf("*\\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, '*3.14,-3.14,1,0,0,0,1,0,1,1,0,2,3,0.0,1.0,0.0,1.0*')
+
+ def test_erf(self):
+ src = '''
+ #include <math.h>
+ #include <stdio.h>
+ int main()
+ {
+ printf("%1.6f, %1.6f, %1.6f, %1.6f, %1.6f, %1.6f\\n",
+ erf(1.0),
+ erf(3.0),
+ erf(-1.0),
+ erfc(1.0),
+ erfc(3.0),
+ erfc(-1.5));
+ return 0;
+ }
+ '''
+ self.do_run(src, '0.842701, 0.999978, -0.842701, 0.157299, 0.000022, 1.966105')
+
+ def test_math_hyperbolic(self):
+ src = open(path_from_root('tests', 'hyperbolic', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_frexp(self):
+ src = '''
+ #include <stdio.h>
+ #include <math.h>
+ #include <assert.h>
+
+ static const double tol=1e-16;
+
+ void test_value(double value)
+ {
+ int exponent;
+ double x=frexp(value, &exponent);
+ double expected=x*pow(2.0, exponent);
+
+ printf("%f=%f*2^%d\\n", value, x, exponent);
+
+ assert(fabs(expected-value)<tol);
+ assert(x==0 || (fabs(x)>=5e-1 && fabs(x)<1)); // x has a magnitude in the interval [1/2, 1)
+ }
+
+ int main()
+ {
+ test_value(0);
+ test_value(100.1);
+ test_value(-100.1);
+ test_value(.5);
+ test_value(-.5);
+ test_value(1-1e-16);
+ test_value(-(1-1e-16));
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''0.000000=0.000000*2^0
+100.100000=0.782031*2^7
+-100.100000=-0.782031*2^7
+0.500000=0.500000*2^0
+-0.500000=-0.500000*2^0
+1.000000=1.000000*2^0
+-1.000000=-1.000000*2^0''')
+
+ def test_rounding(self):
+ src = '''
+ #include <stdio.h>
+ #include <math.h>
+
+ int main()
+ {
+ printf("%.1f ", round(1.4));
+ printf("%.1f ", round(1.6));
+ printf("%.1f ", round(-1.4));
+ printf("%.1f ", round(-1.6));
+
+ printf("%.1f ", round(1.5));
+ printf("%.1f ", round(2.5));
+ printf("%.1f ", round(-1.5));
+ printf("%.1f ", round(-2.5));
+
+ printf("%ld ", lrint(1.4));
+ printf("%ld ", lrint(1.6));
+ printf("%ld ", lrint(-1.4));
+ printf("%ld ", lrint(-1.6));
+
+ printf("%ld ", lrint(1.5));
+ printf("%ld ", lrint(2.5));
+ printf("%ld ", lrint(-1.5));
+ printf("%ld ", lrint(-2.5));
+
+ return 0;
+ }
+ '''
+ self.do_run(src, "1.0 2.0 -1.0 -2.0 2.0 3.0 -2.0 -3.0 "
+ "1 2 -1 -2 2 2 -2 -2")
+
+ # This example borrowed from MSDN documentation
+ def test_fcvt(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ src = '''
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int main() {
+ int decimal, sign;
+ char *buffer;
+ double source = 3.1415926535;
+
+ buffer = fcvt(source, 7, &decimal, &sign);
+ printf("source: %2.10f buffer: '%s' decimal: %d sign: %d\\n",
+ source, buffer, decimal, sign);
+ }
+ '''
+ self.do_run(src, "source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0");
+
+ def test_llrint(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
+ src = r'''
+ #include <stdio.h>
+ #include <math.h>
+ int main() {
+ printf("%lld\n%lld\n%lld\n%lld\n", llrint(0.1), llrint(0.6), llrint(1.25), llrint(1099511627776.667));
+ return 0;
+ }
+ '''
+ self.do_run(src, '0\n1\n1\n1099511627777\n')
+
+ def test_getgep(self):
+ # Generated code includes getelementptr (getelementptr, 0, 1), i.e., GEP as the first param to GEP
+ src = '''
+ #include <stdio.h>
+ struct {
+ int y[10];
+ int z[10];
+ } commonblock;
+
+ int main()
+ {
+ for (int i = 0; i < 10; ++i) {
+ commonblock.y[i] = 1;
+ commonblock.z[i] = 2;
+ }
+ printf("*%d %d*\\n", commonblock.y[0], commonblock.z[0]);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*1 2*')
+
+ def test_multiply_defined_symbols(self):
+ a1 = "int f() { return 1; }"
+ a1_name = os.path.join(self.get_dir(), 'a1.c')
+ open(a1_name, 'w').write(a1)
+ a2 = "void x() {}"
+ a2_name = os.path.join(self.get_dir(), 'a2.c')
+ open(a2_name, 'w').write(a2)
+ b1 = "int f() { return 2; }"
+ b1_name = os.path.join(self.get_dir(), 'b1.c')
+ open(b1_name, 'w').write(b1)
+ b2 = "void y() {}"
+ b2_name = os.path.join(self.get_dir(), 'b2.c')
+ open(b2_name, 'w').write(b2)
+ main = r'''
+ #include <stdio.h>
+ int f();
+ int main() {
+ printf("result: %d\n", f());
+ return 0;
+ }
+ '''
+ main_name = os.path.join(self.get_dir(), 'main.c')
+ open(main_name, 'w').write(main)
+
+ Building.emcc(a1_name)
+ Building.emcc(a2_name)
+ Building.emcc(b1_name)
+ Building.emcc(b2_name)
+ Building.emcc(main_name)
+
+ liba_name = os.path.join(self.get_dir(), 'liba.a')
+ Building.emar('cr', liba_name, [a1_name + '.o', a2_name + '.o'])
+ libb_name = os.path.join(self.get_dir(), 'libb.a')
+ Building.emar('cr', libb_name, [b1_name + '.o', b2_name + '.o'])
+
+ all_name = os.path.join(self.get_dir(), 'all.bc')
+ Building.link([main_name + '.o', liba_name, libb_name], all_name)
+
+ self.do_ll_run(all_name, 'result: 1')
+
+ def test_if(self):
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ int x = 5;
+ if (x > 3) {
+ printf("*yes*\\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, '*yes*')
+
+ def test_if_else(self):
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ int x = 5;
+ if (x > 10) {
+ printf("*yes*\\n");
+ } else {
+ printf("*no*\\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, '*no*')
+
+ def test_loop(self):
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ int x = 5;
+ for (int i = 0; i < 6; i++) {
+ x += x*i;
+ if (x > 1000) {
+ if (x % 7 == 0) printf("cheez\\n");
+ x /= 2;
+ break;
+ }
+ }
+ printf("*%d*\\n", x);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1800*')
+
+ generated = open('src.cpp.o.js', 'r').read()
+
+ def test_stack(self):
+ Settings.INLINING_LIMIT = 50
+
+ src = '''
+ #include <stdio.h>
+ int test(int i) {
+ int x = 10;
+ if (i > 0) {
+ return test(i-1);
+ }
+ return int(&x); // both for the number, and forces x to not be nativized
+ }
+ int main(int argc, char **argv)
+ {
+ // We should get the same value for the first and last - stack has unwound
+ int x1 = test(argc - 2);
+ int x2 = test(100);
+ int x3 = test((argc - 2) / 4);
+ printf("*%d,%d*\\n", x3-x1, x2 != x1);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0,1*')
+
+ def test_strings(self):
+ src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ int main(int argc, char **argv)
+ {
+ int x = 5, y = 9, magic = 7; // fool compiler with magic
+ memmove(&x, &y, magic-7); // 0 should not crash us
+
+ int xx, yy, zz;
+ char s[32];
+ int cc = sscanf("abc_10.b1_xyz_543_defg", "abc_%d.%2x_xyz_%3d_%3s", &xx, &yy, &zz, s);
+ printf("%d:%d,%d,%d,%s\\n", cc, xx, yy, zz, s);
+
+ printf("%d\\n", argc);
+ puts(argv[1]);
+ puts(argv[2]);
+ printf("%d\\n", atoi(argv[3])+2);
+ const char *foolingthecompiler = "\\rabcd";
+ printf("%d\\n", strlen(foolingthecompiler)); // Tests parsing /0D in llvm - should not be a 0 (end string) then a D!
+ printf("%s\\n", NULL); // Should print '(null)', not the string at address 0, which is a real address for us!
+ printf("/* a comment */\\n"); // Should not break the generated code!
+ printf("// another\\n"); // Should not break the generated code!
+
+ char* strdup_val = strdup("test");
+ printf("%s\\n", strdup_val);
+ free(strdup_val);
+
+ {
+ char *one = "one 1 ONE !";
+ char *two = "two 2 TWO ?";
+ char three[1024];
+ memset(three, '.', 1024);
+ three[50] = 0;
+ strncpy(three + argc, one + (argc/2), argc+1);
+ strncpy(three + argc*3, two + (argc/3), argc+2);
+ printf("waka %s\\n", three);
+ }
+
+ {
+ char *one = "string number one top notch";
+ char *two = "fa la sa ho fi FI FO FUM WHEN WHERE WHY HOW WHO";
+ char three[1000];
+ strcpy(three, &one[argc*2]);
+ char *four = strcat(three, &two[argc*3]);
+ printf("cat |%s|\\n", three);
+ printf("returned |%s|\\n", four);
+ }
+
+ return 0;
+ }
+ '''
+ for named in (0, 1):
+ print named
+ Settings.NAMED_GLOBALS = named
+ self.do_run(src, '''4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\nwaka ....e 1 O...wo 2 T................................
+cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|
+returned |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too', '74'])
+ if self.emcc_args == []:
+ gen = open(self.in_dir('src.cpp.o.js')).read()
+ assert ('var __str1;' in gen) == named
+
+ def test_strcmp_uni(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ int main()
+ {
+ #define TEST(func) \
+ { \
+ char *word = "WORD"; \
+ char wordEntry[2] = { -61,-126 }; /* "Â"; */ \
+ int cmp = func(word, wordEntry, 2); \
+ printf("Compare value " #func " is %d\\n", cmp); \
+ }
+ TEST(strncmp);
+ TEST(strncasecmp);
+ TEST(memcmp);
+ }
+ '''
+ self.do_run(src, 'Compare value strncmp is -1\nCompare value strncasecmp is -1\nCompare value memcmp is -1\n')
+
+ def test_strndup(self):
+ src = '''
+ //---------------
+ //- http://pubs.opengroup.org/onlinepubs/9699919799/functions/strndup.html
+ //---------------
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ int main(int argc, char **argv) {
+ const char* source = "strndup - duplicate a specific number of bytes from a string";
+
+ char* strdup_val = strndup(source, 0);
+ printf("1:%s\\n", strdup_val);
+ free(strdup_val);
+
+ strdup_val = strndup(source, 7);
+ printf("2:%s\\n", strdup_val);
+ free(strdup_val);
+
+ strdup_val = strndup(source, 1000);
+ printf("3:%s\\n", strdup_val);
+ free(strdup_val);
+
+ strdup_val = strndup(source, 60);
+ printf("4:%s\\n", strdup_val);
+ free(strdup_val);
+
+ strdup_val = strndup(source, 19);
+ printf("5:%s\\n", strdup_val);
+ free(strdup_val);
+
+ strdup_val = strndup(source, -1);
+ printf("6:%s\\n", strdup_val);
+ free(strdup_val);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '1:\n2:strndup\n3:strndup - duplicate a specific number of bytes from a string\n4:strndup - duplicate a specific number of bytes from a string\n5:strndup - duplicate\n6:\n')
+
+ def test_errar(self):
+ src = r'''
+ #include <stdio.h>
+ #include <errno.h>
+ #include <string.h>
+
+ int main() {
+ char* err;
+ char buffer[200];
+
+ err = strerror(EDOM);
+ strerror_r(EWOULDBLOCK, buffer, 200);
+ printf("<%s>\n", err);
+ printf("<%s>\n", buffer);
+
+ printf("<%d>\n", strerror_r(EWOULDBLOCK, buffer, 0));
+ errno = 123;
+ printf("<%d>\n", errno);
+
+ return 0;
+ }
+ '''
+ expected = '''
+ <Math arg out of domain of func>
+ <No more processes>
+ <34>
+ <123>
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
+
+ def test_mainenv(self):
+ src = '''
+ #include <stdio.h>
+ int main(int argc, char **argv, char **envp)
+ {
+ printf("*%p*\\n", envp);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*(nil)*')
+
+ def test_funcs(self):
+ src = '''
+ #include <stdio.h>
+ int funcy(int x)
+ {
+ return x*9;
+ }
+ int main()
+ {
+ printf("*%d,%d*\\n", funcy(8), funcy(10));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*72,90*')
+
+ def test_structs(self):
+ src = '''
+ #include <stdio.h>
+ struct S
+ {
+ int x, y;
+ };
+ int main()
+ {
+ S a, b;
+ a.x = 5; a.y = 6;
+ b.x = 101; b.y = 7009;
+ S *c, *d;
+ c = &a;
+ c->x *= 2;
+ c = &b;
+ c->y -= 1;
+ d = c;
+ d->y += 10;
+ printf("*%d,%d,%d,%d,%d,%d,%d,%d*\\n", a.x, a.y, b.x, b.y, c->x, c->y, d->x, d->y);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*10,6,101,7018,101,7018,101,7018*')
+
+ gen_struct_src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include "emscripten.h"
+
+ struct S
+ {
+ int x, y;
+ };
+ int main()
+ {
+ S* a = {{gen_struct}};
+ a->x = 51; a->y = 62;
+ printf("*%d,%d*\\n", a->x, a->y);
+ {{del_struct}}(a);
+ return 0;
+ }
+ '''
+
+ def test_mallocstruct(self):
+ self.do_run(self.gen_struct_src.replace('{{gen_struct}}', '(S*)malloc(sizeof(S))').replace('{{del_struct}}', 'free'), '*51,62*')
+
+ def test_newstruct(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ self.do_run(self.gen_struct_src.replace('{{gen_struct}}', 'new S').replace('{{del_struct}}', 'delete'), '*51,62*')
+
+ def test_addr_of_stacked(self):
+ src = '''
+ #include <stdio.h>
+ void alter(int *y)
+ {
+ *y += 5;
+ }
+ int main()
+ {
+ int x = 2;
+ alter(&x);
+ printf("*%d*\\n", x);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*7*')
+
+ def test_globals(self):
+ src = '''
+ #include <stdio.h>
+
+ char cache[256], *next = cache;
+
+ int main()
+ {
+ cache[10] = 25;
+ next[20] = 51;
+ printf("*%d,%d*\\n", next[10], cache[20]);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*25,51*')
+
+ def test_linked_list(self):
+ src = '''
+ #include <stdio.h>
+ struct worker_args {
+ int value;
+ struct worker_args *next;
+ };
+ int main()
+ {
+ worker_args a;
+ worker_args b;
+ a.value = 60;
+ a.next = &b;
+ b.value = 900;
+ b.next = NULL;
+ worker_args* c = &a;
+ int total = 0;
+ while (c) {
+ total += c->value;
+ c = c->next;
+ }
+
+ // Chunk of em
+ worker_args chunk[10];
+ for (int i = 0; i < 9; i++) {
+ chunk[i].value = i*10;
+ chunk[i].next = &chunk[i+1];
+ }
+ chunk[9].value = 90;
+ chunk[9].next = &chunk[0];
+
+ c = chunk;
+ do {
+ total += c->value;
+ c = c->next;
+ } while (c != chunk);
+
+ printf("*%d,%d*\\n", total, b.next);
+ // NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*1410,0*')
+
+ def test_sup(self):
+ src = '''
+ #include <stdio.h>
+
+ struct S4 { int x; }; // size: 4
+ struct S4_2 { short x, y; }; // size: 4, but for alignment purposes, 2
+ struct S6 { short x, y, z; }; // size: 6
+ struct S6w { char x[6]; }; // size: 6 also
+ struct S6z { int x; short y; }; // size: 8, since we align to a multiple of the biggest - 4
+
+ struct C___ { S6 a, b, c; int later; };
+ struct Carr { S6 a[3]; int later; }; // essentially the same, but differently defined
+ struct C__w { S6 a; S6w b; S6 c; int later; }; // same size, different struct
+ struct Cp1_ { int pre; short a; S6 b, c; int later; }; // fillers for a
+ struct Cp2_ { int a; short pre; S6 b, c; int later; }; // fillers for a (get addr of the other filler)
+ struct Cint { S6 a; int b; S6 c; int later; }; // An int (different size) for b
+ struct C4__ { S6 a; S4 b; S6 c; int later; }; // Same size as int from before, but a struct
+ struct C4_2 { S6 a; S4_2 b; S6 c; int later; }; // Same size as int from before, but a struct with max element size 2
+ struct C__z { S6 a; S6z b; S6 c; int later; }; // different size, 8 instead of 6
+
+ int main()
+ {
+ #define TEST(struc) \\
+ { \\
+ struc *s = 0; \\
+ printf("*%s: %d,%d,%d,%d<%d*\\n", #struc, (int)&(s->a), (int)&(s->b), (int)&(s->c), (int)&(s->later), sizeof(struc)); \\
+ }
+ #define TEST_ARR(struc) \\
+ { \\
+ struc *s = 0; \\
+ printf("*%s: %d,%d,%d,%d<%d*\\n", #struc, (int)&(s->a[0]), (int)&(s->a[1]), (int)&(s->a[2]), (int)&(s->later), sizeof(struc)); \\
+ }
+ printf("sizeofs:%d,%d\\n", sizeof(S6), sizeof(S6z));
+ TEST(C___);
+ TEST_ARR(Carr);
+ TEST(C__w);
+ TEST(Cp1_);
+ TEST(Cp2_);
+ TEST(Cint);
+ TEST(C4__);
+ TEST(C4_2);
+ TEST(C__z);
+ return 0;
+ }
+ '''
+ if Settings.QUANTUM_SIZE == 1:
+ self.do_run(src, 'sizeofs:6,8\n*C___: 0,3,6,9<24*\n*Carr: 0,3,6,9<24*\n*C__w: 0,3,9,12<24*\n*Cp1_: 1,2,5,8<24*\n*Cp2_: 0,2,5,8<24*\n*Cint: 0,3,4,7<24*\n*C4__: 0,3,4,7<24*\n*C4_2: 0,3,5,8<20*\n*C__z: 0,3,5,8<28*')
+ else:
+ self.do_run(src, 'sizeofs:6,8\n*C___: 0,6,12,20<24*\n*Carr: 0,6,12,20<24*\n*C__w: 0,6,12,20<24*\n*Cp1_: 4,6,12,20<24*\n*Cp2_: 0,6,12,20<24*\n*Cint: 0,8,12,20<24*\n*C4__: 0,8,12,20<24*\n*C4_2: 0,6,10,16<20*\n*C__z: 0,8,16,24<28*')
+
+ def test_assert(self):
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+ int main() {
+ assert(1 == true); // pass
+ assert(1 == false); // fail
+ return 0;
+ }
+ '''
+ 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>
+ #include <setjmp.h>
+
+ static jmp_buf buf;
+
+ void second(void) {
+ printf("second\n");
+ longjmp(buf,-1);
+ }
+
+ void first(void) {
+ printf("first\n"); // prints
+ longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
+ }
+
+ int main() {
+ volatile int x = 0;
+ int jmpval = setjmp(buf);
+ if (!jmpval) {
+ x++; // should be properly restored once longjmp jumps back
+ first(); // when executed, setjmp returns 1
+ printf("skipped\n"); // does not print
+ } else if (jmpval == 1) { // when first() jumps back, setjmp returns 1
+ printf("result: %d %d\n", x, jmpval); // prints
+ x++;
+ second(); // when executed, setjmp returns -1
+ } else if (jmpval == -1) { // when second() jumps back, setjmp returns -1
+ printf("result: %d %d\n", x, jmpval); // prints
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'first\nresult: 1 1\nsecond\nresult: 2 -1')
+
+ def test_longjmp2(self):
+ src = r'''
+ #include <setjmp.h>
+ #include <stdio.h>
+
+ typedef struct {
+ jmp_buf* jmp;
+ } jmp_state;
+
+ void stack_manipulate_func(jmp_state* s, int level) {
+ jmp_buf buf;
+
+ printf("Entering stack_manipulate_func, level: %d\n", level);
+
+ if (level == 0) {
+ s->jmp = &buf;
+ if (setjmp(*(s->jmp)) == 0) {
+ printf("Setjmp normal execution path, level: %d\n", level);
+ stack_manipulate_func(s, level + 1);
+ } else {
+ printf("Setjmp error execution path, level: %d\n", level);
+ }
+ } else {
+ printf("Perform longjmp at level %d\n", level);
+ longjmp(*(s->jmp), 1);
+ }
+
+ printf("Exiting stack_manipulate_func, level: %d\n", level);
+ }
+
+ int main(int argc, char *argv[]) {
+ jmp_state s;
+ s.jmp = NULL;
+ stack_manipulate_func(&s, 0);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''Entering stack_manipulate_func, level: 0
+Setjmp normal execution path, level: 0
+Entering stack_manipulate_func, level: 1
+Perform longjmp at level 1
+Setjmp error execution path, level: 0
+Exiting stack_manipulate_func, level: 0
+''')
+
+ def test_longjmp3(self):
+ src = r'''
+ #include <setjmp.h>
+ #include <stdio.h>
+
+ typedef struct {
+ jmp_buf* jmp;
+ } jmp_state;
+
+ void setjmp_func(jmp_state* s, int level) {
+ jmp_buf* prev_jmp = s->jmp;
+ jmp_buf c_jmp;
+
+ if (level == 2) {
+ printf("level is 2, perform longjmp!\n");
+ longjmp(*(s->jmp), 1);
+ }
+
+ if (setjmp(c_jmp) == 0) {
+ printf("setjmp normal execution path, level: %d\n", level);
+ s->jmp = &c_jmp;
+ setjmp_func(s, level + 1);
+ } else {
+ printf("setjmp exception execution path, level: %d\n", level);
+ if (prev_jmp) {
+ printf("prev_jmp is not empty, continue with longjmp!\n");
+ s->jmp = prev_jmp;
+ longjmp(*(s->jmp), 1);
+ }
+ }
+
+ printf("Exiting setjmp function, level: %d\n", level);
+ }
+
+ int main(int argc, char *argv[]) {
+ jmp_state s;
+ s.jmp = NULL;
+
+ setjmp_func(&s, 0);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''setjmp normal execution path, level: 0
+setjmp normal execution path, level: 1
+level is 2, perform longjmp!
+setjmp exception execution path, level: 1
+prev_jmp is not empty, continue with longjmp!
+setjmp exception execution path, level: 0
+Exiting setjmp function, level: 0
+''')
+
+ def test_longjmp4(self):
+ src = r'''
+ #include <setjmp.h>
+ #include <stdio.h>
+
+ typedef struct {
+ jmp_buf* jmp;
+ } jmp_state;
+
+ void second_func(jmp_state* s);
+
+ void first_func(jmp_state* s) {
+ jmp_buf* prev_jmp = s->jmp;
+ jmp_buf c_jmp;
+ volatile int once = 0;
+
+ if (setjmp(c_jmp) == 0) {
+ printf("Normal execution path of first function!\n");
+
+ s->jmp = &c_jmp;
+ second_func(s);
+ } else {
+ printf("Exception execution path of first function! %d\n", once);
+
+ if (!once) {
+ printf("Calling longjmp the second time!\n");
+ once = 1;
+ longjmp(*(s->jmp), 1);
+ }
+ }
+ }
+
+ void second_func(jmp_state* s) {
+ longjmp(*(s->jmp), 1);
+ }
+
+ int main(int argc, char *argv[]) {
+ jmp_state s;
+ s.jmp = NULL;
+
+ first_func(&s);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''Normal execution path of first function!
+Exception execution path of first function! 0
+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_longjmp_exc(self):
+ src = r'''
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <setjmp.h>
+ #include <emscripten.h>
+
+ jmp_buf abortframe;
+
+ void dostuff(int a) {
+ printf("pre\n");
+ if (a != 42) emscripten_run_script("waka_waka()"); // this should fail, and never reach "never"
+ printf("never\n");
+
+ if (a == 100) {
+ longjmp (abortframe, -1);
+ }
+
+ if (setjmp(abortframe)) {
+ printf("got 100");
+ }
+ }
+
+ int main(int argc, char **argv) {
+ dostuff(argc);
+ exit(1);
+ return 1;
+ }
+ '''
+ self.do_run(src, 'waka_waka');
+
+ 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')
+
+ Settings.EXCEPTION_DEBUG = 1
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ if '-O2' in self.emcc_args:
+ self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
+
+ src = '''
+ #include <stdio.h>
+ void thrower() {
+ printf("infunc...");
+ throw(99);
+ printf("FAIL");
+ }
+ int main() {
+ try {
+ printf("*throw...");
+ throw(1);
+ printf("FAIL");
+ } catch(...) {
+ printf("caught!");
+ }
+ try {
+ thrower();
+ } catch(...) {
+ printf("done!*\\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, '*throw...caught!infunc...done!*')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
+ self.do_run(src, 'Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0')
+
+ src = '''
+ #include <iostream>
+
+ class MyException
+ {
+ public:
+ MyException(){ std::cout << "Construct..."; }
+ MyException( const MyException & ) { std::cout << "Copy..."; }
+ ~MyException(){ std::cout << "Destruct..."; }
+ };
+
+ int function()
+ {
+ std::cout << "Throw...";
+ throw MyException();
+ }
+
+ int function2()
+ {
+ return function();
+ }
+
+ int main()
+ {
+ try
+ {
+ function2();
+ }
+ catch (MyException & e)
+ {
+ std::cout << "Catched...";
+ }
+
+ try
+ {
+ function2();
+ }
+ catch (MyException e)
+ {
+ std::cout << "Catched...";
+ }
+
+ return 0;
+ }
+ '''
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ if '-O2' in self.emcc_args:
+ self.emcc_args.pop() ; self.emcc_args.pop() # disable closure to work around a closure bug
+ self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...')
+
+ def test_exception_2(self):
+ if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ src = r'''
+ #include <stdexcept>
+ #include <stdio.h>
+
+ typedef void (*FuncPtr)();
+
+ void ThrowException()
+ {
+ throw std::runtime_error("catch me!");
+ }
+
+ FuncPtr ptr = ThrowException;
+
+ int main()
+ {
+ try
+ {
+ ptr();
+ }
+ catch(...)
+ {
+ printf("Exception caught successfully!\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, 'Exception caught successfully!')
+
+ def test_white_list_exception(self):
+ Settings.DISABLE_EXCEPTION_CATCHING = 2
+ Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
+ Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified
+
+ src = '''
+ #include <stdio.h>
+
+ void thrower() {
+ printf("infunc...");
+ throw(99);
+ printf("FAIL");
+ }
+
+ void somefunction() {
+ try {
+ thrower();
+ } catch(...) {
+ printf("done!*\\n");
+ }
+ }
+
+ int main() {
+ somefunction();
+ return 0;
+ }
+ '''
+ self.do_run(src, 'infunc...done!*')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ Settings.EXCEPTION_CATCHING_WHITELIST = []
+
+ def test_uncaught_exception(self):
+ if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+
+ src = r'''
+ #include <stdio.h>
+ #include <exception>
+ struct X {
+ ~X() {
+ printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
+ }
+ };
+ int main() {
+ printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
+ try {
+ X x;
+ throw 1;
+ } catch(...) {
+ printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
+ }
+ printf("exception? %s\n", std::uncaught_exception() ? "yes" : "no");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'exception? no\nexception? yes\nexception? no\nexception? no\n')
+
+ src = r'''
+ #include <fstream>
+ #include <iostream>
+ int main() {
+ std::ofstream os("test");
+ os << std::unitbuf << "foo"; // trigger a call to std::uncaught_exception from
+ // std::basic_ostream::sentry::~sentry
+ std::cout << "success";
+ }
+ '''
+ self.do_run(src, 'success')
+
+ def test_typed_exceptions(self):
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
+ src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read()
+ expected = open(path_from_root('tests', 'exceptions', 'output.txt'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_multiexception(self):
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ src = r'''
+#include <stdio.h>
+
+static int current_exception_id = 0;
+
+typedef struct {
+int jmp;
+} jmp_state;
+
+void setjmp_func(jmp_state* s, int level) {
+int prev_jmp = s->jmp;
+int c_jmp;
+
+if (level == 2) {
+ printf("level is 2, perform longjmp!\n");
+ throw 1;
+}
+
+c_jmp = current_exception_id++;
+try {
+ printf("setjmp normal execution path, level: %d, prev_jmp: %d\n", level, prev_jmp);
+ s->jmp = c_jmp;
+ setjmp_func(s, level + 1);
+} catch (int catched_eid) {
+ printf("caught %d\n", catched_eid);
+ if (catched_eid == c_jmp) {
+ printf("setjmp exception execution path, level: %d, prev_jmp: %d\n", level, prev_jmp);
+ if (prev_jmp != -1) {
+ printf("prev_jmp is not empty, continue with longjmp!\n");
+ s->jmp = prev_jmp;
+ throw s->jmp;
+ }
+ } else {
+ throw;
+ }
+}
+
+printf("Exiting setjmp function, level: %d, prev_jmp: %d\n", level, prev_jmp);
+}
+
+int main(int argc, char *argv[]) {
+jmp_state s;
+s.jmp = -1;
+
+setjmp_func(&s, 0);
+
+return 0;
+}
+'''
+ self.do_run(src, '''setjmp normal execution path, level: 0, prev_jmp: -1
+setjmp normal execution path, level: 1, prev_jmp: 0
+level is 2, perform longjmp!
+caught 1
+setjmp exception execution path, level: 1, prev_jmp: 0
+prev_jmp is not empty, continue with longjmp!
+caught 0
+setjmp exception execution path, level: 0, prev_jmp: -1
+Exiting setjmp function, level: 0, prev_jmp: -1
+''')
+
+ def test_std_exception(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ self.emcc_args += ['-s', 'SAFE_HEAP=0']
+
+ src = r'''
+ #include <stdio.h>
+ #include <exception>
+
+ int main()
+ {
+ std::exception e;
+ try {
+ throw e;
+ } catch(std::exception e) {
+ printf("caught std::exception\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, 'caught std::exception')
+
+ def test_async_exit(self):
+ open('main.c', 'w').write(r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include "emscripten.h"
+
+ void main_loop() {
+ exit(EXIT_SUCCESS);
+ }
+
+ int main() {
+ emscripten_set_main_loop(main_loop, 60, 0);
+ return 0;
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, 'main.c']).communicate()
+ self.assertNotContained('Reached an unreachable!', run_js(self.in_dir('a.out.js'), stderr=STDOUT))
+
+ def test_exit_stack(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.ASM_JS: return self.skip('uses report_stack without exporting')
+
+ Settings.INLINING_LIMIT = 50
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ extern "C" {
+ extern void report_stack(int x);
+ }
+
+ char moar() {
+ char temp[125];
+ for (int i = 0; i < 125; i++) temp[i] = i*i;
+ for (int i = 1; i < 125; i++) temp[i] += temp[i-1]/2;
+ if (temp[100] != 99) exit(1);
+ return temp[120];
+ }
+
+ int main(int argc, char *argv[]) {
+ report_stack((int)alloca(4));
+ printf("*%d*\n", moar());
+ return 0;
+ }
+ '''
+
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ var initialStack = -1;
+ var _report_stack = function(x) {
+ Module.print('reported');
+ initialStack = x;
+ }
+ var Module = {
+ postRun: function() {
+ Module.print('Exit Status: ' + EXITSTATUS);
+ Module.print('postRun');
+ assert(initialStack == STACKTOP, [initialStack, STACKTOP]);
+ Module.print('ok.');
+ }
+ };
+ ''')
+
+ self.emcc_args += ['--pre-js', 'pre.js']
+ self.do_run(src, '''reported\nexit(1) called\nExit Status: 1\npostRun\nok.\n''')
+
+ def test_class(self):
+ src = '''
+ #include <stdio.h>
+ struct Random {
+ enum { IM = 139968, IA = 3877, IC = 29573 };
+ Random() : last(42) {}
+ float get( float max = 1.0f ) {
+ last = ( last * IA + IC ) % IM;
+ return max * last / IM;
+ }
+ protected:
+ unsigned int last;
+ } rng1;
+ int main()
+ {
+ Random rng2;
+ int count = 0;
+ for (int i = 0; i < 100; i++) {
+ float x1 = rng1.get();
+ float x2 = rng2.get();
+ printf("%f, %f\\n", x1, x2);
+ if (x1 != x2) count += 1;
+ }
+ printf("*%d*\\n", count);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0*')
+
+ def test_inherit(self):
+ src = '''
+ #include <stdio.h>
+ struct Parent {
+ int x1, x2;
+ };
+ struct Child : Parent {
+ int y;
+ };
+ int main()
+ {
+ Parent a;
+ a.x1 = 50;
+ a.x2 = 87;
+ Child b;
+ b.x1 = 78;
+ b.x2 = 550;
+ b.y = 101;
+ Child* c = (Child*)&a;
+ c->x1 ++;
+ c = &b;
+ c->y --;
+ printf("*%d,%d,%d,%d,%d,%d,%d*\\n", a.x1, a.x2, b.x1, b.x2, b.y, c->x1, c->x2);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*51,87,78,550,100,78,550*')
+
+ def test_isdigit_l(self):
+ if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
+
+ src = '''
+ #include <iostream>
+ int main() {
+ using namespace std;
+ use_facet<num_put<char> >(cout.getloc()).put(cout, cout, '0', 3.14159265);
+ }
+ '''
+ self.do_run(src, '3.14159')
+
+ def test_polymorph(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = '''
+ #include <stdio.h>
+ struct Pure {
+ virtual int implme() = 0;
+ };
+ struct Parent : Pure {
+ virtual int getit() { return 11; };
+ int implme() { return 32; }
+ };
+ struct Child : Parent {
+ int getit() { return 74; }
+ int implme() { return 1012; }
+ };
+
+ struct Other {
+ int one() { return 11; }
+ int two() { return 22; }
+ };
+
+ int main()
+ {
+ Parent *x = new Parent();
+ Parent *y = new Child();
+ printf("*%d,%d,%d,%d*\\n", x->getit(), y->getit(), x->implme(), y->implme());
+
+ Other *o = new Other;
+ int (Other::*Ls)() = &Other::one;
+ printf("*%d*\\n", (o->*(Ls))());
+ Ls = &Other::two;
+ printf("*%d*\\n", (o->*(Ls))());
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*11,74,32,1012*\n*11*\n*22*')
+
+ def test_segfault(self):
+ if self.emcc_args is None: return self.skip('SAFE_HEAP without ta2 means we check types too, which hide segfaults')
+ if Settings.ASM_JS: return self.skip('asm does not support safe heap')
+
+ Settings.SAFE_HEAP = 1
+
+ for addr in ['0', 'new D2()']:
+ print addr
+ src = r'''
+ #include <stdio.h>
+
+ struct Classey {
+ virtual void doIt() = 0;
+ };
+
+ struct D1 : Classey {
+ virtual void doIt() { printf("fleefl\n"); }
+ };
+
+ struct D2 : Classey {
+ virtual void doIt() { printf("marfoosh\n"); }
+ };
+
+ int main(int argc, char **argv)
+ {
+ Classey *p = argc == 100 ? new D1() : (Classey*)%s;
+
+ p->doIt();
+
+ return 0;
+ }
+ ''' % addr
+ self.do_run(src, 'segmentation fault' if addr.isdigit() else 'marfoosh')
+
+ def test_safe_dyncalls(self):
+ if Settings.ASM_JS: return self.skip('asm does not support missing function stack traces')
+ if Settings.SAFE_HEAP: return self.skip('safe heap warning will appear instead')
+ if self.emcc_args is None: return self.skip('need libc')
+
+ Settings.SAFE_DYNCALLS = 1
+
+ for cond, body, work in [(True, True, False), (True, False, False), (False, True, True), (False, False, False)]:
+ print cond, body, work
+ src = r'''
+ #include <stdio.h>
+
+ struct Classey {
+ virtual void doIt() = 0;
+ };
+
+ struct D1 : Classey {
+ virtual void doIt() BODY;
+ };
+
+ int main(int argc, char **argv)
+ {
+ Classey *p = argc COND 100 ? new D1() : NULL;
+ printf("%p\n", p);
+ p->doIt();
+
+ return 0;
+ }
+ '''.replace('COND', '==' if cond else '!=').replace('BODY', r'{ printf("all good\n"); }' if body else '')
+ self.do_run(src, 'dyncall error: vi' if not work else 'all good')
+
+ def test_dynamic_cast(self):
+ if self.emcc_args is None: return self.skip('need libcxxabi')
+
+ src = r'''
+ #include <stdio.h>
+
+ struct Support {
+ virtual void f() {
+ printf("f()\n");
+ }
+ };
+
+ struct Derived : Support {
+ };
+
+ int main() {
+ Support * p = new Derived;
+ dynamic_cast<Derived*>(p)->f();
+ }
+ '''
+ self.do_run(src, 'f()\n')
+
+ def test_dynamic_cast_b(self):
+ if self.emcc_args is None: return self.skip('need libcxxabi')
+
+ src = '''
+ #include <stdio.h>
+
+ class CBase { virtual void dummy() {} };
+ class CDerived : public CBase { int a; };
+ class CDerivedest : public CDerived { float b; };
+
+ int main ()
+ {
+ CBase *pa = new CBase;
+ CBase *pb = new CDerived;
+ CBase *pc = new CDerivedest;
+
+ printf("a1: %d\\n", dynamic_cast<CDerivedest*>(pa) != NULL);
+ printf("a2: %d\\n", dynamic_cast<CDerived*>(pa) != NULL);
+ printf("a3: %d\\n", dynamic_cast<CBase*>(pa) != NULL);
+
+ printf("b1: %d\\n", dynamic_cast<CDerivedest*>(pb) != NULL);
+ printf("b2: %d\\n", dynamic_cast<CDerived*>(pb) != NULL);
+ printf("b3: %d\\n", dynamic_cast<CBase*>(pb) != NULL);
+
+ printf("c1: %d\\n", dynamic_cast<CDerivedest*>(pc) != NULL);
+ printf("c2: %d\\n", dynamic_cast<CDerived*>(pc) != NULL);
+ printf("c3: %d\\n", dynamic_cast<CBase*>(pc) != NULL);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'a1: 0\na2: 0\na3: 1\nb1: 0\nb2: 1\nb3: 1\nc1: 1\nc2: 1\nc3: 1\n')
+
+ def test_dynamic_cast_2(self):
+ if self.emcc_args is None: return self.skip('need libcxxabi')
+
+ src = r'''
+ #include <stdio.h>
+ #include <typeinfo>
+
+ class Class {};
+
+ int main() {
+ const Class* dp = dynamic_cast<const Class*>(&typeid(Class));
+ // should return dp == NULL,
+ printf("pointer: %p\n", dp);
+ }
+ '''
+ self.do_run(src, "pointer: (nil)")
+
+ def test_funcptr(self):
+ src = '''
+ #include <stdio.h>
+ int calc1() { return 26; }
+ int calc2() { return 90; }
+ typedef int (*fp_t)();
+
+ fp_t globally1 = calc1;
+ fp_t globally2 = calc2;
+
+ int nothing(const char *str) { return 0; }
+
+ int main()
+ {
+ fp_t fp = calc1;
+ void *vp = (void*)fp;
+ fp_t fpb = (fp_t)vp;
+ fp_t fp2 = calc2;
+ void *vp2 = (void*)fp2;
+ fp_t fpb2 = (fp_t)vp2;
+ printf("*%d,%d,%d,%d,%d,%d*\\n", fp(), fpb(), fp2(), fpb2(), globally1(), globally2());
+
+ fp_t t = calc1;
+ printf("*%d,%d", t == calc1, t == calc2);
+ t = calc2;
+ printf(",%d,%d*\\n", t == calc1, t == calc2);
+
+ int (*other)(const char *str);
+ other = nothing;
+ other("*hello!*");
+ other = puts;
+ other("*goodbye!*");
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*26,26,90,90,26,90*\n*1,0,0,1*\n*goodbye!*')
+
+ def test_mathfuncptr(self):
+ src = '''
+ #include <math.h>
+ #include <stdio.h>
+
+ int
+ main(int argc, char **argv) {
+ float (*fn)(float) = argc != 12 ? &sqrtf : &fabsf;
+ float (*fn2)(float) = argc != 13 ? &fabsf : &sqrtf;
+ float (*fn3)(float) = argc != 14 ? &erff : &fabsf;
+ printf("fn2(-5) = %d, fn(10) = %.2f, erf(10) = %.2f\\n", (int)fn2(-5), fn(10), fn3(10));
+ return 0;
+ }
+ '''
+ self.do_run(src, 'fn2(-5) = 5, fn(10) = 3.16, erf(10) = 1.00')
+
+ def test_funcptrfunc(self):
+ src = r'''
+ #include <stdio.h>
+
+ typedef void (*funcptr)(int, int);
+ typedef funcptr (*funcptrfunc)(int);
+
+ funcptr __attribute__ ((noinline)) getIt(int x) {
+ return (funcptr)x;
+ }
+
+ int main(int argc, char **argv)
+ {
+ funcptrfunc fpf = argc < 100 ? getIt : NULL;
+ printf("*%p*\n", fpf(argc));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0x1*')
+
+ def test_funcptr_namecollide(self):
+ src = r'''
+ #include <stdio.h>
+
+ void do_call(void (*puts)(const char *), const char *str);
+
+ void do_print(const char *str) {
+ if (!str) do_call(NULL, "delusion");
+ if ((int)str == -1) do_print(str+10);
+ puts("====");
+ puts(str);
+ puts("====");
+ }
+
+ void do_call(void (*puts)(const char *), const char *str) {
+ if (!str) do_print("confusion");
+ if ((int)str == -1) do_call(NULL, str-10);
+ (*puts)(str);
+ }
+
+ int main(int argc, char **argv)
+ {
+ for (int i = 0; i < argc; i++) {
+ do_call(i != 10 ? do_print : NULL, i != 15 ? "waka waka" : NULL);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, 'waka', force_c=True)
+
+ def test_emptyclass(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = '''
+ #include <stdio.h>
+
+ struct Randomized {
+ Randomized(int x) {
+ printf("*zzcheezzz*\\n");
+ }
+ };
+
+ int main( int argc, const char *argv[] ) {
+ new Randomized(55);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*zzcheezzz*')
+
+ def test_alloca(self):
+ src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ char *pc;
+ pc = (char *)alloca(5);
+ printf("z:%d*%d*\\n", pc > 0, (int)pc);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'z:1*', force_c=True)
+
+ def test_rename(self):
+ src = open(path_from_root('tests', 'stdio', 'test_rename.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_alloca_stack(self):
+ if self.emcc_args is None: return # too slow in other modes
+
+ # We should not blow up the stack with numerous allocas
+ src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ func(int i) {
+ char *pc = (char *)alloca(100);
+ *pc = i;
+ (*pc)++;
+ return (*pc) % 10;
+ }
+ int main() {
+ int total = 0;
+ for (int i = 0; i < 1024*1024; i++)
+ total += func(i);
+ printf("ok:%d*\\n", total);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'ok:-32768*', force_c=True)
+
+ def test_stack_byval(self):
+ if self.emcc_args is None: return # too slow in other modes
+
+ # We should also not blow up the stack with byval arguments
+ src = r'''
+ #include<stdio.h>
+ struct vec {
+ int x, y, z;
+ vec(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {}
+ static vec add(vec a, vec b) {
+ return vec(a.x+b.x, a.y+b.y, a.z+b.z);
+ }
+ };
+ int main() {
+ int total = 0;
+ for (int i = 0; i < 1000; i++) {
+ for (int j = 0; j < 1000; j++) {
+ vec c(i+i%10, j*2, i%255);
+ vec d(j*2, j%255, i%120);
+ vec f = vec::add(c, d);
+ total += (f.x + f.y + f.z) % 100;
+ total %= 10240;
+ }
+ }
+ printf("sum:%d*\n", total);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'sum:9780*')
+
+ def test_stack_varargs(self):
+ if self.emcc_args is None: return # too slow in other modes
+
+ Settings.INLINING_LIMIT = 50
+
+ # We should not blow up the stack with numerous varargs
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ void func(int i) {
+ printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
+ }
+ int main() {
+ for (int i = 0; i < 1024; i++)
+ func(i);
+ printf("ok!\n");
+ return 0;
+ }
+ '''
+ Settings.TOTAL_STACK = 1024
+ self.do_run(src, 'ok!')
+
+ def test_stack_varargs2(self):
+ if self.emcc_args is None: return # too slow in other modes
+ Settings.TOTAL_STACK = 1024
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ void func(int i) {
+ }
+ int main() {
+ for (int i = 0; i < 1024; i++) {
+ printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
+ }
+ printf("ok!\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'ok!')
+
+ print 'with return'
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ for (int i = 0; i < 1024; i++) {
+ int j = printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
+ printf(" (%d)\n", j);
+ }
+ printf("ok!\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'ok!')
+
+ print 'with definitely no return'
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
+
+ void vary(const char *s, ...)
+ {
+ va_list v;
+ va_start(v, s);
+ char d[20];
+ vsnprintf(d, 20, s, v);
+ puts(d);
+
+ // Try it with copying
+ va_list tempva;
+ va_copy(tempva, v);
+ vsnprintf(d, 20, s, tempva);
+ puts(d);
+
+ va_end(v);
+ }
+
+ int main() {
+ for (int i = 0; i < 1024; i++) {
+ int j = printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
+ printf(" (%d)\n", j);
+ vary("*cheez: %d+%d*", 99, 24);
+ vary("*albeit*");
+ }
+ printf("ok!\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'ok!')
+
+ def test_stack_void(self):
+ Settings.INLINING_LIMIT = 50
+
+ src = r'''
+ #include <stdio.h>
+
+ static char s[100]="aaaaa";
+ static int func(void) {
+ if(s[0]!='a') return 0;
+ printf("iso open %s\n", s, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001);
+ return 0;
+ }
+ int main(){
+ int i;
+ for(i=0;i<5000;i++)
+ func();
+ printf(".ok.\n");
+ }
+ '''
+ self.do_run(src, '.ok.\n')
+
+ def test_life(self):
+ if self.emcc_args is None: return self.skip('need c99')
+ self.emcc_args += ['-std=c99']
+ src = open(path_from_root('tests', 'life.c'), 'r').read()
+ self.do_run(src, '''--------------------------------
+[] [] [][][]
+ [] [] [] [][] [] [] []
+[] [][] [][] [][][] []
+ [] [] [] [] [][] [] []
+ [] [][] [] [] [] [] [][][][]
+ [][] [][] [] [][][] [] []
+ [] [][] [][] [][] [][][]
+ [][] [][][] [] []
+ [][] [][] []
+ [][][]
+ []
+
+
+
+
+ [][][]
+ [] [][] [][]
+ [][] [] [][] [][]
+ [][] [][]
+ []
+ [][]
+ [][] []
+[] [][] []
+ [][][] []
+ [] [][]
+[] [] []
+ []
+[] [] []
+ [][][]
+
+ []
+ [][][] []
+--------------------------------
+''', ['2'], force_c=True)
+
+ def test_array2(self):
+ src = '''
+ #include <stdio.h>
+
+ static const double grid[4][2] = {
+ {-3/3.,-1/3.},{+1/3.,-3/3.},
+ {-1/3.,+3/3.},{+3/3.,+1/3.}
+ };
+
+ int main() {
+ for (int i = 0; i < 4; i++)
+ printf("%d:%.2f,%.2f ", i, grid[i][0], grid[i][1]);
+ printf("\\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, '0:-1.00,-0.33 1:0.33,-1.00 2:-0.33,1.00 3:1.00,0.33')
+
+ def test_array2b(self):
+ src = '''
+ #include <stdio.h>
+
+ static const struct {
+ unsigned char left;
+ unsigned char right;
+ } prioritah[] = {
+ {6, 6}, {6, 6}, {7, 95}, {7, 7}
+ };
+
+ int main() {
+ printf("*%d,%d\\n", prioritah[1].left, prioritah[1].right);
+ printf("%d,%d*\\n", prioritah[2].left, prioritah[2].right);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*6,6\n7,95*')
+
+
+ def test_constglobalstructs(self):
+ src = '''
+ #include <stdio.h>
+ struct IUB {
+ int c;
+ double p;
+ unsigned int pi;
+ };
+
+ IUB iub[] = {
+ { 'a', 0.27, 5 },
+ { 'c', 0.15, 4 },
+ { 'g', 0.12, 3 },
+ { 't', 0.27, 2 },
+ };
+
+ const unsigned char faceedgesidx[6][4] =
+ {
+ { 4, 5, 8, 10 },
+ { 6, 7, 9, 11 },
+ { 0, 2, 8, 9 },
+ { 1, 3, 10,11 },
+ { 0, 1, 4, 6 },
+ { 2, 3, 5, 7 },
+ };
+
+ int main( int argc, const char *argv[] ) {
+ printf("*%d,%d,%d,%d*\\n", iub[0].c, int(iub[1].p*100), iub[2].pi, faceedgesidx[3][2]);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*97,15,3,10*')
+
+ def test_conststructs(self):
+ src = '''
+ #include <stdio.h>
+ struct IUB {
+ int c;
+ double p;
+ unsigned int pi;
+ };
+
+ int main( int argc, const char *argv[] ) {
+ int before = 70;
+ IUB iub[] = {
+ { 'a', 0.3029549426680, 5 },
+ { 'c', 0.15, 4 },
+ { 'g', 0.12, 3 },
+ { 't', 0.27, 2 },
+ };
+ int after = 90;
+ printf("*%d,%d,%d,%d,%d,%d*\\n", before, iub[0].c, int(iub[1].p*100), iub[2].pi, int(iub[0].p*10000), after);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*70,97,15,3,3029,90*')
+
+ def test_bigarray(self):
+ if self.emcc_args is None: return self.skip('need ta2 to compress type data on zeroinitializers')
+
+ # avoid "array initializer too large" errors
+ src = r'''
+ #include <stdio.h>
+ #include <assert.h>
+
+ #define SIZE (1024*100)
+ struct Struct {
+ char x;
+ int y;
+ };
+ Struct buffy[SIZE];
+
+ int main() {
+ for (int i = 0; i < SIZE; i++) { assert(buffy[i].x == 0 && buffy[i].y == 0); } // we were zeroinitialized
+ for (int i = 0; i < SIZE; i++) { buffy[i].x = i*i; buffy[i].y = i*i*i; } // we can save data
+ printf("*%d*\n", buffy[SIZE/3].x);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*57*')
+
+ def test_mod_globalstruct(self):
+ src = '''
+ #include <stdio.h>
+
+ struct malloc_params {
+ size_t magic, page_size;
+ };
+
+ malloc_params mparams;
+
+ #define SIZE_T_ONE ((size_t)1)
+ #define page_align(S) (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
+
+ int main()
+ {
+ mparams.page_size = 4096;
+ printf("*%d,%d,%d,%d*\\n", mparams.page_size, page_align(1000), page_align(6000), page_align(66474));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*4096,4096,8192,69632*')
+
+ def test_pystruct(self):
+ src = '''
+ #include <stdio.h>
+
+ // Based on CPython code
+ union PyGC_Head {
+ struct {
+ union PyGC_Head *gc_next;
+ union PyGC_Head *gc_prev;
+ size_t gc_refs;
+ } gc;
+ long double dummy; /* force worst-case alignment */
+ } ;
+
+ struct gc_generation {
+ PyGC_Head head;
+ int threshold; /* collection threshold */
+ int count; /* count of allocations or collections of younger
+ generations */
+ };
+
+ #define NUM_GENERATIONS 3
+ #define GEN_HEAD(n) (&generations[n].head)
+
+ /* linked lists of container objects */
+ static struct gc_generation generations[NUM_GENERATIONS] = {
+ /* PyGC_Head, threshold, count */
+ {{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0},
+ {{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0},
+ {{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0},
+ };
+
+ int main()
+ {
+ gc_generation *n = NULL;
+ printf("*%d,%d,%d,%d,%d,%d,%d,%d*\\n",
+ (int)(&n[0]),
+ (int)(&n[0].head),
+ (int)(&n[0].head.gc.gc_next),
+ (int)(&n[0].head.gc.gc_prev),
+ (int)(&n[0].head.gc.gc_refs),
+ (int)(&n[0].threshold), (int)(&n[0].count), (int)(&n[1])
+ );
+ printf("*%d,%d,%d*\\n",
+ (int)(&generations[0]) ==
+ (int)(&generations[0].head.gc.gc_next),
+ (int)(&generations[0]) ==
+ (int)(&generations[0].head.gc.gc_prev),
+ (int)(&generations[0]) ==
+ (int)(&generations[1])
+ );
+ int x1 = (int)(&generations[0]);
+ int x2 = (int)(&generations[1]);
+ printf("*%d*\\n", x1 == x2);
+ for (int i = 0; i < NUM_GENERATIONS; i++) {
+ PyGC_Head *list = GEN_HEAD(i);
+ printf("%d:%d,%d\\n", i, (int)list == (int)(list->gc.gc_prev), (int)list ==(int)(list->gc.gc_next));
+ }
+ printf("*%d,%d,%d*\\n", sizeof(PyGC_Head), sizeof(gc_generation), int(GEN_HEAD(2)) - int(GEN_HEAD(1)));
+ }
+ '''
+ if Settings.QUANTUM_SIZE == 1:
+ # Compressed memory. Note that sizeof() does give the fat sizes, however!
+ self.do_run(src, '*0,0,0,1,2,3,4,5*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,5*')
+ else:
+ if self.is_le32():
+ self.do_run(src, '*0,0,0,4,8,16,20,24*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*16,24,24*')
+ else:
+ self.do_run(src, '*0,0,0,4,8,12,16,20*\n*1,0,0*\n*0*\n0:1,1\n1:1,1\n2:1,1\n*12,20,20*')
+
+ def test_ptrtoint(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = '''
+ #include <stdio.h>
+
+ int main( int argc, const char *argv[] ) {
+ char *a = new char[10];
+ char *a0 = a+0;
+ char *a5 = a+5;
+ int *b = new int[10];
+ int *b0 = b+0;
+ int *b5 = b+5;
+ int c = (int)b5-(int)b0; // Emscripten should warn!
+ int d = (int)b5-(int)b0; // Emscripten should warn!
+ printf("*%d*\\n", (int)a5-(int)a0);
+ return 0;
+ }
+ '''
+ runner = self
+ def check_warnings(output):
+ runner.assertEquals(filter(lambda line: 'Warning' in line, output.split('\n')).__len__(), 4)
+ self.do_run(src, '*5*', output_processor=check_warnings)
+
+ def test_sizeof(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ # Has invalid writes between printouts
+ Settings.SAFE_HEAP = 0
+
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ #include "emscripten.h"
+
+ struct A { int x, y; };
+
+ int main( int argc, const char *argv[] ) {
+ int *a = new int[10];
+ int *b = new int[1];
+ int *c = new int[10];
+ for (int i = 0; i < 10; i++)
+ a[i] = 2;
+ *b = 5;
+ for (int i = 0; i < 10; i++)
+ c[i] = 8;
+ printf("*%d,%d,%d,%d,%d*\\n", a[0], a[9], *b, c[0], c[9]);
+ // Should overwrite a, but not touch b!
+ memcpy(a, c, 10*sizeof(int));
+ printf("*%d,%d,%d,%d,%d*\\n", a[0], a[9], *b, c[0], c[9]);
+
+ // Part 2
+ A as[3] = { { 5, 12 }, { 6, 990 }, { 7, 2 } };
+ memcpy(&as[0], &as[2], sizeof(A));
+
+ printf("*%d,%d,%d,%d,%d,%d*\\n", as[0].x, as[0].y, as[1].x, as[1].y, as[2].x, as[2].y);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*2,2,5,8,8***8,8,5,8,8***7,2,6,990,7,2*', [], lambda x, err: x.replace('\n', '*'))
+
+ def test_float_h(self):
+ process = Popen([PYTHON, EMCC, path_from_root('tests', 'float+.c')], stdout=PIPE, stderr=PIPE)
+ process.communicate()
+ assert process.returncode is 0, 'float.h should agree with our system'
+
+ def test_emscripten_api(self):
+ #if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME')
+
+ src = r'''
+ #include <stdio.h>
+ #include "emscripten.h"
+
+ extern "C" {
+ void save_me_aimee() { printf("mann\n"); }
+ }
+
+ int main() {
+ // EMSCRIPTEN_COMMENT("hello from the source");
+ emscripten_run_script("Module.print('hello world' + '!')");
+ printf("*%d*\n", emscripten_run_script_int("5*20"));
+ printf("*%s*\n", emscripten_run_script_string("'five'+'six'"));
+ emscripten_run_script("Module['_save_me_aimee']()");
+ return 0;
+ }
+ '''
+
+ check = '''
+def process(filename):
+ src = open(filename, 'r').read()
+ # TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src
+'''
+ Settings.EXPORTED_FUNCTIONS = ['_main', '_save_me_aimee']
+ self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
+
+ # test EXPORT_ALL
+ Settings.EXPORTED_FUNCTIONS = []
+ Settings.EXPORT_ALL = 1
+ self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
+
+ def test_inlinejs(self):
+ if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
+ src = r'''
+ #include <stdio.h>
+
+ double get() {
+ double ret = 0;
+ __asm __volatile__("Math.abs(-12/3.3)":"=r"(ret)); // write to a variable
+ return ret;
+ }
+
+ int main() {
+ asm("Module.print('Inline JS is very cool')");
+ printf("%.2f\n", get());
+ return 0;
+ }
+ '''
+
+ self.do_run(src, 'Inline JS is very cool\n3.64')
+
+ def test_inlinejs2(self):
+ if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
+ src = r'''
+ #include <stdio.h>
+
+ int mix(int x, int y) {
+ int ret;
+ asm("Math.pow(2, %0+%1+1)" : "=r"(ret) : "r"(x), "r"(y)); // read and write
+ return ret;
+ }
+
+ void mult() {
+ asm("var $_$1 = Math.abs(-100); $_$1 *= 2;"); // multiline
+ asm __volatile__("Module.print($_$1); Module.print('\n')");
+ }
+
+ int main(int argc, char **argv) {
+ printf("%d\n", mix(argc, argc/2));
+ mult();
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '4\n200\n')
+
+ def test_memorygrowth(self):
+ if Settings.USE_TYPED_ARRAYS == 0: return self.skip('memory growth is only supported with typed arrays')
+ if Settings.ASM_JS: return self.skip('asm does not support memory growth yet')
+
+ # With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY,
+ # since we then need to enlarge the heap(s).
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <assert.h>
+ #include "emscripten.h"
+
+ int main(int argc, char **argv)
+ {
+ char *buf1 = (char*)malloc(100);
+ char *data1 = "hello";
+ memcpy(buf1, data1, strlen(data1)+1);
+
+ float *buf2 = (float*)malloc(100);
+ float pie = 4.955;
+ memcpy(buf2, &pie, sizeof(float));
+
+ printf("*pre: %s,%.3f*\n", buf1, buf2[0]);
+
+ int totalMemory = emscripten_run_script_int("TOTAL_MEMORY");
+ char *buf3 = (char*)malloc(totalMemory+1);
+ buf3[argc] = (int)buf2;
+ if (argc % 7 == 6) printf("%d\n", memcpy(buf3, buf1, argc));
+ char *buf4 = (char*)malloc(100);
+ float *buf5 = (float*)malloc(100);
+ //printf("totalMemory: %d bufs: %d,%d,%d,%d,%d\n", totalMemory, buf1, buf2, buf3, buf4, buf5);
+ assert((int)buf4 > (int)totalMemory && (int)buf5 > (int)totalMemory);
+
+ printf("*%s,%.3f*\n", buf1, buf2[0]); // the old heap data should still be there
+
+ memcpy(buf4, buf1, strlen(data1)+1);
+ memcpy(buf5, buf2, sizeof(float));
+ printf("*%s,%.3f*\n", buf4, buf5[0]); // and the new heap space should work too
+
+ return 0;
+ }
+ '''
+
+ # Fail without memory growth
+ self.do_run(src, 'Cannot enlarge memory arrays.')
+ fail = open('src.cpp.o.js').read()
+
+ # Win with it
+ Settings.ALLOW_MEMORY_GROWTH = 1
+ self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*')
+ win = open('src.cpp.o.js').read()
+
+ if self.emcc_args and '-O2' in self.emcc_args:
+ # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized)
+ code_start = 'var TOTAL_MEMORY = '
+ fail = fail[fail.find(code_start):]
+ win = win[win.find(code_start):]
+ assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller'
+
+ def test_ssr(self): # struct self-ref
+ src = '''
+ #include <stdio.h>
+
+ // see related things in openjpeg
+ typedef struct opj_mqc_state {
+ unsigned int qeval;
+ int mps;
+ struct opj_mqc_state *nmps;
+ struct opj_mqc_state *nlps;
+ } opj_mqc_state_t;
+
+ static opj_mqc_state_t mqc_states[2] = {
+ {0x5600, 0, &mqc_states[2], &mqc_states[3]},
+ {0x5602, 1, &mqc_states[3], &mqc_states[2]},
+ };
+
+ int main() {
+ printf("*%d*\\n", (int)(mqc_states+1)-(int)mqc_states);
+ for (int i = 0; i < 2; i++)
+ printf("%d:%d,%d,%d,%d\\n", i, mqc_states[i].qeval, mqc_states[i].mps,
+ (int)mqc_states[i].nmps-(int)mqc_states, (int)mqc_states[i].nlps-(int)mqc_states);
+ return 0;
+ }
+ '''
+ if Settings.QUANTUM_SIZE == 1:
+ self.do_run(src, '''*4*\n0:22016,0,8,12\n1:22018,1,12,8\n''')
+ else:
+ self.do_run(src, '''*16*\n0:22016,0,32,48\n1:22018,1,48,32\n''')
+
+ def test_tinyfuncstr(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = '''
+ #include <stdio.h>
+
+ struct Class {
+ static char *name1() { return "nameA"; }
+ char *name2() { return "nameB"; }
+ };
+
+ int main() {
+ printf("*%s,%s*\\n", Class::name1(), (new Class())->name2());
+ return 0;
+ }
+ '''
+ self.do_run(src, '*nameA,nameB*')
+
+ def test_llvmswitch(self):
+ Settings.CORRECT_SIGNS = 1
+
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+
+ int switcher(int p)
+ {
+ switch(p) {
+ case 'a':
+ case 'b':
+ case 'c':
+ return p-1;
+ case -15:
+ return p+1;
+ }
+ return p;
+ }
+
+ int main( int argc, const char *argv[] ) {
+ unsigned int x = 0xfffffff1;
+ x >>= (argc-1); // force it to be unsigned for purpose of checking our switch comparison in signed/unsigned
+ printf("*%d,%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher(x), switcher(-15), switcher('e'));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*96,97,98,-14,-14,101*')
+
+ # By default, when user has not specified a -std flag, Emscripten should always build .cpp files using the C++03 standard,
+ # i.e. as if "-std=c++03" had been passed on the command line. On Linux with Clang 3.2 this is the case, but on Windows
+ # with Clang 3.2 -std=c++11 has been chosen as default, because of
+ # < jrose> clb: it's deliberate, with the idea that for people who don't care about the standard, they should be using the "best" thing we can offer on that platform
+ def test_cxx03_do_run(self):
+ src = '''
+ #include <stdio.h>
+
+ #if __cplusplus != 199711L
+ #error By default, if no -std is specified, emscripten should be compiling with -std=c++03!
+ #endif
+
+ int main( int argc, const char *argv[] ) {
+ printf("Hello world!\\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'Hello world!')
+
+ def test_bigswitch(self):
+ if Settings.RELOOP: return self.skip('TODO: switch in relooper, issue #781')
+ if Settings.ASM_JS: return self.skip('TODO: switch too large for asm')
+
+ src = open(path_from_root('tests', 'bigswitch.cpp')).read()
+ self.do_run(src, '''34962: GL_ARRAY_BUFFER (0x8892)
+26214: what?
+35040: GL_STREAM_DRAW (0x88E0)
+''', args=['34962', '26214', '35040'])
+
+ def test_indirectbr(self):
+ Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS)
+
+ src = '''
+ #include <stdio.h>
+ int main(void) {
+ const void *addrs[2] = { &&FOO, &&BAR };
+
+ // confuse the optimizer so it doesn't hardcode the jump and avoid generating an |indirectbr| instruction
+ int which = 0;
+ for (int x = 0; x < 1000; x++) which = (which + x*x) % 7;
+ which = (which % 2) + 1;
+
+ goto *addrs[which];
+
+ FOO:
+ printf("bad\\n");
+ return 0;
+ BAR:
+ printf("good\\n");
+ const void *addr = &&FOO;
+ goto *addr;
+ }
+ '''
+ self.do_run(src, 'good\nbad')
+
+ def test_indirectbr_many(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('blockaddr > 255 requires ta2')
+
+ blocks = range(1500)
+ init = ', '.join(['&&B%d' % b for b in blocks])
+ defs = '\n'.join(['B%d: printf("%d\\n"); return 0;' % (b,b) for b in blocks])
+ src = '''
+ #include <stdio.h>
+ int main(int argc, char **argv) {
+ printf("\\n");
+ const void *addrs[] = { %s };
+ goto *addrs[argc*argc + 1000];
+
+%s
+ return 0;
+ }
+ ''' % (init, defs)
+ self.do_run(src, '\n1001\n')
+
+ def test_pack(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+
+ #pragma pack(push,1)
+ typedef struct header
+ {
+ unsigned char id;
+ unsigned short colour;
+ unsigned char desc;
+ } header;
+ #pragma pack(pop)
+
+ typedef struct fatheader
+ {
+ unsigned char id;
+ unsigned short colour;
+ unsigned char desc;
+ } fatheader;
+
+ int main( int argc, const char *argv[] ) {
+ header h, *ph = 0;
+ fatheader fh, *pfh = 0;
+ printf("*%d,%d,%d*\\n", sizeof(header), (int)((int)&h.desc - (int)&h.id), (int)(&ph[1])-(int)(&ph[0]));
+ printf("*%d,%d,%d*\\n", sizeof(fatheader), (int)((int)&fh.desc - (int)&fh.id), (int)(&pfh[1])-(int)(&pfh[0]));
+ return 0;
+ }
+ '''
+ if Settings.QUANTUM_SIZE == 1:
+ self.do_run(src, '*4,2,3*\n*6,2,3*')
+ else:
+ self.do_run(src, '*4,3,4*\n*6,4,6*')
+
+ def test_varargs(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
+ if not self.is_le32(): return self.skip('we do not support all varargs stuff without le32')
+
+ src = '''
+ #include <stdio.h>
+ #include <stdarg.h>
+
+ void vary(const char *s, ...)
+ {
+ va_list v;
+ va_start(v, s);
+ char d[20];
+ vsnprintf(d, 20, s, v);
+ puts(d);
+
+ // Try it with copying
+ va_list tempva;
+ va_copy(tempva, v);
+ vsnprintf(d, 20, s, tempva);
+ puts(d);
+
+ va_end(v);
+ }
+
+ void vary2(char color, const char *s, ...)
+ {
+ va_list v;
+ va_start(v, s);
+ char d[21];
+ d[0] = color;
+ vsnprintf(d+1, 20, s, v);
+ puts(d);
+ va_end(v);
+ }
+
+ void varargs_listoffsets_list_evaluate(int count, va_list ap, int vaIteration)
+ {
+ while(count > 0)
+ {
+ const char* string = va_arg(ap, const char*);
+ printf("%s", string);
+ count--;
+ }
+ printf("\\n");
+ }
+
+ void varags_listoffsets_list_copy(int count, va_list ap, int iteration)
+ {
+ va_list ap_copy;
+ va_copy(ap_copy, ap);
+ varargs_listoffsets_list_evaluate(count, ap_copy, iteration);
+ va_end(ap_copy);
+ }
+
+ void varargs_listoffsets_args(int type, int count, ...)
+ {
+ va_list ap;
+ va_start(ap, count);
+
+ // evaluate a copied list
+ varags_listoffsets_list_copy(count, ap, 1);
+ varags_listoffsets_list_copy(count, ap, 2);
+ varags_listoffsets_list_copy(count, ap, 3);
+ varags_listoffsets_list_copy(count, ap, 4);
+
+ varargs_listoffsets_list_evaluate(count, ap, 1);
+
+ // NOTE: we expect this test to fail, so we will check the stdout for <BAD+0><BAD+1>.....
+ varargs_listoffsets_list_evaluate(count, ap, 2);
+
+ // NOTE: this test has to work again, as we restart the list
+ va_end(ap);
+ va_start(ap, count);
+ varargs_listoffsets_list_evaluate(count, ap, 3);
+ va_end(ap);
+ }
+
+ void varargs_listoffsets_main()
+ {
+ varargs_listoffsets_args(0, 5, "abc", "def", "ghi", "jkl", "mno", "<BAD+0>", "<BAD+1>", "<BAD+2>", "<BAD+3>", "<BAD+4>", "<BAD+5>", "<BAD+6>", "<BAD+7>", "<BAD+8>", "<BAD+9>", "<BAD+10>", "<BAD+11>", "<BAD+12>", "<BAD+13>", "<BAD+14>", "<BAD+15>", "<BAD+16>");
+ }
+
+ #define GETMAX(pref, type) \
+ type getMax##pref(int num, ...) \
+ { \
+ va_list vv; \
+ va_start(vv, num); \
+ type maxx = va_arg(vv, type); \
+ for (int i = 1; i < num; i++) \
+ { \
+ type curr = va_arg(vv, type); \
+ maxx = curr > maxx ? curr : maxx; \
+ } \
+ va_end(vv); \
+ return maxx; \
+ }
+ GETMAX(i, int);
+ GETMAX(D, double);
+
+ int main(int argc, char **argv) {
+ vary("*cheez: %d+%d*", 0, 24); // Also tests that '0' is not special as an array ender
+ vary("*albeit*"); // Should not fail with no var args in vararg function
+ vary2('Q', "%d*", 85);
+
+ int maxxi = getMaxi(6, 2, 5, 21, 4, -10, 19);
+ printf("maxxi:%d*\\n", maxxi);
+ double maxxD = getMaxD(6, (double)2.1, (double)5.1, (double)22.1, (double)4.1, (double)-10.1, (double)19.1, (double)2);
+ printf("maxxD:%.2f*\\n", (float)maxxD);
+
+ // And, as a function pointer
+ void (*vfp)(const char *s, ...) = argc == 1211 ? NULL : vary;
+ vfp("*vfp:%d,%d*", 22, 199);
+
+ // ensure lists work properly when copied, reinited etc.
+ varargs_listoffsets_main();
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '*cheez: 0+24*\n*cheez: 0+24*\n*albeit*\n*albeit*\nQ85*\nmaxxi:21*\nmaxxD:22.10*\n*vfp:22,199*\n*vfp:22,199*\n'+
+ 'abcdefghijklmno\nabcdefghijklmno\nabcdefghijklmno\nabcdefghijklmno\nabcdefghijklmno\n<BAD+0><BAD+1><BAD+2><BAD+3><BAD+4>\nabcdefghijklmno\n')
+
+ def test_varargs_byval(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('FIXME: Add support for this')
+ if self.is_le32(): return self.skip('clang cannot compile this code with that target yet')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdarg.h>
+
+ typedef struct type_a {
+ union {
+ double f;
+ void *p;
+ int i;
+ short sym;
+ } value;
+ } type_a;
+
+ enum mrb_vtype {
+ MRB_TT_FALSE = 0, /* 0 */
+ MRB_TT_CLASS = 9 /* 9 */
+ };
+
+ typedef struct type_b {
+ enum mrb_vtype tt:8;
+ } type_b;
+
+ void print_type_a(int argc, ...);
+ void print_type_b(int argc, ...);
+
+ int main(int argc, char *argv[])
+ {
+ type_a a;
+ type_b b;
+ a.value.p = (void*) 0x12345678;
+ b.tt = MRB_TT_CLASS;
+
+ printf("The original address of a is: %p\n", a.value.p);
+ printf("The original type of b is: %d\n", b.tt);
+
+ print_type_a(1, a);
+ print_type_b(1, b);
+
+ return 0;
+ }
+
+ void print_type_a(int argc, ...) {
+ va_list ap;
+ type_a a;
+
+ va_start(ap, argc);
+ a = va_arg(ap, type_a);
+ va_end(ap);
+
+ printf("The current address of a is: %p\n", a.value.p);
+ }
+
+ void print_type_b(int argc, ...) {
+ va_list ap;
+ type_b b;
+
+ va_start(ap, argc);
+ b = va_arg(ap, type_b);
+ va_end(ap);
+
+ printf("The current type of b is: %d\n", b.tt);
+ }
+ '''
+ self.do_run(src, '''The original address of a is: 0x12345678
+The original type of b is: 9
+The current address of a is: 0x12345678
+The current type of b is: 9
+''')
+
+ def test_functionpointer_libfunc_varargs(self):
+ src = r'''
+ #include <stdio.h>
+ #include <fcntl.h>
+ typedef int (*fp_t)(int, int, ...);
+ int main(int argc, char **argv) {
+ fp_t fp = &fcntl;
+ if (argc == 1337) fp = (fp_t)&main;
+ (*fp)(0, 10);
+ (*fp)(0, 10, 5);
+ printf("waka\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, '''waka''')
+
+ def test_structbyval(self):
+ Settings.INLINING_LIMIT = 50
+
+ # part 1: make sure that normally, passing structs by value works
+
+ src = r'''
+ #include <stdio.h>
+
+ struct point
+ {
+ int x, y;
+ };
+
+ void dump(struct point p) {
+ p.x++; // should not modify
+ p.y++; // anything in the caller!
+ printf("dump: %d,%d\n", p.x, p.y);
+ }
+
+ void dumpmod(struct point *p) {
+ p->x++; // should not modify
+ p->y++; // anything in the caller!
+ printf("dump: %d,%d\n", p->x, p->y);
+ }
+
+ int main( int argc, const char *argv[] ) {
+ point p = { 54, 2 };
+ printf("pre: %d,%d\n", p.x, p.y);
+ dump(p);
+ void (*dp)(point p) = dump; // And, as a function pointer
+ dp(p);
+ printf("post: %d,%d\n", p.x, p.y);
+ dumpmod(&p);
+ dumpmod(&p);
+ printf("last: %d,%d\n", p.x, p.y);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'pre: 54,2\ndump: 55,3\ndump: 55,3\npost: 54,2\ndump: 55,3\ndump: 56,4\nlast: 56,4')
+
+ # Check for lack of warning in the generated code (they should appear in part 2)
+ generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
+ assert 'Casting a function pointer type to another with a different number of arguments.' not in generated, 'Unexpected warning'
+
+ # part 2: make sure we warn about mixing c and c++ calling conventions here
+
+ if not (self.emcc_args is None or self.emcc_args == []): return # Optimized code is missing the warning comments
+
+ header = r'''
+ struct point
+ {
+ int x, y;
+ };
+
+ '''
+ open(os.path.join(self.get_dir(), 'header.h'), 'w').write(header)
+
+ supp = r'''
+ #include <stdio.h>
+ #include "header.h"
+
+ void dump(struct point p) {
+ p.x++; // should not modify
+ p.y++; // anything in the caller!
+ printf("dump: %d,%d\n", p.x, p.y);
+ }
+ '''
+ supp_name = os.path.join(self.get_dir(), 'supp.c')
+ open(supp_name, 'w').write(supp)
+
+ main = r'''
+ #include <stdio.h>
+ #include "header.h"
+
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ void dump(struct point p);
+ #ifdef __cplusplus
+ }
+ #endif
+
+ int main( int argc, const char *argv[] ) {
+ struct point p = { 54, 2 };
+ printf("pre: %d,%d\n", p.x, p.y);
+ dump(p);
+ void (*dp)(struct point p) = dump; // And, as a function pointer
+ dp(p);
+ printf("post: %d,%d\n", p.x, p.y);
+ return 0;
+ }
+ '''
+ main_name = os.path.join(self.get_dir(), 'main.cpp')
+ open(main_name, 'w').write(main)
+
+ Building.emcc(supp_name)
+ Building.emcc(main_name)
+ all_name = os.path.join(self.get_dir(), 'all.bc')
+ Building.link([supp_name + '.o', main_name + '.o'], all_name)
+
+ # This will fail! See explanation near the warning we check for, in the compiler source code
+ output = Popen([PYTHON, EMCC, all_name], stderr=PIPE).communicate()
+
+ # Check for warning in the generated code
+ generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
+ if 'i386-pc-linux-gnu' in COMPILER_OPTS:
+ assert 'Casting a function pointer type to a potentially incompatible one' in output[1], 'Missing expected warning'
+ else:
+ print >> sys.stderr, 'skipping C/C++ conventions warning check, since not i386-pc-linux-gnu'
+
+ def test_stdlibs(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.USE_TYPED_ARRAYS == 2:
+ # Typed arrays = 2 + safe heap prints a warning that messes up our output.
+ Settings.SAFE_HEAP = 0
+ src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/time.h>
+
+ void clean()
+ {
+ printf("*cleaned*\\n");
+ }
+
+ int comparer(const void *a, const void *b) {
+ int aa = *((int*)a);
+ int bb = *((int*)b);
+ return aa - bb;
+ }
+
+ int main() {
+ // timeofday
+ timeval t;
+ gettimeofday(&t, NULL);
+ printf("*%d,%d\\n", int(t.tv_sec), int(t.tv_usec)); // should not crash
+
+ // atexit
+ atexit(clean);
+
+ // qsort
+ int values[6] = { 3, 2, 5, 1, 5, 6 };
+ qsort(values, 5, sizeof(int), comparer);
+ printf("*%d,%d,%d,%d,%d,%d*\\n", values[0], values[1], values[2], values[3], values[4], values[5]);
+
+ printf("*stdin==0:%d*\\n", stdin == 0); // check that external values are at least not NULL
+ printf("*%%*\\n");
+ printf("*%.1ld*\\n", 5);
+
+ printf("*%.1f*\\n", strtod("66", NULL)); // checks dependency system, as our strtod needs _isspace etc.
+
+ printf("*%ld*\\n", strtol("10", NULL, 0));
+ printf("*%ld*\\n", strtol("0", NULL, 0));
+ printf("*%ld*\\n", strtol("-10", NULL, 0));
+ printf("*%ld*\\n", strtol("12", NULL, 16));
+
+ printf("*%lu*\\n", strtoul("10", NULL, 0));
+ printf("*%lu*\\n", strtoul("0", NULL, 0));
+ printf("*%lu*\\n", strtoul("-10", NULL, 0));
+
+ printf("*malloc(0)!=0:%d*\\n", malloc(0) != 0); // We should not fail horribly
+
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1,2,3,5,5,6*\n*stdin==0:0*\n*%*\n*5*\n*66.0*\n*10*\n*0*\n*-10*\n*18*\n*10*\n*0*\n*4294967286*\n*malloc(0)!=0:1*\n*cleaned*')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdbool.h>
+
+ int main() {
+ bool x = true;
+ bool y = false;
+ printf("*%d*\n", x != y);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1*', force_c=True)
+
+ def test_strtoll_hex(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ # tests strtoll for hex strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "0x4 -0x3A +0xDEADBEEF";
+ char *end_char;
+
+ // undefined base
+ long long int l1 = strtoll(STRING, &end_char, 0);
+ long long int l2 = strtoll(end_char, &end_char, 0);
+ long long int l3 = strtoll(end_char, NULL, 0);
+
+ // defined base
+ long long int l4 = strtoll(STRING, &end_char, 16);
+ long long int l5 = strtoll(end_char, &end_char, 16);
+ long long int l6 = strtoll(end_char, NULL, 16);
+
+ printf("%d%d%d%d%d%d\n", l1==0x4, l2==-0x3a, l3==0xdeadbeef, l4==0x4, l5==-0x3a, l6==0xdeadbeef);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111111')
+
+ def test_strtoll_dec(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ # tests strtoll for decimal strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "4 -38 +4711";
+ char *end_char;
+
+ // undefined base
+ long long int l1 = strtoll(STRING, &end_char, 0);
+ long long int l2 = strtoll(end_char, &end_char, 0);
+ long long int l3 = strtoll(end_char, NULL, 0);
+
+ // defined base
+ long long int l4 = strtoll(STRING, &end_char, 10);
+ long long int l5 = strtoll(end_char, &end_char, 10);
+ long long int l6 = strtoll(end_char, NULL, 10);
+
+ printf("%d%d%d%d%d%d\n", l1==4, l2==-38, l3==4711, l4==4, l5==-38, l6==4711);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111111')
+
+ def test_strtoll_bin(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ # tests strtoll for binary strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "1 -101 +1011";
+ char *end_char;
+
+ // defined base
+ long long int l4 = strtoll(STRING, &end_char, 2);
+ long long int l5 = strtoll(end_char, &end_char, 2);
+ long long int l6 = strtoll(end_char, NULL, 2);
+
+ printf("%d%d%d\n", l4==1, l5==-5, l6==11);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111')
+
+ def test_strtoll_oct(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ # tests strtoll for decimal strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "0 -035 +04711";
+ char *end_char;
+
+ // undefined base
+ long long int l1 = strtoll(STRING, &end_char, 0);
+ long long int l2 = strtoll(end_char, &end_char, 0);
+ long long int l3 = strtoll(end_char, NULL, 0);
+
+ // defined base
+ long long int l4 = strtoll(STRING, &end_char, 8);
+ long long int l5 = strtoll(end_char, &end_char, 8);
+ long long int l6 = strtoll(end_char, NULL, 8);
+
+ printf("%d%d%d%d%d%d\n", l1==0, l2==-29, l3==2505, l4==0, l5==-29, l6==2505);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111111')
+
+ def test_strtol_hex(self):
+ # tests strtoll for hex strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "0x4 -0x3A +0xDEAD";
+ char *end_char;
+
+ // undefined base
+ long l1 = strtol(STRING, &end_char, 0);
+ long l2 = strtol(end_char, &end_char, 0);
+ long l3 = strtol(end_char, NULL, 0);
+
+ // defined base
+ long l4 = strtol(STRING, &end_char, 16);
+ long l5 = strtol(end_char, &end_char, 16);
+ long l6 = strtol(end_char, NULL, 16);
+
+ printf("%d%d%d%d%d%d\n", l1==0x4, l2==-0x3a, l3==0xdead, l4==0x4, l5==-0x3a, l6==0xdead);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111111')
+
+ def test_strtol_dec(self):
+ # tests strtoll for decimal strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "4 -38 +4711";
+ char *end_char;
+
+ // undefined base
+ long l1 = strtol(STRING, &end_char, 0);
+ long l2 = strtol(end_char, &end_char, 0);
+ long l3 = strtol(end_char, NULL, 0);
+
+ // defined base
+ long l4 = strtol(STRING, &end_char, 10);
+ long l5 = strtol(end_char, &end_char, 10);
+ long l6 = strtol(end_char, NULL, 10);
+
+ printf("%d%d%d%d%d%d\n", l1==4, l2==-38, l3==4711, l4==4, l5==-38, l6==4711);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111111')
+
+ def test_strtol_bin(self):
+ # tests strtoll for binary strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "1 -101 +1011";
+ char *end_char;
+
+ // defined base
+ long l4 = strtol(STRING, &end_char, 2);
+ long l5 = strtol(end_char, &end_char, 2);
+ long l6 = strtol(end_char, NULL, 2);
+
+ printf("%d%d%d\n", l4==1, l5==-5, l6==11);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111')
+
+ def test_strtol_oct(self):
+ # tests strtoll for decimal strings (0x...)
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ const char *STRING = "0 -035 +04711";
+ char *end_char;
+
+ // undefined base
+ long l1 = strtol(STRING, &end_char, 0);
+ long l2 = strtol(end_char, &end_char, 0);
+ long l3 = strtol(end_char, NULL, 0);
+
+ // defined base
+ long l4 = strtol(STRING, &end_char, 8);
+ long l5 = strtol(end_char, &end_char, 8);
+ long l6 = strtol(end_char, NULL, 8);
+
+ printf("%d%d%d%d%d%d\n", l1==0, l2==-29, l3==2505, l4==0, l5==-29, l6==2505);
+ return 0;
+ }
+ '''
+ self.do_run(src, '111111')
+
+ def test_atexit(self):
+ # Confirms they are called in reverse order
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ static void cleanA() {
+ printf("A");
+ }
+ static void cleanB() {
+ printf("B");
+ }
+
+ int main() {
+ atexit(cleanA);
+ atexit(cleanB);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'BA')
+
+ def test_time(self):
+ # XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again.
+ src = open(path_from_root('tests', 'time', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read()
+ expected2 = open(path_from_root('tests', 'time', 'output2.txt'), 'r').read()
+ self.do_run(src, [expected, expected2],
+ extra_emscripten_args=['-H', 'libc/time.h'])
+ #extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
+
+ def test_timeb(self):
+ # Confirms they are called in reverse order
+ src = r'''
+ #include <stdio.h>
+ #include <assert.h>
+ #include <sys/timeb.h>
+
+ int main() {
+ timeb tb;
+ tb.timezone = 1;
+ printf("*%d\n", ftime(&tb));
+ assert(tb.time > 10000);
+ assert(tb.timezone == 0);
+ assert(tb.dstflag == 0);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0\n')
+
+ def test_time_c(self):
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+
+ int main() {
+ time_t t = time(0);
+ printf("time: %s\n", ctime(&t));
+ }
+ '''
+ self.do_run(src, 'time: ') # compilation check, mainly
+
+ def test_gmtime(self):
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <time.h>
+ #include <assert.h>
+
+ int main(void)
+ {
+ time_t t=time(NULL);
+ struct tm *ptm=gmtime(&t);
+ struct tm tmCurrent=*ptm;
+ int hour=tmCurrent.tm_hour;
+
+ t-=hour*3600; // back to midnight
+ int yday = -1;
+ for(hour=0;hour<24;hour++)
+ {
+ ptm=gmtime(&t);
+ // tm_yday must be constant all day...
+ printf("yday: %d, hour: %d\n", ptm->tm_yday, hour);
+ if (yday == -1) yday = ptm->tm_yday;
+ else assert(yday == ptm->tm_yday);
+ t+=3600; // add one hour
+ }
+ printf("ok!\n");
+ return(0);
+ }
+ '''
+ self.do_run(src, '''ok!''')
+
+ def test_strptime_tm(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ int main() {
+ struct tm tm;
+ char *ptr = strptime("17410105012000", "%H%M%S%d%m%Y", &tm);
+
+ printf("%s: %s, %d/%d/%d %d:%d:%d",
+ (ptr != NULL && *ptr=='\0') ? "OK" : "ERR",
+ tm.tm_wday == 0 ? "Sun" : (tm.tm_wday == 1 ? "Mon" : (tm.tm_wday == 2 ? "Tue" : (tm.tm_wday == 3 ? "Wed" : (tm.tm_wday == 4 ? "Thu" : (tm.tm_wday == 5 ? "Fri" : (tm.tm_wday == 6 ? "Sat" : "ERR")))))),
+ tm.tm_mon+1,
+ tm.tm_mday,
+ tm.tm_year+1900,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec
+ );
+ }
+ '''
+ self.do_run(src, 'OK: Wed, 1/5/2000 17:41:1')
+
+ def test_strptime_days(self):
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ static const struct {
+ const char *input;
+ const char *format;
+ } day_tests[] = {
+ { "2000-01-01", "%Y-%m-%d"},
+ { "03/03/00", "%D"},
+ { "9/9/99", "%x"},
+ { "19990502123412", "%Y%m%d%H%M%S"},
+ { "2001 20 Mon", "%Y %U %a"},
+ { "2006 4 Fri", "%Y %U %a"},
+ { "2001 21 Mon", "%Y %W %a"},
+ { "2013 29 Wed", "%Y %W %a"},
+ { "2000-01-01 08:12:21 AM", "%Y-%m-%d %I:%M:%S %p"},
+ { "2000-01-01 08:12:21 PM", "%Y-%m-%d %I:%M:%S %p"},
+ { "2001 17 Tue", "%Y %U %a"},
+ { "2001 8 Thursday", "%Y %W %a"},
+ };
+
+ int main() {
+ struct tm tm;
+
+ for (int i = 0; i < sizeof (day_tests) / sizeof (day_tests[0]); ++i) {
+ memset (&tm, '\0', sizeof (tm));
+ char *ptr = strptime(day_tests[i].input, day_tests[i].format, &tm);
+
+ printf("%s: %d/%d/%d (%dth DoW, %dth DoY)\n", (ptr != NULL && *ptr=='\0') ? "OK" : "ERR", tm.tm_mon+1, tm.tm_mday, 1900+tm.tm_year, tm.tm_wday, tm.tm_yday);
+ }
+ }
+ '''
+ self.do_run(src, 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 3/3/2000 (5th DoW, 62th DoY)\n'\
+ 'OK: 9/9/1999 (4th DoW, 251th DoY)\n'\
+ 'OK: 5/2/1999 (0th DoW, 121th DoY)\n'\
+ 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
+ 'OK: 1/27/2006 (5th DoW, 26th DoY)\n'\
+ 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
+ 'OK: 7/24/2013 (3th DoW, 204th DoY)\n'\
+ 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 5/1/2001 (2th DoW, 120th DoY)\n'\
+ 'OK: 2/22/2001 (4th DoW, 52th DoY)\n'\
+ )
+
+ def test_strptime_reentrant(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ int main () {
+ int result = 0;
+ struct tm tm;
+
+ memset (&tm, 0xaa, sizeof (tm));
+
+ /* Test we don't crash on uninitialized struct tm.
+ Some fields might contain bogus values until everything
+ needed is initialized, but we shouldn't crash. */
+ if (strptime ("2007", "%Y", &tm) == NULL
+ || strptime ("12", "%d", &tm) == NULL
+ || strptime ("Feb", "%b", &tm) == NULL
+ || strptime ("13", "%M", &tm) == NULL
+ || strptime ("21", "%S", &tm) == NULL
+ || strptime ("16", "%H", &tm) == NULL) {
+ printf("ERR: returned NULL");
+ exit(EXIT_FAILURE);
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 1 || tm.tm_yday != 42) {
+ printf("ERR: unexpected tm content (1) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strptime ("8", "%d", &tm) == NULL) {
+ printf("ERR: strptime failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 4 || tm.tm_yday != 38) {
+ printf("ERR: unexpected tm content (2) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("OK");
+ }
+ '''
+ self.do_run(src, 'OK')
+
+ def test_strftime(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ void test(int result, const char* comment, const char* parsed = "") {
+ printf("%d",result);
+ if (!result) {
+ printf("\nERROR: %s (\"%s\")\n", comment, parsed);
+ }
+ }
+
+ int cmp(const char *s1, const char *s2) {
+ for ( ; *s1 == *s2 ; s1++,s2++ ) {
+ if ( *s1 == '\0' )
+ break;
+ }
+
+ return (*s1 - *s2);
+ }
+
+ int main() {
+ struct tm tm;
+ char s[1000];
+ size_t size;
+
+ tm.tm_sec = 4;
+ tm.tm_min = 23;
+ tm.tm_hour = 20;
+ tm.tm_mday = 21;
+ tm.tm_mon = 1;
+ tm.tm_year = 74;
+ tm.tm_wday = 4;
+ tm.tm_yday = 51;
+ tm.tm_isdst = 0;
+
+ size = strftime(s, 1000, "", &tm);
+ test((size==0) && (*s=='\0'), "strftime test #1", s);
+
+ size = strftime(s, 1000, "%a", &tm);
+ test((size==3) && !cmp(s, "Thu"), "strftime test #2", s);
+
+ size = strftime(s, 1000, "%A", &tm);
+ test((size==8) && !cmp(s, "Thursday"), "strftime test #3", s);
+
+ size = strftime(s, 1000, "%b", &tm);
+ test((size==3) && !cmp(s, "Feb"), "strftime test #4", s);
+
+ size = strftime(s, 1000, "%B", &tm);
+ test((size==8) && !cmp(s, "February"),
+ "strftime test #5", s);
+
+ size = strftime(s, 1000, "%d", &tm);
+ test((size==2) && !cmp(s, "21"),
+ "strftime test #6", s);
+
+ size = strftime(s, 1000, "%H", &tm);
+ test((size==2) && !cmp(s, "20"),
+ "strftime test #7", s);
+
+ size = strftime(s, 1000, "%I", &tm);
+ test((size==2) && !cmp(s, "08"),
+ "strftime test #8", s);
+
+ size = strftime(s, 1000, "%j", &tm);
+ test((size==3) && !cmp(s, "052"),
+ "strftime test #9", s);
+
+ size = strftime(s, 1000, "%m", &tm);
+ test((size==2) && !cmp(s, "02"),
+ "strftime test #10", s);
+
+ size = strftime(s, 1000, "%M", &tm);
+ test((size==2) && !cmp(s, "23"),
+ "strftime test #11", s);
+
+ size = strftime(s, 1000, "%p", &tm);
+ test((size==2) && !cmp(s, "PM"),
+ "strftime test #12", s);
+
+ size = strftime(s, 1000, "%S", &tm);
+ test((size==2) && !cmp(s, "04"),
+ "strftime test #13", s);
+
+ size = strftime(s, 1000, "%U", &tm);
+ test((size==2) && !cmp(s, "07"),
+ "strftime test #14", s);
+
+ size = strftime(s, 1000, "%w", &tm);
+ test((size==1) && !cmp(s, "4"),
+ "strftime test #15", s);
+
+ size = strftime(s, 1000, "%W", &tm);
+ test((size==2) && !cmp(s, "07"),
+ "strftime test #16", s);
+
+ size = strftime(s, 1000, "%y", &tm);
+ test((size==2) && !cmp(s, "74"),
+ "strftime test #17", s);
+
+ size = strftime(s, 1000, "%Y", &tm);
+ test((size==4) && !cmp(s, "1974"),
+ "strftime test #18", s);
+
+ size = strftime(s, 1000, "%%", &tm);
+ test((size==1) && !cmp(s, "%"),
+ "strftime test #19", s);
+
+ size = strftime(s, 5, "%Y", &tm);
+ test((size==4) && !cmp(s, "1974"),
+ "strftime test #20", s);
+
+ size = strftime(s, 4, "%Y", &tm);
+ test((size==0), "strftime test #21", s);
+
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ size = strftime(s, 10, "%U", &tm);
+ test((size==2) && !cmp(s, "00"), "strftime test #22", s);
+
+ size = strftime(s, 10, "%W", &tm);
+ test((size==2) && !cmp(s, "00"), "strftime test #23", s);
+
+ // 1/1/1973 was a Sunday and is in CW 1
+ tm.tm_year = 73;
+ size = strftime(s, 10, "%W", &tm);
+ test((size==2) && !cmp(s, "01"), "strftime test #24", s);
+
+ // 1/1/1978 was a Monday and is in CW 1
+ tm.tm_year = 78;
+ size = strftime(s, 10, "%U", &tm);
+ test((size==2) && !cmp(s, "01"), "strftime test #25", s);
+
+ // 2/1/1999
+ tm.tm_year = 99;
+ tm.tm_yday = 1;
+ size = strftime(s, 10, "%G (%V)", &tm);
+ test((size==9) && !cmp(s, "1998 (53)"), "strftime test #26", s);
+
+ size = strftime(s, 10, "%g", &tm);
+ test((size==2) && !cmp(s, "98"), "strftime test #27", s);
+
+ // 30/12/1997
+ tm.tm_year = 97;
+ tm.tm_yday = 363;
+ size = strftime(s, 10, "%G (%V)", &tm);
+ test((size==9) && !cmp(s, "1998 (01)"), "strftime test #28", s);
+
+ size = strftime(s, 10, "%g", &tm);
+ test((size==2) && !cmp(s, "98"), "strftime test #29", s);
+ }
+ '''
+ self.do_run(src, '11111111111111111111111111111')
+
+ def test_intentional_fault(self):
+ # Some programs intentionally segfault themselves, we should compile that into a throw
+ src = r'''
+ int main () {
+ *(volatile char *)0 = 0;
+ return 0;
+ }
+ '''
+ self.do_run(src, 'fault on write to 0' if not Settings.ASM_JS else 'abort()')
+
+ def test_trickystring(self):
+ src = r'''
+ #include <stdio.h>
+
+ typedef struct
+ {
+ int (*f)(void *);
+ void *d;
+ char s[16];
+ } LMEXFunctionStruct;
+
+ int f(void *user)
+ {
+ return 0;
+ }
+
+ static LMEXFunctionStruct const a[] =
+ {
+ {f, (void *)(int)'a', "aa"}
+ };
+
+ int main()
+ {
+ printf("ok\n");
+ return a[0].f(a[0].d);
+ }
+ '''
+ self.do_run(src, 'ok\n')
+
+ def test_statics(self):
+ # static initializers save i16 but load i8 for some reason (or i64 and load i8)
+ if Settings.SAFE_HEAP:
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26', 'src.cpp:28']
+
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+
+ #define CONSTRLEN 32
+
+ char * (*func)(char *, const char *) = NULL;
+
+ void conoutfv(const char *fmt)
+ {
+ static char buf[CONSTRLEN];
+ func(buf, fmt); // call by function pointer to make sure we test strcpy here
+ puts(buf);
+ }
+
+ struct XYZ {
+ float x, y, z;
+ XYZ(float a, float b, float c) : x(a), y(b), z(c) { }
+ static const XYZ& getIdentity()
+ {
+ static XYZ iT(1,2,3);
+ return iT;
+ }
+ };
+ struct S {
+ static const XYZ& getIdentity()
+ {
+ static const XYZ iT(XYZ::getIdentity());
+ return iT;
+ }
+ };
+
+ int main() {
+ func = &strcpy;
+ conoutfv("*staticccz*");
+ printf("*%.2f,%.2f,%.2f*\\n", S::getIdentity().x, S::getIdentity().y, S::getIdentity().z);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*staticccz*\n*1.00,2.00,3.00*')
+
+ def test_copyop(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ # clang generated code is vulnerable to this, as it uses
+ # memcpy for assignments, with hardcoded numbers of bytes
+ # (llvm-gcc copies items one by one). See QUANTUM_SIZE in
+ # settings.js.
+ src = '''
+ #include <stdio.h>
+ #include <math.h>
+ #include <string.h>
+
+ struct vec {
+ double x,y,z;
+ vec() : x(0), y(0), z(0) { };
+ vec(const double a, const double b, const double c) : x(a), y(b), z(c) { };
+ };
+
+ struct basis {
+ vec a, b, c;
+ basis(const vec& v) {
+ a=v; // should not touch b!
+ printf("*%.2f,%.2f,%.2f*\\n", b.x, b.y, b.z);
+ }
+ };
+
+ int main() {
+ basis B(vec(1,0,0));
+
+ // Part 2: similar problem with memset and memmove
+ int x = 1, y = 77, z = 2;
+ memset((void*)&x, 0, sizeof(int));
+ memset((void*)&z, 0, sizeof(int));
+ printf("*%d,%d,%d*\\n", x, y, z);
+ memcpy((void*)&x, (void*)&z, sizeof(int));
+ memcpy((void*)&z, (void*)&x, sizeof(int));
+ printf("*%d,%d,%d*\\n", x, y, z);
+ memmove((void*)&x, (void*)&z, sizeof(int));
+ memmove((void*)&z, (void*)&x, sizeof(int));
+ printf("*%d,%d,%d*\\n", x, y, z);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0.00,0.00,0.00*\n*0,77,0*\n*0,77,0*\n*0,77,0*')
+
+ def test_memcpy_memcmp(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ #include <assert.h>
+
+ #define MAXX 48
+ void reset(unsigned char *buffer) {
+ for (int i = 0; i < MAXX; i++) buffer[i] = i+1;
+ }
+ void dump(unsigned char *buffer) {
+ for (int i = 0; i < MAXX-1; i++) printf("%2d,", buffer[i]);
+ printf("%d\\n", buffer[MAXX-1]);
+ }
+ int main() {
+ unsigned char buffer[MAXX];
+ for (int i = MAXX/4; i < MAXX-MAXX/4; i++) {
+ for (int j = MAXX/4; j < MAXX-MAXX/4; j++) {
+ for (int k = 1; k < MAXX/4; k++) {
+ if (i == j) continue;
+ if (i < j && i+k > j) continue;
+ if (j < i && j+k > i) continue;
+ printf("[%d,%d,%d] ", i, j, k);
+ reset(buffer);
+ memcpy(buffer+i, buffer+j, k);
+ dump(buffer);
+ assert(memcmp(buffer+i, buffer+j, k) == 0);
+ buffer[i + k/2]++;
+ if (buffer[i + k/2] != 0) {
+ assert(memcmp(buffer+i, buffer+j, k) > 0);
+ } else {
+ assert(memcmp(buffer+i, buffer+j, k) < 0);
+ }
+ buffer[i + k/2]--;
+ buffer[j + k/2]++;
+ if (buffer[j + k/2] != 0) {
+ assert(memcmp(buffer+i, buffer+j, k) < 0);
+ } else {
+ assert(memcmp(buffer+i, buffer+j, k) > 0);
+ }
+ }
+ }
+ }
+ return 0;
+ }
+ '''
+ def check(result, err):
+ return hashlib.sha1(result).hexdigest()
+ self.do_run(src, '6c9cdfe937383b79e52ca7a2cce83a21d9f5422c',
+ output_nicerizer = check)
+
+ def test_memcpy2(self):
+ src = r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <assert.h>
+ int main() {
+ char buffer[256];
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ for (int k = 0; k < 35; k++) {
+ for (int t = 0; t < 256; t++) buffer[t] = t;
+ char *dest = buffer + i + 128;
+ char *src = buffer+j;
+ //printf("%d, %d, %d\n", i, j, k);
+ assert(memcpy(dest, src, k) == dest);
+ assert(memcmp(dest, src, k) == 0);
+ }
+ }
+ }
+ printf("ok.\n");
+ return 1;
+ }
+ '''
+ self.do_run(src, 'ok.');
+
+ def test_getopt(self):
+ if self.emcc_args is None: return self.skip('needs emcc for libc')
+
+ src = '''
+ #pragma clang diagnostic ignored "-Winvalid-pp-token"
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int
+ main(int argc, char *argv[])
+ {
+ int flags, opt;
+ int nsecs, tfnd;
+
+ nsecs = 0;
+ tfnd = 0;
+ flags = 0;
+ while ((opt = getopt(argc, argv, "nt:")) != -1) {
+ switch (opt) {
+ case 'n':
+ flags = 1;
+ break;
+ case 't':
+ nsecs = atoi(optarg);
+ tfnd = 1;
+ break;
+ default: /* '?' */
+ fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf("flags=%d; tfnd=%d; optind=%d\\n", flags, tfnd, optind);
+
+ if (optind >= argc) {
+ fprintf(stderr, "Expected argument after options\\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("name argument = %s\\n", argv[optind]);
+
+ /* Other code omitted */
+
+ exit(EXIT_SUCCESS);
+ }
+ '''
+ self.do_run(src, 'flags=1; tfnd=1; optind=4\nname argument = foobar', args=['-t', '12', '-n', 'foobar'])
+
+ def test_getopt_long(self):
+ if self.emcc_args is None: return self.skip('needs emcc for libc')
+
+ src = '''
+ #pragma clang diagnostic ignored "-Winvalid-pp-token"
+ #pragma clang diagnostic ignored "-Wdeprecated-writable-strings"
+ #include <stdio.h> /* for printf */
+ #include <stdlib.h> /* for exit */
+ #include <getopt.h>
+
+ int
+ main(int argc, char **argv)
+ {
+ int c;
+ int digit_optind = 0;
+
+ while (1) {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"add", required_argument, 0, 0 },
+ {"append", no_argument, 0, 0 },
+ {"delete", required_argument, 0, 0 },
+ {"verbose", no_argument, 0, 0 },
+ {"create", required_argument, 0, 'c'},
+ {"file", required_argument, 0, 0 },
+ {0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "abc:d:012",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ printf("option %s", long_options[option_index].name);
+ if (optarg)
+ printf(" with arg %s", optarg);
+ printf("\\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf("digits occur in two different argv-elements.\\n");
+ digit_optind = this_option_optind;
+ printf("option %c\\n", c);
+ break;
+
+ case 'a':
+ printf("option a\\n");
+ break;
+
+ case 'b':
+ printf("option b\\n");
+ break;
+
+ case 'c':
+ printf("option c with value '%s'\\n", optarg);
+ break;
+
+ case 'd':
+ printf("option d with value '%s'\\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf("?? getopt returned character code 0%o ??\\n", c);
+ }
+ }
+
+ if (optind < argc) {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\\n");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ '''
+ self.do_run(src, 'option file with arg foobar\noption b', args=['--file', 'foobar', '-b'])
+
+ def test_memmove(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ int main() {
+ char str[] = "memmove can be very useful....!";
+ memmove (str+20, str+15, 11);
+ puts(str);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'memmove can be very very useful')
+
+ def test_memmove2(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('need ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <assert.h>
+ int main() {
+ int sum = 0;
+ char buffer[256];
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ for (int k = 0; k < 35; k++) {
+ for (int t = 0; t < 256; t++) buffer[t] = t;
+ char *dest = buffer + i;
+ char *src = buffer + j;
+ if (dest == src) continue;
+ //printf("%d, %d, %d\n", i, j, k);
+ assert(memmove(dest, src, k) == dest);
+ for (int t = 0; t < 256; t++) sum += buffer[t];
+ }
+ }
+ }
+ printf("final: %d.\n", sum);
+ return 1;
+ }
+ '''
+ self.do_run(src, 'final: -403200.');
+
+ def test_memmove3(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ int main() {
+ char str[] = "memmove can be vvery useful....!";
+ memmove(str+15, str+16, 17);
+ puts(str);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'memmove can be very useful....!')
+
+ def test_bsearch(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip('Test cannot work with q1')
+
+ src = '''
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int cmp(const void* key, const void* member) {
+ return *(int *)key - *(int *)member;
+ }
+
+ void printResult(int* needle, int* haystack, unsigned int len) {
+ void *result = bsearch(needle, haystack, len, sizeof(unsigned int), cmp);
+
+ if (result == NULL) {
+ printf("null\\n");
+ } else {
+ printf("%d\\n", *(unsigned int *)result);
+ }
+ }
+
+ int main() {
+ int a[] = { -2, -1, 0, 6, 7, 9 };
+ int b[] = { 0, 1 };
+
+ /* Find all keys that exist. */
+ for(int i = 0; i < 6; i++) {
+ int val = a[i];
+
+ printResult(&val, a, 6);
+ }
+
+ /* Keys that are covered by the range of the array but aren't in
+ * the array cannot be found.
+ */
+ int v1 = 3;
+ int v2 = 8;
+ printResult(&v1, a, 6);
+ printResult(&v2, a, 6);
+
+ /* Keys outside the range of the array cannot be found. */
+ int v3 = -1;
+ int v4 = 2;
+
+ printResult(&v3, b, 2);
+ printResult(&v4, b, 2);
+
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '-2\n-1\n0\n6\n7\n9\nnull\nnull\nnull\nnull')
+
+ def test_nestedstructs(self):
+ src = '''
+ #include <stdio.h>
+ #include "emscripten.h"
+
+ struct base {
+ int x;
+ float y;
+ union {
+ int a;
+ float b;
+ };
+ char c;
+ };
+
+ struct hashtableentry {
+ int key;
+ base data;
+ };
+
+ struct hashset {
+ typedef hashtableentry entry;
+ struct chain { entry elem; chain *next; };
+ // struct chainchunk { chain chains[100]; chainchunk *next; };
+ };
+
+ struct hashtable : hashset {
+ hashtable() {
+ base *b = NULL;
+ entry *e = NULL;
+ chain *c = NULL;
+ printf("*%d,%d,%d,%d,%d,%d|%d,%d,%d,%d,%d,%d,%d,%d|%d,%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n",
+ sizeof(base),
+ int(&(b->x)), int(&(b->y)), int(&(b->a)), int(&(b->b)), int(&(b->c)),
+ sizeof(hashtableentry),
+ int(&(e->key)), int(&(e->data)), int(&(e->data.x)), int(&(e->data.y)), int(&(e->data.a)), int(&(e->data.b)), int(&(e->data.c)),
+ sizeof(hashset::chain),
+ int(&(c->elem)), int(&(c->next)), int(&(c->elem.key)), int(&(c->elem.data)), int(&(c->elem.data.x)), int(&(c->elem.data.y)), int(&(c->elem.data.a)), int(&(c->elem.data.b)), int(&(c->elem.data.c))
+ );
+ }
+ };
+
+ struct B { char buffer[62]; int last; char laster; char laster2; };
+
+ struct Bits {
+ unsigned short A : 1;
+ unsigned short B : 1;
+ unsigned short C : 1;
+ unsigned short D : 1;
+ unsigned short x1 : 1;
+ unsigned short x2 : 1;
+ unsigned short x3 : 1;
+ unsigned short x4 : 1;
+ };
+
+ int main() {
+ hashtable t;
+
+ // Part 2 - the char[] should be compressed, BUT have a padding space at the end so the next
+ // one is aligned properly. Also handle char; char; etc. properly.
+ B *b = NULL;
+ printf("*%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n", int(b), int(&(b->buffer)), int(&(b->buffer[0])), int(&(b->buffer[1])), int(&(b->buffer[2])),
+ int(&(b->last)), int(&(b->laster)), int(&(b->laster2)), sizeof(B));
+
+ // Part 3 - bitfields, and small structures
+ Bits *b2 = NULL;
+ printf("*%d*\\n", sizeof(Bits));
+
+ return 0;
+ }
+ '''
+ if Settings.QUANTUM_SIZE == 1:
+ # Compressed memory. Note that sizeof() does give the fat sizes, however!
+ self.do_run(src, '*16,0,1,2,2,3|20,0,1,1,2,3,3,4|24,0,5,0,1,1,2,3,3,4*\n*0,0,0,1,2,62,63,64,72*\n*2*')
+ else:
+ # Bloated memory; same layout as C/C++
+ self.do_run(src, '*16,0,4,8,8,12|20,0,4,4,8,12,12,16|24,0,20,0,4,4,8,12,12,16*\n*0,0,0,1,2,64,68,69,72*\n*2*')
+
+ def test_runtimelink(self):
+ return self.skip('BUILD_AS_SHARED_LIB=2 is deprecated')
+ if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize printf into puts in the parent, and the child will still look for puts')
+ if Settings.ASM_JS: return self.skip('asm does not support runtime linking')
+
+ main, supp = self.setup_runtimelink_test()
+
+ self.banned_js_engines = [NODE_JS] # node's global scope behaves differently than everything else, needs investigation FIXME
+ Settings.LINKABLE = 1
+ Settings.BUILD_AS_SHARED_LIB = 2
+ Settings.NAMED_GLOBALS = 1
+
+ self.build(supp, self.get_dir(), self.in_dir('supp.cpp'))
+ shutil.move(self.in_dir('supp.cpp.o.js'), self.in_dir('liblib.so'))
+ Settings.BUILD_AS_SHARED_LIB = 0
+
+ Settings.RUNTIME_LINKED_LIBS = ['liblib.so'];
+ self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.')
+
+ def test_dlfcn_basic(self):
+ if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
+
+ Settings.NAMED_GLOBALS = 1
+ Settings.LINKABLE = 1
+
+ lib_src = '''
+ #include <cstdio>
+
+ class Foo {
+ public:
+ Foo() {
+ printf("Constructing lib object.\\n");
+ }
+ };
+
+ Foo global;
+ '''
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, 'liblib.cpp')
+ Settings.BUILD_AS_SHARED_LIB = 1
+ self.build(lib_src, dirname, filename)
+ shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
+
+ src = '''
+ #include <cstdio>
+ #include <dlfcn.h>
+
+ class Bar {
+ public:
+ Bar() {
+ printf("Constructing main object.\\n");
+ }
+ };
+
+ Bar global;
+
+ int main() {
+ dlopen("liblib.so", RTLD_NOW);
+ return 0;
+ }
+ '''
+ Settings.BUILD_AS_SHARED_LIB = 0
+ add_pre_run_and_checks = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
+ )
+ open(filename, 'w').write(src)
+'''
+ self.do_run(src, 'Constructing main object.\nConstructing lib object.\n',
+ post_build=add_pre_run_and_checks)
+
+ def test_dlfcn_qsort(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
+
+ Settings.LINKABLE = 1
+ Settings.NAMED_GLOBALS = 1
+
+ if Settings.USE_TYPED_ARRAYS == 2:
+ Settings.CORRECT_SIGNS = 1 # Needed for unsafe optimizations
+
+ lib_src = '''
+ int lib_cmp(const void* left, const void* right) {
+ const int* a = (const int*) left;
+ const int* b = (const int*) right;
+ if(*a > *b) return 1;
+ else if(*a == *b) return 0;
+ else return -1;
+ }
+
+ typedef int (*CMP_TYPE)(const void*, const void*);
+
+ extern "C" CMP_TYPE get_cmp() {
+ return lib_cmp;
+ }
+ '''
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, 'liblib.cpp')
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_get_cmp']
+ self.build(lib_src, dirname, filename)
+ shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
+
+ src = '''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <dlfcn.h>
+
+ typedef int (*CMP_TYPE)(const void*, const void*);
+
+ int main_cmp(const void* left, const void* right) {
+ const int* a = (const int*) left;
+ const int* b = (const int*) right;
+ if(*a < *b) return 1;
+ else if(*a == *b) return 0;
+ else return -1;
+ }
+
+ int main() {
+ void* lib_handle;
+ CMP_TYPE (*getter_ptr)();
+ CMP_TYPE lib_cmp_ptr;
+ int arr[5] = {4, 2, 5, 1, 3};
+
+ lib_handle = dlopen("liblib.so", RTLD_NOW);
+ if (lib_handle == NULL) {
+ printf("Could not load lib.\\n");
+ return 1;
+ }
+ getter_ptr = (CMP_TYPE (*)()) dlsym(lib_handle, "get_cmp");
+ if (getter_ptr == NULL) {
+ printf("Could not find func.\\n");
+ return 1;
+ }
+ lib_cmp_ptr = getter_ptr();
+
+ qsort((void*)arr, 5, sizeof(int), main_cmp);
+ printf("Sort with main comparison: ");
+ for (int i = 0; i < 5; i++) {
+ printf("%d ", arr[i]);
+ }
+ printf("\\n");
+
+ qsort((void*)arr, 5, sizeof(int), lib_cmp_ptr);
+ printf("Sort with lib comparison: ");
+ for (int i = 0; i < 5; i++) {
+ printf("%d ", arr[i]);
+ }
+ printf("\\n");
+
+ return 0;
+ }
+ '''
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.EXPORTED_FUNCTIONS = ['_main']
+ add_pre_run_and_checks = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
+ )
+ open(filename, 'w').write(src)
+'''
+ self.do_run(src, 'Sort with main comparison: 5 4 3 2 1 *Sort with lib comparison: 1 2 3 4 5 *',
+ output_nicerizer=lambda x, err: x.replace('\n', '*'),
+ post_build=add_pre_run_and_checks)
+
+ def test_dlfcn_data_and_fptr(self):
+ if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
+ if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func')
+
+ Settings.LINKABLE = 1
+ Settings.NAMED_GLOBALS = 1
+
+ lib_src = '''
+ #include <stdio.h>
+
+ int global = 42;
+
+ extern void parent_func(); // a function that is defined in the parent
+
+ void lib_fptr() {
+ printf("Second calling lib_fptr from main.\\n");
+ parent_func();
+ // call it also through a pointer, to check indexizing
+ void (*p_f)();
+ p_f = parent_func;
+ p_f();
+ }
+
+ extern "C" void (*func(int x, void(*fptr)()))() {
+ printf("In func: %d\\n", x);
+ fptr();
+ return lib_fptr;
+ }
+ '''
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, 'liblib.cpp')
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_func']
+ Settings.EXPORTED_GLOBALS = ['_global']
+ self.build(lib_src, dirname, filename)
+ shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
+
+ src = '''
+ #include <stdio.h>
+ #include <dlfcn.h>
+
+ typedef void (*FUNCTYPE(int, void(*)()))();
+
+ FUNCTYPE func;
+
+ void parent_func() {
+ printf("parent_func called from child\\n");
+ }
+
+ void main_fptr() {
+ printf("First calling main_fptr from lib.\\n");
+ }
+
+ int main() {
+ void* lib_handle;
+ FUNCTYPE* func_fptr;
+
+ // Test basic lib loading.
+ lib_handle = dlopen("liblib.so", RTLD_NOW);
+ if (lib_handle == NULL) {
+ printf("Could not load lib.\\n");
+ return 1;
+ }
+
+ // Test looked up function.
+ func_fptr = (FUNCTYPE*) dlsym(lib_handle, "func");
+ // Load twice to test cache.
+ func_fptr = (FUNCTYPE*) dlsym(lib_handle, "func");
+ if (func_fptr == NULL) {
+ printf("Could not find func.\\n");
+ return 1;
+ }
+
+ // Test passing function pointers across module bounds.
+ void (*fptr)() = func_fptr(13, main_fptr);
+ fptr();
+
+ // Test global data.
+ int* global = (int*) dlsym(lib_handle, "global");
+ if (global == NULL) {
+ printf("Could not find global.\\n");
+ return 1;
+ }
+
+ printf("Var: %d\\n", *global);
+
+ return 0;
+ }
+ '''
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.EXPORTED_FUNCTIONS = ['_main']
+ Settings.EXPORTED_GLOBALS = []
+ add_pre_run_and_checks = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
+ )
+ open(filename, 'w').write(src)
+'''
+ self.do_run(src, 'In func: 13*First calling main_fptr from lib.*Second calling lib_fptr from main.*parent_func called from child*parent_func called from child*Var: 42*',
+ output_nicerizer=lambda x, err: x.replace('\n', '*'),
+ post_build=add_pre_run_and_checks)
+
+ def test_dlfcn_alias(self):
+ if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
+
+ Settings.LINKABLE = 1
+ Settings.NAMED_GLOBALS = 1
+
+ if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize away stuff we expect from the shared library')
+
+ lib_src = r'''
+ #include <stdio.h>
+ extern int parent_global;
+ extern "C" void func() {
+ printf("Parent global: %d.\n", parent_global);
+ }
+ '''
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, 'liblib.cpp')
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_func']
+ self.build(lib_src, dirname, filename)
+ shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
+
+ src = r'''
+ #include <dlfcn.h>
+
+ int parent_global = 123;
+
+ int main() {
+ void* lib_handle;
+ void (*fptr)();
+
+ lib_handle = dlopen("liblib.so", RTLD_NOW);
+ fptr = (void (*)())dlsym(lib_handle, "func");
+ fptr();
+ parent_global = 456;
+ fptr();
+
+ return 0;
+ }
+ '''
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.INCLUDE_FULL_LIBRARY = 1
+ Settings.EXPORTED_FUNCTIONS = ['_main']
+ add_pre_run_and_checks = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
+ )
+ open(filename, 'w').write(src)
+'''
+ self.do_run(src, 'Parent global: 123.*Parent global: 456.*',
+ output_nicerizer=lambda x, err: x.replace('\n', '*'),
+ post_build=add_pre_run_and_checks,
+ extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/time.h,libc/langinfo.h'])
+ Settings.INCLUDE_FULL_LIBRARY = 0
+
+ def test_dlfcn_varargs(self):
+ if Settings.ASM_JS: return self.skip('TODO: dlopen in asm')
+
+ Settings.LINKABLE = 1
+ Settings.NAMED_GLOBALS = 1
+
+ if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize things that prevent shared objects from working')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
+
+ lib_src = r'''
+ void print_ints(int n, ...);
+ extern "C" void func() {
+ print_ints(2, 13, 42);
+ }
+ '''
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, 'liblib.cpp')
+ Settings.BUILD_AS_SHARED_LIB = 1
+ Settings.EXPORTED_FUNCTIONS = ['_func']
+ self.build(lib_src, dirname, filename)
+ shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
+
+ src = r'''
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <dlfcn.h>
+
+ void print_ints(int n, ...) {
+ va_list args;
+ va_start(args, n);
+ for (int i = 0; i < n; i++) {
+ printf("%d\n", va_arg(args, int));
+ }
+ va_end(args);
+ }
+
+ int main() {
+ void* lib_handle;
+ void (*fptr)();
+
+ print_ints(2, 100, 200);
+
+ lib_handle = dlopen("liblib.so", RTLD_NOW);
+ fptr = (void (*)())dlsym(lib_handle, "func");
+ fptr();
+
+ return 0;
+ }
+ '''
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.EXPORTED_FUNCTIONS = ['_main']
+ add_pre_run_and_checks = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);"
+ )
+ open(filename, 'w').write(src)
+'''
+ self.do_run(src, '100\n200\n13\n42\n',
+ post_build=add_pre_run_and_checks)
+
+ def test_dlfcn_self(self):
+ if Settings.USE_TYPED_ARRAYS == 1: return self.skip('Does not work with USE_TYPED_ARRAYS=1')
+ Settings.DLOPEN_SUPPORT = 1
+
+ src = r'''
+#include <stdio.h>
+#include <dlfcn.h>
+
+int global = 123;
+
+extern "C" __attribute__((noinline)) void foo(int x) {
+printf("%d\n", x);
+}
+
+extern "C" __attribute__((noinline)) void repeatable() {
+void* self = dlopen(NULL, RTLD_LAZY);
+int* global_ptr = (int*)dlsym(self, "global");
+void (*foo_ptr)(int) = (void (*)(int))dlsym(self, "foo");
+foo_ptr(*global_ptr);
+dlclose(self);
+}
+
+int main() {
+repeatable();
+repeatable();
+return 0;
+}'''
+ def post(filename):
+ with open(filename) as f:
+ for line in f:
+ if 'var SYMBOL_TABLE' in line:
+ table = line
+ break
+ else:
+ raise Exception('Could not find symbol table!')
+ import json
+ table = json.loads(table[table.find('{'):table.rfind('}')+1])
+ actual = list(sorted(table.keys()))
+ # ensure there aren't too many globals; we don't want unnamed_addr
+ assert actual == ['_foo', '_global', '_main', '_repeatable'], \
+ "Symbol table does not match: %s" % actual
+
+ self.do_run(src, '123\n123', post_build=(None, post))
+
+ def test_rand(self):
+ return self.skip('rand() is now random') # FIXME
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ printf("%d\n", rand());
+ printf("%d\n", rand());
+
+ srand(123);
+ printf("%d\n", rand());
+ printf("%d\n", rand());
+ srand(123);
+ printf("%d\n", rand());
+ printf("%d\n", rand());
+
+ unsigned state = 0;
+ int r;
+ r = rand_r(&state);
+ printf("%d, %u\n", r, state);
+ r = rand_r(&state);
+ printf("%d, %u\n", r, state);
+ state = 0;
+ r = rand_r(&state);
+ printf("%d, %u\n", r, state);
+
+ return 0;
+ }
+ '''
+ expected = '''
+ 1250496027
+ 1116302336
+ 440917656
+ 1476150784
+ 440917656
+ 1476150784
+ 12345, 12345
+ 1406932606, 3554416254
+ 12345, 12345
+ '''
+ self.do_run(src, re.sub(r'(^|\n)\s+', r'\1', expected))
+
+ def test_strtod(self):
+ if self.emcc_args is None: return self.skip('needs emcc for libc')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ char* endptr;
+
+ printf("\n");
+ printf("%g\n", strtod("0", &endptr));
+ printf("%g\n", strtod("0.", &endptr));
+ printf("%g\n", strtod("0.0", &endptr));
+ printf("%g\n", strtod("-0.0", &endptr));
+ printf("%g\n", strtod("1", &endptr));
+ printf("%g\n", strtod("1.", &endptr));
+ printf("%g\n", strtod("1.0", &endptr));
+ printf("%g\n", strtod("z1.0", &endptr));
+ printf("%g\n", strtod("0.5", &endptr));
+ printf("%g\n", strtod(".5", &endptr));
+ printf("%g\n", strtod(".a5", &endptr));
+ printf("%g\n", strtod("123", &endptr));
+ printf("%g\n", strtod("123.456", &endptr));
+ printf("%g\n", strtod("-123.456", &endptr));
+ printf("%g\n", strtod("1234567891234567890", &endptr));
+ printf("%g\n", strtod("1234567891234567890e+50", &endptr));
+ printf("%g\n", strtod("84e+220", &endptr));
+ printf("%g\n", strtod("123e-50", &endptr));
+ printf("%g\n", strtod("123e-250", &endptr));
+ printf("%g\n", strtod("123e-450", &endptr));
+
+ char str[] = " 12.34e56end";
+ printf("%g\n", strtod(str, &endptr));
+ printf("%d\n", endptr - str);
+ printf("%g\n", strtod("84e+420", &endptr));
+
+ printf("%.12f\n", strtod("1.2345678900000000e+08", NULL));
+
+ return 0;
+ }
+ '''
+ expected = '''
+ 0
+ 0
+ 0
+ -0
+ 1
+ 1
+ 1
+ 0
+ 0.5
+ 0.5
+ 0
+ 123
+ 123.456
+ -123.456
+ 1.23457e+18
+ 1.23457e+68
+ 8.4e+221
+ 1.23e-48
+ 1.23e-248
+ 0
+ 1.234e+57
+ 10
+ inf
+ 123456789.000000000000
+ '''
+
+ self.do_run(src, re.sub(r'\n\s+', '\n', expected))
+ self.do_run(src.replace('strtod', 'strtold'), re.sub(r'\n\s+', '\n', expected)) # XXX add real support for long double
+
+ def test_strtok(self):
+ src = r'''
+ #include<stdio.h>
+ #include<string.h>
+
+ int main() {
+ char test[80], blah[80];
+ char *sep = "\\/:;=-";
+ char *word, *phrase, *brkt, *brkb;
+
+ strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
+
+ for (word = strtok_r(test, sep, &brkt); word; word = strtok_r(NULL, sep, &brkt)) {
+ strcpy(blah, "blah:blat:blab:blag");
+ for (phrase = strtok_r(blah, sep, &brkb); phrase; phrase = strtok_r(NULL, sep, &brkb)) {
+ printf("at %s:%s\n", word, phrase);
+ }
+ }
+ return 0;
+ }
+ '''
+
+ expected = '''at This:blah
+at This:blat
+at This:blab
+at This:blag
+at is.a:blah
+at is.a:blat
+at is.a:blab
+at is.a:blag
+at test:blah
+at test:blat
+at test:blab
+at test:blag
+at of:blah
+at of:blat
+at of:blab
+at of:blag
+at the:blah
+at the:blat
+at the:blab
+at the:blag
+at string:blah
+at string:blat
+at string:blab
+at string:blag
+at tokenizer:blah
+at tokenizer:blat
+at tokenizer:blab
+at tokenizer:blag
+at function.:blah
+at function.:blat
+at function.:blab
+at function.:blag
+'''
+ self.do_run(src, expected)
+
+ def test_parseInt(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('Q1 and I64_1 do not mix well yet')
+ src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_transtrcase(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ int main() {
+ char szToupr[] = "hello, ";
+ char szTolwr[] = "EMSCRIPTEN";
+ strupr(szToupr);
+ strlwr(szTolwr);
+ printf(szToupr);
+ printf(szTolwr);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'HELLO, emscripten')
+
+ def test_printf(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
+ self.banned_js_engines = [NODE_JS, V8_ENGINE] # SpiderMonkey and V8 do different things to float64 typed arrays, un-NaNing, etc.
+ src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read()
+ expected = [open(path_from_root('tests', 'printf', 'output.txt'), 'r').read(),
+ open(path_from_root('tests', 'printf', 'output_i64_1.txt'), 'r').read()]
+ self.do_run(src, expected)
+
+ def test_printf_2(self):
+ src = r'''
+ #include <stdio.h>
+
+ int main() {
+ char c = '1';
+ short s = 2;
+ int i = 3;
+ long long l = 4;
+ float f = 5.5;
+ double d = 6.6;
+
+ printf("%c,%hd,%d,%lld,%.1f,%.1llf\n", c, s, i, l, f, d);
+ printf("%#x,%#x\n", 1, 0);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '1,2,3,4,5.5,6.6\n0x1,0\n')
+
+ def test_vprintf(self):
+ src = r'''
+ #include <stdio.h>
+ #include <stdarg.h>
+
+ void print(char* format, ...) {
+ va_list args;
+ va_start (args, format);
+ vprintf (format, args);
+ va_end (args);
+ }
+
+ int main () {
+ print("Call with %d variable argument.\n", 1);
+ print("Call with %d variable %s.\n", 2, "arguments");
+
+ return 0;
+ }
+ '''
+ expected = '''
+ Call with 1 variable argument.
+ Call with 2 variable arguments.
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
+
+ def test_vsnprintf(self):
+ if self.emcc_args is None: return self.skip('needs i64 math')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdarg.h>
+ #include <stdint.h>
+
+ void printy(const char *f, ...)
+ {
+ char buffer[256];
+ va_list args;
+ va_start(args, f);
+ vsnprintf(buffer, 256, f, args);
+ puts(buffer);
+ va_end(args);
+ }
+
+ int main(int argc, char **argv) {
+ int64_t x = argc - 1;
+ int64_t y = argc - 1 + 0x400000;
+ if (x % 3 == 2) y *= 2;
+
+ printy("0x%llx_0x%llx", x, y);
+ printy("0x%llx_0x%llx", x, x);
+ printy("0x%llx_0x%llx", y, x);
+ printy("0x%llx_0x%llx", y, y);
+
+ {
+ uint64_t A = 0x800000;
+ uint64_t B = 0x800000000000ULL;
+ printy("0x%llx_0x%llx", A, B);
+ }
+ {
+ uint64_t A = 0x800;
+ uint64_t B = 0x12340000000000ULL;
+ printy("0x%llx_0x%llx", A, B);
+ }
+ {
+ uint64_t A = 0x000009182746756;
+ uint64_t B = 0x192837465631ACBDULL;
+ printy("0x%llx_0x%llx", A, B);
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''0x0_0x400000
+0x0_0x0
+0x400000_0x0
+0x400000_0x400000
+0x800000_0x800000000000
+0x800_0x12340000000000
+0x9182746756_0x192837465631acbd
+''')
+
+ def test_printf_more(self):
+ src = r'''
+ #include <stdio.h>
+ int main() {
+ int size = snprintf(NULL, 0, "%s %d %.2f\n", "me and myself", 25, 1.345);
+ char buf[size];
+ snprintf(buf, size, "%s %d %.2f\n", "me and myself", 25, 1.345);
+ printf("%d : %s\n", size, buf);
+ char *buff = NULL;
+ asprintf(&buff, "%d waka %d\n", 21, 95);
+ puts(buff);
+ return 0;
+ }
+ '''
+ self.do_run(src, '22 : me and myself 25 1.34\n21 waka 95\n')
+
+ def test_perrar(self):
+ src = r'''
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <stdio.h>
+
+ int main( int argc, char** argv ){
+ int retval = open( "NonExistingFile", O_RDONLY );
+ if( retval == -1 )
+ perror( "Cannot open NonExistingFile" );
+ return 0;
+ }
+ '''
+ self.do_run(src, 'Cannot open NonExistingFile: No such file or directory\n')
+
+ def test_atoX(self):
+ if self.emcc_args is None: return self.skip('requires ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main () {
+ printf("%d*", atoi(""));
+ printf("%d*", atoi("a"));
+ printf("%d*", atoi(" b"));
+ printf("%d*", atoi(" c "));
+ printf("%d*", atoi("6"));
+ printf("%d*", atoi(" 5"));
+ printf("%d*", atoi("4 "));
+ printf("%d*", atoi("3 6"));
+ printf("%d*", atoi(" 3 7"));
+ printf("%d*", atoi("9 d"));
+ printf("%d\n", atoi(" 8 e"));
+ printf("%d*", atol(""));
+ printf("%d*", atol("a"));
+ printf("%d*", atol(" b"));
+ printf("%d*", atol(" c "));
+ printf("%d*", atol("6"));
+ printf("%d*", atol(" 5"));
+ printf("%d*", atol("4 "));
+ printf("%d*", atol("3 6"));
+ printf("%d*", atol(" 3 7"));
+ printf("%d*", atol("9 d"));
+ printf("%d\n", atol(" 8 e"));
+ printf("%lld*", atoll("6294967296"));
+ printf("%lld*", atoll(""));
+ printf("%lld*", atoll("a"));
+ printf("%lld*", atoll(" b"));
+ printf("%lld*", atoll(" c "));
+ printf("%lld*", atoll("6"));
+ printf("%lld*", atoll(" 5"));
+ printf("%lld*", atoll("4 "));
+ printf("%lld*", atoll("3 6"));
+ printf("%lld*", atoll(" 3 7"));
+ printf("%lld*", atoll("9 d"));
+ printf("%lld\n", atoll(" 8 e"));
+ return 0;
+ }
+ '''
+ self.do_run(src, '0*0*0*0*6*5*4*3*3*9*8\n0*0*0*0*6*5*4*3*3*9*8\n6294967296*0*0*0*0*6*5*4*3*3*9*8\n')
+
+ def test_strstr(self):
+ src = r'''
+ #include <stdio.h>
+ #include <string.h>
+
+ int main()
+ {
+ printf("%d\n", !!strstr("\\n", "\\n"));
+ printf("%d\n", !!strstr("cheezy", "ez"));
+ printf("%d\n", !!strstr("cheeezy", "ez"));
+ printf("%d\n", !!strstr("cheeeeeeeeeezy", "ez"));
+ printf("%d\n", !!strstr("cheeeeeeeeee1zy", "ez"));
+ printf("%d\n", !!strstr("che1ezy", "ez"));
+ printf("%d\n", !!strstr("che1ezy", "che"));
+ printf("%d\n", !!strstr("ce1ezy", "che"));
+ printf("%d\n", !!strstr("ce1ezy", "ezy"));
+ printf("%d\n", !!strstr("ce1ezyt", "ezy"));
+ printf("%d\n", !!strstr("ce1ez1y", "ezy"));
+ printf("%d\n", !!strstr("cheezy", "a"));
+ printf("%d\n", !!strstr("cheezy", "b"));
+ printf("%d\n", !!strstr("cheezy", "c"));
+ printf("%d\n", !!strstr("cheezy", "d"));
+ printf("%d\n", !!strstr("cheezy", "g"));
+ printf("%d\n", !!strstr("cheezy", "h"));
+ printf("%d\n", !!strstr("cheezy", "i"));
+ printf("%d\n", !!strstr("cheezy", "e"));
+ printf("%d\n", !!strstr("cheezy", "x"));
+ printf("%d\n", !!strstr("cheezy", "y"));
+ printf("%d\n", !!strstr("cheezy", "z"));
+ printf("%d\n", !!strstr("cheezy", "_"));
+
+ const char *str = "a big string";
+ printf("%d\n", strstr(str, "big") - str);
+ return 0;
+ }
+ '''
+ self.do_run(src, '''1
+1
+1
+1
+0
+1
+1
+0
+1
+1
+0
+0
+0
+1
+0
+0
+1
+0
+1
+0
+1
+1
+0
+2
+''')
+
+ def test_sscanf(self):
+ if self.emcc_args is None: return self.skip('needs emcc for libc')
+
+ src = r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ int main () {
+ #define CHECK(str) \
+ { \
+ char name[1000]; \
+ memset(name, 0, 1000); \
+ int prio = 99; \
+ sscanf(str, "%s %d", name, &prio); \
+ printf("%s : %d\n", name, prio); \
+ }
+ CHECK("en-us 2");
+ CHECK("en-r");
+ CHECK("en 3");
+
+ printf("%f, %f\n", atof("1.234567"), atof("cheez"));
+
+ char float_formats[] = "fegE";
+ char format[] = "%_";
+ for(int i = 0; i < 4; ++i) {
+ format[1] = float_formats[i];
+
+ float n = -1;
+ sscanf(" 2.8208", format, &n);
+ printf("%.4f\n", n);
+
+ float a = -1;
+ sscanf("-3.03", format, &a);
+ printf("%.4f\n", a);
+ }
+
+ char buffy[100];
+ sscanf("cheez some thing moar 123\nyet more\n", "cheez %s", buffy);
+ printf("|%s|\n", buffy);
+ sscanf("cheez something\nmoar 123\nyet more\n", "cheez %s", buffy);
+ printf("|%s|\n", buffy);
+ sscanf("cheez somethingmoar\tyet more\n", "cheez %s", buffy);
+ printf("|%s|\n", buffy);
+
+ int numverts = -1;
+ printf("%d\n", sscanf(" numverts 1499\n", " numverts %d", &numverts)); // white space is the same, even if tab vs space
+ printf("%d\n", numverts);
+
+ int index;
+ float u, v;
+ short start, count;
+ printf("%d\n", sscanf(" vert 87 ( 0.481565 0.059481 ) 0 1\n", " vert %d ( %f %f ) %hu %hu", &index, &u, &v, &start, &count));
+ printf("%d,%.6f,%.6f,%hu,%hu\n", index, u, v, start, count);
+
+ int neg, neg2, neg3 = 0;
+ printf("%d\n", sscanf("-123 -765 -34-6", "%d %u %d", &neg, &neg2, &neg3));
+ printf("%d,%u,%d\n", neg, neg2, neg3);
+
+ {
+ int a = 0;
+ sscanf("1", "%i", &a);
+ printf("%i\n", a);
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'en-us : 2\nen-r : 99\nen : 3\n1.234567, 0.000000\n2.8208\n-3.0300\n2.8208\n-3.0300\n2.8208\n-3.0300\n2.8208\n-3.0300\n|some|\n|something|\n|somethingmoar|\n' +
+ '1\n1499\n' +
+ '5\n87,0.481565,0.059481,0,1\n' +
+ '3\n-123,4294966531,-34\n' +
+ '1\n')
+
+ def test_sscanf_2(self):
+ # doubles
+ if Settings.USE_TYPED_ARRAYS == 2:
+ for ftype in ['float', 'double']:
+ src = r'''
+ #include <stdio.h>
+
+ int main(){
+ char strval1[] = "1.2345678901";
+ char strval2[] = "1.23456789e5";
+ char strval3[] = "1.23456789E5";
+ char strval4[] = "1.2345678e-5";
+ char strval5[] = "1.2345678E-5";
+ double dblval = 1.2345678901;
+ double tstval;
+
+ sscanf(strval1, "%lf", &tstval);
+ if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
+ else printf("Pass: %lf %lf\n", tstval, dblval);
+
+ sscanf(strval2, "%lf", &tstval);
+ dblval = 123456.789;
+ if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
+ else printf("Pass: %lf %lf\n", tstval, dblval);
+
+ sscanf(strval3, "%lf", &tstval);
+ dblval = 123456.789;
+ if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
+ else printf("Pass: %lf %lf\n", tstval, dblval);
+
+ sscanf(strval4, "%lf", &tstval);
+ dblval = 0.000012345678;
+ if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
+ else printf("Pass: %lf %lf\n", tstval, dblval);
+
+ sscanf(strval5, "%lf", &tstval);
+ dblval = 0.000012345678;
+ if(dblval != tstval) printf("FAIL: Values are not equal: %lf %lf\n", dblval, tstval);
+ else printf("Pass: %lf %lf\n", tstval, dblval);
+
+ return 0;
+ }
+ '''
+ if ftype == 'float':
+ self.do_run(src.replace('%lf', '%f').replace('double', 'float'), '''Pass: 1.234568 1.234568
+Pass: 123456.789063 123456.789063
+Pass: 123456.789063 123456.789063
+Pass: 0.000012 0.000012
+Pass: 0.000012 0.000012''')
+ else:
+ self.do_run(src, '''Pass: 1.234568 1.234568
+Pass: 123456.789000 123456.789000
+Pass: 123456.789000 123456.789000
+Pass: 0.000012 0.000012
+Pass: 0.000012 0.000012''')
+
+ def test_sscanf_n(self):
+ src = r'''
+ #include<stdio.h>
+ int main() {
+ char *line = "version 1.0";
+ int i, l, lineno;
+ char word[80];
+ if (sscanf(line, "%s%n", word, &l) != 1) {
+ printf("Header format error, line %d\n", lineno);
+ }
+ printf("[DEBUG] word 1: %s, l: %d\n", word, l);
+
+ int x = sscanf("one %n two", "%s %n", word, &l);
+ printf("%d,%s,%d\n", x, word, l);
+ {
+ int a, b, c, count;
+ count = sscanf("12345 6789", "%d %n%d", &a, &b, &c);
+ printf("%i %i %i %i\n", count, a, b, c);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, '''[DEBUG] word 1: version, l: 7\n1,one,4\n2 12345 6 6789\n''')
+
+ def test_sscanf_whitespace(self):
+ src = r'''
+ #include<stdio.h>
+
+ int main() {
+ short int x;
+ short int y;
+
+ const char* buffer[] = {
+ "173,16",
+ " 16,173",
+ "183, 173",
+ " 17, 287",
+ " 98, 123, "
+ };
+
+ for (int i=0; i<5; ++i) {
+ sscanf(buffer[i], "%hd,%hd", &x, &y);
+ printf("%d:%d,%d ", i, x, y);
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''0:173,16 1:16,173 2:183,173 3:17,287 4:98,123''')
+
+ def test_sscanf_other_whitespace(self):
+ Settings.SAFE_HEAP = 0 # use i16s in printf
+
+ src = r'''
+ #include<stdio.h>
+
+ int main() {
+ short int x;
+ short int y;
+
+ const char* buffer[] = {
+ "\t2\t3\t", /* TAB - horizontal tab */
+ "\t\t5\t\t7\t\t",
+ "\n11\n13\n", /* LF - line feed */
+ "\n\n17\n\n19\n\n",
+ "\v23\v29\v", /* VT - vertical tab */
+ "\v\v31\v\v37\v\v",
+ "\f41\f43\f", /* FF - form feed */
+ "\f\f47\f\f53\f\f",
+ "\r59\r61\r", /* CR - carrage return */
+ "\r\r67\r\r71\r\r"
+ };
+
+ for (int i=0; i<10; ++i) {
+ x = 0; y = 0;
+ sscanf(buffer[i], " %d %d ", &x, &y);
+ printf("%d, %d, ", x, y);
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, ''')
+
+ def test_sscanf_3(self):
+ # i64
+ if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('64-bit sscanf only supported in ta2')
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+
+ int main(){
+
+ int64_t s, m, l;
+ printf("%d\n", sscanf("123 1073741823 1125899906842620", "%lld %lld %lld", &s, &m, &l));
+ printf("%lld,%lld,%lld\n", s, m, l);
+
+ int64_t negS, negM, negL;
+ printf("%d\n", sscanf("-123 -1073741823 -1125899906842620", "%lld %lld %lld", &negS, &negM, &negL));
+ printf("%lld,%lld,%lld\n", negS, negM, negL);
+
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '3\n123,1073741823,1125899906842620\n' +
+ '3\n-123,-1073741823,-1125899906842620\n')
+
+ def test_sscanf_4(self):
+ src = r'''
+ #include <stdio.h>
+
+ int main()
+ {
+ char pYear[16], pMonth[16], pDay[16], pDate[64];
+ printf("%d\n", sscanf("Nov 19 2012", "%s%s%s", pMonth, pDay, pYear));
+ printf("day %s, month %s, year %s \n", pDay, pMonth, pYear);
+ return(0);
+ }
+ '''
+ self.do_run(src, '3\nday 19, month Nov, year 2012');
+
+ def test_sscanf_5(self):
+ src = r'''
+ #include "stdio.h"
+
+ static const char *colors[] = {
+ " c black",
+ ". c #001100",
+ "X c #111100"
+ };
+
+ int main(){
+ unsigned char code;
+ char color[32];
+ int rcode;
+ for(int i = 0; i < 3; i++) {
+ rcode = sscanf(colors[i], "%c c %s", &code, color);
+ printf("%i, %c, %s\n", rcode, code, color);
+ }
+ }
+ '''
+ self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100');
+
+ def test_sscanf_6(self):
+ src = r'''
+ #include <stdio.h>
+ #include <string.h>
+ int main()
+ {
+ char *date = "18.07.2013w";
+ char c[10];
+ memset(c, 0, 10);
+ int y, m, d, i;
+ i = sscanf(date, "%d.%d.%4d%c", &d, &m, &y, c);
+ printf("date: %s; day %2d, month %2d, year %4d, extra: %c, %d\n", date, d, m, y, c[0], i);
+ i = sscanf(date, "%d.%d.%3c", &d, &m, c);
+ printf("date: %s; day %2d, month %2d, year %4d, extra: %s, %d\n", date, d, m, y, c, i);
+ }
+ '''
+ self.do_run(src, '''date: 18.07.2013w; day 18, month 7, year 2013, extra: w, 4
+date: 18.07.2013w; day 18, month 7, year 2013, extra: 201, 3
+''');
+
+ def test_sscanf_skip(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip("need ta2 for full i64")
+
+ src = r'''
+ #include <stdint.h>
+ #include <stdio.h>
+
+ int main(){
+ int val1;
+ printf("%d\n", sscanf("10 20 30 40", "%*lld %*d %d", &val1));
+ printf("%d\n", val1);
+
+ int64_t large, val2;
+ printf("%d\n", sscanf("1000000 -1125899906842620 -123 -1073741823", "%lld %*lld %ld %*d", &large, &val2));
+ printf("%lld,%d\n", large, val2);
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '1\n30\n2\n1000000,-123\n')
+
+ def test_sscanf_caps(self):
+ src = r'''
+ #include "stdio.h"
+
+ int main(){
+ unsigned int a;
+ float e, f, g;
+ sscanf("a 1.1 1.1 1.1", "%X %E %F %G", &a, &e, &f, &g);
+ printf("%d %.1F %.1F %.1F\n", a, e, f, g);
+ }
+ '''
+ self.do_run(src, '10 1.1 1.1 1.1');
+
+ def test_langinfo(self):
+ src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
+ expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
+ self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h'])
+
+ def test_files(self):
+ if self.emcc_args is not None and '-O2' in self.emcc_args:
+ self.emcc_args += ['--closure', '1'] # Use closure here, to test we don't break FS stuff
+
+ Settings.CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both.
+ post = '''
+def process(filename):
+ src = \'\'\'
+ var Module = {
+ 'noFSInit': true,
+ 'preRun': function() {
+ FS.createLazyFile('/', 'test.file', 'test.file', true, false);
+ // Test FS_* exporting
+ Module['FS_createDataFile']('/', 'somefile.binary', [100, 200, 50, 25, 10, 77, 123], true, false); // 200 becomes -56, since signed chars are used in memory
+ var test_files_input = 'hi there!';
+ var test_files_input_index = 0;
+ FS.init(function() {
+ return test_files_input.charCodeAt(test_files_input_index++) || null;
+ });
+ }
+ };
+ \'\'\' + open(filename, 'r').read()
+ open(filename, 'w').write(src)
+'''
+ other = open(os.path.join(self.get_dir(), 'test.file'), 'w')
+ other.write('some data');
+ other.close()
+
+ src = open(path_from_root('tests', 'files.cpp'), 'r').read()
+ self.do_run(src, ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\n'),
+ post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+
+ def test_files_m(self):
+ # Test for Module.stdin etc.
+
+ Settings.CORRECT_SIGNS = 1
+
+ post = '''
+def process(filename):
+ src = \'\'\'
+ var data = [10, 20, 40, 30];
+ var Module = {
+ stdin: function() { return data.pop() || null },
+ stdout: function(x) { Module.print('got: ' + x) }
+ };
+ \'\'\' + open(filename, 'r').read()
+ open(filename, 'w').write(src)
+'''
+ src = r'''
+ #include <stdio.h>
+ #include <unistd.h>
+
+ int main () {
+ char c;
+ fprintf(stderr, "isatty? %d,%d,%d\n", isatty(fileno(stdin)), isatty(fileno(stdout)), isatty(fileno(stderr)));
+ while ((c = fgetc(stdin)) != EOF) {
+ putc(c+5, stdout);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, ('got: 35\ngot: 45\ngot: 25\ngot: 15\nisatty? 0,0,1\n', 'isatty? 0,0,1\ngot: 35\ngot: 45\ngot: 25\ngot: 15\n'), post_build=post)
+
+ def test_fwrite_0(self):
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main ()
+ {
+ FILE *fh;
+
+ fh = fopen("a.txt", "wb");
+ if (!fh) exit(1);
+ fclose(fh);
+
+ fh = fopen("a.txt", "rb");
+ if (!fh) exit(1);
+
+ char data[] = "foobar";
+ size_t written = fwrite(data, 1, sizeof(data), fh);
+
+ printf("written=%zu\n", written);
+ }
+ '''
+ self.do_run(src, 'written=0')
+
+ def test_fgetc_ungetc(self):
+ src = open(path_from_root('tests', 'stdio', 'test_fgetc_ungetc.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_fgetc_unsigned(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = r'''
+ #include <stdio.h>
+ int main() {
+ FILE *file = fopen("file_with_byte_234.txt", "rb");
+ int c = fgetc(file);
+ printf("*%d\n", c);
+ }
+ '''
+ open('file_with_byte_234.txt', 'wb').write('\xea')
+ self.emcc_args += ['--embed-file', 'file_with_byte_234.txt']
+ self.do_run(src, '*234\n')
+
+ def test_fgets_eol(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = r'''
+ #include <stdio.h>
+ char buf[32];
+ int main()
+ {
+ char *r = "SUCCESS";
+ FILE *f = fopen("eol.txt", "r");
+ while (fgets(buf, 32, f) != NULL) {
+ if (buf[0] == '\0') {
+ r = "FAIL";
+ break;
+ }
+ }
+ printf("%s\n", r);
+ fclose(f);
+ return 0;
+ }
+ '''
+ open('eol.txt', 'wb').write('\n')
+ self.emcc_args += ['--embed-file', 'eol.txt']
+ self.do_run(src, 'SUCCESS\n')
+
+ def test_fscanf(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ open(os.path.join(self.get_dir(), 'three_numbers.txt'), 'w').write('''-1 0.1 -.1''')
+ src = r'''
+ #include <stdio.h>
+ #include <assert.h>
+ #include <float.h>
+ int main()
+ {
+ float x = FLT_MAX, y = FLT_MAX, z = FLT_MAX;
+
+ FILE* fp = fopen("three_numbers.txt", "r");
+ if (fp) {
+ int match = fscanf(fp, " %f %f %f ", &x, &y, &z);
+ printf("match = %d\n", match);
+ printf("x = %0.1f, y = %0.1f, z = %0.1f\n", x, y, z);
+ } else {
+ printf("failed to open three_numbers.txt\n");
+ }
+ return 0;
+ }
+ '''
+ self.emcc_args += ['--embed-file', 'three_numbers.txt']
+ self.do_run(src, 'match = 3\nx = -1.0, y = 0.1, z = -0.1\n')
+
+ def test_readdir(self):
+ src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat(self):
+ src = open(path_from_root('tests', 'stat', 'test_stat.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat_chmod(self):
+ src = open(path_from_root('tests', 'stat', 'test_chmod.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat_mknod(self):
+ src = open(path_from_root('tests', 'stat', 'test_mknod.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_fcntl(self):
+ add_pre_run = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createDataFile('/', 'test', 'abcdef', true, true);"
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'fcntl', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'fcntl', 'output.txt'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+
+ def test_fcntl_open(self):
+ src = open(path_from_root('tests', 'fcntl-open', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read()
+ self.do_run(src, expected, force_c=True, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+
+ def test_fcntl_misc(self):
+ add_pre_run = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createDataFile('/', 'test', 'abcdef', true, true);"
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'fcntl-misc', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'fcntl-misc', 'output.txt'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+
+ def test_poll(self):
+ add_pre_run = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ \'\'\'
+ FS.createDataFile('/', 'file', 'abcdef', true, true);
+ FS.createDevice('/', 'device', function() {}, function() {});
+ \'\'\'
+ )
+ open(filename, 'w').write(src)
+'''
+ src = r'''
+ #include <stdio.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <poll.h>
+
+ int main() {
+ struct pollfd multi[5];
+ multi[0].fd = open("/file", O_RDONLY, 0777);
+ multi[1].fd = open("/device", O_RDONLY, 0777);
+ multi[2].fd = 123;
+ multi[3].fd = open("/file", O_RDONLY, 0777);
+ multi[4].fd = open("/file", O_RDONLY, 0777);
+ multi[0].events = POLLIN | POLLOUT | POLLNVAL | POLLERR;
+ multi[1].events = POLLIN | POLLOUT | POLLNVAL | POLLERR;
+ multi[2].events = POLLIN | POLLOUT | POLLNVAL | POLLERR;
+ multi[3].events = 0x00;
+ multi[4].events = POLLOUT | POLLNVAL | POLLERR;
+
+ printf("ret: %d\n", poll(multi, 5, 123));
+ printf("errno: %d\n", errno);
+ printf("multi[0].revents: %d\n", multi[0].revents == (POLLIN | POLLOUT));
+ printf("multi[1].revents: %d\n", multi[1].revents == (POLLIN | POLLOUT));
+ printf("multi[2].revents: %d\n", multi[2].revents == POLLNVAL);
+ printf("multi[3].revents: %d\n", multi[3].revents == 0);
+ printf("multi[4].revents: %d\n", multi[4].revents == POLLOUT);
+
+ return 0;
+ }
+ '''
+ expected = r'''
+ ret: 4
+ errno: 0
+ multi[0].revents: 1
+ multi[1].revents: 1
+ multi[2].revents: 1
+ multi[3].revents: 1
+ multi[4].revents: 1
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h,poll.h'])
+
+ def test_statvfs(self):
+ src = r'''
+ #include <stdio.h>
+ #include <errno.h>
+ #include <sys/statvfs.h>
+
+ int main() {
+ struct statvfs s;
+
+ printf("result: %d\n", statvfs("/test", &s));
+ printf("errno: %d\n", errno);
+
+ printf("f_bsize: %lu\n", s.f_bsize);
+ printf("f_frsize: %lu\n", s.f_frsize);
+ printf("f_blocks: %lu\n", s.f_blocks);
+ printf("f_bfree: %lu\n", s.f_bfree);
+ printf("f_bavail: %lu\n", s.f_bavail);
+ printf("f_files: %d\n", s.f_files > 5);
+ printf("f_ffree: %lu\n", s.f_ffree);
+ printf("f_favail: %lu\n", s.f_favail);
+ printf("f_fsid: %lu\n", s.f_fsid);
+ printf("f_flag: %lu\n", s.f_flag);
+ printf("f_namemax: %lu\n", s.f_namemax);
+
+ return 0;
+ }
+ '''
+ expected = r'''
+ result: 0
+ errno: 0
+ f_bsize: 4096
+ f_frsize: 4096
+ f_blocks: 1000000
+ f_bfree: 500000
+ f_bavail: 500000
+ f_files: 1
+ f_ffree: 1000000
+ f_favail: 1000000
+ f_fsid: 42
+ f_flag: 2
+ f_namemax: 255
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
+
+ def test_libgen(self):
+ src = r'''
+ #include <stdio.h>
+ #include <libgen.h>
+
+ int main() {
+ char p1[16] = "/usr/lib", p1x[16] = "/usr/lib";
+ printf("%s -> ", p1);
+ printf("%s : %s\n", dirname(p1x), basename(p1));
+
+ char p2[16] = "/usr", p2x[16] = "/usr";
+ printf("%s -> ", p2);
+ printf("%s : %s\n", dirname(p2x), basename(p2));
+
+ char p3[16] = "/usr/", p3x[16] = "/usr/";
+ printf("%s -> ", p3);
+ printf("%s : %s\n", dirname(p3x), basename(p3));
+
+ char p4[16] = "/usr/lib///", p4x[16] = "/usr/lib///";
+ printf("%s -> ", p4);
+ printf("%s : %s\n", dirname(p4x), basename(p4));
+
+ char p5[16] = "/", p5x[16] = "/";
+ printf("%s -> ", p5);
+ printf("%s : %s\n", dirname(p5x), basename(p5));
+
+ char p6[16] = "///", p6x[16] = "///";
+ printf("%s -> ", p6);
+ printf("%s : %s\n", dirname(p6x), basename(p6));
+
+ char p7[16] = "/usr/../lib/..", p7x[16] = "/usr/../lib/..";
+ printf("%s -> ", p7);
+ printf("%s : %s\n", dirname(p7x), basename(p7));
+
+ char p8[16] = "", p8x[16] = "";
+ printf("(empty) -> %s : %s\n", dirname(p8x), basename(p8));
+
+ printf("(null) -> %s : %s\n", dirname(0), basename(0));
+
+ return 0;
+ }
+ '''
+ expected = '''
+ /usr/lib -> /usr : lib
+ /usr -> / : usr
+ /usr/ -> / : usr
+ /usr/lib/// -> /usr : lib
+ / -> / : /
+ /// -> / : /
+ /usr/../lib/.. -> /usr/../lib : ..
+ (empty) -> . : .
+ (null) -> . : .
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
+
+ def test_utime(self):
+ src = open(path_from_root('tests', 'utime', 'test_utime.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_utf(self):
+ self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well
+ Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc']
+
+ src = r'''
+ #include <stdio.h>
+ #include <emscripten.h>
+
+ int main() {
+ char *c = "μ†ℱ ╋ℯ╳╋";
+ printf("%d %d %d %d %s\n", c[0]&0xff, c[1]&0xff, c[2]&0xff, c[3]&0xff, c);
+ emscripten_run_script("cheez = _malloc(100);"
+ "Module.writeStringToMemory(\"μ†ℱ ╋ℯ╳╋\", cheez);"
+ "Module.print([Pointer_stringify(cheez), Module.getValue(cheez, 'i8')&0xff, Module.getValue(cheez+1, 'i8')&0xff, Module.getValue(cheez+2, 'i8')&0xff, Module.getValue(cheez+3, 'i8')&0xff, ]);");
+ }
+ '''
+ self.do_run(src, '206 188 226 128 μ†ℱ ╋ℯ╳╋\nμ†ℱ ╋ℯ╳╋,206,188,226,128\n');
+
+ def test_direct_string_constant_usage(self):
+ if self.emcc_args is None: return self.skip('requires libcxx')
+
+ src = '''
+ #include <iostream>
+ template<int i>
+ void printText( const char (&text)[ i ] )
+ {
+ std::cout << text;
+ }
+ int main()
+ {
+ printText( "some string constant" );
+ return 0;
+ }
+ '''
+ self.do_run(src, "some string constant")
+
+ def test_std_cout_new(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ src = '''
+ #include <iostream>
+
+ struct NodeInfo { //structure that we want to transmit to our shaders
+ float x;
+ float y;
+ float s;
+ float c;
+ };
+ const int nbNodes = 100;
+ NodeInfo * data = new NodeInfo[nbNodes]; //our data that will be transmitted using float texture.
+
+ template<int i>
+ void printText( const char (&text)[ i ] )
+ {
+ std::cout << text << std::endl;
+ }
+
+ int main()
+ {
+ printText( "some string constant" );
+ return 0;
+ }
+ '''
+
+ self.do_run(src, "some string constant")
+
+ def test_istream(self):
+ if self.emcc_args is None: return self.skip('requires libcxx')
+
+ src = '''
+ #include <string>
+ #include <sstream>
+ #include <iostream>
+
+ int main()
+ {
+ std::string mystring("1 2 3");
+ std::istringstream is(mystring);
+ int one, two, three;
+
+ is >> one >> two >> three;
+
+ printf( "%i %i %i", one, two, three );
+ }
+ '''
+ for linkable in [0]:#, 1]:
+ print linkable
+ Settings.LINKABLE = linkable # regression check for issue #273
+ self.do_run(src, "1 2 3")
+
+ def test_fs_base(self):
+ Settings.INCLUDE_FULL_LIBRARY = 1
+ try:
+ addJS = '''
+def process(filename):
+ import tools.shared as shared
+ src = open(filename, 'r').read().replace('FS.init();', '').replace( # Disable normal initialization, replace with ours
+ '// {{PRE_RUN_ADDITIONS}}',
+ open(shared.path_from_root('tests', 'filesystem', 'src.js'), 'r').read())
+ open(filename, 'w').write(src)
+'''
+ src = 'int main() {return 0;}\n'
+ expected = open(path_from_root('tests', 'filesystem', 'output.txt'), 'r').read()
+ self.do_run(src, expected, post_build=addJS, extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
+ finally:
+ Settings.INCLUDE_FULL_LIBRARY = 0
+
+ def test_unistd_access(self):
+ add_pre_run = '''
+def process(filename):
+ import tools.shared as shared
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ open(shared.path_from_root('tests', 'unistd', 'access.js'), 'r').read()
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'unistd', 'access.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'access.out'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run)
+
+ def test_unistd_curdir(self):
+ add_pre_run = '''
+def process(filename):
+ import tools.shared as shared
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ open(shared.path_from_root('tests', 'unistd', 'curdir.js'), 'r').read()
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'unistd', 'curdir.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'curdir.out'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run)
+
+ def test_unistd_close(self):
+ src = open(path_from_root('tests', 'unistd', 'close.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'close.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_confstr(self):
+ src = open(path_from_root('tests', 'unistd', 'confstr.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'confstr.out'), 'r').read()
+ self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/unistd.h'])
+
+ def test_unistd_ttyname(self):
+ src = open(path_from_root('tests', 'unistd', 'ttyname.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_unistd_dup(self):
+ src = open(path_from_root('tests', 'unistd', 'dup.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'dup.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_pathconf(self):
+ src = open(path_from_root('tests', 'unistd', 'pathconf.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'pathconf.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_truncate(self):
+ add_pre_run = '''
+def process(filename):
+ import tools.shared as shared
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ open(shared.path_from_root('tests', 'unistd', 'truncate.js'), 'r').read()
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'unistd', 'truncate.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'truncate.out'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run)
+
+ def test_unistd_swab(self):
+ src = open(path_from_root('tests', 'unistd', 'swab.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'swab.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_isatty(self):
+ src = open(path_from_root('tests', 'unistd', 'isatty.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_unistd_sysconf(self):
+ src = open(path_from_root('tests', 'unistd', 'sysconf.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'sysconf.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_login(self):
+ src = open(path_from_root('tests', 'unistd', 'login.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'login.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_unlink(self):
+ src = open(path_from_root('tests', 'unistd', 'unlink.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_unistd_links(self):
+ add_pre_run = '''
+def process(filename):
+ import tools.shared as shared
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ open(shared.path_from_root('tests', 'unistd', 'links.js'), 'r').read()
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'unistd', 'links.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'links.out'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run)
+
+ def test_unistd_sleep(self):
+ src = open(path_from_root('tests', 'unistd', 'sleep.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'sleep.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_unistd_io(self):
+ add_pre_run = '''
+def process(filename):
+ import tools.shared as shared
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ open(shared.path_from_root('tests', 'unistd', 'io.js'), 'r').read()
+ )
+ open(filename, 'w').write(src)
+'''
+ src = open(path_from_root('tests', 'unistd', 'io.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'io.out'), 'r').read()
+ self.do_run(src, expected, post_build=add_pre_run)
+
+ def test_unistd_misc(self):
+ src = open(path_from_root('tests', 'unistd', 'misc.c'), 'r').read()
+ expected = open(path_from_root('tests', 'unistd', 'misc.out'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_uname(self):
+ src = r'''
+ #include <stdio.h>
+ #include <sys/utsname.h>
+
+ int main() {
+ struct utsname u;
+ printf("ret: %d\n", uname(&u));
+ printf("sysname: %s\n", u.sysname);
+ printf("nodename: %s\n", u.nodename);
+ printf("release: %s\n", u.release);
+ printf("version: %s\n", u.version);
+ printf("machine: %s\n", u.machine);
+ printf("invalid: %d\n", uname(0));
+ return 0;
+ }
+ '''
+ expected = '''
+ ret: 0
+ sysname: Emscripten
+ nodename: emscripten
+ release: 1.0
+ version: #1
+ machine: x86-JS
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
+
+ def test_env(self):
+ src = open(path_from_root('tests', 'env', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'env', 'output.txt'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_systypes(self):
+ src = open(path_from_root('tests', 'systypes', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'systypes', 'output.txt'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_getloadavg(self):
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main() {
+ double load[5] = {42.13, 42.13, 42.13, 42.13, 42.13};
+ printf("ret: %d\n", getloadavg(load, 5));
+ printf("load[0]: %.3lf\n", load[0]);
+ printf("load[1]: %.3lf\n", load[1]);
+ printf("load[2]: %.3lf\n", load[2]);
+ printf("load[3]: %.3lf\n", load[3]);
+ printf("load[4]: %.3lf\n", load[4]);
+ return 0;
+ }
+ '''
+ expected = '''
+ ret: 3
+ load[0]: 0.100
+ load[1]: 0.100
+ load[2]: 0.100
+ load[3]: 42.130
+ load[4]: 42.130
+ '''
+ self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
+
+ def test_inet(self):
+ src = r'''
+ #include <stdio.h>
+ #include <arpa/inet.h>
+
+ int main() {
+ printf("*%x,%x,%x,%x,%x,%x*\n", htonl(0xa1b2c3d4), htonl(0xfe3572e0), htonl(0x07abcdf0), htons(0xabcd), ntohl(0x43211234), ntohs(0xbeaf));
+ in_addr_t i = inet_addr("190.180.10.78");
+ printf("%x\n", i);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*d4c3b2a1,e07235fe,f0cdab07,cdab,34122143,afbe*\n4e0ab4be\n')
+
+ def test_inet2(self):
+ src = r'''
+ #include <stdio.h>
+ #include <arpa/inet.h>
+
+ int main() {
+ struct in_addr x, x2;
+ int *y = (int*)&x;
+ *y = 0x12345678;
+ printf("%s\n", inet_ntoa(x));
+ int r = inet_aton(inet_ntoa(x), &x2);
+ printf("%s\n", inet_ntoa(x2));
+ return 0;
+ }
+ '''
+ self.do_run(src, '120.86.52.18\n120.86.52.18\n')
+
+ def test_inet3(self):
+ src = r'''
+ #include <stdio.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+ int main() {
+ char dst[64];
+ struct in_addr x, x2;
+ int *y = (int*)&x;
+ *y = 0x12345678;
+ printf("%s\n", inet_ntop(AF_INET,&x,dst,sizeof dst));
+ int r = inet_aton(inet_ntoa(x), &x2);
+ printf("%s\n", inet_ntop(AF_INET,&x2,dst,sizeof dst));
+ return 0;
+ }
+ '''
+ self.do_run(src, '120.86.52.18\n120.86.52.18\n')
+
+ def test_inet4(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+
+ void test(char *test_addr){
+ char str[40];
+ struct in6_addr addr;
+ unsigned char *p = (unsigned char*)&addr;
+ int ret;
+ ret = inet_pton(AF_INET6,test_addr,&addr);
+ if(ret == -1) return;
+ if(ret == 0) return;
+ if(inet_ntop(AF_INET6,&addr,str,sizeof(str)) == NULL ) return;
+ printf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x - %s\n",
+ p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15],str);
+ }
+ int main(){
+ test("::");
+ test("::1");
+ test("::1.2.3.4");
+ test("::17.18.19.20");
+ test("::ffff:1.2.3.4");
+ test("1::ffff");
+ test("::255.255.255.255");
+ test("0:ff00:1::");
+ test("0:ff::");
+ test("abcd::");
+ test("ffff::a");
+ test("ffff::a:b");
+ test("ffff::a:b:c");
+ test("ffff::a:b:c:d");
+ test("ffff::a:b:c:d:e");
+ test("::1:2:0:0:0");
+ test("0:0:1:2:3::");
+ test("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ test("1::255.255.255.255");
+
+ //below should fail and not produce results..
+ test("1.2.3.4");
+ test("");
+ test("-");
+ }
+ '''
+ self.do_run(src,
+ "0000:0000:0000:0000:0000:0000:0000:0000 - ::\n"
+ "0000:0000:0000:0000:0000:0000:0000:0001 - ::1\n"
+ "0000:0000:0000:0000:0000:0000:0102:0304 - ::1.2.3.4\n"
+ "0000:0000:0000:0000:0000:0000:1112:1314 - ::17.18.19.20\n"
+ "0000:0000:0000:0000:0000:ffff:0102:0304 - ::ffff:1.2.3.4\n"
+ "0001:0000:0000:0000:0000:0000:0000:ffff - 1::ffff\n"
+ "0000:0000:0000:0000:0000:0000:ffff:ffff - ::255.255.255.255\n"
+ "0000:ff00:0001:0000:0000:0000:0000:0000 - 0:ff00:1::\n"
+ "0000:00ff:0000:0000:0000:0000:0000:0000 - 0:ff::\n"
+ "abcd:0000:0000:0000:0000:0000:0000:0000 - abcd::\n"
+ "ffff:0000:0000:0000:0000:0000:0000:000a - ffff::a\n"
+ "ffff:0000:0000:0000:0000:0000:000a:000b - ffff::a:b\n"
+ "ffff:0000:0000:0000:0000:000a:000b:000c - ffff::a:b:c\n"
+ "ffff:0000:0000:0000:000a:000b:000c:000d - ffff::a:b:c:d\n"
+ "ffff:0000:0000:000a:000b:000c:000d:000e - ffff::a:b:c:d:e\n"
+ "0000:0000:0000:0001:0002:0000:0000:0000 - ::1:2:0:0:0\n"
+ "0000:0000:0001:0002:0003:0000:0000:0000 - 0:0:1:2:3::\n"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\n"
+ "0001:0000:0000:0000:0000:0000:ffff:ffff - 1::ffff:ffff\n"
+ )
+
+ def test_gethostbyname(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip("assume t2 in gethostbyname")
+
+ src = r'''
+ #include <netdb.h>
+ #include <stdio.h>
+
+ void test(char *hostname) {
+ hostent *host = gethostbyname(hostname);
+ if (!host) {
+ printf("no such thing\n");
+ return;
+ }
+ printf("%s : %d : %d\n", host->h_name, host->h_addrtype, host->h_length);
+ char **name = host->h_aliases;
+ while (*name) {
+ printf("- %s\n", *name);
+ name++;
+ }
+ name = host->h_addr_list;
+ while (name && *name) {
+ printf("* ");
+ for (int i = 0; i < host->h_length; i++)
+ printf("%d.", (*name)[i]);
+ printf("\n");
+ name++;
+ }
+ }
+
+ int main() {
+ test("www.cheezburger.com");
+ test("fail.on.this.never.work"); // we will "work" on this - because we are just making aliases of names to ips
+ test("localhost");
+ return 0;
+ }
+ '''
+ self.do_run(src, '''www.cheezburger.com : 2 : 4
+* -84.29.1.0.
+fail.on.this.never.work : 2 : 4
+* -84.29.2.0.
+localhost : 2 : 4
+* -84.29.3.0.
+''')
+
+ def test_799(self):
+ src = open(path_from_root('tests', '799.cpp'), 'r').read()
+ self.do_run(src, '''Set PORT family: 0, port: 3979
+Get PORT family: 0
+PORT: 3979
+''')
+
+ def test_ctype(self):
+ # The bit fiddling done by the macros using __ctype_b_loc requires this.
+ Settings.CORRECT_SIGNS = 1
+ src = open(path_from_root('tests', 'ctype', 'src.c'), 'r').read()
+ expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read()
+ self.do_run(src, expected)
+
+ def test_strcasecmp(self):
+ src = r'''
+ #include <stdio.h>
+ #include <strings.h>
+ int sign(int x) {
+ if (x < 0) return -1;
+ if (x > 0) return 1;
+ return 0;
+ }
+ int main() {
+ printf("*\n");
+
+ printf("%d\n", sign(strcasecmp("hello", "hello")));
+ printf("%d\n", sign(strcasecmp("hello1", "hello")));
+ printf("%d\n", sign(strcasecmp("hello", "hello1")));
+ printf("%d\n", sign(strcasecmp("hello1", "hello1")));
+ printf("%d\n", sign(strcasecmp("iello", "hello")));
+ printf("%d\n", sign(strcasecmp("hello", "iello")));
+ printf("%d\n", sign(strcasecmp("A", "hello")));
+ printf("%d\n", sign(strcasecmp("Z", "hello")));
+ printf("%d\n", sign(strcasecmp("a", "hello")));
+ printf("%d\n", sign(strcasecmp("z", "hello")));
+ printf("%d\n", sign(strcasecmp("hello", "a")));
+ printf("%d\n", sign(strcasecmp("hello", "z")));
+
+ printf("%d\n", sign(strcasecmp("Hello", "hello")));
+ printf("%d\n", sign(strcasecmp("Hello1", "hello")));
+ printf("%d\n", sign(strcasecmp("Hello", "hello1")));
+ printf("%d\n", sign(strcasecmp("Hello1", "hello1")));
+ printf("%d\n", sign(strcasecmp("Iello", "hello")));
+ printf("%d\n", sign(strcasecmp("Hello", "iello")));
+ printf("%d\n", sign(strcasecmp("A", "hello")));
+ printf("%d\n", sign(strcasecmp("Z", "hello")));
+ printf("%d\n", sign(strcasecmp("a", "hello")));
+ printf("%d\n", sign(strcasecmp("z", "hello")));
+ printf("%d\n", sign(strcasecmp("Hello", "a")));
+ printf("%d\n", sign(strcasecmp("Hello", "z")));
+
+ printf("%d\n", sign(strcasecmp("hello", "Hello")));
+ printf("%d\n", sign(strcasecmp("hello1", "Hello")));
+ printf("%d\n", sign(strcasecmp("hello", "Hello1")));
+ printf("%d\n", sign(strcasecmp("hello1", "Hello1")));
+ printf("%d\n", sign(strcasecmp("iello", "Hello")));
+ printf("%d\n", sign(strcasecmp("hello", "Iello")));
+ printf("%d\n", sign(strcasecmp("A", "Hello")));
+ printf("%d\n", sign(strcasecmp("Z", "Hello")));
+ printf("%d\n", sign(strcasecmp("a", "Hello")));
+ printf("%d\n", sign(strcasecmp("z", "Hello")));
+ printf("%d\n", sign(strcasecmp("hello", "a")));
+ printf("%d\n", sign(strcasecmp("hello", "z")));
+
+ printf("%d\n", sign(strcasecmp("Hello", "Hello")));
+ printf("%d\n", sign(strcasecmp("Hello1", "Hello")));
+ printf("%d\n", sign(strcasecmp("Hello", "Hello1")));
+ printf("%d\n", sign(strcasecmp("Hello1", "Hello1")));
+ printf("%d\n", sign(strcasecmp("Iello", "Hello")));
+ printf("%d\n", sign(strcasecmp("Hello", "Iello")));
+ printf("%d\n", sign(strcasecmp("A", "Hello")));
+ printf("%d\n", sign(strcasecmp("Z", "Hello")));
+ printf("%d\n", sign(strcasecmp("a", "Hello")));
+ printf("%d\n", sign(strcasecmp("z", "Hello")));
+ printf("%d\n", sign(strcasecmp("Hello", "a")));
+ printf("%d\n", sign(strcasecmp("Hello", "z")));
+
+ printf("%d\n", sign(strncasecmp("hello", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("hello1", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("hello", "hello1", 3)));
+ printf("%d\n", sign(strncasecmp("hello1", "hello1", 3)));
+ printf("%d\n", sign(strncasecmp("iello", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("hello", "iello", 3)));
+ printf("%d\n", sign(strncasecmp("A", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("Z", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("a", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("z", "hello", 3)));
+ printf("%d\n", sign(strncasecmp("hello", "a", 3)));
+ printf("%d\n", sign(strncasecmp("hello", "z", 3)));
+
+ printf("*\n");
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''*\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n0\n0\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n*\n''')
+
+ def test_atomic(self):
+ src = '''
+ #include <stdio.h>
+ int main() {
+ int x = 10;
+ int y = __sync_add_and_fetch(&x, 5);
+ printf("*%d,%d*\\n", x, y);
+ x = 10;
+ y = __sync_fetch_and_add(&x, 5);
+ printf("*%d,%d*\\n", x, y);
+ x = 10;
+ y = __sync_lock_test_and_set(&x, 6);
+ printf("*%d,%d*\\n", x, y);
+ x = 10;
+ y = __sync_bool_compare_and_swap(&x, 9, 7);
+ printf("*%d,%d*\\n", x, y);
+ y = __sync_bool_compare_and_swap(&x, 10, 7);
+ printf("*%d,%d*\\n", x, y);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*15,15*\n*15,10*\n*6,10*\n*10,0*\n*7,1*')
+
+ def test_phiundef(self):
+ src = r'''
+#include <stdlib.h>
+#include <stdio.h>
+
+static int state;
+
+struct my_struct {
+union {
+ struct {
+ unsigned char a;
+ unsigned char b;
+ } c;
+ unsigned int d;
+} e;
+unsigned int f;
+};
+
+int main(int argc, char **argv) {
+ struct my_struct r;
+
+ state = 0;
+
+ for (int i=0;i<argc+10;i++)
+ {
+ if (state % 2 == 0)
+ r.e.c.a = 3;
+ else
+ printf("%d\n", r.e.c.a);
+ state++;
+ }
+ return 0;
+}
+ '''
+
+ self.do_run(src, '3\n3\n3\n3\n3\n')
+
+ # libc++ tests
+
+ def test_iostream(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
+
+ if self.emcc_args is None:
+ if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion')
+ self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc
+ Settings.SAFE_HEAP = 0 # Some spurious warnings from libc++ internals
+
+ src = '''
+ #include <iostream>
+
+ int main()
+ {
+ std::cout << "hello world" << std::endl << 77 << "." << std::endl;
+ return 0;
+ }
+ '''
+
+ # FIXME: should not have so many newlines in output here
+ self.do_run(src, 'hello world\n77.\n')
+
+ def test_stdvec(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = '''
+ #include <vector>
+ #include <stdio.h>
+
+ struct S {
+ int a;
+ float b;
+ };
+
+ void foo(int a, float b)
+ {
+ printf("%d:%.2f\\n", a, b);
+ }
+
+ int main ( int argc, char *argv[] )
+ {
+ std::vector<S> ar;
+ S s;
+
+ s.a = 789;
+ s.b = 123.456f;
+ ar.push_back(s);
+
+ s.a = 0;
+ s.b = 100.1f;
+ ar.push_back(s);
+
+ foo(ar[0].a, ar[0].b);
+ foo(ar[1].a, ar[1].b);
+ }
+ '''
+
+ self.do_run(src, '789:123.46\n0:100.1')
+
+ def test_reinterpreted_ptrs(self):
+ if self.emcc_args is None: return self.skip('needs emcc and libc')
+
+ src = r'''
+#include <stdio.h>
+
+class Foo {
+private:
+ float bar;
+public:
+ int baz;
+
+ Foo(): bar(0), baz(4711) {};
+
+ int getBar() const;
+};
+
+int Foo::getBar() const {
+ return this->bar;
+};
+
+const Foo *magic1 = reinterpret_cast<Foo*>(0xDEAD111F);
+const Foo *magic2 = reinterpret_cast<Foo*>(0xDEAD888F);
+
+static void runTest() {
+
+ const Foo *a = new Foo();
+ const Foo *b = a;
+
+ if (a->getBar() == 0) {
+ if (a->baz == 4712)
+ b = magic1;
+ else
+ b = magic2;
+ }
+
+ printf("%s\n", (b == magic1 ? "magic1" : (b == magic2 ? "magic2" : "neither")));
+};
+
+extern "C" {
+ int main(int argc, char **argv) {
+ runTest();
+ }
+}
+'''
+ self.do_run(src, 'magic2')
+
+ def test_jansson(self):
+ return self.skip('currently broken')
+
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
+ if Settings.SAFE_HEAP: return self.skip('jansson is not safe-heap safe')
+
+ src = '''
+ #include <jansson.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ int main()
+ {
+ const char* jsonString = "{\\"key\\": \\"value\\",\\"array\\": [\\"array_item1\\",\\"array_item2\\",\\"array_item3\\"],\\"dict\\":{\\"number\\": 3,\\"float\\": 2.2}}";
+
+ json_error_t error;
+ json_t *root = json_loadb(jsonString, strlen(jsonString), 0, &error);
+
+ if(!root) {
+ printf("Node `root` is `null`.");
+ return 0;
+ }
+
+ if(!json_is_object(root)) {
+ printf("Node `root` is no object.");
+ return 0;
+ }
+
+ printf("%s\\n", json_string_value(json_object_get(root, "key")));
+
+ json_t *array = json_object_get(root, "array");
+ if(!array) {
+ printf("Node `array` is `null`.");
+ return 0;
+ }
+
+ if(!json_is_array(array)) {
+ printf("Node `array` is no array.");
+ return 0;
+ }
+
+ for(size_t i=0; i<json_array_size(array); ++i)
+ {
+ json_t *arrayNode = json_array_get(array, i);
+ if(!root || !json_is_string(arrayNode))
+ return 0;
+ printf("%s\\n", json_string_value(arrayNode));
+ }
+
+ json_t *dict = json_object_get(root, "dict");
+ if(!dict || !json_is_object(dict))
+ return 0;
+
+ json_t *numberNode = json_object_get(dict, "number");
+ json_t *floatNode = json_object_get(dict, "float");
+
+ if(!numberNode || !json_is_number(numberNode) ||
+ !floatNode || !json_is_real(floatNode))
+ return 0;
+
+ printf("%i\\n", json_integer_value(numberNode));
+ printf("%.2f\\n", json_number_value(numberNode));
+ printf("%.2f\\n", json_real_value(floatNode));
+
+ json_t *invalidNode = json_object_get(dict, "invalidNode");
+ if(invalidNode)
+ return 0;
+
+ printf("%i\\n", json_number_value(invalidNode));
+
+ json_decref(root);
+
+ if(!json_is_object(root))
+ printf("jansson!\\n");
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'value\narray_item1\narray_item2\narray_item3\n3\n3.00\n2.20\nJansson: Node with ID `0` not found. Context has `10` nodes.\n0\nJansson: No JSON context.\njansson!')
+
+ ### 'Medium' tests
+
+ def test_fannkuch(self):
+ results = [ (1,0), (2,1), (3,2), (4,4), (5,7), (6,10), (7, 16), (8,22) ]
+ for i, j in results:
+ src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read()
+ self.do_run(src, 'Pfannkuchen(%d) = %d.' % (i,j), [str(i)], no_build=i>1)
+
+ def test_raytrace(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Relies on double value rounding, extremely sensitive')
+
+ src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read().replace('double', 'float')
+ output = open(path_from_root('tests', 'raytrace.ppm'), 'r').read()
+ self.do_run(src, output, ['3', '16'])#, build_ll_hook=self.do_autodebug)
+
+ def test_fasta(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ results = [ (1,'''GG*ctt**tgagc*'''), (20,'''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tacgtgtagcctagtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaa**tgacgtcttttgatctgacggcgttaacaaagatactctg*'''),
+(50,'''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA*TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa**NtactMcSMtYtcMgRtacttctWBacgaa**agatactctgggcaacacacatacttctctcatgttgtttcttcggacctttcataacct**ttcctggcacatggttagctgcacatcacaggattgtaagggtctagtggttcagtgagc**ggaatatcattcgtcggtggtgttaatctatctcggtgtagcttataaatgcatccgtaa**gaatattatgtttatttgtcggtacgttcatggtagtggtgtcgccgatttagacgtaaa**ggcatgtatg*''') ]
+ for i, j in results:
+ src = open(path_from_root('tests', 'fasta.cpp'), 'r').read()
+ self.do_run(src, j, [str(i)], lambda x, err: x.replace('\n', '*'), no_build=i>1)
+
+ def test_whets(self):
+ if not Settings.ASM_JS: return self.skip('mainly a test for asm validation here')
+ self.do_run(open(path_from_root('tests', 'whets.cpp')).read(), 'Single Precision C Whetstone Benchmark')
+
+ def test_dlmalloc(self):
+ if self.emcc_args is None: self.emcc_args = [] # dlmalloc auto-inclusion is only done if we use emcc
+
+ self.banned_js_engines = [NODE_JS] # slower, and fail on 64-bit
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
+ Settings.TOTAL_MEMORY = 128*1024*1024 # needed with typed arrays
+
+ src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
+ self.do_run(src, '*1,0*', ['200', '1'])
+ self.do_run(src, '*400,0*', ['400', '400'], no_build=True)
+
+ # Linked version
+ src = open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
+ self.do_run(src, '*1,0*', ['200', '1'], extra_emscripten_args=['-m'])
+ self.do_run(src, '*400,0*', ['400', '400'], extra_emscripten_args=['-m'], no_build=True)
+
+ if self.emcc_args == []: # TODO: do this in other passes too, passing their opts into emcc
+ # emcc should build in dlmalloc automatically, and do all the sign correction etc. for it
+
+ try_delete(os.path.join(self.get_dir(), 'src.cpp.o.js'))
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'dlmalloc_test.c'), '-s', 'TOTAL_MEMORY=' + str(128*1024*1024),
+ '-o', os.path.join(self.get_dir(), 'src.cpp.o.js')], stdout=PIPE, stderr=self.stderr_redirect).communicate()
+
+ self.do_run('x', '*1,0*', ['200', '1'], no_build=True)
+ self.do_run('x', '*400,0*', ['400', '400'], no_build=True)
+
+ # The same for new and all its variants
+ src = open(path_from_root('tests', 'new.cpp')).read()
+ for new, delete in [
+ ('malloc(100)', 'free'),
+ ('new char[100]', 'delete[]'),
+ ('new Structy', 'delete'),
+ ('new int', 'delete'),
+ ('new Structy[10]', 'delete[]'),
+ ]:
+ self.do_run(src.replace('{{{ NEW }}}', new).replace('{{{ DELETE }}}', delete), '*1,0*')
+
+ def test_dlmalloc_partial(self):
+ if self.emcc_args is None: return self.skip('only emcc will link in dlmalloc')
+ # present part of the symbols of dlmalloc, not all
+ src = open(path_from_root('tests', 'new.cpp')).read().replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + '''
+void *
+operator new(size_t size)
+{
+printf("new %d!\\n", size);
+return malloc(size);
+}
+'''
+ self.do_run(src, 'new 4!\n*1,0*')
+
+ def test_dlmalloc_partial_2(self):
+ if self.emcc_args is None or 'SAFE_HEAP' in str(self.emcc_args) or 'CHECK_HEAP_ALIGN' in str(self.emcc_args): return self.skip('only emcc will link in dlmalloc, and we do unsafe stuff')
+ # present part of the symbols of dlmalloc, not all. malloc is harder to link than new which is weak.
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ void *malloc(size_t size)
+ {
+ return (void*)123;
+ }
+ int main() {
+ void *x = malloc(10);
+ printf("got %p\n", x);
+ free(x);
+ printf("freed the faker\n");
+ return 1;
+ }
+'''
+ self.do_run(src, 'got 0x7b\nfreed')
+
+ def test_libcxx(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ self.do_run(open(path_from_root('tests', 'hashtest.cpp')).read(),
+ 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march')
+
+ self.do_run('''
+ #include <set>
+ #include <stdio.h>
+ int main() {
+ std::set<int> *fetchOriginatorNums = new std::set<int>();
+ fetchOriginatorNums->insert(171);
+ printf("hello world\\n");
+ return 0;
+ }
+ ''', 'hello world');
+
+ def test_typeid(self):
+ self.do_run(r'''
+ #include <stdio.h>
+ #include <string.h>
+ #include <typeinfo>
+ int main() {
+ printf("*\n");
+ #define MAX 100
+ int ptrs[MAX];
+ int groups[MAX];
+ memset(ptrs, 0, MAX*sizeof(int));
+ memset(groups, 0, MAX*sizeof(int));
+ int next_group = 1;
+ #define TEST(X) { \
+ int ptr = (int)&typeid(X); \
+ int group = 0; \
+ int i; \
+ for (i = 0; i < MAX; i++) { \
+ if (!groups[i]) break; \
+ if (ptrs[i] == ptr) { \
+ group = groups[i]; \
+ break; \
+ } \
+ } \
+ if (!group) { \
+ groups[i] = group = next_group++; \
+ ptrs[i] = ptr; \
+ } \
+ printf("%s:%d\n", #X, group); \
+ }
+ TEST(int);
+ TEST(unsigned int);
+ TEST(unsigned);
+ TEST(signed int);
+ TEST(long);
+ TEST(unsigned long);
+ TEST(signed long);
+ TEST(long long);
+ TEST(unsigned long long);
+ TEST(signed long long);
+ TEST(short);
+ TEST(unsigned short);
+ TEST(signed short);
+ TEST(char);
+ TEST(unsigned char);
+ TEST(signed char);
+ TEST(float);
+ TEST(double);
+ TEST(long double);
+ TEST(void);
+ TEST(void*);
+ printf("*\n");
+ }
+ ''', '''*
+int:1
+unsigned int:2
+unsigned:2
+signed int:1
+long:3
+unsigned long:4
+signed long:3
+long long:5
+unsigned long long:6
+signed long long:5
+short:7
+unsigned short:8
+signed short:7
+char:9
+unsigned char:10
+signed char:11
+float:12
+double:13
+long double:14
+void:15
+void*:16
+*
+''');
+
+ def test_static_variable(self):
+ if self.emcc_args is None: Settings.SAFE_HEAP = 0 # LLVM mixes i64 and i8 in the guard check
+ src = '''
+ #include <stdio.h>
+
+ struct DATA
+ {
+ int value;
+
+ DATA()
+ {
+ value = 0;
+ }
+ };
+
+ DATA & GetData()
+ {
+ static DATA data;
+
+ return data;
+ }
+
+ int main()
+ {
+ GetData().value = 10;
+ printf( "value:%i", GetData().value );
+ }
+ '''
+ self.do_run(src, 'value:10')
+
+ def test_fakestat(self):
+ src = r'''
+ #include <stdio.h>
+ struct stat { int x, y; };
+ int main() {
+ stat s;
+ s.x = 10;
+ s.y = 22;
+ printf("*%d,%d*\n", s.x, s.y);
+ }
+ '''
+ self.do_run(src, '*10,22*')
+
+ def test_mmap(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ Settings.TOTAL_MEMORY = 128*1024*1024
+
+ src = '''
+ #include <stdio.h>
+ #include <sys/mman.h>
+ #include <assert.h>
+
+ int main(int argc, char *argv[]) {
+ for (int i = 0; i < 10; i++) {
+ int* map = (int*)mmap(0, 5000, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANON, -1, 0);
+ /* TODO: Should we align to 4k?
+ assert(((int)map) % 4096 == 0); // aligned
+ */
+ assert(munmap(map, 5000) == 0);
+ }
+
+ const int NUM_BYTES = 8 * 1024 * 1024;
+ const int NUM_INTS = NUM_BYTES / sizeof(int);
+
+ int* map = (int*)mmap(0, NUM_BYTES, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANON, -1, 0);
+ assert(map != MAP_FAILED);
+
+ int i;
+
+ for (i = 0; i < NUM_INTS; i++) {
+ map[i] = i;
+ }
+
+ for (i = 0; i < NUM_INTS; i++) {
+ assert(map[i] == i);
+ }
+
+ assert(munmap(map, NUM_BYTES) == 0);
+
+ printf("hello,world");
+ return 0;
+ }
+ '''
+ self.do_run(src, 'hello,world')
+ self.do_run(src, 'hello,world', force_c=True)
+
+ def test_mmap_file(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ self.emcc_args += ['--embed-file', 'data.dat']
+
+ open(self.in_dir('data.dat'), 'w').write('data from the file ' + ('.' * 9000))
+
+ src = r'''
+ #include <stdio.h>
+ #include <sys/mman.h>
+
+ int main() {
+ printf("*\n");
+ FILE *f = fopen("data.dat", "r");
+ char *m;
+ m = (char*)mmap(NULL, 9000, PROT_READ, MAP_PRIVATE, fileno(f), 0);
+ for (int i = 0; i < 20; i++) putchar(m[i]);
+ munmap(m, 9000);
+ printf("\n");
+ m = (char*)mmap(NULL, 9000, PROT_READ, MAP_PRIVATE, fileno(f), 5);
+ for (int i = 0; i < 20; i++) putchar(m[i]);
+ munmap(m, 9000);
+ printf("\n*\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, '*\ndata from the file .\nfrom the file ......\n*\n')
+
+ def test_cubescript(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if self.run_name == 'o2':
+ self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
+
+ Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default
+ if self.emcc_args is None: Settings.SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
+
+ # Overflows happen in hash loop
+ Settings.CORRECT_OVERFLOWS = 1
+ Settings.CHECK_OVERFLOWS = 0
+
+ if Settings.USE_TYPED_ARRAYS == 2:
+ Settings.CORRECT_SIGNS = 1
+
+ self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
+
+ assert 'asm2g' in test_modes
+ if self.run_name == 'asm2g':
+ results = {}
+ original = open('src.cpp.o.js').read()
+ results[Settings.ALIASING_FUNCTION_POINTERS] = len(original)
+ Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS
+ self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
+ final = open('src.cpp.o.js').read()
+ results[Settings.ALIASING_FUNCTION_POINTERS] = len(final)
+ open('original.js', 'w').write(original)
+ print results
+ assert results[1] < 0.99*results[0]
+ assert ' & 3]()' in original, 'small function table exists'
+ assert ' & 3]()' not in final, 'small function table does not exist'
+ assert ' & 255]()' not in original, 'big function table does not exist'
+ assert ' & 255]()' in final, 'big function table exists'
+
+ def test_gcc_unmangler(self):
+ Settings.NAMED_GLOBALS = 1 # test coverage for this
+
+ Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('third_party')]
+
+ self.do_run(open(path_from_root('third_party', 'gcc_demangler.c')).read(), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'])
+
+ #### Code snippet that is helpful to search for nonportable optimizations ####
+ #global LLVM_OPT_OPTS
+ #for opt in ['-aa-eval', '-adce', '-always-inline', '-argpromotion', '-basicaa', '-basiccg', '-block-placement', '-break-crit-edges', '-codegenprepare', '-constmerge', '-constprop', '-correlated-propagation', '-count-aa', '-dce', '-deadargelim', '-deadtypeelim', '-debug-aa', '-die', '-domfrontier', '-domtree', '-dse', '-extract-blocks', '-functionattrs', '-globaldce', '-globalopt', '-globalsmodref-aa', '-gvn', '-indvars', '-inline', '-insert-edge-profiling', '-insert-optimal-edge-profiling', '-instcombine', '-instcount', '-instnamer', '-internalize', '-intervals', '-ipconstprop', '-ipsccp', '-iv-users', '-jump-threading', '-lazy-value-info', '-lcssa', '-lda', '-libcall-aa', '-licm', '-lint', '-live-values', '-loop-deletion', '-loop-extract', '-loop-extract-single', '-loop-index-split', '-loop-reduce', '-loop-rotate', '-loop-unroll', '-loop-unswitch', '-loops', '-loopsimplify', '-loweratomic', '-lowerinvoke', '-lowersetjmp', '-lowerswitch', '-mem2reg', '-memcpyopt', '-memdep', '-mergefunc', '-mergereturn', '-module-debuginfo', '-no-aa', '-no-profile', '-partial-inliner', '-partialspecialization', '-pointertracking', '-postdomfrontier', '-postdomtree', '-preverify', '-prune-eh', '-reassociate', '-reg2mem', '-regions', '-scalar-evolution', '-scalarrepl', '-sccp', '-scev-aa', '-simplify-libcalls', '-simplify-libcalls-halfpowr', '-simplifycfg', '-sink', '-split-geps', '-sretpromotion', '-strip', '-strip-dead-debug-info', '-strip-dead-prototypes', '-strip-debug-declare', '-strip-nondebug', '-tailcallelim', '-tailduplicate', '-targetdata', '-tbaa']:
+ # LLVM_OPT_OPTS = [opt]
+ # try:
+ # self.do_run(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
+ # print opt, "ok"
+ # except:
+ # print opt, "FAIL"
+
+ def test_lua(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
+
+ self.do_run('',
+ 'hello lua world!\n17\n1\n2\n3\n4\n7',
+ args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
+ libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None),
+ includes=[path_from_root('tests', 'lua')],
+ output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n'))
+
+ def get_freetype(self):
+ Settings.DEAD_FUNCTIONS += ['_inflateEnd', '_inflate', '_inflateReset', '_inflateInit2_']
+
+ return self.get_library('freetype',
+ os.path.join('objs', '.libs', 'libfreetype.a'))
+
+ def test_freetype(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
+ if Settings.ASM_JS and '-O2' not in self.emcc_args: return self.skip('mozilla bug 863867')
+
+ if Settings.CORRECT_SIGNS == 0: Settings.CORRECT_SIGNS = 1 # Not sure why, but needed
+
+ post = '''
+def process(filename):
+ import tools.shared as shared
+ # Embed the font into the document
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createDataFile('/', 'font.ttf', %s, true, false);" % str(
+ map(ord, open(shared.path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), 'rb').read())
+ )
+ )
+ open(filename, 'w').write(src)
+'''
+
+ # Not needed for js, but useful for debugging
+ shutil.copyfile(path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), os.path.join(self.get_dir(), 'font.ttf'))
+
+ # Main
+ self.do_run(open(path_from_root('tests', 'freetype', 'main.c'), 'r').read(),
+ open(path_from_root('tests', 'freetype', 'ref.txt'), 'r').read(),
+ ['font.ttf', 'test!', '150', '120', '25'],
+ libraries=self.get_freetype(),
+ includes=[path_from_root('tests', 'freetype', 'include')],
+ post_build=post)
+ #build_ll_hook=self.do_autodebug)
+
+ # github issue 324
+ print '[issue 324]'
+ self.do_run(open(path_from_root('tests', 'freetype', 'main_2.c'), 'r').read(),
+ open(path_from_root('tests', 'freetype', 'ref_2.txt'), 'r').read(),
+ ['font.ttf', 'w', '32', '32', '25'],
+ libraries=self.get_freetype(),
+ includes=[path_from_root('tests', 'freetype', 'include')],
+ post_build=post)
+
+ print '[issue 324 case 2]'
+ self.do_run(open(path_from_root('tests', 'freetype', 'main_3.c'), 'r').read(),
+ open(path_from_root('tests', 'freetype', 'ref_3.txt'), 'r').read(),
+ ['font.ttf', 'W', '32', '32', '0'],
+ libraries=self.get_freetype(),
+ includes=[path_from_root('tests', 'freetype', 'include')],
+ post_build=post)
+
+ print '[issue 324 case 3]'
+ self.do_run('',
+ open(path_from_root('tests', 'freetype', 'ref_4.txt'), 'r').read(),
+ ['font.ttf', 'ea', '40', '32', '0'],
+ no_build=True)
+
+ def test_sqlite(self):
+ # gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
+ if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
+ self.banned_js_engines = [NODE_JS] # OOM in older node
+
+ Settings.CORRECT_SIGNS = 1
+ Settings.CORRECT_OVERFLOWS = 0
+ Settings.CORRECT_ROUNDINGS = 0
+ if self.emcc_args is None: Settings.SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
+ Settings.FAST_MEMORY = 4*1024*1024
+ Settings.EXPORTED_FUNCTIONS += ['_sqlite3_open', '_sqlite3_close', '_sqlite3_exec', '_sqlite3_free', '_callback'];
+ if Settings.ASM_JS == 1 and '-g' in self.emcc_args:
+ print "disabling inlining" # without registerize (which -g disables), we generate huge amounts of code
+ Settings.INLINING_LIMIT = 50
+
+ self.do_run(r'''
+ #define SQLITE_DISABLE_LFS
+ #define LONGDOUBLE_TYPE double
+ #define SQLITE_INT64_TYPE long long int
+ #define SQLITE_THREADSAFE 0
+ ''' + open(path_from_root('tests', 'sqlite', 'sqlite3.c'), 'r').read() +
+ open(path_from_root('tests', 'sqlite', 'benchmark.c'), 'r').read(),
+ open(path_from_root('tests', 'sqlite', 'benchmark.txt'), 'r').read(),
+ includes=[path_from_root('tests', 'sqlite')],
+ force_c=True)
+
+ def test_zlib(self):
+ if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('works in general, but cached build will be optimized and fail, so disable this')
+
+ if Settings.ASM_JS:
+ self.banned_js_engines = [NODE_JS] # TODO investigate
+
+ if self.emcc_args is not None and '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args: # without asm, closure minifies Math.imul badly
+ self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
+
+ Settings.CORRECT_SIGNS = 1
+
+ self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
+ open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
+ libraries=self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
+ includes=[path_from_root('tests', 'zlib')],
+ force_c=True)
+
+ def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Building.LLVM_OPTS and self.emcc_args is None: Settings.SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore
+
+ Settings.DEAD_FUNCTIONS = ['__ZSt9terminatev']
+
+ # Note: this is also a good test of per-file and per-line changes (since we have multiple files, and correct specific lines)
+ if Settings.SAFE_HEAP:
+ # Ignore bitfield warnings
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ['btVoronoiSimplexSolver.h:40', 'btVoronoiSimplexSolver.h:41',
+ 'btVoronoiSimplexSolver.h:42', 'btVoronoiSimplexSolver.h:43']
+
+ def test():
+ self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
+ [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
+ open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
+ open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
+ libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
+ os.path.join('src', '.libs', 'libBulletCollision.a'),
+ os.path.join('src', '.libs', 'libLinearMath.a')],
+ configure_args=['--disable-demos','--disable-dependency-tracking']),
+ includes=[path_from_root('tests', 'bullet', 'src')])
+ test()
+
+ assert 'asm2g' in test_modes
+ if self.run_name == 'asm2g':
+ # Test forced alignment
+ print >> sys.stderr, 'testing FORCE_ALIGNED_MEMORY'
+ old = open('src.cpp.o.js').read()
+ Settings.FORCE_ALIGNED_MEMORY = 1
+ test()
+ new = open('src.cpp.o.js').read()
+ print len(old), len(new), old.count('tempBigInt'), new.count('tempBigInt')
+ assert len(old) > len(new)
+ assert old.count('tempBigInt') > new.count('tempBigInt')
+
+ def test_poppler(self):
+ if self.emcc_args is None: return self.skip('very slow, we only do this in emcc runs')
+
+ Settings.CORRECT_OVERFLOWS = 1
+ Settings.CORRECT_SIGNS = 1
+
+ Building.COMPILER_TEST_OPTS += [
+ '-I' + path_from_root('tests', 'freetype', 'include'),
+ '-I' + path_from_root('tests', 'poppler', 'include'),
+ ]
+
+ Settings.INVOKE_RUN = 0 # We append code that does run() ourselves
+
+ # See post(), below
+ input_file = open(os.path.join(self.get_dir(), 'paper.pdf.js'), 'w')
+ input_file.write(str(map(ord, open(path_from_root('tests', 'poppler', 'paper.pdf'), 'rb').read())))
+ input_file.close()
+
+ post = '''
+def process(filename):
+ # To avoid loading this large file to memory and altering it, we simply append to the end
+ src = open(filename, 'a')
+ src.write(
+ \'\'\'
+ FS.createDataFile('/', 'paper.pdf', eval(Module.read('paper.pdf.js')), true, false);
+ Module.callMain(Module.arguments);
+ Module.print("Data: " + JSON.stringify(FS.root.contents['filename-1.ppm'].contents.map(function(x) { return unSign(x, 8) })));
+ \'\'\'
+ )
+ src.close()
+'''
+
+ #fontconfig = self.get_library('fontconfig', [os.path.join('src', '.libs', 'libfontconfig.a')]) # Used in file, but not needed, mostly
+
+ freetype = self.get_freetype()
+
+ poppler = self.get_library('poppler',
+ [os.path.join('utils', 'pdftoppm.o'),
+ os.path.join('utils', 'parseargs.o'),
+ os.path.join('poppler', '.libs', 'libpoppler.a')],
+ env_init={ 'FONTCONFIG_CFLAGS': ' ', 'FONTCONFIG_LIBS': ' ' },
+ configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--enable-shared=no'])
+
+ # Combine libraries
+
+ combined = os.path.join(self.get_dir(), 'poppler-combined.bc')
+ Building.link(poppler + freetype, combined)
+
+ self.do_ll_run(combined,
+ map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''),
+ args='-scale-to 512 paper.pdf filename'.split(' '),
+ post_build=post)
+ #, build_ll_hook=self.do_autodebug)
+
+ def test_openjpeg(self):
+ if self.emcc_args is None: return self.skip('needs libc for getopt')
+
+ Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default
+
+ if Settings.USE_TYPED_ARRAYS == 2:
+ Settings.CORRECT_SIGNS = 1
+ else:
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ["mqc.c:566", "mqc.c:317"]
+
+ post = '''
+def process(filename):
+ import tools.shared as shared
+ original_j2k = shared.path_from_root('tests', 'openjpeg', 'syntensity_lobby_s.j2k')
+ src = open(filename, 'r').read().replace(
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createDataFile('/', 'image.j2k', %s, true, false);" % shared.line_splitter(str(
+ map(ord, open(original_j2k, 'rb').read())
+ ))
+ ).replace(
+ '// {{POST_RUN_ADDITIONS}}',
+ "Module.print('Data: ' + JSON.stringify(FS.analyzePath('image.raw').object.contents));"
+ )
+ open(filename, 'w').write(src)
+'''
+
+ shutil.copy(path_from_root('tests', 'openjpeg', 'opj_config.h'), self.get_dir())
+
+ lib = self.get_library('openjpeg',
+ [os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')),
+ os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')),
+ os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')),
+ os.path.join('bin', 'libopenjpeg.so.1.4.0')],
+ configure=['cmake', '.'],
+ #configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'],
+ make_args=[]) # no -j 2, since parallel builds can fail
+
+ # We use doubles in JS, so we get slightly different values than native code. So we
+ # check our output by comparing the average pixel difference
+ def image_compare(output, err):
+ # Get the image generated by JS, from the JSON.stringify'd array
+ m = re.search('\[[\d, -]*\]', output)
+ try:
+ js_data = eval(m.group(0))
+ except AttributeError:
+ print 'Failed to find proper image output in: ' + output
+ raise
+
+ js_data = map(lambda x: x if x >= 0 else 256+x, js_data) # Our output may be signed, so unsign it
+
+ # Get the correct output
+ true_data = open(path_from_root('tests', 'openjpeg', 'syntensity_lobby_s.raw'), 'rb').read()
+
+ # Compare them
+ assert(len(js_data) == len(true_data))
+ num = len(js_data)
+ diff_total = js_total = true_total = 0
+ for i in range(num):
+ js_total += js_data[i]
+ true_total += ord(true_data[i])
+ diff_total += abs(js_data[i] - ord(true_data[i]))
+ js_mean = js_total/float(num)
+ true_mean = true_total/float(num)
+ diff_mean = diff_total/float(num)
+
+ image_mean = 83.265
+ #print '[image stats:', js_mean, image_mean, true_mean, diff_mean, num, ']'
+ assert abs(js_mean - image_mean) < 0.01
+ assert abs(true_mean - image_mean) < 0.01
+ assert diff_mean < 0.01
+
+ return output
+
+ self.emcc_args += ['--minify', '0'] # to compare the versions
+
+ def do_test():
+ self.do_run(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(),
+ 'Successfully generated', # The real test for valid output is in image_compare
+ '-i image.j2k -o image.raw'.split(' '),
+ libraries=lib,
+ includes=[path_from_root('tests', 'openjpeg', 'libopenjpeg'),
+ path_from_root('tests', 'openjpeg', 'codec'),
+ path_from_root('tests', 'openjpeg', 'common'),
+ os.path.join(self.get_build_dir(), 'openjpeg')],
+ force_c=True,
+ post_build=post,
+ output_nicerizer=image_compare)#, build_ll_hook=self.do_autodebug)
+
+ do_test()
+
+ # some test coverage for EMCC_DEBUG 1 and 2
+ if self.emcc_args and '-O2' in self.emcc_args and 'EMCC_DEBUG' not in os.environ:
+ shutil.copyfile('src.c.o.js', 'release.js')
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ print '2'
+ do_test()
+ shutil.copyfile('src.c.o.js', 'debug1.js')
+ os.environ['EMCC_DEBUG'] = '2'
+ print '3'
+ do_test()
+ shutil.copyfile('src.c.o.js', 'debug2.js')
+ finally:
+ del os.environ['EMCC_DEBUG']
+ for debug in [1,2]:
+ def clean(text):
+ return text.replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('{\n}', '{}')
+ self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code!
+ print >> sys.stderr, 'debug check %d passed too' % debug
+
+ try:
+ os.environ['EMCC_FORCE_STDLIBS'] = '1'
+ print 'EMCC_FORCE_STDLIBS'
+ do_test()
+ finally:
+ del os.environ['EMCC_FORCE_STDLIBS']
+ print >> sys.stderr, 'EMCC_FORCE_STDLIBS ok'
+
+ try_delete(CANONICAL_TEMP_DIR)
+ else:
+ print >> sys.stderr, 'not doing debug check'
+
+ def test_python(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work')
+ if not self.is_le32(): return self.skip('fails on non-le32') # FIXME
+
+ #Settings.EXPORTED_FUNCTIONS += ['_PyRun_SimpleStringFlags'] # for the demo
+
+ if self.is_le32():
+ bitcode = path_from_root('tests', 'python', 'python.le32.bc')
+ else:
+ bitcode = path_from_root('tests', 'python', 'python.small.bc')
+
+ self.do_ll_run(bitcode,
+ 'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
+ args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''])
+
+ def test_lifetime(self):
+ if self.emcc_args is None: return self.skip('test relies on emcc opts')
+
+ self.do_ll_run(path_from_root('tests', 'lifetime.ll'), 'hello, world!\n')
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args:
+ assert 'a18' not in open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read(), 'lifetime stuff and their vars must be culled'
+
+ # Test cases in separate files. Note that these files may contain invalid .ll!
+ # They are only valid enough for us to read for test purposes, not for llvm-as
+ # to process.
+ def test_cases(self):
+ if Building.LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
+
+ try:
+ os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
+ Settings.CHECK_OVERFLOWS = 0
+
+ for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
+ shortname = name.replace('.ll', '')
+ if '' not in shortname: continue
+ if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2:
+ print self.skip('case "%s" only relevant for ta2' % shortname)
+ continue
+ if '_noasm' in shortname and Settings.ASM_JS:
+ print self.skip('case "%s" not relevant for asm.js' % shortname)
+ continue
+ print >> sys.stderr, "Testing case '%s'..." % shortname
+ output_file = path_from_root('tests', 'cases', shortname + '.txt')
+ if Settings.QUANTUM_SIZE == 1:
+ q1_output_file = path_from_root('tests', 'cases', shortname + '_q1.txt')
+ if os.path.exists(q1_output_file):
+ output_file = q1_output_file
+ if os.path.exists(output_file):
+ output = open(output_file, 'r').read()
+ else:
+ output = 'hello, world!'
+ if output.rstrip() != 'skip':
+ self.do_ll_run(path_from_root('tests', 'cases', name), output)
+ # Optional source checking, a python script that gets a global generated with the source
+ src_checker = path_from_root('tests', 'cases', shortname + '.py')
+ if os.path.exists(src_checker):
+ generated = open('src.cpp.o.js').read()
+ exec(open(src_checker).read())
+
+ finally:
+ del os.environ['EMCC_LEAVE_INPUTS_RAW']
+
+ def test_fuzz(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
+
+ Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('tests', 'fuzz')]
+
+ def run_all(x):
+ print x
+ for name in glob.glob(path_from_root('tests', 'fuzz', '*.c')):
+ print name
+ self.do_run(open(path_from_root('tests', 'fuzz', name)).read(),
+ open(path_from_root('tests', 'fuzz', name + '.txt')).read(), force_c=True)
+
+ run_all('normal')
+
+ self.emcc_args += ['--llvm-lto', '1']
+
+ run_all('lto')
+
+ # Autodebug the code
+ def do_autodebug(self, filename):
+ output = Popen([PYTHON, AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
+ assert 'Success.' in output, output
+ self.prep_ll_run(filename, filename+'.o.ll.ll', force_recompile=True) # rebuild .bc # TODO: use code in do_autodebug_post for this
+
+ # Autodebug the code, after LLVM opts. Will only work once!
+ def do_autodebug_post(self, filename):
+ if not hasattr(self, 'post'):
+ print 'Asking for post re-call'
+ self.post = True
+ return True
+ print 'Autodebugging during post time'
+ delattr(self, 'post')
+ output = Popen([PYTHON, AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
+ assert 'Success.' in output, output
+ shutil.copyfile(filename + '.o.ll.ll', filename + '.o.ll')
+ Building.llvm_as(filename)
+ Building.llvm_dis(filename)
+
+ def test_autodebug(self):
+ if Building.LLVM_OPTS: return self.skip('LLVM opts mess us up')
+ Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
+
+ # Run a test that should work, generating some code
+ self.test_structs()
+
+ filename = os.path.join(self.get_dir(), 'src.cpp')
+ self.do_autodebug(filename)
+
+ # Compare to each other, and to expected output
+ self.do_ll_run(path_from_root('tests', filename+'.o.ll.ll'), '''AD:-1,1''')
+ assert open('stdout').read().startswith('AD:-1'), 'We must note when we enter functions'
+
+ # Test using build_ll_hook
+ src = '''
+ #include <stdio.h>
+
+ char cache[256], *next = cache;
+
+ int main()
+ {
+ cache[10] = 25;
+ next[20] = 51;
+ int x = cache[10];
+ double y = 11.52;
+ printf("*%d,%d,%.2f*\\n", x, cache[20], y);
+ return 0;
+ }
+ '''
+ self.do_run(src, '''AD:-1,1''', build_ll_hook=self.do_autodebug)
+
+ def test_corruption(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
+
+ Settings.CORRUPTION_CHECK = 1
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ int main(int argc, char **argv) {
+ int size = 1024*argc;
+ char *buffer = (char*)malloc(size);
+ #if CORRUPT
+ memset(buffer, argc, size+15);
+ #else
+ memset(buffer, argc, size);
+ #endif
+ for (int x = 0; x < size; x += argc*3) buffer[x] = x/3;
+ int ret = 0;
+ for (int x = 0; x < size; x++) ret += buffer[x];
+ free(buffer);
+ printf("All ok, %d\n", ret);
+ }
+ '''
+
+ for corrupt in [1]:
+ self.do_run(src.replace('CORRUPT', str(corrupt)), 'Heap corruption detected!' if corrupt else 'All ok, 4209')
+
+ def test_corruption_2(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
+
+ Settings.SAFE_HEAP = 1
+ Settings.CORRUPTION_CHECK = 1
+
+ # test for free(0), malloc(0), etc.
+ src = r'''
+ #include <iostream>
+ #include <fstream>
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ void bye() {
+ printf("all ok\n");
+ }
+
+ int main() {
+ atexit(bye);
+
+ std::string testPath = "/Script/WA-KA.txt";
+ std::fstream str(testPath.c_str(), std::ios::in | std::ios::binary);
+
+ if (str.is_open())
+ {
+ std::cout << "open!" << std::endl;
+ } else {
+ std::cout << "missing!" << std::endl;
+ }
+
+ return 1;
+ }
+ '''
+ self.do_run(src, 'missing!\nall ok\n')
+
+ def test_corruption_3(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
+
+ Settings.CORRUPTION_CHECK = 1
+
+ # realloc
+ src = r'''
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <assert.h>
+
+ void bye() {
+ printf("all ok\n");
+ }
+
+ int main(int argc, char **argv) {
+ atexit(bye);
+
+ char *buffer = (char*)malloc(100);
+ for (int i = 0; i < 100; i++) buffer[i] = (i*i)%256;
+ buffer = (char*)realloc(buffer, argc + 50);
+ for (int i = 0; i < argc + 50; i++) {
+ //printf("%d : %d : %d : %d\n", i, (int)(buffer + i), buffer[i], (char)((i*i)%256));
+ assert(buffer[i] == (char)((i*i)%256));
+ }
+ return 1;
+ }
+ '''
+ self.do_run(src, 'all ok\n')
+
+ ### Integration tests
+
+ def test_ccall(self):
+ if self.emcc_args is not None and '-O2' in self.emcc_args:
+ self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ extern "C" {
+ int get_int() { return 5; }
+ float get_float() { return 3.14; }
+ char * get_string() { return "hello world"; }
+ void print_int(int x) { printf("%d\n", x); }
+ void print_float(float x) { printf("%.2f\n", x); }
+ void print_string(char *x) { printf("%s\n", x); }
+ int multi(int x, float y, int z, char *str) { if (x) puts(str); return (x+y)*z; }
+ int * pointer(int *in) { printf("%d\n", *in); static int ret = 21; return &ret; }
+ }
+
+ int main(int argc, char **argv) {
+ return 0;
+ }
+ '''
+
+ post = '''
+def process(filename):
+ src = \'\'\'
+ var Module = { 'noInitialRun': true };
+ \'\'\' + open(filename, 'r').read() + \'\'\'
+ Module.addOnExit(function () {
+ Module.print('*');
+ var ret;
+ ret = Module['ccall']('get_int', 'number'); Module.print([typeof ret, ret]);
+ ret = ccall('get_float', 'number'); Module.print([typeof ret, ret.toFixed(2)]);
+ ret = ccall('get_string', 'string'); Module.print([typeof ret, ret]);
+ ret = ccall('print_int', null, ['number'], [12]); Module.print(typeof ret);
+ ret = ccall('print_float', null, ['number'], [14.56]); Module.print(typeof ret);
+ ret = ccall('print_string', null, ['string'], ["cheez"]); Module.print(typeof ret);
+ ret = ccall('print_string', null, ['array'], [[97, 114, 114, 45, 97, 121, 0]]); Module.print(typeof ret);
+ ret = ccall('multi', 'number', ['number', 'number', 'number', 'string'], [2, 1.4, 3, 'more']); Module.print([typeof ret, ret]);
+ var p = ccall('malloc', 'pointer', ['number'], [4]);
+ setValue(p, 650, 'i32');
+ ret = ccall('pointer', 'pointer', ['pointer'], [p]); Module.print([typeof ret, getValue(ret, 'i32')]);
+ Module.print('*');
+ // part 2: cwrap
+ var multi = Module['cwrap']('multi', 'number', ['number', 'number', 'number', 'string']);
+ Module.print(multi(2, 1.4, 3, 'atr'));
+ Module.print(multi(8, 5.4, 4, 'bret'));
+ Module.print('*');
+ // part 3: avoid stack explosion
+ for (var i = 0; i < TOTAL_STACK/60; i++) {
+ ccall('multi', 'number', ['number', 'number', 'number', 'string'], [0, 0, 0, '123456789012345678901234567890123456789012345678901234567890']);
+ }
+ Module.print('stack is ok.');
+ });
+ Module.callMain();
+ \'\'\'
+ open(filename, 'w').write(src)
+'''
+
+ Settings.EXPORTED_FUNCTIONS += ['_get_int', '_get_float', '_get_string', '_print_int', '_print_float', '_print_string', '_multi', '_pointer', '_malloc']
+
+ self.do_run(src, '*\nnumber,5\nnumber,3.14\nstring,hello world\n12\nundefined\n14.56\nundefined\ncheez\nundefined\narr-ay\nundefined\nmore\nnumber,10\n650\nnumber,21\n*\natr\n10\nbret\n53\n*\nstack is ok.\n', post_build=post)
+
+ def test_pgo(self):
+ if Settings.ASM_JS: return self.skip('PGO does not work in asm mode')
+
+ def run_all(name, src):
+ print name
+ def test(expected, args=[], no_build=False):
+ self.do_run(src, expected, args=args, no_build=no_build)
+ return open(self.in_dir('src.cpp.o.js')).read()
+
+ # Sanity check that it works and the dead function is emitted
+ js = test('*9*')
+ assert 'function _unused(' in js
+
+ # Run with PGO, see that unused is true to its name
+ Settings.PGO = 1
+ test("*9*\n-s DEAD_FUNCTIONS='[\"_unused\"]'")
+ Settings.PGO = 0
+
+ # 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 # 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(('missing function: unused'), args=['a', 'b'], no_build=True)
+
+ # Normal stuff
+ run_all('normal', r'''
+ #include <stdio.h>
+ extern "C" {
+ int used(int x) {
+ if (x == 0) return -1;
+ return used(x/3) + used(x/17) + x%5;
+ }
+ int unused(int x) {
+ if (x == 0) return -1;
+ return unused(x/4) + unused(x/23) + x%7;
+ }
+ }
+ int main(int argc, char **argv) {
+ printf("*%d*\n", argc == 3 ? unused(argv[0][0] + 1024) : used(argc + 1555));
+ return 0;
+ }
+ ''')
+
+ # Call by function pointer
+ run_all('function pointers', r'''
+ #include <stdio.h>
+ extern "C" {
+ int used(int x) {
+ if (x == 0) return -1;
+ return used(x/3) + used(x/17) + x%5;
+ }
+ int unused(int x) {
+ if (x == 0) return -1;
+ return unused(x/4) + unused(x/23) + x%7;
+ }
+ }
+ typedef int (*ii)(int);
+ int main(int argc, char **argv) {
+ ii pointers[256];
+ for (int i = 0; i < 256; i++) {
+ pointers[i] = (i == 3) ? unused : used;
+ }
+ printf("*%d*\n", pointers[argc](argc + 1555));
+ return 0;
+ }
+ ''')
+
+ def test_asm_pgo(self):
+ if not Settings.ASM_JS: return self.skip('this is a test for PGO for asm (NB: not *in* asm)')
+
+ src = open(path_from_root('tests', 'hello_libcxx.cpp')).read()
+ output = 'hello, world!'
+
+ self.do_run(src, output)
+ shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('normal.js'))
+
+ Settings.ASM_JS = 0
+ Settings.PGO = 1
+ self.do_run(src, output)
+ Settings.ASM_JS = 1
+ Settings.PGO = 0
+
+ shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js'))
+ pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1]
+ open('pgo_data.rsp', 'w').write(pgo_output)
+
+ # with response file
+
+ self.emcc_args += ['@pgo_data.rsp']
+ self.do_run(src, output)
+ self.emcc_args.pop()
+ shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed.js'))
+
+ before = len(open('normal.js').read())
+ after = len(open('pgoed.js').read())
+ assert after < 0.90 * before, [before, after] # expect a size reduction
+
+ # with response in settings element itself
+
+ open('dead_funcs', 'w').write(pgo_output[pgo_output.find('['):-1])
+ self.emcc_args += ['-s', 'DEAD_FUNCTIONS=@' + self.in_dir('dead_funcs')]
+ self.do_run(src, output)
+ self.emcc_args.pop()
+ self.emcc_args.pop()
+ shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js'))
+ assert open('pgoed.js').read() == open('pgoed2.js').read()
+
+ # with relative response in settings element itself
+
+ open('dead_funcs', 'w').write(pgo_output[pgo_output.find('['):-1])
+ self.emcc_args += ['-s', 'DEAD_FUNCTIONS=@dead_funcs']
+ self.do_run(src, output)
+ self.emcc_args.pop()
+ self.emcc_args.pop()
+ shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js'))
+ assert open('pgoed.js').read() == open('pgoed2.js').read()
+
+ def test_exported_response(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ extern "C" {
+ int other_function() { return 5; }
+ }
+
+ int main() {
+ printf("waka!\n");
+ return 0;
+ }
+ '''
+ open('exps', 'w').write('["_main","_other_function"]')
+
+ self.emcc_args += ['-s', 'EXPORTED_FUNCTIONS=@exps']
+ self.do_run(src, '''waka!''')
+ assert 'other_function' in open('src.cpp.o.js').read()
+
+ def test_add_function(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ Settings.INVOKE_RUN = 0
+ Settings.RESERVED_FUNCTION_POINTERS = 1
+
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main(int argc, char **argv) {
+ int fp = atoi(argv[1]);
+ printf("fp: %d\n", fp);
+ void (*f)(int) = reinterpret_cast<void (*)(int)>(fp);
+ f(7);
+ return 0;
+ }
+ '''
+
+ open(os.path.join(self.get_dir(), 'post.js'), 'w').write('''
+ var newFuncPtr = Runtime.addFunction(function(num) {
+ Module.print('Hello ' + num + ' from JS!');
+ });
+ Module.callMain([newFuncPtr.toString()]);
+ ''')
+
+ self.emcc_args += ['--post-js', 'post.js']
+ self.do_run(src, '''Hello 7 from JS!''')
+
+ if Settings.ASM_JS:
+ Settings.RESERVED_FUNCTION_POINTERS = 0
+ self.do_run(src, '''Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.''')
+ generated = open('src.cpp.o.js').read()
+ assert 'jsCall' not in generated
+ Settings.RESERVED_FUNCTION_POINTERS = 1
+
+ Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS # flip the test
+ self.do_run(src, '''Hello 7 from JS!''')
+
+ def test_embind(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ Building.COMPILER_TEST_OPTS += ['--bind']
+
+ src = r'''
+ #include<stdio.h>
+ #include<emscripten/val.h>
+
+ using namespace emscripten;
+
+ int main() {
+ val Math = val::global("Math");
+
+ // two ways to call Math.abs
+ printf("abs(-10): %d\n", Math.call<int>("abs", -10));
+ printf("abs(-11): %d\n", Math["abs"](-11).as<int>());
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'abs(-10): 10\nabs(-11): 11');
+
+ def test_embind_2(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js']
+ open('post.js', 'w').write('''
+ Module.print('lerp ' + Module.lerp(1, 2, 0.66) + '.');
+ ''')
+ src = r'''
+ #include <stdio.h>
+ #include <SDL/SDL.h>
+ #include <emscripten/bind.h>
+ using namespace emscripten;
+ float lerp(float a, float b, float t) {
+ return (1 - t) * a + t * b;
+ }
+ EMSCRIPTEN_BINDINGS(my_module) {
+ function("lerp", &lerp);
+ }
+ '''
+ self.do_run(src, 'lerp 1.66');
+
+ def test_scriptaclass(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ Settings.EXPORT_BINDINGS = 1
+
+ header_filename = os.path.join(self.get_dir(), 'header.h')
+ header = '''
+ struct ScriptMe {
+ int value;
+ ScriptMe(int val);
+ int getVal(); // XXX Sadly, inlining these will result in LLVM not
+ // producing any code for them (when just building
+ // as a library)
+ void mulVal(int mul);
+ };
+ '''
+ h = open(header_filename, 'w')
+ h.write(header)
+ h.close()
+
+ src = '''
+ #include "header.h"
+
+ ScriptMe::ScriptMe(int val) : value(val) { }
+ int ScriptMe::getVal() { return value; }
+ void ScriptMe::mulVal(int mul) { value *= mul; }
+ '''
+
+ # Way 1: use demangler and namespacer
+
+ script_src = '''
+ var sme = Module._.ScriptMe.__new__(83); // malloc(sizeof(ScriptMe)), ScriptMe::ScriptMe(sme, 83) / new ScriptMe(83) (at addr sme)
+ Module._.ScriptMe.mulVal(sme, 2); // ScriptMe::mulVal(sme, 2) sme.mulVal(2)
+ Module.print('*' + Module._.ScriptMe.getVal(sme) + '*');
+ _free(sme);
+ Module.print('*ok*');
+ '''
+ post = '''
+def process(filename):
+ Popen([PYTHON, DEMANGLER, filename], stdout=open(filename + '.tmp', 'w')).communicate()
+ Popen([PYTHON, NAMESPACER, filename, filename + '.tmp'], stdout=open(filename + '.tmp2', 'w')).communicate()
+ src = open(filename, 'r').read().replace(
+ '// {{MODULE_ADDITIONS}',
+ 'Module["_"] = ' + open(filename + '.tmp2', 'r').read().replace('var ModuleNames = ', '').rstrip() + ';\n\n' + script_src + '\n\n' +
+ '// {{MODULE_ADDITIONS}'
+ )
+ open(filename, 'w').write(src)
+'''
+ # XXX disable due to possible v8 bug -- self.do_run(src, '*166*\n*ok*', post_build=post)
+
+ if self.emcc_args is not None and '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args: # without asm, closure minifies Math.imul badly
+ self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
+
+ # Way 2: use CppHeaderParser
+
+ Settings.RUNTIME_TYPE_INFO = 1
+
+ header = '''
+ #include <stdio.h>
+
+ class Parent {
+ protected:
+ int value;
+ public:
+ Parent(int val);
+ Parent(Parent *p, Parent *q); // overload constructor
+ int getVal() { return value; }; // inline should work just fine here, unlike Way 1 before
+ void mulVal(int mul);
+ };
+
+ class Child1 : public Parent {
+ public:
+ Child1() : Parent(7) { printf("Child1:%d\\n", value); };
+ Child1(int val) : Parent(val*2) { value -= 1; printf("Child1:%d\\n", value); };
+ int getValSqr() { return value*value; }
+ int getValSqr(int more) { return value*value*more; }
+ int getValTimes(int times=1) { return value*times; }
+ };
+
+ class Child2 : public Parent {
+ public:
+ Child2() : Parent(9) { printf("Child2:%d\\n", value); };
+ int getValCube() { return value*value*value; }
+ static void printStatic() { printf("*static*\\n"); }
+
+ virtual void virtualFunc() { printf("*virtualf*\\n"); }
+ virtual void virtualFunc2() { printf("*virtualf2*\\n"); }
+ static void runVirtualFunc(Child2 *self) { self->virtualFunc(); };
+ private:
+ void doSomethingSecret() { printf("security breached!\\n"); }; // we should not be able to do this
+ };
+ '''
+ open(header_filename, 'w').write(header)
+
+ basename = os.path.join(self.get_dir(), 'bindingtest')
+ output = Popen([PYTHON, BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
+ #print output
+ assert 'Traceback' not in output, 'Failure in binding generation: ' + output
+
+ src = '''
+ #include "header.h"
+
+ Parent::Parent(int val) : value(val) { printf("Parent:%d\\n", val); }
+ Parent::Parent(Parent *p, Parent *q) : value(p->value + q->value) { printf("Parent:%d\\n", value); }
+ void Parent::mulVal(int mul) { value *= mul; }
+
+ #include "bindingtest.cpp"
+ '''
+
+ post2 = '''
+def process(filename):
+ src = open(filename, 'a')
+ src.write(open('bindingtest.js').read() + '\\n\\n')
+ src.close()
+'''
+
+ def post3(filename):
+ script_src_2 = '''
+ var sme = new Module.Parent(42);
+ sme.mulVal(2);
+ Module.print('*')
+ Module.print(sme.getVal());
+
+ Module.print('c1');
+
+ var c1 = new Module.Child1();
+ Module.print(c1.getVal());
+ c1.mulVal(2);
+ Module.print(c1.getVal());
+ Module.print(c1.getValSqr());
+ Module.print(c1.getValSqr(3));
+ Module.print(c1.getValTimes()); // default argument should be 1
+ Module.print(c1.getValTimes(2));
+
+ Module.print('c1 v2');
+
+ c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
+ Module.print(c1.getVal());
+ c1.mulVal(2);
+ Module.print(c1.getVal());
+ Module.print(c1.getValSqr());
+ Module.print(c1.getValSqr(3));
+
+ Module.print('c2')
+
+ var c2 = new Module.Child2();
+ Module.print(c2.getVal());
+ c2.mulVal(2);
+ Module.print(c2.getVal());
+ Module.print(c2.getValCube());
+ var succeeded;
+ try {
+ succeeded = 0;
+ Module.print(c2.doSomethingSecret()); // should fail since private
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+ try {
+ succeeded = 0;
+ Module.print(c2.getValSqr()); // function from the other class
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+ try {
+ succeeded = 0;
+ c2.getValCube(); // sanity
+ succeeded = 1;
+ } catch(e) {}
+ Module.print(succeeded);
+
+ Module.Child2.prototype.printStatic(); // static calls go through the prototype
+
+ // virtual function
+ c2.virtualFunc();
+ Module.Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+
+ // extend the class from JS
+ var c3 = new Module.Child2;
+ Module.customizeVTable(c3, [{
+ original: Module.Child2.prototype.virtualFunc,
+ replacement: function() {
+ Module.print('*js virtualf replacement*');
+ }
+ }, {
+ original: Module.Child2.prototype.virtualFunc2,
+ replacement: function() {
+ Module.print('*js virtualf2 replacement*');
+ }
+ }]);
+ c3.virtualFunc();
+ Module.Child2.prototype.runVirtualFunc(c3);
+ c3.virtualFunc2();
+
+ c2.virtualFunc(); // original should remain the same
+ Module.Child2.prototype.runVirtualFunc(c2);
+ c2.virtualFunc2();
+ Module.print('*ok*');
+ '''
+ code = open(filename).read()
+ src = open(filename, 'w')
+ src.write('var Module = {};\n') # name Module
+ src.write(code)
+ src.write(script_src_2 + '\n')
+ src.close()
+
+ Settings.RESERVED_FUNCTION_POINTERS = 20
+
+ self.do_run(src, '''*
+84
+c1
+Parent:7
+Child1:7
+7
+14
+196
+588
+14
+28
+c1 v2
+Parent:16
+Child1:15
+15
+30
+900
+2700
+c2
+Parent:9
+Child2:9
+9
+18
+5832
+0
+0
+1
+*static*
+*virtualf*
+*virtualf*
+*virtualf2*''' + ('''
+Parent:9
+Child2:9
+*js virtualf replacement*
+*js virtualf replacement*
+*js virtualf2 replacement*
+*virtualf*
+*virtualf*
+*virtualf2*''') + '''
+*ok*
+''', post_build=(post2, post3))
+
+ def test_scriptaclass_2(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+
+ Settings.EXPORT_BINDINGS = 1
+
+ header_filename = os.path.join(self.get_dir(), 'header.h')
+ header = '''
+ #include <stdio.h>
+ #include <string.h>
+
+ class StringUser {
+ char *s;
+ int i;
+ public:
+ StringUser(char *string, int integer) : s(strdup(string)), i(integer) {}
+ void Print(int anotherInteger, char *anotherString) {
+ printf("|%s|%d|%s|%d|\\n", s, i, anotherString, anotherInteger);
+ }
+ void CallOther(StringUser *fr) { fr->Print(i, s); }
+ };
+ '''
+ open(header_filename, 'w').write(header)
+
+ basename = os.path.join(self.get_dir(), 'bindingtest')
+ output = Popen([PYTHON, BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
+ #print output
+ assert 'Traceback' not in output, 'Failure in binding generation: ' + output
+
+ src = '''
+ #include "header.h"
+
+ #include "bindingtest.cpp"
+ '''
+
+ post = '''
+def process(filename):
+ src = open(filename, 'a')
+ src.write(open('bindingtest.js').read() + '\\n\\n')
+ src.write(\'\'\'
+ var user = new Module.StringUser("hello", 43);
+ user.Print(41, "world");
+ \'\'\')
+ src.close()
+'''
+ self.do_run(src, '|hello|43|world|41|', post_build=post)
+
+ def test_typeinfo(self):
+ if self.emcc_args is not None and self.emcc_args != []: return self.skip('full LLVM opts optimize out all the code that uses the type')
+
+ Settings.RUNTIME_TYPE_INFO = 1
+ if Settings.QUANTUM_SIZE != 4: return self.skip('We assume normal sizes in the output here')
+
+ src = '''
+ #include<stdio.h>
+ struct UserStruct {
+ int x;
+ char y;
+ short z;
+ };
+ struct Encloser {
+ short x;
+ UserStruct us;
+ int y;
+ };
+ int main() {
+ Encloser e;
+ e.us.y = 5;
+ printf("*ok:%d*\\n", e.us.y);
+ return 0;
+ }
+ '''
+
+ post = '''
+def process(filename):
+ src = open(filename, 'r').read().replace(
+ '// {{POST_RUN_ADDITIONS}}',
+ \'\'\'
+ if (Runtime.typeInfo) {
+ Module.print('|' + Runtime.typeInfo.UserStruct.fields + '|' + Runtime.typeInfo.UserStruct.flatIndexes + '|');
+ var t = Runtime.generateStructInfo(['x', { us: ['x', 'y', 'z'] }, 'y'], 'Encloser')
+ Module.print('|' + [t.x, t.us.x, t.us.y, t.us.z, t.y] + '|');
+ Module.print('|' + JSON.stringify(Runtime.generateStructInfo(['x', 'y', 'z'], 'UserStruct')) + '|');
+ } else {
+ Module.print('No type info.');
+ }
+ \'\'\'
+ )
+ open(filename, 'w').write(src)
+'''
+
+ self.do_run(src,
+ '*ok:5*\n|i32,i8,i16|0,4,6|\n|0,4,8,10,12|\n|{"__size__":8,"x":0,"y":4,"z":6}|',
+ post_build=post)
+
+ # Make sure that without the setting, we don't spam the .js with the type info
+ Settings.RUNTIME_TYPE_INFO = 0
+ self.do_run(src, 'No type info.', post_build=post)
+
+ ### Tests for tools
+
+ def test_safe_heap(self):
+ if not Settings.SAFE_HEAP: return self.skip('We need SAFE_HEAP to test SAFE_HEAP')
+ if Settings.USE_TYPED_ARRAYS == 2: return self.skip('It is ok to violate the load-store assumption with TA2')
+ if Building.LLVM_OPTS: return self.skip('LLVM can optimize away the intermediate |x|')
+
+ src = '''
+ #include<stdio.h>
+ #include<stdlib.h>
+ int main() { int *x = (int*)malloc(sizeof(int));
+ *x = 20;
+ float *y = (float*)x;
+ printf("%f\\n", *y);
+ printf("*ok*\\n");
+ return 0;
+ }
+ '''
+
+ try:
+ self.do_run(src, '*nothingatall*')
+ except Exception, e:
+ # This test *should* fail, by throwing this exception
+ assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
+
+ # And we should not fail if we disable checking on that line
+
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ["src.cpp:7"]
+
+ self.do_run(src, '*ok*')
+
+ # But if we disable the wrong lines, we still fail
+
+ Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
+
+ try:
+ self.do_run(src, '*nothingatall*')
+ except Exception, e:
+ # This test *should* fail, by throwing this exception
+ assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
+
+ # And reverse the checks with = 2
+
+ Settings.SAFE_HEAP = 2
+ Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
+
+ self.do_run(src, '*ok*')
+
+ Settings.SAFE_HEAP = 1
+
+ # Linking multiple files should work too
+
+ module = '''
+ #include<stdio.h>
+ #include<stdlib.h>
+ void callFunc() { int *x = (int*)malloc(sizeof(int));
+ *x = 20;
+ float *y = (float*)x;
+ printf("%f\\n", *y);
+ }
+ '''
+ module_name = os.path.join(self.get_dir(), 'module.cpp')
+ open(module_name, 'w').write(module)
+
+ main = '''
+ #include<stdio.h>
+ #include<stdlib.h>
+ extern void callFunc();
+ int main() { callFunc();
+ int *x = (int*)malloc(sizeof(int));
+ *x = 20;
+ float *y = (float*)x;
+ printf("%f\\n", *y);
+ printf("*ok*\\n");
+ return 0;
+ }
+ '''
+ main_name = os.path.join(self.get_dir(), 'main.cpp')
+ open(main_name, 'w').write(main)
+
+ Building.emcc(module_name, ['-g'])
+ Building.emcc(main_name, ['-g'])
+ all_name = os.path.join(self.get_dir(), 'all.bc')
+ Building.link([module_name + '.o', main_name + '.o'], all_name)
+
+ try:
+ self.do_ll_run(all_name, '*nothingatall*')
+ except Exception, e:
+ # This test *should* fail, by throwing this exception
+ assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
+
+ # And we should not fail if we disable checking on those lines
+
+ Settings.SAFE_HEAP = 3
+ Settings.SAFE_HEAP_LINES = ["module.cpp:7", "main.cpp:9"]
+
+ self.do_ll_run(all_name, '*ok*')
+
+ # But we will fail if we do not disable exactly what we need to - any mistake leads to error
+
+ for lines in [["module.cpp:22", "main.cpp:9"], ["module.cpp:7", "main.cpp:29"], ["module.cpp:127", "main.cpp:449"], ["module.cpp:7"], ["main.cpp:9"]]:
+ Settings.SAFE_HEAP_LINES = lines
+ try:
+ self.do_ll_run(all_name, '*nothingatall*')
+ except Exception, e:
+ # This test *should* fail, by throwing this exception
+ assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
+
+ def test_debug(self):
+ if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+ if self.emcc_args is not None:
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args: return self.skip('optimizations remove LLVM debug info')
+
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+
+ void checker(int x) {
+ x += 20;
+ assert(x < 15); // this is line 7!
+ }
+
+ int main() {
+ checker(10);
+ return 0;
+ }
+ '''
+ try:
+ self.do_run(src, '*nothingatall*')
+ except Exception, e:
+ # This test *should* fail
+ assert 'Assertion failed: x < 15' in str(e), str(e)
+
+ lines = open('src.cpp.o.js', 'r').readlines()
+ lines = filter(lambda line: '___assert_fail(' in line or '___assert_func(' in line, lines)
+ found_line_num = any(('//@line 7 "' in line) for line in lines)
+ found_filename = any(('src.cpp"\n' in line) for line in lines)
+ assert found_line_num, 'Must have debug info with the line number'
+ assert found_filename, 'Must have debug info with the filename'
+
+ def test_source_map(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
+ if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
+ if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+
+ __attribute__((noinline)) int foo() {
+ printf("hi"); // line 6
+ return 1; // line 7
+ }
+
+ int main() {
+ printf("%d", foo()); // line 11
+ return 0; // line 12
+ }
+ '''
+
+ dirname = self.get_dir()
+ src_filename = os.path.join(dirname, 'src.cpp')
+ out_filename = os.path.join(dirname, 'a.out.js')
+ no_maps_filename = os.path.join(dirname, 'no-maps.out.js')
+
+ with open(src_filename, 'w') as f: f.write(src)
+ assert '-g4' not in Building.COMPILER_TEST_OPTS
+ Building.emcc(src_filename, Settings.serialize() + self.emcc_args +
+ Building.COMPILER_TEST_OPTS, out_filename)
+ # the file name may find its way into the generated code, so make sure we
+ # can do an apples-to-apples comparison by compiling with the same file name
+ shutil.move(out_filename, no_maps_filename)
+ with open(no_maps_filename) as f: no_maps_file = f.read()
+ no_maps_file = re.sub(' *//@.*$', '', no_maps_file, flags=re.MULTILINE)
+ Building.COMPILER_TEST_OPTS.append('-g4')
+
+ def build_and_check():
+ import json
+ Building.emcc(src_filename, Settings.serialize() + self.emcc_args +
+ Building.COMPILER_TEST_OPTS, out_filename, stderr=PIPE)
+ with open(out_filename) as f: out_file = f.read()
+ # after removing the @line and @sourceMappingURL comments, the build
+ # result should be identical to the non-source-mapped debug version.
+ # this is worth checking because the parser AST swaps strings for token
+ # objects when generating source maps, so we want to make sure the
+ # optimizer can deal with both types.
+ out_file = re.sub(' *//@.*$', '', out_file, flags=re.MULTILINE)
+ def clean(code):
+ return code.replace('{\n}', '{}')
+ self.assertIdentical(clean(no_maps_file), clean(out_file))
+ map_filename = out_filename + '.map'
+ data = json.load(open(map_filename, 'r'))
+ self.assertPathsIdentical(out_filename, data['file'])
+ self.assertPathsIdentical(src_filename, data['sources'][0])
+ self.assertTextDataIdentical(src, data['sourcesContent'][0])
+ mappings = json.loads(jsrun.run_js(
+ path_from_root('tools', 'source-maps', 'sourcemap2json.js'),
+ tools.shared.NODE_JS, [map_filename]))
+ seen_lines = set()
+ for m in mappings:
+ self.assertPathsIdentical(src_filename, m['source'])
+ seen_lines.add(m['originalLine'])
+ # ensure that all the 'meaningful' lines in the original code get mapped
+ assert seen_lines.issuperset([6, 7, 11, 12])
+
+ # EMCC_DEBUG=2 causes lots of intermediate files to be written, and so
+ # serves as a stress test for source maps because it needs to correlate
+ # line numbers across all those files.
+ old_emcc_debug = os.environ.get('EMCC_DEBUG', None)
+ os.environ.pop('EMCC_DEBUG', None)
+ try:
+ build_and_check()
+ os.environ['EMCC_DEBUG'] = '2'
+ build_and_check()
+ finally:
+ if old_emcc_debug is not None:
+ os.environ['EMCC_DEBUG'] = old_emcc_debug
+ else:
+ os.environ.pop('EMCC_DEBUG', None)
+
+ def test_exception_source_map(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
+ if '-g4' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g4')
+ if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
+
+ src = '''
+ #include <stdio.h>
+
+ __attribute__((noinline)) void foo(int i) {
+ if (i < 10) throw i; // line 5
+ }
+
+ int main() {
+ int i;
+ scanf("%d", &i);
+ foo(i);
+ return 0;
+ }
+ '''
+
+ def post(filename):
+ import json
+ map_filename = filename + '.map'
+ mappings = json.loads(jsrun.run_js(
+ path_from_root('tools', 'source-maps', 'sourcemap2json.js'),
+ tools.shared.NODE_JS, [map_filename]))
+ with open(filename) as f: lines = f.readlines()
+ for m in mappings:
+ if m['originalLine'] == 5 and '__cxa_throw' in lines[m['generatedLine']]:
+ return
+ assert False, 'Must label throw statements with line numbers'
+
+ dirname = self.get_dir()
+ self.build(src, dirname, os.path.join(dirname, 'src.cpp'), post_build=(None, post))
+
+ def test_linespecific(self):
+ if Settings.ASM_JS: return self.skip('asm always has corrections on')
+
+ if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+ if self.emcc_args:
+ self.emcc_args += ['--llvm-opts', '0'] # llvm full opts make the expected failures here not happen
+ Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
+
+ Settings.CHECK_SIGNS = 0
+ Settings.CHECK_OVERFLOWS = 0
+
+ # Signs
+
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+
+ int main()
+ {
+ int varey = 100;
+ unsigned int MAXEY = -1;
+ printf("*%d*\\n", varey >= MAXEY); // 100 >= -1? not in unsigned!
+ }
+ '''
+
+ Settings.CORRECT_SIGNS = 0
+ self.do_run(src, '*1*') # This is a fail - we expect 0
+
+ Settings.CORRECT_SIGNS = 1
+ self.do_run(src, '*0*') # Now it will work properly
+
+ # And now let's fix just that one line
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
+ self.do_run(src, '*0*')
+
+ # Fixing the wrong line should not work
+ Settings.CORRECT_SIGNS = 2
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"]
+ self.do_run(src, '*1*')
+
+ # And reverse the checks with = 2
+ Settings.CORRECT_SIGNS = 3
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"]
+ self.do_run(src, '*0*')
+ Settings.CORRECT_SIGNS = 3
+ Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"]
+ self.do_run(src, '*1*')
+
+ Settings.CORRECT_SIGNS = 0
+
+ # Overflows
+
+ src = '''
+ #include<stdio.h>
+ int main() {
+ int t = 77;
+ for (int i = 0; i < 30; i++) {
+ t = t + t + t + t + t + 1;
+ }
+ printf("*%d,%d*\\n", t, t & 127);
+ return 0;
+ }
+ '''
+
+ correct = '*186854335,63*'
+ Settings.CORRECT_OVERFLOWS = 0
+ try:
+ self.do_run(src, correct)
+ raise Exception('UNEXPECTED-PASS')
+ except Exception, e:
+ assert 'UNEXPECTED' not in str(e), str(e)
+ assert 'Expected to find' in str(e), str(e)
+
+ Settings.CORRECT_OVERFLOWS = 1
+ self.do_run(src, correct) # Now it will work properly
+
+ # And now let's fix just that one line
+ Settings.CORRECT_OVERFLOWS = 2
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
+ self.do_run(src, correct)
+
+ # Fixing the wrong line should not work
+ Settings.CORRECT_OVERFLOWS = 2
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
+ try:
+ self.do_run(src, correct)
+ raise Exception('UNEXPECTED-PASS')
+ except Exception, e:
+ assert 'UNEXPECTED' not in str(e), str(e)
+ assert 'Expected to find' in str(e), str(e)
+
+ # And reverse the checks with = 2
+ Settings.CORRECT_OVERFLOWS = 3
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"]
+ self.do_run(src, correct)
+ Settings.CORRECT_OVERFLOWS = 3
+ Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"]
+ try:
+ self.do_run(src, correct)
+ raise Exception('UNEXPECTED-PASS')
+ except Exception, e:
+ assert 'UNEXPECTED' not in str(e), str(e)
+ assert 'Expected to find' in str(e), str(e)
+
+ Settings.CORRECT_OVERFLOWS = 0
+
+ # Roundings
+
+ src = '''
+ #include <stdio.h>
+ #include <assert.h>
+
+ int main()
+ {
+ TYPE x = -5;
+ printf("*%d*", x/2);
+ x = 5;
+ printf("*%d*", x/2);
+
+ float y = -5.33;
+ x = y;
+ printf("*%d*", x);
+ y = 5.33;
+ x = y;
+ printf("*%d*", x);
+
+ printf("\\n");
+ }
+ '''
+
+ if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
+ Settings.CORRECT_ROUNDINGS = 0
+ self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here!
+ self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*-2**2**-6**5*')
+
+ Settings.CORRECT_ROUNDINGS = 1
+ Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
+ self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') # Correct
+ self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Correct
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') # Correct
+ Settings.CORRECT_SIGNS = 0
+
+ if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
+ Settings.CORRECT_ROUNDINGS = 2
+ Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
+ self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*')
+ self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*-2**2**-5**5*')
+
+ # And reverse the check with = 2
+ if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
+ Settings.CORRECT_ROUNDINGS = 3
+ Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"]
+ self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*')
+ self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*')
+ Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*')
+ Settings.CORRECT_SIGNS = 0
+
+ def test_exit_status(self):
+ if self.emcc_args is None: return self.skip('need emcc')
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ static void cleanup() {
+ printf("cleanup\n");
+ }
+
+ int main() {
+ atexit(cleanup); // this atexit should still be called
+ printf("hello, world!\n");
+ exit(118); // Unusual exit status to make sure it's working!
+ }
+ '''
+ open('post.js', 'w').write('''
+ Module.addOnExit(function () {
+ Module.print('I see exit status: ' + EXITSTATUS);
+ });
+ Module.callMain();
+ ''')
+ self.emcc_args += ['-s', 'INVOKE_RUN=0', '--post-js', 'post.js']
+ self.do_run(src, 'hello, world!\nexit(118) called\ncleanup\nI see exit status: 118')
+
+ def test_gc(self):
+ if self.emcc_args == None: return self.skip('needs ta2')
+ if Settings.ASM_JS: return self.skip('asm cannot support generic function table')
+
+ Settings.GC_SUPPORT = 1
+
+ src = r'''
+ #include <stdio.h>
+ #include <gc.h>
+ #include <assert.h>
+
+ void *global;
+
+ void finalizer(void *ptr, void *arg) {
+ printf("finalizing %d (global == %d)\n", (int)arg, ptr == global);
+ }
+
+ void finalizer2(void *ptr, void *arg) {
+ printf("finalizing2 %d (global == %d)\n", (int)arg, ptr == global);
+ }
+
+ int main() {
+ GC_INIT();
+
+ void *local, *local2, *local3, *local4, *local5, *local6;
+
+ // Hold on to global, drop locals
+
+ global = GC_MALLOC(1024); // rooted since in a static allocation
+ GC_REGISTER_FINALIZER_NO_ORDER(global, finalizer, 0, 0, 0);
+ printf("alloc %p\n", global);
+
+ local = GC_MALLOC(1024); // not rooted since stack is not scanned
+ GC_REGISTER_FINALIZER_NO_ORDER(local, finalizer, (void*)1, 0, 0);
+ printf("alloc %p\n", local);
+
+ assert((char*)local - (char*)global >= 1024 || (char*)global - (char*)local >= 1024);
+
+ local2 = GC_MALLOC(1024); // no finalizer
+ printf("alloc %p\n", local2);
+
+ local3 = GC_MALLOC(1024); // with finalizable2
+ GC_REGISTER_FINALIZER_NO_ORDER(local3, finalizer2, (void*)2, 0, 0);
+ printf("alloc %p\n", local);
+
+ local4 = GC_MALLOC(1024); // yet another
+ GC_REGISTER_FINALIZER_NO_ORDER(local4, finalizer2, (void*)3, 0, 0);
+ printf("alloc %p\n", local);
+
+ printf("basic test\n");
+
+ GC_FORCE_COLLECT();
+
+ printf("*\n");
+
+ GC_FREE(global); // force free will actually work
+
+ // scanning inside objects
+
+ global = GC_MALLOC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(global, finalizer, 0, 0, 0);
+ local = GC_MALLOC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(local, finalizer, (void*)1, 0, 0);
+ local2 = GC_MALLOC_ATOMIC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(local2, finalizer, (void*)2, 0, 0);
+ local3 = GC_MALLOC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(local3, finalizer, (void*)3, 0, 0);
+ local4 = GC_MALLOC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(local4, finalizer, (void*)4, 0, 0);
+ local5 = GC_MALLOC_UNCOLLECTABLE(12);
+ // This should never trigger since local5 is uncollectable
+ GC_REGISTER_FINALIZER_NO_ORDER(local5, finalizer, (void*)5, 0, 0);
+
+ printf("heap size = %d\n", GC_get_heap_size());
+
+ local4 = GC_REALLOC(local4, 24);
+
+ printf("heap size = %d\n", GC_get_heap_size());
+
+ local6 = GC_MALLOC(12);
+ GC_REGISTER_FINALIZER_NO_ORDER(local6, finalizer, (void*)6, 0, 0);
+ // This should be the same as a free
+ GC_REALLOC(local6, 0);
+
+ void **globalData = (void**)global;
+ globalData[0] = local;
+ globalData[1] = local2;
+
+ void **localData = (void**)local;
+ localData[0] = local3;
+
+ void **local2Data = (void**)local2;
+ local2Data[0] = local4; // actually ignored, because local2 is atomic, so 4 is freeable
+
+ printf("object scan test test\n");
+
+ GC_FORCE_COLLECT();
+
+ printf("*\n");
+
+ GC_FREE(global); // force free will actually work
+
+ printf("*\n");
+
+ GC_FORCE_COLLECT();
+
+ printf(".\n");
+
+ global = 0;
+
+ return 0;
+ }
+ '''
+ self.do_run(src, '''basic test
+finalizing 1 (global == 0)
+finalizing2 2 (global == 0)
+finalizing2 3 (global == 0)
+*
+finalizing 0 (global == 1)
+heap size = 72
+heap size = 84
+finalizing 6 (global == 0)
+object scan test test
+finalizing 4 (global == 0)
+*
+finalizing 0 (global == 1)
+*
+finalizing 1 (global == 0)
+finalizing 2 (global == 0)
+finalizing 3 (global == 0)
+.
+''')
+
+# Generate tests for everything
+def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0,
+ typed_arrays=0, emcc_args=None, env=None):
+
+ if env is None: env = {}
+
+ TT = type(fullname, (T,), dict(run_name = fullname, env = env))
+
+ def tearDown(self):
+ super(TT, self).tearDown()
+
+ for k, v in self.env.iteritems():
+ del os.environ[k]
+
+ # clear global changes to Building
+ Building.COMPILER_TEST_OPTS = []
+ Building.COMPILER = CLANG
+ Building.LLVM_OPTS = 0
+
+ TT.tearDown = tearDown
+
+ def setUp(self):
+ super(TT, self).setUp()
+ for k, v in self.env.iteritems():
+ assert k not in os.environ, k + ' should not be in environment'
+ os.environ[k] = v
+
+ global checked_sanity
+ if not checked_sanity:
+ print '(checking sanity from test runner)' # do this after we set env stuff
+ check_sanity(force=True)
+ checked_sanity = True
+
+ Building.COMPILER_TEST_OPTS = ['-g']
+ os.chdir(self.get_dir()) # Ensure the directory exists and go there
+ Building.COMPILER = compiler
+
+ self.emcc_args = None if emcc_args is None else emcc_args[:]
+ if self.emcc_args is not None:
+ Settings.load(self.emcc_args)
+ Building.LLVM_OPTS = 0
+ if '-O2' in self.emcc_args:
+ Building.COMPILER_TEST_OPTS = [] # remove -g in -O2 tests, for more coverage
+ #Building.COMPILER_TEST_OPTS += self.emcc_args
+ for arg in self.emcc_args:
+ if arg.startswith('-O'):
+ Building.COMPILER_TEST_OPTS.append(arg) # so bitcode is optimized too, this is for cpp to ll
+ else:
+ try:
+ key, value = arg.split('=')
+ Settings[key] = value # forward -s K=V
+ except:
+ pass
+ return
+
+ # TODO: Move much of these to a init() function in shared.py, and reuse that
+ Settings.USE_TYPED_ARRAYS = typed_arrays
+ Settings.INVOKE_RUN = 1
+ Settings.RELOOP = 0 # we only do them in the "o2" pass
+ Settings.MICRO_OPTS = embetter
+ Settings.QUANTUM_SIZE = quantum_size
+ Settings.ASSERTIONS = 1-embetter
+ Settings.SAFE_HEAP = 1-embetter
+ Settings.CHECK_OVERFLOWS = 1-embetter
+ Settings.CORRECT_OVERFLOWS = 1-embetter
+ Settings.CORRECT_SIGNS = 0
+ Settings.CORRECT_ROUNDINGS = 0
+ Settings.CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
+ Settings.CHECK_SIGNS = 0 #1-embetter
+ Settings.RUNTIME_TYPE_INFO = 0
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ Settings.INCLUDE_FULL_LIBRARY = 0
+ Settings.BUILD_AS_SHARED_LIB = 0
+ Settings.RUNTIME_LINKED_LIBS = []
+ Settings.EMULATE_UNALIGNED_ACCESSES = int(Settings.USE_TYPED_ARRAYS == 2 and Building.LLVM_OPTS == 2)
+ Settings.DOUBLE_MODE = 1 if Settings.USE_TYPED_ARRAYS and Building.LLVM_OPTS == 0 else 0
+ Settings.PRECISE_I64_MATH = 0
+ Settings.NAMED_GLOBALS = 0 if not embetter else 1
+
+ TT.setUp = setUp
+
+ return TT
+
+# Make one run with the defaults
+default = make_run("default", compiler=CLANG, emcc_args=[])
+
+# Make one run with -O1, with safe heap
+o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "ASM_JS=0", "-s", "SAFE_HEAP=1"])
+
+# Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow)
+o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "JS_CHUNK_SIZE=1024"])
+
+# asm.js
+asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1", "-s", "CHECK_HEAP_ALIGN=1"])
+asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])
+asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1"])
+asm2x86 = make_run("asm2x86", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "CHECK_HEAP_ALIGN=1"], env={"EMCC_LLVM_TARGET": "i386-pc-linux-gnu"})
+
+# Make custom runs with various options
+for compiler, quantum, embetter, typed_arrays in [
+ (CLANG, 4, 0, 0),
+ (CLANG, 4, 1, 1),
+]:
+ fullname = 's_0_%d%s%s' % (
+ embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays)
+ )
+ locals()[fullname] = make_run(fullname, fullname, compiler, embetter, quantum, typed_arrays)
+
+del T # T is just a shape for the specific subclasses, we don't test it itself \ No newline at end of file
diff --git a/tests/test_other.py b/tests/test_other.py
new file mode 100644
index 00000000..3b3887d6
--- /dev/null
+++ b/tests/test_other.py
@@ -0,0 +1,1913 @@
+import multiprocessing, os, re, shutil, subprocess, sys
+import tools.shared
+from tools.shared import *
+from runner import RunnerCore, path_from_root
+
+class other(RunnerCore):
+ def test_emcc(self):
+ for compiler in [EMCC, EMXX]:
+ shortcompiler = os.path.basename(compiler)
+ suffix = '.c' if compiler == EMCC else '.cpp'
+
+ # --version
+ output = Popen([PYTHON, compiler, '--version'], stdout=PIPE, stderr=PIPE).communicate()
+ output = output[0].replace('\r', '')
+ self.assertContained('''emcc (Emscripten GCC-like replacement)''', output)
+ self.assertContained('''Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt)
+This is free and open source software under the MIT license.
+There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+''', output)
+
+ # -v, without input files
+ output = Popen([PYTHON, compiler, '-v'], stdout=PIPE, stderr=PIPE).communicate()
+ self.assertContained('''clang version''', output[1].replace('\r', ''), output[1].replace('\r', ''))
+
+ # --help
+ output = Popen([PYTHON, compiler, '--help'], stdout=PIPE, stderr=PIPE).communicate()
+ self.assertContained('''%s [options] file...
+
+Most normal gcc/g++ options will work, for example:
+ --help Display this information
+ --version Display compiler version information
+
+Options that are modified or new in %s include:
+ -O0 No optimizations (default)
+''' % (shortcompiler, shortcompiler), output[0].replace('\r', ''), output[1].replace('\r', ''))
+
+ # emcc src.cpp ==> writes a.out.js
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix)], stdout=PIPE, stderr=PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists('a.out.js'), '\n'.join(output)
+ self.assertContained('hello, world!', run_js('a.out.js'))
+
+ # properly report source code errors, and stop there
+ self.clear()
+ assert not os.path.exists('a.out.js')
+ process = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_error' + suffix)], stdout=PIPE, stderr=PIPE)
+ output = process.communicate()
+ assert not os.path.exists('a.out.js'), 'compilation failed, so no output file is expected'
+ assert len(output[0]) == 0, output[0]
+ assert process.returncode is not 0, 'Failed compilation must return a nonzero error code!'
+ self.assertNotContained('IOError', output[1]) # no python stack
+ self.assertNotContained('Traceback', output[1]) # no python stack
+ self.assertContained('error: invalid preprocessing directive', output[1])
+ self.assertContained(["error: use of undeclared identifier 'cheez", "error: unknown type name 'cheez'"], output[1])
+ self.assertContained('errors generated', output[1])
+ assert 'compiler frontend failed to generate LLVM bitcode, halting' in output[1].split('errors generated.')[1]
+
+ # emcc src.cpp -c and emcc src.cpp -o src.[o|bc] ==> should give a .bc file
+ # regression check: -o js should create "js", with bitcode content
+ for args in [['-c'], ['-o', 'src.o'], ['-o', 'src.bc'], ['-o', 'src.so'], ['-o', 'js']]:
+ target = args[1] if len(args) == 2 else 'hello_world.o'
+ self.clear()
+ Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate()
+ syms = Building.llvm_nm(target)
+ assert len(syms.defs) == 1 and 'main' in syms.defs, 'Failed to generate valid bitcode'
+ if target == 'js': # make sure emcc can recognize the target as a bitcode file
+ shutil.move(target, target + '.bc')
+ target += '.bc'
+ output = Popen([PYTHON, compiler, target, '-o', target + '.js'], stdout = PIPE, stderr = PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists(target + '.js'), 'Expected %s to exist since args are %s : %s' % (target + '.js', str(args), '\n'.join(output))
+ self.assertContained('hello, world!', run_js(target + '.js'))
+
+ # handle singleton archives
+ self.clear()
+ Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix), '-o', 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
+ Popen([LLVM_AR, 'r', 'a.a', 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists('a.a')
+ output = Popen([PYTHON, compiler, 'a.a']).communicate()
+ assert os.path.exists('a.out.js'), output
+ self.assertContained('hello, world!', run_js('a.out.js'))
+
+ # emcc src.ll ==> generates .js
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.ll')], stdout=PIPE, stderr=PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists('a.out.js'), '\n'.join(output)
+ self.assertContained('hello, world!', run_js('a.out.js'))
+
+ # emcc [..] -o [path] ==> should work with absolute paths
+ try:
+ for path in [os.path.abspath(os.path.join('..', 'file1.js')), os.path.join('b_dir', 'file2.js')]:
+ print path
+ self.clear(in_curr=True)
+ os.chdir(self.get_dir())
+ if not os.path.exists('a_dir'): os.mkdir('a_dir')
+ os.chdir('a_dir')
+ if not os.path.exists('b_dir'): os.mkdir('b_dir')
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.ll'), '-o', path], stdout=PIPE, stderr=PIPE).communicate()
+ print output
+ assert os.path.exists(path), path + ' does not exist; ' + '\n'.join(output)
+ last = os.getcwd()
+ os.chdir(os.path.dirname(path))
+ self.assertContained('hello, world!', run_js(os.path.basename(path)))
+ os.chdir(last)
+ finally:
+ os.chdir(self.get_dir())
+ self.clear()
+
+ # dlmalloc. dlmalloc is special in that it is the only part of libc that is (1) hard to write well, and
+ # very speed-sensitive. So we do not implement it in JS in library.js, instead we compile it from source
+ for source, has_malloc in [('hello_world' + suffix, False), ('hello_malloc.cpp', True)]:
+ print source, has_malloc
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', source)], stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists('a.out.js'), '\n'.join(output)
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ generated = open('a.out.js').read()
+ assert ('function _malloc(bytes) {' in generated) == (not has_malloc), 'If malloc is needed, it should be there, if not not'
+
+ # Optimization: emcc src.cpp -o something.js [-Ox]. -O0 is the same as not specifying any optimization setting
+ for params, opt_level, bc_params, closure, has_malloc in [ # bc params are used after compiling to bitcode
+ (['-o', 'something.js'], 0, None, 0, 1),
+ (['-o', 'something.js', '-O0'], 0, None, 0, 0),
+ (['-o', 'something.js', '-O1'], 1, None, 0, 0),
+ (['-o', 'something.js', '-O1', '-g'], 1, None, 0, 0), # no closure since debug
+ (['-o', 'something.js', '-O1', '--closure', '1'], 1, None, 1, 0),
+ (['-o', 'something.js', '-O1', '--closure', '1', '-s', 'ASM_JS=0'], 1, None, 1, 0),
+ (['-o', 'something.js', '-O2'], 2, None, 0, 1),
+ (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0),
+ (['-o', 'something.js', '-Os'], 2, None, 0, 1),
+ (['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 1, 1),
+ # and, test compiling to bitcode first
+ (['-o', 'something.bc'], 0, [], 0, 0),
+ (['-o', 'something.bc', '-O0'], 0, [], 0, 0),
+ (['-o', 'something.bc', '-O1'], 1, ['-O1'], 0, 0),
+ (['-o', 'something.bc', '-O2'], 2, ['-O2'], 0, 0),
+ (['-o', 'something.bc', '-O3'], 3, ['-O3', '-s', 'ASM_JS=0'], 1, 0),
+ (['-O1', '-o', 'something.bc'], 1, [], 0, 0),
+ ]:
+ print params, opt_level, bc_params, closure, has_malloc
+ self.clear()
+ keep_debug = '-g' in params
+ args = [PYTHON, compiler, path_from_root('tests', 'hello_world_loop' + ('_malloc' if has_malloc else '') + '.cpp')] + params
+ print '..', args
+ output = Popen(args,
+ stdout=PIPE, stderr=PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ if bc_params is not None:
+ assert os.path.exists('something.bc'), output[1]
+ bc_args = [PYTHON, compiler, 'something.bc', '-o', 'something.js'] + bc_params
+ print '....', bc_args
+ output = Popen(bc_args, stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists('something.js'), output[1]
+ assert ('Applying some potentially unsafe optimizations!' in output[1]) == (opt_level >= 3), 'unsafe warning should appear in opt >= 3'
+ self.assertContained('hello, world!', run_js('something.js'))
+
+ # Verify optimization level etc. in the generated code
+ # XXX these are quite sensitive, and will need updating when code generation changes
+ generated = open('something.js').read() # TODO: parse out the _main function itself, not support code, if the tests below need that some day
+ assert 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 should be used by default'
+ assert 'SAFE_HEAP' not in generated, 'safe heap should not be used by default'
+ assert ': while(' not in generated, 'when relooping we also js-optimize, so there should be no labelled whiles'
+ if closure:
+ if opt_level == 0: assert '._main =' in generated, 'closure compiler should have been run'
+ elif opt_level >= 1: assert '._main=' in generated, 'closure compiler should have been run (and output should be minified)'
+ else:
+ # closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure
+ assert '._main = ' not in generated, 'closure compiler should not have been run'
+ if keep_debug:
+ assert ('(label)' in generated or '(label | 0)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2'
+ assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0'
+ assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated or 'var $original = 0' in generated, 'micro opts should always be on'
+ if opt_level >= 2 and '-g' in params:
+ assert re.search('HEAP8\[\$?\w+ ?\+ ?\(+\$?\w+ ?', generated) or re.search('HEAP8\[HEAP32\[', generated), 'eliminator should create compound expressions, and fewer one-time vars' # also in -O1, but easier to test in -O2
+ assert ('_puts(' in generated) == (opt_level >= 1), 'with opt >= 1, llvm opts are run and they should optimize printf to puts'
+ if opt_level == 0 or '-g' in params: assert 'function _main() {' in generated, 'Should be unminified, including whitespace'
+ elif opt_level >= 2: assert ('function _main(){' in generated or '"use asm";var a=' in generated), 'Should be whitespace-minified'
+
+ # emcc -s RELOOP=1 src.cpp ==> should pass -s to emscripten.py. --typed-arrays is a convenient alias for -s USE_TYPED_ARRAYS
+ for params, test, text in [
+ (['-O2'], lambda generated: 'function intArrayToString' in generated, 'shell has unminified utilities'),
+ (['-O2', '--closure', '1'], lambda generated: 'function intArrayToString' not in generated, 'closure minifies the shell'),
+ (['-O2'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2'),
+ (['-O2', '--minify', '0'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'minify is cancelled, but not registerize'),
+ (['-O2', '--js-opts', '0'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'js opts are cancelled'),
+ (['-O2', '-g'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize/minify is cancelled by -g'),
+ (['-O2', '-g0'], lambda generated: 'var b=0' in generated and not 'function _main' in generated, 'registerize/minify is run by default in -O2 -g0'),
+ (['-O2', '-g1'], lambda generated: 'var b = 0' in generated and not 'function _main' in generated, 'compress is cancelled by -g1'),
+ (['-O2', '-g2'], lambda generated: ('var b = 0' in generated or 'var i1 = 0' in generated) and 'function _main' in generated, 'minify is cancelled by -g2'),
+ (['-O2', '-g3'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'registerize is cancelled by -g3'),
+ #(['-O2', '-g4'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'same as -g3 for now'),
+ (['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'),
+ (['-O3', '-s', 'INLINING_LIMIT=0', '--closure', '0'], lambda generated: 'function _dump' not in generated, 'lto/inlining'),
+ (['-Os', '--llvm-lto', '1', '-s', 'ASM_JS=0'], lambda generated: 'function _dump' in generated, '-Os disables inlining'),
+ (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
+ (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
+ ([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'),
+ (['-s', 'EXPORTED_FUNCTIONS=["_main", "_dump"]'], lambda generated: 'Module["_dump"]' in generated, 'dump is now exported'),
+ (['--typed-arrays', '0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
+ (['--typed-arrays', '1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
+ (['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'),
+ (['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'),
+ ]:
+ print params, text
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop.cpp'), '-o', 'a.out.js'] + params, stdout=PIPE, stderr=PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists('a.out.js'), '\n'.join(output)
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ assert test(open('a.out.js').read()), text
+
+ # Compiling two source files into a final JS.
+ for args, target in [([], 'a.out.js'), (['-o', 'combined.js'], 'combined.js')]:
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'twopart_main.cpp'), path_from_root('tests', 'twopart_side.cpp')] + args,
+ stdout=PIPE, stderr=PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists(target), '\n'.join(output)
+ self.assertContained('side got: hello from main, over', run_js(target))
+
+ # Compiling two files with -c will generate separate .bc files
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'twopart_main.cpp'), path_from_root('tests', 'twopart_side.cpp'), '-c'] + args,
+ stdout=PIPE, stderr=PIPE).communicate()
+ if '-o' in args:
+ # specifying -o and -c is an error
+ assert 'fatal error' in output[1], output[1]
+ continue
+
+ assert os.path.exists('twopart_main.o'), '\n'.join(output)
+ assert os.path.exists('twopart_side.o'), '\n'.join(output)
+ assert not os.path.exists(target), 'We should only have created bitcode here: ' + '\n'.join(output)
+
+ # Compiling one of them alone is expected to fail
+ output = Popen([PYTHON, compiler, 'twopart_main.o', '-O1', '-g'] + args, stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists(target), '\n'.join(output)
+ #print '\n'.join(output)
+ self.assertContained('missing function', run_js(target, stderr=STDOUT))
+ try_delete(target)
+
+ # Combining those bc files into js should work
+ output = Popen([PYTHON, compiler, 'twopart_main.o', 'twopart_side.o'] + args, stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists(target), '\n'.join(output)
+ self.assertContained('side got: hello from main, over', run_js(target))
+
+ # Combining bc files into another bc should also work
+ try_delete(target)
+ assert not os.path.exists(target)
+ output = Popen([PYTHON, compiler, 'twopart_main.o', 'twopart_side.o', '-o', 'combined.bc'] + args, stdout=PIPE, stderr=PIPE).communicate()
+ syms = Building.llvm_nm('combined.bc')
+ assert len(syms.defs) == 2 and 'main' in syms.defs, 'Failed to generate valid bitcode'
+ output = Popen([PYTHON, compiler, 'combined.bc', '-o', 'combined.bc.js'], stdout = PIPE, stderr = PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists('combined.bc.js'), 'Expected %s to exist' % ('combined.bc.js')
+ self.assertContained('side got: hello from main, over', run_js('combined.bc.js'))
+
+ # --js-transform <transform>
+ self.clear()
+ trans = os.path.join(self.get_dir(), 't.py')
+ trans_file = open(trans, 'w')
+ trans_file.write('''
+import sys
+f = open(sys.argv[1], 'w')
+f.write('transformed!')
+f.close()
+''')
+ trans_file.close()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix), '--js-transform', '%s t.py' % (PYTHON)], stdout=PIPE, stderr=PIPE).communicate()
+ assert open('a.out.js').read() == 'transformed!', 'Transformed output must be as expected'
+
+ # TODO: Add in files test a clear example of using disablePermissions, and link to it from the wiki
+ # TODO: test normal project linking, static and dynamic: get_library should not need to be told what to link!
+ # TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
+
+ def test_cmake(self):
+ # On Windows, we want to build cmake-generated Makefiles with mingw32-make instead of e.g. cygwin make, since mingw32-make
+ # understands Windows paths, and cygwin make additionally produces a cryptic 'not valid bitcode file' errors on files that
+ # *are* valid bitcode files.
+
+ if os.name == 'nt':
+ make_command = 'mingw32-make'
+ emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten.cmake')
+ else:
+ make_command = 'make'
+ emscriptencmaketoolchain = path_from_root('cmake', 'Platform', 'Emscripten_unix.cmake')
+
+ cmake_cases = ['target_js', 'target_html']
+ cmake_outputs = ['hello_world.js', 'hello_world_gles.html']
+ for i in range(0, 2):
+ for configuration in ['Debug', 'Release']:
+
+ # Create a temp workspace folder
+ cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i])
+ tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
+ try:
+ os.chdir(tempdirname)
+
+ # Run Cmake
+ cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain,
+ '-DCMAKE_BUILD_TYPE=' + configuration,
+ '-DCMAKE_MODULE_PATH=' + path_from_root('cmake').replace('\\', '/'),
+ '-G' 'Unix Makefiles', cmakelistsdir]
+ ret = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
+ if ret[1] != None and len(ret[1].strip()) > 0:
+ print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics.
+ if 'error' in ret[1].lower():
+ print >> sys.stderr, 'Failed command: ' + ' '.join(cmd)
+ print >> sys.stderr, 'Result:\n' + ret[1]
+ raise Exception('cmake call failed!')
+ assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
+
+ # Build
+ cmd = [make_command]
+ ret = Popen(cmd, stdout=PIPE).communicate()
+ if ret[1] != None and len(ret[1].strip()) > 0:
+ print >> sys.stderr, ret[1] # If there were any errors, print them directly to console for diagnostics.
+ if 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower():
+ print >> sys.stderr, 'Failed command: ' + ' '.join(cmd)
+ print >> sys.stderr, 'Result:\n' + ret[0]
+ raise Exception('make failed!')
+ assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i]
+
+ # Run through node, if CMake produced a .js file.
+ if cmake_outputs[i].endswith('.js'):
+ ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0]
+ assert 'hello, world!' in ret, 'Running cmake-based .js application failed!'
+ finally:
+ os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove.
+ shutil.rmtree(tempdirname)
+
+ def test_nostdincxx(self):
+ try:
+ old = os.environ.get('EMCC_LLVM_TARGET') or ''
+ for compiler in [EMCC, EMXX]:
+ for target in ['i386-pc-linux-gnu', 'le32-unknown-nacl']:
+ print compiler, target
+ os.environ['EMCC_LLVM_TARGET'] = target
+ out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v'], stdout=PIPE, stderr=PIPE).communicate()
+ out2, err2 = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE).communicate()
+ assert out == out2
+ def focus(e):
+ assert 'search starts here:' in e, e
+ assert e.count('End of search list.') == 1, e
+ return e[e.index('search starts here:'):e.index('End of search list.')+20]
+ err = focus(err)
+ err2 = focus(err2)
+ assert err == err2, err + '\n\n\n\n' + err2
+ finally:
+ if old:
+ os.environ['EMCC_LLVM_TARGET'] = old
+
+ def test_failure_error_code(self):
+ for compiler in [EMCC, EMXX]:
+ # Test that if one file is missing from the build, then emcc shouldn't succeed, and shouldn't try to produce an output file.
+ process = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.c'), 'this_file_is_missing.c', '-o', 'this_output_file_should_never_exist.js'], stdout=PIPE, stderr=PIPE)
+ process.communicate()
+ assert process.returncode is not 0, 'Trying to compile a nonexisting file should return with a nonzero error code!'
+ assert os.path.exists('this_output_file_should_never_exist.js') == False, 'Emcc should not produce an output file when build fails!'
+
+ def test_cxx03(self):
+ for compiler in [EMCC, EMXX]:
+ process = Popen([PYTHON, compiler, path_from_root('tests', 'hello_cxx03.cpp')], stdout=PIPE, stderr=PIPE)
+ process.communicate()
+ assert process.returncode is 0, 'By default, emscripten should build using -std=c++03!'
+
+ def test_cxx11(self):
+ for compiler in [EMCC, EMXX]:
+ process = Popen([PYTHON, compiler, '-std=c++11', path_from_root('tests', 'hello_cxx11.cpp')], stdout=PIPE, stderr=PIPE)
+ process.communicate()
+ assert process.returncode is 0, 'User should be able to specify custom -std= on the command line!'
+
+ def test_catch_undef(self):
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <vector>
+ #include <stdio.h>
+
+ class Test {
+ public:
+ std::vector<int> vector;
+ };
+
+ Test globalInstance;
+
+ int main() {
+ printf("hello, world!\n");
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-fsanitize=undefined']).communicate()
+ self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_unaligned_memory(self):
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ typedef unsigned char Bit8u;
+ typedef unsigned short Bit16u;
+ typedef unsigned int Bit32u;
+
+ int main()
+ {
+ Bit8u data[4] = {0x01,0x23,0x45,0x67};
+
+ printf("data: %x\n", *(Bit32u*)data);
+ printf("data[0,1] 16bit: %x\n", *(Bit16u*)data);
+ printf("data[1,2] 16bit: %x\n", *(Bit16u*)(data+1));
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
+ self.assertContained('data: 67452301\ndata[0,1] 16bit: 2301\ndata[1,2] 16bit: 4523', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_unaligned_memory_2(self):
+ open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
+ #include <string>
+ #include <stdio.h>
+
+ int main( int argc, char ** argv )
+ {
+ std::string testString( "Hello, World!" );
+
+ printf( "testString = %s\n", testString.c_str() );
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'test.cpp'), '-s', 'UNALIGNED_MEMORY=1']).communicate()
+ self.assertContained('testString = Hello, World!', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_asm_minify(self):
+ def test(args):
+ Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop_malloc.cpp')] + args).communicate()
+ self.assertContained('hello, world!', run_js(self.in_dir('a.out.js')))
+ return open(self.in_dir('a.out.js')).read()
+
+ src = test([])
+ assert 'function _malloc' in src
+
+ src = test(['-O2', '-s', 'ASM_JS=1'])
+ normal_size = len(src)
+ print 'normal', normal_size
+ assert 'function _malloc' not in src
+
+ src = test(['-O2', '-s', 'ASM_JS=1', '--minify', '0'])
+ unminified_size = len(src)
+ print 'unminified', unminified_size
+ assert unminified_size > normal_size
+ assert 'function _malloc' not in src
+
+ src = test(['-O2', '-s', 'ASM_JS=1', '-g'])
+ debug_size = len(src)
+ print 'debug', debug_size
+ assert debug_size > unminified_size
+ assert 'function _malloc' in src
+
+ def test_dangerous_func_cast(self):
+ src = r'''
+ #include <stdio.h>
+ typedef void (*voidfunc)();
+ int my_func() {
+ printf("my func\n");
+ return 10;
+ }
+ int main(int argc, char **argv) {
+ voidfunc fps[10];
+ for (int i = 0; i < 10; i++) fps[i] = (i == argc) ? (void (*)())my_func : NULL;
+ fps[2*(argc-1) + 1]();
+ return 0;
+ }
+ '''
+ open('src.c', 'w').write(src)
+ def test(args, expected, err_expected=None):
+ out, err = Popen([PYTHON, EMCC, 'src.c'] + args, stderr=PIPE).communicate()
+ if err_expected: self.assertContained(err_expected, err)
+ self.assertContained(expected, run_js(self.in_dir('a.out.js'), stderr=PIPE, full_output=True))
+ return open(self.in_dir('a.out.js')).read()
+
+ test([], 'my func') # no asm, so casting func works
+ test(['-O2'], 'abort', ['Casting potentially incompatible function pointer i32 ()* to void (...)*, for my_func',
+ 'Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these']) # asm, so failure
+ test(['-O2', '-s', 'ASSERTIONS=1'],
+ 'Invalid function pointer called. Perhaps a miscast function pointer (check compilation warnings) or bad vtable lookup (maybe due to derefing a bad pointer, like NULL)?',
+ ['Casting potentially incompatible function pointer i32 ()* to void (...)*, for my_func',
+ 'Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these']) # asm, so failure
+
+ def test_l_link(self):
+ # Linking with -lLIBNAME and -L/DIRNAME should work
+
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ extern void printey();
+ int main() {
+ printey();
+ return 0;
+ }
+ ''')
+
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'libdir'));
+ except:
+ pass
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib\\n");
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-c']).communicate()
+ shutil.move(os.path.join(self.get_dir(), 'libfile.o'), os.path.join(self.get_dir(), 'libdir', 'libfile.so'))
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile']).communicate()
+ self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ assert not os.path.exists('a.out') and not os.path.exists('a.exe'), 'Must not leave unneeded linker stubs'
+
+ def test_static_link(self):
+ def test(name, header, main, side, expected, args=[], suffix='cpp', first=True):
+ print name
+ #t = main ; main = side ; side = t
+ original_main = main
+ original_side = side
+ if header: open(os.path.join(self.get_dir(), 'header.h'), 'w').write(header)
+ if type(main) == str:
+ open(os.path.join(self.get_dir(), 'main.' + suffix), 'w').write(main)
+ main = ['main.' + suffix]
+ if type(side) == str:
+ open(os.path.join(self.get_dir(), 'side.' + suffix), 'w').write(side)
+ side = ['side.' + suffix]
+ Popen([PYTHON, EMCC] + side + ['-o', 'side.js', '-s', 'SIDE_MODULE=1', '-O2'] + args).communicate()
+ # TODO: test with and without DISABLE_GL_EMULATION, check that file sizes change
+ Popen([PYTHON, EMCC] + main + ['-o', 'main.js', '-s', 'MAIN_MODULE=1', '-O2', '-s', 'DISABLE_GL_EMULATION=1'] + args).communicate()
+ Popen([PYTHON, EMLINK, 'main.js', 'side.js', 'together.js'], stdout=PIPE).communicate()
+ assert os.path.exists('together.js')
+ for engine in JS_ENGINES:
+ out = run_js('together.js', engine=engine, stderr=PIPE, full_output=True)
+ self.assertContained(expected, out)
+ if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
+ if first:
+ shutil.copyfile('together.js', 'first.js')
+ test(name + ' (reverse)', header, original_side, original_main, expected, args, suffix, False) # test reverse order
+
+ # test a simple call from one module to another. only one has a string (and constant memory initialization for it)
+ test('basics', '', '''
+ #include <stdio.h>
+ extern int sidey();
+ int main() {
+ printf("other says %d.", sidey());
+ return 0;
+ }
+ ''', '''
+ int sidey() { return 11; }
+ ''', 'other says 11.')
+
+ # finalization of float variables should pass asm.js validation
+ test('floats', '', '''
+ #include <stdio.h>
+ extern float sidey();
+ int main() {
+ printf("other says %.2f.", sidey()+1);
+ return 0;
+ }
+ ''', '''
+ float sidey() { return 11.5; }
+ ''', 'other says 12.50')
+
+ # memory initialization in both
+ test('multiple memory inits', '', r'''
+ #include <stdio.h>
+ extern void sidey();
+ int main() {
+ printf("hello from main\n");
+ sidey();
+ return 0;
+ }
+ ''', r'''
+ #include <stdio.h>
+ void sidey() { printf("hello from side\n"); }
+ ''', 'hello from main\nhello from side\n')
+
+ # function pointers
+ test('fp1', 'typedef void (*voidfunc)();', r'''
+ #include <stdio.h>
+ #include "header.h"
+ voidfunc sidey(voidfunc f);
+ void a() { printf("hello from funcptr\n"); }
+ int main() {
+ sidey(a)();
+ return 0;
+ }
+ ''', '''
+ #include "header.h"
+ voidfunc sidey(voidfunc f) { return f; }
+ ''', 'hello from funcptr\n')
+
+ # function pointers with 'return' in the name
+ test('fp2', 'typedef void (*voidfunc)();', r'''
+ #include <stdio.h>
+ #include "header.h"
+ int sidey(voidfunc f);
+ void areturn0() { printf("hello 0\n"); }
+ void areturn1() { printf("hello 1\n"); }
+ void areturn2() { printf("hello 2\n"); }
+ int main(int argc, char **argv) {
+ voidfunc table[3] = { areturn0, areturn1, areturn2 };
+ table[sidey(NULL)]();
+ return 0;
+ }
+ ''', '''
+ #include "header.h"
+ int sidey(voidfunc f) { if (f) f(); return 1; }
+ ''', 'hello 1\n')
+
+ # Global initializer
+ test('global init', '', r'''
+ #include <stdio.h>
+ struct Class {
+ Class() { printf("a new Class\n"); }
+ };
+ static Class c;
+ int main() {
+ return 0;
+ }
+ ''', r'''
+ void nothing() {}
+ ''', 'a new Class\n')
+
+ # Multiple global initializers (LLVM generates overlapping names for them)
+ test('global inits', r'''
+ #include <stdio.h>
+ struct Class {
+ Class(const char *name) { printf("new %s\n", name); }
+ };
+ ''', r'''
+ #include "header.h"
+ static Class c("main");
+ int main() {
+ return 0;
+ }
+ ''', r'''
+ #include "header.h"
+ static Class c("side");
+ ''', ['new main\nnew side\n', 'new side\nnew main\n'])
+
+ # Class code used across modules
+ test('codecall', r'''
+ #include <stdio.h>
+ struct Class {
+ Class(const char *name);
+ };
+ ''', r'''
+ #include "header.h"
+ int main() {
+ Class c("main");
+ return 0;
+ }
+ ''', r'''
+ #include "header.h"
+ Class::Class(const char *name) { printf("new %s\n", name); }
+ ''', ['new main\n'])
+
+ # malloc usage in both modules
+ test('malloc', r'''
+ #include <stdlib.h>
+ #include <string.h>
+ char *side(const char *data);
+ ''', r'''
+ #include <stdio.h>
+ #include "header.h"
+ int main() {
+ char *temp = side("hello through side\n");
+ char *ret = (char*)malloc(strlen(temp)+1);
+ strcpy(ret, temp);
+ temp[1] = 'x';
+ puts(ret);
+ return 0;
+ }
+ ''', r'''
+ #include "header.h"
+ char *side(const char *data) {
+ char *ret = (char*)malloc(strlen(data)+1);
+ strcpy(ret, data);
+ return ret;
+ }
+ ''', ['hello through side\n'])
+
+ # libc usage in one modules. must force libc inclusion in the main module if that isn't the one using mallinfo()
+ try:
+ os.environ['EMCC_FORCE_STDLIBS'] = 'libc'
+ test('malloc-1', r'''
+ #include <string.h>
+ int side();
+ ''', r'''
+ #include <stdio.h>
+ #include "header.h"
+ int main() {
+ printf("|%d|\n", side());
+ return 0;
+ }
+ ''', r'''
+ #include <stdlib.h>
+ #include <malloc.h>
+ #include "header.h"
+ int side() {
+ struct mallinfo m = mallinfo();
+ return m.arena > 1;
+ }
+ ''', ['|1|\n'])
+ finally:
+ del os.environ['EMCC_FORCE_STDLIBS']
+
+ # iostream usage in one and std::string in both
+ test('iostream', r'''
+ #include <iostream>
+ #include <string>
+ std::string side();
+ ''', r'''
+ #include "header.h"
+ int main() {
+ std::cout << "hello from main " << side() << std::endl;
+ return 0;
+ }
+ ''', r'''
+ #include "header.h"
+ std::string side() { return "and hello from side"; }
+ ''', ['hello from main and hello from side\n'])
+
+ # followup to iostream test: a second linking
+ print 'second linking of a linking output'
+ open('moar.cpp', 'w').write(r'''
+ #include <iostream>
+ struct Moar {
+ Moar() { std::cout << "moar!" << std::endl; }
+ };
+ Moar m;
+ ''')
+ Popen([PYTHON, EMCC, 'moar.cpp', '-o', 'moar.js', '-s', 'SIDE_MODULE=1', '-O2']).communicate()
+ Popen([PYTHON, EMLINK, 'together.js', 'moar.js', 'triple.js'], stdout=PIPE).communicate()
+ assert os.path.exists('triple.js')
+ for engine in JS_ENGINES:
+ out = run_js('triple.js', engine=engine, stderr=PIPE, full_output=True)
+ self.assertContained('moar!\nhello from main and hello from side\n', out)
+ if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
+
+ # zlib compression library. tests function pointers in initializers and many other things
+ test('zlib', '', open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
+ self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
+ open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
+ args=['-I' + path_from_root('tests', 'zlib')], suffix='c')
+
+ # bullet physics engine. tests all the things
+ test('bullet', '', open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
+ self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
+ os.path.join('src', '.libs', 'libBulletCollision.a'),
+ os.path.join('src', '.libs', 'libLinearMath.a')]),
+ [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
+ open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
+ open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
+ args=['-I' + path_from_root('tests', 'bullet', 'src')])
+
+
+ def test_outline(self):
+ def test(name, src, libs, expected, expected_ranges, args=[], suffix='cpp'):
+ print name
+
+ def measure_funcs(filename):
+ i = 0
+ start = -1
+ curr = None
+ ret = {}
+ for line in open(filename):
+ i += 1
+ if line.startswith('function '):
+ start = i
+ curr = line
+ elif line.startswith('}') and curr:
+ size = i - start
+ ret[curr] = size
+ curr = None
+ return ret
+
+ for debug, outlining_limits in [
+ ([], (1000,)),
+ (['-g1'], (1000,)),
+ (['-g2'], (1000,)),
+ (['-g'], (100, 250, 500, 1000, 2000, 5000, 0))
+ ]:
+ for outlining_limit in outlining_limits:
+ print '\n', Building.COMPILER_TEST_OPTS, debug, outlining_limit, '\n'
+ # TODO: test without -g3, tell all sorts
+ Popen([PYTHON, EMCC, src] + libs + ['-o', 'test.js', '-O2'] + debug + ['-s', 'OUTLINING_LIMIT=%d' % outlining_limit] + args).communicate()
+ assert os.path.exists('test.js')
+ shutil.copyfile('test.js', '%d_test.js' % outlining_limit)
+ for engine in JS_ENGINES:
+ out = run_js('test.js', engine=engine, stderr=PIPE, full_output=True)
+ self.assertContained(expected, out)
+ if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
+ if debug == ['-g']:
+ low = expected_ranges[outlining_limit][0]
+ seen = max(measure_funcs('test.js').values())
+ high = expected_ranges[outlining_limit][1]
+ print Building.COMPILER_TEST_OPTS, outlining_limit, ' ', low, '<=', seen, '<=', high
+ assert low <= seen <= high
+
+ for test_opts, expected_ranges in [
+ ([], {
+ 100: (190, 250),
+ 250: (200, 330),
+ 500: (250, 500),
+ 1000: (230, 1000),
+ 2000: (380, 2000),
+ 5000: (800, 5000),
+ 0: (1500, 5000)
+ }),
+ (['-O2'], {
+ 100: (0, 1500),
+ 250: (0, 1500),
+ 500: (0, 1500),
+ 1000: (0, 1500),
+ 2000: (0, 2000),
+ 5000: (0, 5000),
+ 0: (0, 5000)
+ }),
+ ]:
+ Building.COMPILER_TEST_OPTS = test_opts
+ test('zlib', path_from_root('tests', 'zlib', 'example.c'),
+ self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
+ open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
+ expected_ranges,
+ args=['-I' + path_from_root('tests', 'zlib')], suffix='c')
+
+ def test_symlink(self):
+ if os.name == 'nt':
+ return self.skip('Windows FS does not need to be tested for symlinks support, since it does not have them.')
+ open(os.path.join(self.get_dir(), 'foobar.xxx'), 'w').write('int main(){ return 0; }')
+ os.symlink(os.path.join(self.get_dir(), 'foobar.xxx'), os.path.join(self.get_dir(), 'foobar.c'))
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foobar.c'), '-o', os.path.join(self.get_dir(), 'foobar')], stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'foobar'))
+ try_delete(os.path.join(self.get_dir(), 'foobar'))
+ try_delete(os.path.join(self.get_dir(), 'foobar.xxx'))
+ try_delete(os.path.join(self.get_dir(), 'foobar.c'))
+
+ open(os.path.join(self.get_dir(), 'foobar.c'), 'w').write('int main(){ return 0; }')
+ os.symlink(os.path.join(self.get_dir(), 'foobar.c'), os.path.join(self.get_dir(), 'foobar.xxx'))
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foobar.xxx'), '-o', os.path.join(self.get_dir(), 'foobar')], stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists(os.path.join(self.get_dir(), 'foobar'))
+ try_delete(os.path.join(self.get_dir(), 'foobar'))
+ try_delete(os.path.join(self.get_dir(), 'foobar.xxx'))
+ try_delete(os.path.join(self.get_dir(), 'foobar.c'))
+
+ def test_multiply_defined_libsymbols(self):
+ lib = "int mult() { return 1; }"
+ lib_name = os.path.join(self.get_dir(), 'libA.c')
+ open(lib_name, 'w').write(lib)
+ a2 = "void x() {}"
+ a2_name = os.path.join(self.get_dir(), 'a2.c')
+ open(a2_name, 'w').write(a2)
+ b2 = "void y() {}"
+ b2_name = os.path.join(self.get_dir(), 'b2.c')
+ open(b2_name, 'w').write(b2)
+ main = r'''
+ #include <stdio.h>
+ int mult();
+ int main() {
+ printf("result: %d\n", mult());
+ return 0;
+ }
+ '''
+ main_name = os.path.join(self.get_dir(), 'main.c')
+ open(main_name, 'w').write(main)
+
+ Building.emcc(lib_name, output_filename='libA.so')
+
+ Building.emcc(a2_name, ['-L.', '-lA'])
+ Building.emcc(b2_name, ['-L.', '-lA'])
+
+ Building.emcc(main_name, ['-L.', '-lA', a2_name+'.o', b2_name+'.o'], output_filename='a.out.js')
+
+ self.assertContained('result: 1', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_multiply_defined_libsymbols_2(self):
+ a = "int x() { return 55; }"
+ a_name = os.path.join(self.get_dir(), 'a.c')
+ open(a_name, 'w').write(a)
+ b = "int y() { return 2; }"
+ b_name = os.path.join(self.get_dir(), 'b.c')
+ open(b_name, 'w').write(b)
+ c = "int z() { return 5; }"
+ c_name = os.path.join(self.get_dir(), 'c.c')
+ open(c_name, 'w').write(c)
+ main = r'''
+ #include <stdio.h>
+ int x();
+ int y();
+ int z();
+ int main() {
+ printf("result: %d\n", x() + y() + z());
+ return 0;
+ }
+ '''
+ main_name = os.path.join(self.get_dir(), 'main.c')
+ open(main_name, 'w').write(main)
+
+ Building.emcc(a_name) # a.c.o
+ Building.emcc(b_name) # b.c.o
+ Building.emcc(c_name) # c.c.o
+ lib_name = os.path.join(self.get_dir(), 'libLIB.a')
+ Building.emar('cr', lib_name, [a_name + '.o', b_name + '.o']) # libLIB.a with a and b
+
+ # a is in the lib AND in an .o, so should be ignored in the lib. We do still need b from the lib though
+ Building.emcc(main_name, ['-L.', '-lLIB', a_name+'.o', c_name + '.o'], output_filename='a.out.js')
+
+ self.assertContained('result: 62', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_redundant_link(self):
+ lib = "int mult() { return 1; }"
+ lib_name = os.path.join(self.get_dir(), 'libA.c')
+ open(lib_name, 'w').write(lib)
+ main = r'''
+ #include <stdio.h>
+ int mult();
+ int main() {
+ printf("result: %d\n", mult());
+ return 0;
+ }
+ '''
+ main_name = os.path.join(self.get_dir(), 'main.c')
+ open(main_name, 'w').write(main)
+
+ Building.emcc(lib_name, output_filename='libA.so')
+
+ Building.emcc(main_name, ['libA.so']*2, output_filename='a.out.js')
+
+ self.assertContained('result: 1', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_export_all(self):
+ lib = r'''
+ #include <stdio.h>
+ void libf1() { printf("libf1\n"); }
+ void libf2() { printf("libf2\n"); }
+ '''
+ lib_name = os.path.join(self.get_dir(), 'lib.c')
+ open(lib_name, 'w').write(lib)
+
+ open('main.js', 'w').write('''
+ _libf1();
+ _libf2();
+ ''')
+
+ Building.emcc(lib_name, ['-s', 'EXPORT_ALL=1', '--post-js', 'main.js'], output_filename='a.out.js')
+
+ self.assertContained('libf1\nlibf2\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_stdin(self):
+ open('main.cpp', 'w').write(r'''
+#include <stdio.h>
+int main(int argc, char const *argv[])
+{
+ char str[10] = {0};
+ scanf("%10s", str);
+ printf("%s\n", str);
+ return 0;
+}
+''')
+ Building.emcc('main.cpp', output_filename='a.out.js')
+ open('in.txt', 'w').write('abc')
+ # node's stdin support is broken
+ self.assertContained('abc', Popen(listify(SPIDERMONKEY_ENGINE) + ['a.out.js'], stdin=open('in.txt'), stdout=PIPE, stderr=PIPE).communicate()[0])
+
+ def test_ungetc_fscanf(self):
+ open('main.cpp', 'w').write(r'''
+ #include <stdio.h>
+ int main(int argc, char const *argv[])
+ {
+ char str[4] = {0};
+ FILE* f = fopen("my_test.input", "r");
+ if (f == NULL) {
+ printf("cannot open file\n");
+ return -1;
+ }
+ ungetc('x', f);
+ ungetc('y', f);
+ ungetc('z', f);
+ fscanf(f, "%3s", str);
+ printf("%s\n", str);
+ return 0;
+ }
+ ''')
+ open('my_test.input', 'w').write('abc')
+ Building.emcc('main.cpp', ['--embed-file', 'my_test.input'], output_filename='a.out.js')
+ self.assertContained('zyx', Popen(listify(JS_ENGINES[0]) + ['a.out.js'], stdout=PIPE, stderr=PIPE).communicate()[0])
+
+ def test_abspaths(self):
+ # Includes with absolute paths are generally dangerous, things like -I/usr/.. will get to system local headers, not our portable ones.
+
+ shutil.copyfile(path_from_root('tests', 'hello_world.c'), 'main.c')
+
+ for args, expected in [(['-I/usr/something'], True),
+ (['-L/usr/something'], True),
+ (['-I/usr/something', '-Wno-warn-absolute-paths'], False),
+ (['-L/usr/something', '-Wno-warn-absolute-paths'], False),
+ (['-Isubdir/something'], False),
+ (['-Lsubdir/something'], False),
+ ([], False)]:
+ err = Popen([PYTHON, EMCC, 'main.c'] + args, stderr=PIPE).communicate()[1]
+ assert ('encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' in err) == expected, err
+
+ def test_local_link(self):
+ # Linking a local library directly, like /usr/lib/libsomething.so, cannot work of course since it
+ # doesn't contain bitcode. However, when we see that we should look for a bitcode file for that
+ # library in the -L paths and system/lib
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ extern void printey();
+ int main() {
+ printey();
+ return 0;
+ }
+ ''')
+
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'subdir'));
+ except:
+ pass
+ open(os.path.join(self.get_dir(), 'subdir', 'libfile.so'), 'w').write('this is not llvm bitcode!')
+
+ open(os.path.join(self.get_dir(), 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib\\n");
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'libfile.cpp'), '-o', 'libfile.so']).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), os.path.join(self.get_dir(), 'subdir', 'libfile.so'), '-L.'], stderr=PIPE).communicate()
+ self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_runtimelink_multi(self):
+ return self.skip('BUILD_AS_SHARED_LIB=2 is deprecated')
+ if Settings.ASM_JS: return self.skip('asm does not support runtime linking yet')
+
+ if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations')
+
+ open('testa.h', 'w').write(r'''
+ #ifndef _TESTA_H_
+ #define _TESTA_H_
+
+ class TestA {
+ public:
+ TestA();
+ };
+
+ #endif
+ ''')
+ open('testb.h', 'w').write(r'''
+ #ifndef _TESTB_H_
+ #define _TESTB_H_
+
+ class TestB {
+ public:
+ TestB();
+ };
+
+ #endif
+ ''')
+ open('testa.cpp', 'w').write(r'''
+ #include <stdio.h>
+ #include <testa.h>
+
+ TestA::TestA() {
+ printf("TestA\n");
+ }
+ ''')
+ open('testb.cpp', 'w').write(r'''
+ #include <stdio.h>
+ #include <testb.h>
+ #include <testa.h>
+ /*
+ */
+ TestB::TestB() {
+ printf("TestB\n");
+ TestA* testa = new TestA();
+ }
+ ''')
+ open('main.cpp', 'w').write(r'''
+ #include <stdio.h>
+ #include <testa.h>
+ #include <testb.h>
+
+ /*
+ */
+ int main(int argc, char** argv) {
+ printf("Main\n");
+ TestA* testa = new TestA();
+ TestB* testb = new TestB();
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, 'testa.cpp', '-o', 'liba.js', '-s', 'BUILD_AS_SHARED_LIB=2', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-I.']).communicate()
+ Popen([PYTHON, EMCC, 'testb.cpp', '-o', 'libb.js', '-s', 'BUILD_AS_SHARED_LIB=2', '-s', 'LINKABLE=1', '-s', 'NAMED_GLOBALS=1', '-I.']).communicate()
+ Popen([PYTHON, EMCC, 'main.cpp', '-o', 'main.js', '-s', 'RUNTIME_LINKED_LIBS=["liba.js", "libb.js"]', '-s', 'NAMED_GLOBALS=1', '-I.', '-s', 'LINKABLE=1']).communicate()
+
+ Popen([PYTHON, EMCC, 'main.cpp', 'testa.cpp', 'testb.cpp', '-o', 'full.js', '-I.']).communicate()
+
+ self.assertContained('TestA\nTestB\nTestA\n', run_js('main.js', engine=SPIDERMONKEY_ENGINE))
+
+ def test_js_libraries(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ extern "C" {
+ extern void printey();
+ extern int calcey(int x, int y);
+ }
+ int main() {
+ printey();
+ printf("*%d*\\n", calcey(10, 22));
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'mylib1.js'), 'w').write('''
+ mergeInto(LibraryManager.library, {
+ printey: function() {
+ Module.print('hello from lib!');
+ }
+ });
+ ''')
+ open(os.path.join(self.get_dir(), 'mylib2.js'), 'w').write('''
+ mergeInto(LibraryManager.library, {
+ calcey: function(x, y) {
+ return x + y;
+ }
+ });
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--js-library', os.path.join(self.get_dir(), 'mylib1.js'),
+ '--js-library', os.path.join(self.get_dir(), 'mylib2.js')]).communicate()
+ self.assertContained('hello from lib!\n*32*\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_identical_basenames(self):
+ # Issue 287: files in different dirs but with the same basename get confused as the same,
+ # causing multiply defined symbol errors
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'foo'));
+ except:
+ pass
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'bar'));
+ except:
+ pass
+ open(os.path.join(self.get_dir(), 'foo', 'main.cpp'), 'w').write('''
+ extern void printey();
+ int main() {
+ printey();
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'bar', 'main.cpp'), 'w').write('''
+ #include<stdio.h>
+ void printey() { printf("hello there\\n"); }
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo', 'main.cpp'), os.path.join(self.get_dir(), 'bar', 'main.cpp')]).communicate()
+ self.assertContained('hello there', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ # ditto with first creating .o files
+ try_delete(os.path.join(self.get_dir(), 'a.out.js'))
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo', 'main.cpp'), '-o', os.path.join(self.get_dir(), 'foo', 'main.o')]).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'bar', 'main.cpp'), '-o', os.path.join(self.get_dir(), 'bar', 'main.o')]).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo', 'main.o'), os.path.join(self.get_dir(), 'bar', 'main.o')]).communicate()
+ self.assertContained('hello there', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_main_a(self):
+ # if main() is in a .a, we need to pull in that .a
+
+ main_name = os.path.join(self.get_dir(), 'main.c')
+ open(main_name, 'w').write(r'''
+ #include <stdio.h>
+ extern int f();
+ int main() {
+ printf("result: %d.\n", f());
+ return 0;
+ }
+ ''')
+
+ other_name = os.path.join(self.get_dir(), 'other.c')
+ open(other_name, 'w').write(r'''
+ #include <stdio.h>
+ int f() { return 12346; }
+ ''')
+
+ Popen([PYTHON, EMCC, main_name, '-c', '-o', main_name+'.bc']).communicate()
+ Popen([PYTHON, EMCC, other_name, '-c', '-o', other_name+'.bc']).communicate()
+
+ Popen([PYTHON, EMAR, 'cr', main_name+'.a', main_name+'.bc']).communicate()
+
+ Popen([PYTHON, EMCC, other_name+'.bc', main_name+'.a']).communicate()
+
+ self.assertContained('result: 12346.', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_dup_o_in_a(self):
+ open('common.c', 'w').write(r'''
+ #include <stdio.h>
+ void a(void) {
+ printf("a\n");
+ }
+ ''')
+ Popen([PYTHON, EMCC, 'common.c', '-c', '-o', 'common.o']).communicate()
+ Popen([PYTHON, EMAR, 'rc', 'liba.a', 'common.o']).communicate()
+
+ open('common.c', 'w').write(r'''
+ #include <stdio.h>
+ void b(void) {
+ printf("b\n");
+ }
+ ''')
+ Popen([PYTHON, EMCC, 'common.c', '-c', '-o', 'common.o']).communicate()
+ Popen([PYTHON, EMAR, 'rc', 'libb.a', 'common.o']).communicate()
+
+ open('main.c', 'w').write(r'''
+ void a(void);
+ void b(void);
+ int main() {
+ a();
+ b();
+ }
+ ''')
+ Popen([PYTHON, EMCC, 'main.c', '-L.', '-la', '-lb']).communicate()
+
+ self.assertContained('a\nb\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_export_in_a(self):
+ export_name = 'this_is_an_entry_point'
+
+ open('export.c', 'w').write(r'''
+ #include <stdio.h>
+ void %s(void) {
+ printf("Hello, world!\n");
+ }
+ ''' % export_name)
+ Popen([PYTHON, EMCC, 'export.c', '-c', '-o', 'export.o']).communicate()
+ Popen([PYTHON, EMAR, 'rc', 'libexport.a', 'export.o']).communicate()
+
+ open('main.c', 'w').write(r'''
+ int main() {
+ return 0;
+ }
+ ''')
+
+ definition = 'function _%s(' % export_name
+
+ # Sanity check: the symbol should not be linked in if not requested.
+ Popen([PYTHON, EMCC, 'main.c', '-L.', '-lexport']).communicate()
+ self.assertNotContained(definition, open(os.path.join(self.get_dir(), 'a.out.js')).read())
+
+ # Sanity check: exporting without a definition does not cause it to appear.
+ # Note: exporting main prevents emcc from warning that it generated no code.
+ Popen([PYTHON, EMCC, 'main.c', '-s', '''EXPORTED_FUNCTIONS=['_main', '_%s']''' % export_name]).communicate()
+ self.assertNotContained(definition, open(os.path.join(self.get_dir(), 'a.out.js')).read())
+
+ # Actual test: defining symbol in library and exporting it causes it to appear in the output.
+ Popen([PYTHON, EMCC, 'main.c', '-L.', '-lexport', '-s', '''EXPORTED_FUNCTIONS=['_%s']''' % export_name]).communicate()
+ self.assertContained(definition, open(os.path.join(self.get_dir(), 'a.out.js')).read())
+
+ def test_embed_file(self):
+ open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''hello from a file with lots of data and stuff in it thank you very much''')
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ int main() {
+ FILE *f = fopen("somefile.txt", "r");
+ char buf[100];
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("|%s|\n", buf);
+ return 0;
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'somefile.txt']).communicate()
+ self.assertContained('|hello from a file wi|', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ # preload twice, should not err
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'somefile.txt', '--embed-file', 'somefile.txt']).communicate()
+ self.assertContained('|hello from a file wi|', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_embed_file_dup(self):
+ try_delete(os.path.join(self.get_dir(), 'tst'))
+ os.mkdir(os.path.join(self.get_dir(), 'tst'))
+ os.mkdir(os.path.join(self.get_dir(), 'tst', 'test1'))
+ os.mkdir(os.path.join(self.get_dir(), 'tst', 'test2'))
+
+ open(os.path.join(self.get_dir(), 'tst', 'aa.txt'), 'w').write('''frist''')
+ open(os.path.join(self.get_dir(), 'tst', 'test1', 'aa.txt'), 'w').write('''sacond''')
+ open(os.path.join(self.get_dir(), 'tst', 'test2', 'aa.txt'), 'w').write('''thard''')
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ #include <string.h>
+ void print_file(const char *name) {
+ FILE *f = fopen(name, "r");
+ char buf[100];
+ memset(buf, 0, 100);
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("|%s|\n", buf);
+ }
+ int main() {
+ print_file("tst/aa.txt");
+ print_file("tst/test1/aa.txt");
+ print_file("tst/test2/aa.txt");
+ return 0;
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'tst']).communicate()
+ self.assertContained('|frist|\n|sacond|\n|thard|\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_multidynamic_link(self):
+ # Linking the same dynamic library in will error, normally, since we statically link it, causing dupe symbols
+ # A workaround is to use --ignore-dynamic-linking, see emcc --help for details
+
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ extern void printey();
+ extern void printother();
+ int main() {
+ printf("*");
+ printey();
+ printf("\n");
+ printother();
+ printf("\n");
+ printf("*");
+ return 0;
+ }
+ ''')
+
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'libdir'));
+ except:
+ pass
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib");
+ }
+ ''')
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write('''
+ #include <stdio.h>
+ extern void printey();
+ void printother() {
+ printf("|");
+ printey();
+ printf("|");
+ }
+ ''')
+
+ # This lets us link the same dynamic lib twice. We will need to link it in manually at the end.
+ compiler = [PYTHON, EMCC, '--ignore-dynamic-linking']
+
+ # Build libfile normally into an .so
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so')]).communicate()
+ # Build libother and dynamically link it to libfile - but add --ignore-dynamic-linking
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate()
+ # Build the main file, linking in both the libs
+ Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother', '-c']).communicate()
+
+ # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother']).communicate()
+
+ self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_js_link(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ int main() {
+ printf("hello from main\\n");
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'before.js'), 'w').write('''
+ var MESSAGE = 'hello from js';
+ if (typeof Module != 'undefined') throw 'This code should run before anything else!';
+ ''')
+ open(os.path.join(self.get_dir(), 'after.js'), 'w').write('''
+ Module.print(MESSAGE);
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'before.js', '--post-js', 'after.js']).communicate()
+ self.assertContained('hello from main\nhello from js\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_sdl_endianness(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ #include <SDL/SDL.h>
+
+ int main() {
+ printf("%d, %d, %d\n", SDL_BYTEORDER, SDL_LIL_ENDIAN, SDL_BIG_ENDIAN);
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')]).communicate()
+ self.assertContained('1234, 1234, 4321\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_link_memcpy(self):
+ # memcpy can show up *after* optimizations, so after our opportunity to link in libc, so it must be special-cased
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ int main(int argc, char **argv) {
+ int num = argc + 10;
+ char buf[num], buf2[num];
+ for (int i = 0; i < num; i++) {
+ buf[i] = i*i+i/3;
+ }
+ for (int i = 1; i < num; i++) {
+ buf[i] += buf[i-1];
+ }
+ for (int i = 0; i < num; i++) {
+ buf2[i] = buf[i];
+ }
+ for (int i = 1; i < num; i++) {
+ buf2[i] += buf2[i-1];
+ }
+ for (int i = 0; i < num; i++) {
+ printf("%d:%d\n", i, buf2[i]);
+ }
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'main.cpp')]).communicate()
+ output = run_js(os.path.join(self.get_dir(), 'a.out.js'), full_output=True, stderr=PIPE)
+ self.assertContained('''0:0
+1:1
+2:6
+3:21
+4:53
+5:111
+6:-49
+7:98
+8:55
+9:96
+10:-16
+''', output)
+ self.assertNotContained('warning: library.js memcpy should not be running, it is only for testing!', output)
+
+ def test_warn_undefined(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ extern "C" {
+ void something();
+ }
+
+ int main() {
+ something();
+ return 0;
+ }
+ ''')
+
+ def clear(): try_delete('a.out.js')
+
+ for args in [[], ['-O2']]:
+ clear()
+ print 'warn', args
+ output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'WARN_ON_UNDEFINED_SYMBOLS=1'] + args, stderr=PIPE).communicate()
+ self.assertContained('unresolved symbol: something', output[1])
+
+ clear()
+ output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + args, stderr=PIPE).communicate()
+ self.assertNotContained('unresolved symbol: something\n', output[1])
+
+ for args in [[], ['-O2']]:
+ clear()
+ print 'error', args
+ output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] + args, stderr=PIPE).communicate()
+ self.assertContained('unresolved symbol: something', output[1])
+ assert not os.path.exists('a.out.js')
+
+ clear()
+ output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + args, stderr=PIPE).communicate()
+ self.assertNotContained('unresolved symbol: something\n', output[1])
+ assert os.path.exists('a.out.js')
+
+ def test_toobig(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ #define BYTES 100*1024*1024
+
+ int main(int argc, char **argv) {
+ if (argc == 100) {
+ static char buf[BYTES];
+ static char buf2[BYTES];
+ for (int i = 0; i < BYTES; i++) {
+ buf[i] = i*i;
+ buf2[i] = i/3;
+ }
+ for (int i = 0; i < BYTES; i++) {
+ buf[i] = buf2[i/2];
+ buf2[i] = buf[i/3];
+ }
+ printf("%d\n", buf[10] + buf2[20]);
+ }
+ return 0;
+ }
+ ''')
+ output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')], stderr=PIPE).communicate()[1]
+ assert 'Emscripten failed' in output, output
+ assert 'warning: very large fixed-size structural type' in output, output
+
+ def test_prepost(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ int main() {
+ printf("hello from main\\n");
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ var Module = {
+ preRun: function() { Module.print('pre-run') },
+ postRun: function() { Module.print('post-run') }
+ };
+ ''')
+
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js']).communicate()
+ self.assertContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ # never run, so no preRun or postRun
+ src = open(os.path.join(self.get_dir(), 'a.out.js')).read().replace('// {{PRE_RUN_ADDITIONS}}', 'addRunDependency()')
+ open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src)
+ self.assertNotContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ # noInitialRun prevents run
+ for no_initial_run, run_dep in [(0, 0), (1, 0), (0, 1)]:
+ print no_initial_run, run_dep
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')]).communicate()
+ src = 'var Module = { noInitialRun: %d };\n' % no_initial_run + open(os.path.join(self.get_dir(), 'a.out.js')).read()
+ if run_dep:
+ src = src.replace('// {{PRE_RUN_ADDITIONS}}', '// {{PRE_RUN_ADDITIONS}}\naddRunDependency("test");') \
+ .replace('// {{POST_RUN_ADDITIONS}}', '// {{POST_RUN_ADDITIONS}}\nremoveRunDependency("test");')
+ open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src)
+ assert ('hello from main' in run_js(os.path.join(self.get_dir(), 'a.out.js'))) != no_initial_run, 'only run if no noInitialRun'
+
+ if no_initial_run:
+ # Calling main later should still work, filesystem etc. must be set up.
+ print 'call main later'
+ src = open(os.path.join(self.get_dir(), 'a.out.js')).read() + '\nModule.callMain();\n';
+ open(os.path.join(self.get_dir(), 'a.out.js'), 'w').write(src)
+ assert 'hello from main' in run_js(os.path.join(self.get_dir(), 'a.out.js')), 'main should print when called manually'
+
+ # Use postInit
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ var Module = {
+ preRun: function() { Module.print('pre-run') },
+ postRun: function() { Module.print('post-run') },
+ preInit: function() { Module.print('pre-init') }
+ };
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js']).communicate()
+ self.assertContained('pre-init\npre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_prepost2(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ int main() {
+ printf("hello from main\\n");
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ var Module = {
+ preRun: function() { Module.print('pre-run') },
+ };
+ ''')
+ open(os.path.join(self.get_dir(), 'pre2.js'), 'w').write('''
+ Module.postRun = function() { Module.print('post-run') };
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate()
+ self.assertContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_prepre(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ int main() {
+ printf("hello from main\\n");
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ var Module = {
+ preRun: [function() { Module.print('pre-run') }],
+ };
+ ''')
+ open(os.path.join(self.get_dir(), 'pre2.js'), 'w').write('''
+ Module.preRun.push(function() { Module.print('prepre') });
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate()
+ self.assertContained('prepre\npre-run\nhello from main\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_save_bc(self):
+ for save in [0, 1]:
+ self.clear()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop_malloc.cpp')] + ([] if not save else ['--save-bc', self.in_dir('my_bitcode.bc')])).communicate()
+ assert 'hello, world!' in run_js(self.in_dir('a.out.js'))
+ assert os.path.exists(self.in_dir('my_bitcode.bc')) == save
+ if save:
+ try_delete('a.out.js')
+ Building.llvm_dis(self.in_dir('my_bitcode.bc'), self.in_dir('my_ll.ll'))
+ try:
+ os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
+ Popen([PYTHON, EMCC, 'my_ll.ll', '-o', 'two.js']).communicate()
+ assert 'hello, world!' in run_js(self.in_dir('two.js'))
+ finally:
+ del os.environ['EMCC_LEAVE_INPUTS_RAW']
+
+ def test_fix_closure(self):
+ input = path_from_root('tests', 'test-fix-closure.js')
+ expected = path_from_root('tests', 'test-fix-closure.out.js')
+ Popen([PYTHON, path_from_root('tools', 'fix_closure.py'), input, 'out.js']).communicate(input)
+ output = open('out.js').read()
+ assert '0,zzz_Q_39fa,0' in output
+ assert 'function(a,c)' not in output # should be uninlined, so it gets a name
+ assert run_js(input) == run_js('out.js')
+
+ def test_js_optimizer(self):
+ for input, expected, passes in [
+ (path_from_root('tools', 'test-js-optimizer.js'), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(),
+ ['hoistMultiples', 'loopOptimizer', 'removeAssignsToUndefined', 'simplifyExpressions']),
+ (path_from_root('tools', 'test-js-optimizer-t2c.js'), open(path_from_root('tools', 'test-js-optimizer-t2c-output.js')).read(),
+ ['simplifyExpressions', 'optimizeShiftsConservative']),
+ (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(),
+ ['simplifyExpressions', 'optimizeShiftsAggressive']),
+ # Make sure that optimizeShifts handles functions with shift statements.
+ (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(),
+ ['optimizeShiftsAggressive']),
+ (path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(),
+ ['registerize']),
+ (path_from_root('tools', 'eliminator', 'eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read(),
+ ['eliminate']),
+ (path_from_root('tools', 'eliminator', 'safe-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'safe-eliminator-test-output.js')).read(),
+ ['eliminateMemSafe']),
+ (path_from_root('tools', 'eliminator', 'asm-eliminator-test.js'), open(path_from_root('tools', 'eliminator', 'asm-eliminator-test-output.js')).read(),
+ ['asm', 'eliminate']),
+ (path_from_root('tools', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-output.js')).read(),
+ ['asm', 'registerize']),
+ (path_from_root('tools', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-min-output.js')).read(),
+ ['asm', 'registerize']),
+ (path_from_root('tools', 'test-js-optimizer-asm-pre.js'), open(path_from_root('tools', 'test-js-optimizer-asm-pre-output.js')).read(),
+ ['asm', 'simplifyExpressions']),
+ (path_from_root('tools', 'test-js-optimizer-asm-last.js'), open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(),
+ ['asm', 'last']),
+ (path_from_root('tools', 'test-js-optimizer-asm-relocate.js'), open(path_from_root('tools', 'test-js-optimizer-asm-relocate-output.js')).read(),
+ ['asm', 'relocate']),
+ (path_from_root('tools', 'test-js-optimizer-asm-outline1.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline1-output.js')).read(),
+ ['asm', 'outline']),
+ (path_from_root('tools', 'test-js-optimizer-asm-outline2.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline2-output.js')).read(),
+ ['asm', 'outline']),
+ (path_from_root('tools', 'test-js-optimizer-asm-outline3.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline3-output.js')).read(),
+ ['asm', 'outline']),
+ ]:
+ print input
+ output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0]
+ self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n'))
+
+ def test_m_mm(self):
+ open(os.path.join(self.get_dir(), 'foo.c'), 'w').write('''#include <emscripten.h>''')
+ for opt in ['M', 'MM']:
+ output, err = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'foo.c'), '-' + opt], stdout=PIPE, stderr=PIPE).communicate()
+ assert 'foo.o: ' in output, '-%s failed to produce the right output: %s' % (opt, output)
+ assert 'error' not in err, 'Unexpected stderr: ' + err
+
+ def test_chunking(self):
+ if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
+ if os.environ.get('EMCC_CORES'): return self.skip('cannot run if cores are altered')
+ if multiprocessing.cpu_count() < 2: return self.skip('need multiple cores')
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ os.environ['EMCC_CORES'] = '2'
+ for asm, linkable, chunks, js_chunks in [
+ (0, 0, 3, 2), (0, 1, 3, 4),
+ (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] + (['-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)
+ assert ok, err
+ ok = False
+ for c in range(js_chunks, js_chunks+2):
+ ok = ok or ('splitting up js optimization into %d chunks' % c in err)
+ assert ok, err
+ finally:
+ del os.environ['EMCC_DEBUG']
+ del os.environ['EMCC_CORES']
+
+ def test_debuginfo(self):
+ if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ # llvm debug info is kept only when we can see it, which is without the js optimize, -O0. js debug info is lost by registerize in -O2, so - g disables it
+ for args, expect_llvm, expect_js in [
+ (['-O0'], True, True),
+ (['-O0', '-g'], True, True),
+ (['-O1'], False, True),
+ (['-O1', '-g'], False, True),
+ (['-O2'], False, False),
+ (['-O2', '-g'], False, True),
+ ]:
+ print args, expect_llvm, expect_js
+ output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
+ assert expect_llvm == ('strip-debug' not in err)
+ assert expect_js == ('registerize' not in err)
+ finally:
+ del os.environ['EMCC_DEBUG']
+
+ def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1
+ try_delete(os.path.join(self.get_dir(), 'test'))
+ shutil.copytree(path_from_root('tests', 'scons'), os.path.join(self.get_dir(), 'test'))
+ shutil.copytree(path_from_root('tools', 'scons', 'site_scons'), os.path.join(self.get_dir(), 'test', 'site_scons'))
+ os.chdir(os.path.join(self.get_dir(), 'test'))
+ Popen(['scons']).communicate()
+ output = run_js('scons_integration.js')
+ assert 'If you see this - the world is all right!' in output
+
+ def test_embind(self):
+ for args, fail in [
+ ([], True), # without --bind, we fail
+ (['--bind'], False),
+ (['--bind', '-O1'], False),
+ (['--bind', '-O2'], False),
+ (['--bind', '-O1', '-s', 'ASM_JS=0'], False),
+ (['--bind', '-O2', '-s', 'ASM_JS=0'], False)
+ ]:
+ print args, fail
+ self.clear()
+ try_delete(self.in_dir('a.out.js'))
+ Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate()
+ assert os.path.exists(self.in_dir('a.out.js')) == (not fail)
+ if not fail:
+ output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True)
+ assert "FAIL" not in output, output
+
+ def test_llvm_nativizer(self):
+ try:
+ Popen(['as', '--version'], stdout=PIPE, stderr=PIPE).communicate()
+ except:
+ return self.skip('no gnu as, cannot run nativizer')
+
+ # avoid impure_ptr problems etc.
+ shutil.copyfile(path_from_root('tests', 'files.cpp'), os.path.join(self.get_dir(), 'files.cpp'))
+ open(os.path.join(self.get_dir(), 'somefile.binary'), 'w').write('''waka waka############################''')
+ open(os.path.join(self.get_dir(), 'test.file'), 'w').write('''ay file..............,,,,,,,,,,,,,,''')
+ open(os.path.join(self.get_dir(), 'stdin'), 'w').write('''inter-active''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'files.cpp'), '-c']).communicate()
+ Popen([PYTHON, path_from_root('tools', 'nativize_llvm.py'), os.path.join(self.get_dir(), 'files.o')], stdout=PIPE, stderr=PIPE).communicate(input)
+ output = Popen([os.path.join(self.get_dir(), 'files.o.run')], stdin=open(os.path.join(self.get_dir(), 'stdin')), stdout=PIPE, stderr=PIPE).communicate()
+ self.assertContained('''size: 37
+data: 119,97,107,97,32,119,97,107,97,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35
+loop: 119 97 107 97 32 119 97 107 97 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
+input:inter-active
+texto
+$
+5 : 10,30,20,11,88
+other=ay file...
+seeked= file.
+''', output[0])
+ self.assertIdentical('texte\n', output[1])
+
+ def test_emconfig(self):
+ output = Popen([PYTHON, EMCONFIG, 'LLVM_ROOT'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
+ try:
+ assert output == LLVM_ROOT
+ except:
+ print >> sys.stderr, 'Assertion failed: python %s LLVM_ROOT returned "%s" instead of expected "%s"!' % (EMCONFIG, output, LLVM_ROOT)
+ raise
+ invalid = 'Usage: em-config VAR_NAME'
+ # Don't accept variables that do not exist
+ output = Popen([PYTHON, EMCONFIG, 'VAR_WHICH_DOES_NOT_EXIST'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
+ assert output == invalid
+ # Don't accept no arguments
+ output = Popen([PYTHON, EMCONFIG], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
+ assert output == invalid
+ # Don't accept more than one variable
+ output = Popen([PYTHON, EMCONFIG, 'LLVM_ROOT', 'EMCC'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
+ assert output == invalid
+ # Don't accept arbitrary python code
+ output = Popen([PYTHON, EMCONFIG, 'sys.argv[1]'], stdout=PIPE, stderr=PIPE).communicate()[0].strip()
+ assert output == invalid
+
+ def test_link_s(self):
+ # -s OPT=VALUE can conflict with -s as a linker option. We warn and ignore
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ extern "C" {
+ void something();
+ }
+
+ int main() {
+ something();
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'supp.cpp'), 'w').write(r'''
+ #include <stdio.h>
+
+ extern "C" {
+ void something() {
+ printf("yello\n");
+ }
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-o', 'main.o']).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'supp.cpp'), '-o', 'supp.o']).communicate()
+
+ output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o'), '-s', os.path.join(self.get_dir(), 'supp.o'), '-s', 'SAFE_HEAP=1'], stderr=PIPE).communicate()
+ self.assertContained('treating -s as linker option', output[1])
+ output = run_js('a.out.js')
+ assert 'yello' in output, 'code works'
+ code = open('a.out.js').read()
+ assert 'SAFE_HEAP' in code, 'valid -s option had an effect'
+
+ def test_jcache_printf(self):
+ open(self.in_dir('src.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <emscripten.h>
+ int main() {
+ emscripten_jcache_printf("hello world\n");
+ emscripten_jcache_printf("hello %d world\n", 5);
+ emscripten_jcache_printf("hello %.3f world\n", 123.456789123);
+ emscripten_jcache_printf("hello %llx world\n", 0x1234567811223344ULL);
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, self.in_dir('src.cpp')]).communicate()
+ output = run_js('a.out.js')
+ self.assertIdentical('hello world\nhello 5 world\nhello 123.457 world\nhello 1234567811223300 world\n', output)
+
+ def test_conftest_s_flag_passing(self):
+ open(os.path.join(self.get_dir(), 'conftest.c'), 'w').write(r'''
+ int main() {
+ return 0;
+ }
+ ''')
+ os.environ["EMMAKEN_JUST_CONFIGURE"] = "1"
+ cmd = [PYTHON, EMCC, '-s', 'ASSERTIONS=1', os.path.join(self.get_dir(), 'conftest.c'), '-o', 'conftest']
+ output = Popen(cmd, stderr=PIPE).communicate()
+ del os.environ["EMMAKEN_JUST_CONFIGURE"]
+ self.assertNotContained('emcc: warning: treating -s as linker option', output[1])
+ assert os.path.exists('conftest')
+
+ def test_file_packager(self):
+ try:
+ os.mkdir('subdir')
+ except:
+ pass
+ open('data1.txt', 'w').write('data1')
+ os.chdir('subdir')
+ open('data2.txt', 'w').write('data2')
+ # relative path to below the current dir is invalid
+ out, err = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', '../data1.txt'], stdout=PIPE, stderr=PIPE).communicate()
+ assert len(out) == 0
+ assert 'below the current directory' in err
+ # relative path that ends up under us is cool
+ out, err = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', '../subdir/data2.txt'], stdout=PIPE, stderr=PIPE).communicate()
+ assert len(out) > 0
+ assert 'below the current directory' not in err
+ # direct path leads to the same code being generated - relative path does not make us do anything different
+ out2, err2 = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', 'data2.txt'], stdout=PIPE, stderr=PIPE).communicate()
+ assert len(out2) > 0
+ assert 'below the current directory' not in err2
+ def clean(txt):
+ return filter(lambda line: 'PACKAGE_UUID' not in line, txt.split('\n'))
+ out = clean(out)
+ out2 = clean(out2)
+ assert out == out2
+ # sanity check that we do generate different code for different inputs
+ out3, err3 = Popen([PYTHON, FILE_PACKAGER, 'test.data', '--preload', 'data2.txt', 'data2.txt@waka.txt'], stdout=PIPE, stderr=PIPE).communicate()
+ out3 = clean(out3)
+ assert out != out3
+
+ def test_crunch(self):
+ # crunch should not be run if a .crn exists that is more recent than the .dds
+ shutil.copyfile(path_from_root('tests', 'ship.dds'), 'ship.dds')
+ time.sleep(0.1)
+ Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate()
+ assert os.stat('test.data').st_size < 0.25*os.stat('ship.dds').st_size, 'Compressed should be much smaller than dds'
+ crunch_time = os.stat('ship.crn').st_mtime
+ dds_time = os.stat('ship.dds').st_mtime
+ assert crunch_time > dds_time, 'Crunch is more recent'
+ # run again, should not recrunch!
+ time.sleep(0.1)
+ Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate()
+ assert crunch_time == os.stat('ship.crn').st_mtime, 'Crunch is unchanged'
+ # update dds, so should recrunch
+ time.sleep(0.1)
+ os.utime('ship.dds', None)
+ Popen([PYTHON, FILE_PACKAGER, 'test.data', '--pre-run', '--crunch=32', '--preload', 'ship.dds'], stdout=open('pre.js', 'w')).communicate()
+ assert crunch_time < os.stat('ship.crn').st_mtime, 'Crunch was changed'
+
+ def test_headless(self):
+ if SPIDERMONKEY_ENGINE not in JS_ENGINES: return self.skip('cannot run without spidermonkey due to node limitations (Uint8ClampedArray etc.)')
+
+ shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'example.png'))
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_canvas.c'), '-s', 'HEADLESS=1']).communicate()
+ output = run_js('a.out.js', engine=SPIDERMONKEY_ENGINE, stderr=PIPE)
+ assert '''Init: 0
+Font: 0x1
+Sum: 0
+you should see two lines of text in different colors and a blue rectangle
+SDL_Quit called (and ignored)
+done.
+''' in output, output
diff --git a/tests/test_sanity.py b/tests/test_sanity.py
new file mode 100644
index 00000000..931645e2
--- /dev/null
+++ b/tests/test_sanity.py
@@ -0,0 +1,522 @@
+import os, shutil, stat, subprocess
+from runner import RunnerCore, path_from_root
+from tools.shared import *
+
+SANITY_FILE = CONFIG_FILE + '_sanity'
+commands = [[EMCC], [PYTHON, path_from_root('tests', 'runner.py'), 'blahblah']]
+
+def restore():
+ shutil.copyfile(CONFIG_FILE + '_backup', CONFIG_FILE)
+
+def wipe():
+ try_delete(CONFIG_FILE)
+ try_delete(SANITY_FILE)
+
+def mtime(filename):
+ return os.stat(filename).st_mtime
+
+class sanity(RunnerCore):
+ @classmethod
+ def setUpClass(self):
+ super(RunnerCore, self).setUpClass()
+ shutil.copyfile(CONFIG_FILE, CONFIG_FILE + '_backup')
+
+ print
+ print 'Running sanity checks.'
+ print 'WARNING: This will modify %s, and in theory can break it although it should be restored properly. A backup will be saved in %s_backup' % (EM_CONFIG, EM_CONFIG)
+ print
+
+ assert os.path.exists(CONFIG_FILE), 'To run these tests, we need a (working!) %s file to already exist' % EM_CONFIG
+ assert not os.environ.get('EMCC_DEBUG'), 'do not run sanity checks in debug mode!'
+
+ @classmethod
+ def tearDownClass(self):
+ super(RunnerCore, self).tearDownClass()
+
+ def setUp(self):
+ wipe()
+
+ def tearDown(self):
+ restore()
+
+ def do(self, command):
+ if type(command) is not list:
+ command = [command]
+ if command[0] == EMCC:
+ command = [PYTHON] + command
+
+ return Popen(command, stdout=PIPE, stderr=STDOUT).communicate()[0]
+
+ def check_working(self, command, expected=None):
+ if type(command) is not list:
+ command = [command]
+ if expected is None:
+ if command[0] == EMCC:
+ expected = 'no input files'
+ else:
+ expected = "No tests found for ['blahblah']"
+
+ output = self.do(command)
+ self.assertContained(expected, output)
+ return output
+
+ def test_aaa_normal(self): # this should be the very first thing that runs. if this fails, everything else is irrelevant!
+ for command in commands:
+ # Your existing EM_CONFIG should work!
+ restore()
+ self.check_working(command)
+
+ def test_firstrun(self):
+ for command in commands:
+ wipe()
+
+ def make_executable(name):
+ with open(os.path.join(temp_bin, name), 'w') as f:
+ os.fchmod(f.fileno(), stat.S_IRWXU)
+
+ try:
+ temp_bin = tempfile.mkdtemp()
+ old_environ_path = os.environ['PATH']
+ os.environ['PATH'] = temp_bin + os.pathsep + old_environ_path
+ make_executable('llvm-dis')
+ make_executable('node')
+ make_executable('python2')
+ output = self.do(command)
+ finally:
+ os.environ['PATH'] = old_environ_path
+ shutil.rmtree(temp_bin)
+
+ self.assertContained('Welcome to Emscripten!', output)
+ self.assertContained('This is the first time any of the Emscripten tools has been run.', output)
+ self.assertContained('A settings file has been copied to %s, at absolute path: %s' % (EM_CONFIG, CONFIG_FILE), output)
+ self.assertContained('It contains our best guesses for the important paths, which are:', output)
+ self.assertContained('LLVM_ROOT', output)
+ self.assertContained('NODE_JS', output)
+ self.assertContained('PYTHON', output)
+ if platform.system() is not 'Windows':
+ # os.chmod can't make files executable on Windows
+ self.assertIdentical(temp_bin, re.search("^ *LLVM_ROOT *= (.*)$", output, re.M).group(1))
+ self.assertIdentical(os.path.join(temp_bin, 'node'), re.search("^ *NODE_JS *= (.*)$", output, re.M).group(1))
+ self.assertIdentical(os.path.join(temp_bin, 'python2'), re.search("^ *PYTHON *= (.*)$", output, re.M).group(1))
+ self.assertContained('Please edit the file if any of those are incorrect', output)
+ self.assertContained('This command will now exit. When you are done editing those paths, re-run it.', output)
+ assert output.split()[-1].endswith('===='), 'We should have stopped: ' + output
+ config_file = open(CONFIG_FILE).read()
+ template_file = open(path_from_root('tools', 'settings_template_readonly.py')).read()
+ self.assertNotContained('~/.emscripten', config_file)
+ self.assertContained('~/.emscripten', template_file)
+ self.assertNotContained('{{{', config_file)
+ self.assertNotContained('}}}', config_file)
+ self.assertContained('{{{', template_file)
+ self.assertContained('}}}', template_file)
+ for content in ['EMSCRIPTEN_ROOT', 'LLVM_ROOT', 'NODE_JS', 'TEMP_DIR', 'COMPILER_ENGINE', 'JS_ENGINES']:
+ self.assertContained(content, config_file)
+
+ # The guessed config should be ok XXX This depends on your local system! it is possible `which` guesses wrong
+ #try_delete('a.out.js')
+ #output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c')], stdout=PIPE, stderr=PIPE).communicate()
+ #self.assertContained('hello, world!', run_js('a.out.js'), output)
+
+ # Second run, with bad EM_CONFIG
+ for settings in ['blah', 'LLVM_ROOT="blarg"; JS_ENGINES=[]; COMPILER_ENGINE=NODE_JS=SPIDERMONKEY_ENGINE=[]']:
+ f = open(CONFIG_FILE, 'w')
+ f.write(settings)
+ f.close()
+ output = self.do(command)
+
+ if 'LLVM_ROOT' not in settings:
+ self.assertContained('Error in evaluating %s' % EM_CONFIG, output)
+ elif 'runner.py' not in ' '.join(command):
+ self.assertContained('CRITICAL', output) # sanity check should fail
+
+ def test_closure_compiler(self):
+ CLOSURE_FATAL = 'fatal: Closure compiler'
+ CLOSURE_WARNING = 'does not exist'
+
+ # Sanity check should find closure
+ restore()
+ output = self.check_working(EMCC)
+ self.assertNotContained(CLOSURE_FATAL, output)
+ self.assertNotContained(CLOSURE_WARNING, output)
+
+ # Append a bad path for closure, will warn
+ f = open(CONFIG_FILE, 'a')
+ f.write('CLOSURE_COMPILER = "/tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt"\n')
+ f.close()
+ output = self.check_working(EMCC, CLOSURE_WARNING)
+
+ # And if you actually try to use the bad path, will be fatal
+ f = open(CONFIG_FILE, 'a')
+ f.write('CLOSURE_COMPILER = "/tmp/nowhere/nothingtoseehere/kjadsfkjwelkjsdfkqgas/nonexistent.txt"\n')
+ f.close()
+ output = self.check_working([EMCC, '-O2', '-s', 'ASM_JS=0', '--closure', '1', 'tests/hello_world.cpp'], CLOSURE_FATAL)
+
+ # With a working path, all is well
+ restore()
+ try_delete('a.out.js')
+ output = self.check_working([EMCC, '-O2', '-s', 'ASM_JS=0', '--closure', '1', 'tests/hello_world.cpp'], '')
+ assert os.path.exists('a.out.js'), output
+
+ def test_llvm(self):
+ LLVM_WARNING = 'LLVM version appears incorrect'
+
+ restore()
+
+ # Clang should report the version number we expect, and emcc should not warn
+ assert check_clang_version()
+ output = self.check_working(EMCC)
+ assert LLVM_WARNING not in output, output
+
+ # Fake a different llvm version
+ restore()
+ f = open(CONFIG_FILE, 'a')
+ f.write('LLVM_ROOT = "' + path_from_root('tests', 'fake') + '"')
+ f.close()
+
+ if not os.path.exists(path_from_root('tests', 'fake')):
+ os.makedirs(path_from_root('tests', 'fake'))
+
+ try:
+ os.environ['EM_IGNORE_SANITY'] = '1'
+ for x in range(-2, 3):
+ for y in range(-2, 3):
+ f = open(path_from_root('tests', 'fake', 'clang'), 'w')
+ f.write('#!/bin/sh\n')
+ f.write('echo "clang version %d.%d" 1>&2\n' % (EXPECTED_LLVM_VERSION[0] + x, EXPECTED_LLVM_VERSION[1] + y))
+ f.close()
+ shutil.copyfile(path_from_root('tests', 'fake', 'clang'), path_from_root('tests', 'fake', 'clang++'))
+ os.chmod(path_from_root('tests', 'fake', 'clang'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
+ os.chmod(path_from_root('tests', 'fake', 'clang++'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
+ if x != 0 or y != 0:
+ output = self.check_working(EMCC, LLVM_WARNING)
+ else:
+ output = self.check_working(EMCC)
+ assert LLVM_WARNING not in output, output
+ finally:
+ del os.environ['EM_IGNORE_SANITY']
+
+ def test_node(self):
+ NODE_WARNING = 'node version appears too old'
+ NODE_WARNING_2 = 'cannot check node version'
+
+ restore()
+
+ # Clang should report the version number we expect, and emcc should not warn
+ assert check_node_version()
+ output = self.check_working(EMCC)
+ assert NODE_WARNING not in output, output
+
+ # Fake a different node version
+ restore()
+ f = open(CONFIG_FILE, 'a')
+ f.write('NODE_JS = "' + path_from_root('tests', 'fake', 'nodejs') + '"')
+ f.close()
+
+ if not os.path.exists(path_from_root('tests', 'fake')):
+ os.makedirs(path_from_root('tests', 'fake'))
+
+ try:
+ os.environ['EM_IGNORE_SANITY'] = '1'
+ for version, succeed in [('v0.7.9', False), ('v0.8.0', True), ('v0.8.1', True), ('cheez', False)]:
+ f = open(path_from_root('tests', 'fake', 'nodejs'), 'w')
+ f.write('#!/bin/sh\n')
+ f.write('''if [ $1 = "--version" ]; then
+echo "%s"
+else
+%s $@
+fi
+''' % (version, NODE_JS))
+ f.close()
+ os.chmod(path_from_root('tests', 'fake', 'nodejs'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
+ if not succeed:
+ if version[0] == 'v':
+ self.check_working(EMCC, NODE_WARNING)
+ else:
+ self.check_working(EMCC, NODE_WARNING_2)
+ else:
+ output = self.check_working(EMCC)
+ assert NODE_WARNING not in output, output
+ finally:
+ del os.environ['EM_IGNORE_SANITY']
+
+ def test_emcc(self):
+ SANITY_MESSAGE = 'Emscripten: Running sanity checks'
+ SANITY_FAIL_MESSAGE = 'sanity check failed to run'
+
+ # emcc should check sanity if no ${EM_CONFIG}_sanity
+ restore()
+ time.sleep(0.1)
+ assert not os.path.exists(SANITY_FILE) # restore is just the settings, not the sanity
+ output = self.check_working(EMCC)
+ self.assertContained(SANITY_MESSAGE, output)
+ assert os.path.exists(SANITY_FILE) # EMCC should have checked sanity successfully
+ assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
+ assert generate_sanity() == open(SANITY_FILE).read()
+ self.assertNotContained(SANITY_FAIL_MESSAGE, output)
+
+ # emcc run again should not sanity check, because the sanity file is newer
+ output = self.check_working(EMCC)
+ self.assertNotContained(SANITY_MESSAGE, output)
+ self.assertNotContained(SANITY_FAIL_MESSAGE, output)
+
+ # correct sanity contents mean we need not check
+ open(SANITY_FILE, 'w').write(generate_sanity())
+ output = self.check_working(EMCC)
+ self.assertNotContained(SANITY_MESSAGE, output)
+
+ # incorrect sanity contents mean we *must* check
+ open(SANITY_FILE, 'w').write('wakawaka')
+ output = self.check_working(EMCC)
+ self.assertContained(SANITY_MESSAGE, output)
+
+ # but with EMCC_DEBUG=1 we should check
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ output = self.check_working(EMCC)
+ finally:
+ del os.environ['EMCC_DEBUG']
+ self.assertContained(SANITY_MESSAGE, output)
+ output = self.check_working(EMCC)
+ self.assertNotContained(SANITY_MESSAGE, output)
+
+ # Make sure the test runner didn't do anything to the setup
+ output = self.check_working(EMCC)
+ self.assertNotContained(SANITY_MESSAGE, output)
+ self.assertNotContained(SANITY_FAIL_MESSAGE, output)
+
+ # emcc should also check sanity if the file is outdated
+ time.sleep(0.1)
+ restore()
+ assert mtime(SANITY_FILE) < mtime(CONFIG_FILE)
+ output = self.check_working(EMCC)
+ self.assertContained(SANITY_MESSAGE, output)
+ assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
+ self.assertNotContained(SANITY_FAIL_MESSAGE, output)
+
+ # emcc should be configurable directly from EM_CONFIG without any config file
+ restore()
+ config = open(CONFIG_FILE, 'r').read()
+ os.environ['EM_CONFIG'] = config
+ wipe()
+ dirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
+ open(os.path.join(dirname, 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ int main() {
+ printf("hello from emcc with no config file\\n");
+ return 0;
+ }
+ ''')
+ Popen([PYTHON, EMCC, os.path.join(dirname, 'main.cpp'), '-o', os.path.join(dirname, 'a.out.js')]).communicate()
+ del os.environ['EM_CONFIG']
+ old_dir = os.getcwd()
+ try:
+ os.chdir(dirname)
+ self.assertContained('hello from emcc with no config file', run_js('a.out.js'))
+ finally:
+ os.chdir(old_dir)
+ shutil.rmtree(dirname)
+
+ try_delete(CANONICAL_TEMP_DIR)
+
+ def test_emcc_caching(self):
+ INCLUDING_MESSAGE = 'including X'
+ BUILDING_MESSAGE = 'building X for cache'
+ ERASING_MESSAGE = 'clearing cache'
+
+ EMCC_CACHE = Cache.dirname
+
+ for compiler in [EMCC, EMXX]:
+ print compiler
+
+ restore()
+
+ Cache.erase()
+ assert not os.path.exists(EMCC_CACHE)
+
+ try:
+ os.environ['EMCC_DEBUG'] ='1'
+ self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
+
+ # Building a file that doesn't need cached stuff should not trigger cache generation
+ output = self.do([compiler, path_from_root('tests', 'hello_world.cpp')])
+ assert INCLUDING_MESSAGE.replace('X', 'libc') not in output
+ assert BUILDING_MESSAGE.replace('X', 'libc') not in output
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ assert not os.path.exists(EMCC_CACHE)
+ try_delete('a.out.js')
+
+ basebc_name = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-0-basebc.bc')
+ dcebc_name = os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-1-linktime.bc')
+ ll_names = [os.path.join(TEMP_DIR, 'emscripten_temp', 'emcc-X-ll.ll').replace('X', str(x)) for x in range(2,5)]
+
+ # Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time
+ for filename, libname in [('hello_malloc.cpp', 'libc'), ('hello_libcxx.cpp', 'libcxx')]:
+ for i in range(3):
+ print filename, libname, i
+ self.clear()
+ try_delete(basebc_name) # we might need to check this file later
+ try_delete(dcebc_name) # we might need to check this file later
+ for ll_name in ll_names: try_delete(ll_name)
+ output = self.do([compiler, '-O' + str(i), '-s', 'RELOOP=0', '--llvm-lto', '0', path_from_root('tests', filename)])
+ #print output
+ assert INCLUDING_MESSAGE.replace('X', libname) in output
+ if libname == 'libc':
+ assert INCLUDING_MESSAGE.replace('X', 'libcxx') not in output # we don't need libcxx in this code
+ else:
+ assert INCLUDING_MESSAGE.replace('X', 'libc') in output # libcxx always forces inclusion of libc
+ assert (BUILDING_MESSAGE.replace('X', libname) in output) == (i == 0), 'Must only build the first time'
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ assert os.path.exists(EMCC_CACHE)
+ assert os.path.exists(os.path.join(EMCC_CACHE, libname + '.bc'))
+ if libname == 'libcxx':
+ print os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size, os.stat(basebc_name).st_size, os.stat(dcebc_name).st_size
+ assert os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size > 1000000, 'libc++ is big'
+ assert os.stat(basebc_name).st_size > 1000000, 'libc++ is indeed big'
+ assert os.stat(dcebc_name).st_size < os.stat(basebc_name).st_size/2, 'Dead code elimination must remove most of libc++'
+ # should only have metadata in -O0, not 1 and 2
+ if i > 0:
+ for ll_name in ll_names:
+ ll = None
+ try:
+ ll = open(ll_name).read()
+ break
+ except:
+ pass
+ assert ll
+ assert ll.count('\n!') < 10 # a few lines are left even in -O1 and -O2
+ finally:
+ del os.environ['EMCC_DEBUG']
+
+ restore()
+
+ def ensure_cache():
+ self.do([EMCC, '-O2', path_from_root('tests', 'hello_world.c')])
+
+ # Manual cache clearing
+ ensure_cache()
+ assert os.path.exists(EMCC_CACHE)
+ output = self.do([EMCC, '--clear-cache'])
+ assert ERASING_MESSAGE in output
+ assert not os.path.exists(EMCC_CACHE)
+
+ # Changing LLVM_ROOT, even without altering .emscripten, clears the cache
+ ensure_cache()
+ old = os.environ.get('LLVM')
+ try:
+ os.environ['LLVM'] = 'waka'
+ assert os.path.exists(EMCC_CACHE)
+ output = self.do([EMCC])
+ assert ERASING_MESSAGE in output
+ assert not os.path.exists(EMCC_CACHE)
+ finally:
+ if old: os.environ['LLVM'] = old
+ else: del os.environ['LLVM']
+
+ try_delete(CANONICAL_TEMP_DIR)
+
+ def test_relooper(self):
+ RELOOPER = Cache.get_path('relooper.js')
+
+ restore()
+ for phase in range(2): # 0: we wipe the relooper dir. 1: we have it, so should just update
+ if phase == 0: Cache.erase()
+ try_delete(RELOOPER)
+
+ for i in range(4):
+ print >> sys.stderr, phase, i
+ opt = min(i, 2)
+ try_delete('a.out.js')
+ output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '-g'],
+ stdout=PIPE, stderr=PIPE).communicate()
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ output = '\n'.join(output)
+ assert ('bootstrapping relooper succeeded' in output) == (i == 2), 'only bootstrap on first O2: ' + output
+ assert os.path.exists(RELOOPER) == (i >= 2), 'have relooper on O2: ' + output
+ src = open('a.out.js').read()
+ main = src.split('function _main()')[1].split('\n}\n')[0]
+ assert ('while (1) {' in main or 'while(1){' in main or '} while ($' in main or '}while($' in main) == (i >= 2), 'reloop code on O2: ' + main
+ assert ('switch' not in main) == (i >= 2), 'reloop code on O2: ' + main
+
+ def test_jcache(self):
+ PRE_LOAD_MSG = 'loading pre from jcache'
+ PRE_SAVE_MSG = 'saving pre to jcache'
+ FUNC_CHUNKS_LOAD_MSG = ' funcchunks from jcache'
+ FUNC_CHUNKS_SAVE_MSG = ' funcchunks to jcache'
+ JSFUNC_CHUNKS_LOAD_MSG = 'jsfuncchunks from jcache'
+ JSFUNC_CHUNKS_SAVE_MSG = 'jsfuncchunks to jcache'
+
+ restore()
+ Cache.erase()
+
+ try:
+ os.environ['EMCC_DEBUG'] = '1'
+ os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE'] = str(1024*512)
+
+ self.working_dir = os.path.join(TEMP_DIR, 'emscripten_temp')
+ if not os.path.exists(self.working_dir): os.makedirs(self.working_dir)
+
+ assert not os.path.exists(JCache.get_cachename('emscript_files'))
+
+ srcs = {}
+ used_jcache = False
+
+ for args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected in [
+ ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
+ (['--jcache'], 'hello_world_loop.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_world_loop.cpp', False, False, False, False, False, False, []),
+ # new
+ ([], 'hello_world.cpp', False, False, False, False, False, False, []),
+ (['--jcache'], 'hello_world.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_world.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_world.cpp', False, False, False, False, False, False, []),
+ # go back to old file, experience caching
+ (['--jcache'], 'hello_world_loop.cpp', False, True, False, True, False, True, []),
+ # new, large file
+ ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
+ (['--jcache'], 'hello_malloc.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_malloc.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_malloc.cpp', False, False, False, False, False, False, []),
+ # new, huge file
+ ([], 'hello_libcxx.cpp', False, False, False, False, False, False, ('3 chunks',)),
+ (['--jcache'], 'hello_libcxx.cpp', True, False, True, False, True, False, []),
+ (['--jcache'], 'hello_libcxx.cpp', False, True, False, True, False, True, []),
+ ([], 'hello_libcxx.cpp', False, False, False, False, False, False, []),
+ # finally, build a file close to the previous, to see that some chunks are found in the cache and some not
+ (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, True, True, True, True, []), # win on pre, mix on funcs, mix on jsfuncs
+ (['--jcache'], 'hello_libcxx_mod1.cpp', False, True, False, True, False, True, []),
+ (None, None, None, None, None, None, None, None, None), # clear
+ (['--jcache'], 'hello_libcxx_mod2.cpp', True, False, True, False, True, False, []), # load into cache
+ (['--jcache'], 'hello_libcxx_mod2a.cpp', False, True, True, True, True, True, []) # add a printf, do not lose everything
+ ]:
+ self.clear()
+ if args is None:
+ Cache.erase()
+ continue
+
+ print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected
+
+ out, err = Popen([PYTHON, EMCC, '-O2', '-g', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
+ errtail = err.split('emcc invocation')[-1]
+ self.assertContained('hello, world!', run_js('a.out.js'), errtail)
+ assert (PRE_SAVE_MSG in err) == expect_pre_save, errtail
+ assert (PRE_LOAD_MSG in err) == expect_pre_load, errtail
+ assert (FUNC_CHUNKS_SAVE_MSG in err) == expect_funcs_save, errtail
+ assert (FUNC_CHUNKS_LOAD_MSG in err) == expect_funcs_load, errtail
+ assert (JSFUNC_CHUNKS_SAVE_MSG in err) == expect_jsfuncs_save, errtail
+ assert (JSFUNC_CHUNKS_LOAD_MSG in err) == expect_jsfuncs_load, errtail
+ for expect in expected: assert expect in err, expect + ' ? ' + errtail
+ curr = open('a.out.js').read()
+ if input_file not in srcs:
+ srcs[input_file] = curr
+ else:
+ #open('/home/alon/Dev/emscripten/a', 'w').write(srcs[input_file])
+ #open('/home/alon/Dev/emscripten/b', 'w').write(curr)
+ assert abs(len(curr)/float(len(srcs[input_file]))-1)<0.01, 'contents may shift in order, but must remain the same size %d vs %d' % (len(curr), len(srcs[input_file])) + '\n' + errtail
+ used_jcache = used_jcache or ('--jcache' in args)
+ assert used_jcache == os.path.exists(JCache.get_cachename('emscript_files'))
+ #print >> sys.stderr, errtail
+
+ finally:
+ del os.environ['EMCC_DEBUG']
+ del os.environ['EMCC_JSOPT_MIN_CHUNK_SIZE'] \ No newline at end of file
diff --git a/tests/test_sockets.py b/tests/test_sockets.py
new file mode 100644
index 00000000..4f6ee2a9
--- /dev/null
+++ b/tests/test_sockets.py
@@ -0,0 +1,268 @@
+import os, multiprocessing, subprocess
+from runner import BrowserCore, path_from_root
+from tools.shared import *
+
+def clean_pids(pids):
+ import signal, errno
+ def pid_exists(pid):
+ try:
+ # NOTE: may just kill the process in Windows
+ os.kill(pid, 0)
+ except OSError, e:
+ return e.errno == errno.EPERM
+ else:
+ return True
+ def kill_pids(pids, sig):
+ for pid in pids:
+ if not pid_exists(pid):
+ break
+ print '[killing %d]' % pid
+ try:
+ os.kill(pid, sig)
+ print '[kill succeeded]'
+ except:
+ print '[kill fail]'
+ # ask nicely (to try and catch the children)
+ kill_pids(pids, signal.SIGTERM)
+ time.sleep(1)
+ # extreme prejudice, may leave children
+ kill_pids(pids, signal.SIGKILL)
+
+def make_relay_server(port1, port2):
+ print >> sys.stderr, 'creating relay server on ports %d,%d' % (port1, port2)
+ proc = Popen([PYTHON, path_from_root('tests', 'sockets', 'socket_relay.py'), str(port1), str(port2)])
+ return proc
+
+class WebsockifyServerHarness:
+ def __init__(self, filename, args, listen_port, target_port):
+ self.pids = []
+ self.filename = filename
+ self.target_port = target_port
+ self.listen_port = listen_port
+ self.args = args or []
+
+ def __enter__(self):
+ import socket, websockify
+
+ # compile the server
+ # NOTE empty filename support is a hack to support
+ # the current test_enet
+ if self.filename:
+ Popen([CLANG_CC, path_from_root('tests', self.filename), '-o', 'server'] + self.args).communicate()
+ process = Popen([os.path.abspath('server')])
+ self.pids.append(process.pid)
+
+ # start the websocket proxy
+ print >> sys.stderr, 'running websockify on %d, forward to tcp %d' % (self.listen_port, self.target_port)
+ wsp = websockify.WebSocketProxy(verbose=True, listen_port=self.listen_port, target_host="127.0.0.1", target_port=self.target_port, run_once=True)
+ self.websockify = multiprocessing.Process(target=wsp.start_server)
+ self.websockify.start()
+ self.pids.append(self.websockify.pid)
+ print '[Websockify on process %s]' % str(self.pids[-2:])
+
+ def __exit__(self, *args, **kwargs):
+ # try to kill the websockify proxy gracefully
+ if self.websockify.is_alive():
+ self.websockify.terminate()
+ self.websockify.join()
+
+ # clean up any processes we started
+ clean_pids(self.pids)
+
+
+class CompiledServerHarness:
+ def __init__(self, filename, args):
+ self.pids = []
+ self.filename = filename
+ self.args = args or []
+
+ def __enter__(self):
+ import socket, websockify
+
+ # compile the server
+ Popen([PYTHON, EMCC, path_from_root('tests', self.filename), '-o', 'server.js'] + self.args).communicate()
+ process = Popen([NODE_JS, 'server.js'])
+ self.pids.append(process.pid)
+
+ def __exit__(self, *args, **kwargs):
+ # clean up any processes we started
+ clean_pids(self.pids)
+
+ # always run these tests last
+ # make sure to use different ports in each one because it takes a while for the processes to be cleaned up
+
+ # NOTE all datagram tests are temporarily disabled, as
+ # we can't truly test datagram sockets until we have
+ # proper listen server support.
+
+class sockets(BrowserCore):
+ def test_sockets_echo(self):
+ sockets_include = '-I'+path_from_root('tests', 'sockets')
+
+ for datagram in [0]:
+ dgram_define = '-DTEST_DGRAM=%d' % datagram
+
+ for harness in [
+ WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), ['-DSOCKK=8990', dgram_define, sockets_include], 8991, 8990)
+ # CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), ['-DSOCKK=8990', dgram_define, sockets_include])
+ ]:
+ with harness:
+ self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=8991', dgram_define, sockets_include])
+
+ def test_sockets_echo_bigdata(self):
+ sockets_include = '-I'+path_from_root('tests', 'sockets')
+
+ for datagram in [0]:
+ dgram_define = '-DTEST_DGRAM=%d' % datagram
+
+ # generate a large string literal to use as our message
+ message = ''
+ for i in range(256*256*2):
+ message += str(unichr(ord('a') + (i % 26)))
+
+ # re-write the client test with this literal (it's too big to pass via command line)
+ input_filename = path_from_root('tests', 'sockets', 'test_sockets_echo_client.c')
+ input = open(input_filename).read()
+ output = input.replace('#define MESSAGE "pingtothepong"', '#define MESSAGE "%s"' % message)
+
+ for harness in [
+ WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), ['-DSOCKK=8992', dgram_define, sockets_include], 8993, 8992)
+ ]:
+ with harness:
+ self.btest(output, expected='0', args=['-DSOCKK=8993', dgram_define, sockets_include], force_c=True)
+
+ def test_sockets_partial(self):
+ for harness in [
+ WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_partial_server.c'), ['-DSOCKK=8994'], 8995, 8994)
+ ]:
+ with harness:
+ self.btest(os.path.join('sockets', 'test_sockets_partial_client.c'), expected='165', args=['-DSOCKK=8995'])
+
+ # TODO add support for gethostbyaddr to re-enable this test
+ # def test_sockets_gethostbyname(self):
+ # self.btest(os.path.join('sockets', 'test_sockets_gethostbyname.c'), expected='0', args=['-O2', '-DSOCKK=8997'])
+
+ def test_sockets_select_server_no_accept(self):
+ for harness in [
+ WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_select_server_no_accept_server.c'), ['-DSOCKK=8995'], 8996, 8995)
+ ]:
+ self.btest(os.path.join('sockets', 'test_sockets_select_server_no_accept_client.c'), expected='266', args=['-DSOCKK=8996'])
+
+ def test_sockets_select_server_closes_connection_rw(self):
+ sockets_include = '-I'+path_from_root('tests', 'sockets')
+
+ for harness in [
+ WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), ['-DSOCKK=9004', sockets_include], 9005, 9004)
+ ]:
+ with harness:
+ self.btest(os.path.join('sockets', 'test_sockets_select_server_closes_connection_client_rw.c'), expected='266', args=['-DSOCKK=9005', sockets_include])
+
+ # TODO remove this once we have proper listen server support built into emscripten.
+ # being that enet uses datagram sockets, we can't proxy to a native server with
+ # websockify, so we're emulating the listen server in the browser and relaying
+ # between two TCP servers.
+ def test_enet(self):
+ try_delete(self.in_dir('enet'))
+ shutil.copytree(path_from_root('tests', 'enet'), self.in_dir('enet'))
+ pwd = os.getcwd()
+ os.chdir(self.in_dir('enet'))
+ Popen([PYTHON, path_from_root('emconfigure'), './configure']).communicate()
+ Popen([PYTHON, path_from_root('emmake'), 'make']).communicate()
+ enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I'+path_from_root('tests', 'enet', 'include')]
+ os.chdir(pwd)
+ Popen([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_enet_server.c'), '-o', 'server.html', '-DSOCKK=2235'] + enet).communicate()
+
+ with WebsockifyServerHarness('', [], 2235, 2234):
+ with WebsockifyServerHarness('', [], 2237, 2236):
+ pids = []
+ try:
+ proc = make_relay_server(2234, 2236)
+ pids.append(proc.pid)
+ self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=['-DSOCKK=2237'] + enet)
+ finally:
+ clean_pids(pids);
+
+ # TODO use this once we have listen server support
+ # def test_enet(self):
+ # try_delete(self.in_dir('enet'))
+ # shutil.copytree(path_from_root('tests', 'enet'), self.in_dir('enet'))
+ # pwd = os.getcwd()
+ # os.chdir(self.in_dir('enet'))
+ # Popen([PYTHON, path_from_root('emconfigure'), './configure']).communicate()
+ # Popen([PYTHON, path_from_root('emmake'), 'make']).communicate()
+ # enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I'+path_from_root('tests', 'enet', 'include')]
+ # os.chdir(pwd)
+
+ # for harness in [
+ # self.CompiledServerHarness(os.path.join('sockets', 'test_enet_server.c'), ['-DSOCKK=9010'] + enet, 9011, 9010)
+ # ]:
+ # with harness:
+ # self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=['-DSOCKK=9011'] + enet)
+
+ def test_webrtc(self):
+ host_src = 'webrtc_host.c'
+ peer_src = 'webrtc_peer.c'
+
+ host_outfile = 'host.html'
+ peer_outfile = 'peer.html'
+
+ host_filepath = path_from_root('tests', 'sockets', host_src)
+ temp_host_filepath = os.path.join(self.get_dir(), os.path.basename(host_src))
+ with open(host_filepath) as f: host_src = f.read()
+ with open(temp_host_filepath, 'w') as f: f.write(self.with_report_result(host_src))
+
+ peer_filepath = path_from_root('tests', 'sockets', peer_src)
+ temp_peer_filepath = os.path.join(self.get_dir(), os.path.basename(peer_src))
+ with open(peer_filepath) as f: peer_src = f.read()
+ with open(temp_peer_filepath, 'w') as f: f.write(self.with_report_result(peer_src))
+
+ open(os.path.join(self.get_dir(), 'host_pre.js'), 'w').write('''
+ var Module = {
+ webrtc: {
+ broker: 'https://mdsw.ch:8080',
+ session: undefined,
+ onpeer: function(peer, route) {
+ window.open('http://localhost:8888/peer.html?' + route);
+ // iframe = document.createElement("IFRAME");
+ // iframe.setAttribute("src", "http://localhost:8888/peer.html?" + route);
+ // iframe.style.display = "none";
+ // document.body.appendChild(iframe);
+ peer.listen();
+ },
+ onconnect: function(peer) {
+ },
+ ondisconnect: function(peer) {
+ },
+ onerror: function(error) {
+ console.error(error);
+ }
+ },
+ };
+ ''')
+
+ open(os.path.join(self.get_dir(), 'peer_pre.js'), 'w').write('''
+ var Module = {
+ webrtc: {
+ broker: 'https://mdsw.ch:8080',
+ session: window.location.toString().split('?')[1],
+ onpeer: function(peer, route) {
+ peer.connect(Module['webrtc']['session']);
+ },
+ onconnect: function(peer) {
+ },
+ ondisconnect: function(peer) {
+ // Calling window.close() from this handler hangs my browser, so run it in the next turn
+ setTimeout(window.close, 0);
+ },
+ onerror: function(error) {
+ console.error(error);
+ }
+ }
+ };
+ ''')
+
+ Popen([PYTHON, EMCC, temp_host_filepath, '-o', host_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'host_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate()
+ Popen([PYTHON, EMCC, temp_peer_filepath, '-o', peer_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'peer_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1']).communicate()
+
+ expected = '1'
+ self.run_browser(host_outfile, '.', ['/report_result?' + e for e in expected]) \ No newline at end of file
diff --git a/tests/websockets.c b/tests/websockets.c
deleted file mode 100644
index 8882f5ba..00000000
--- a/tests/websockets.c
+++ /dev/null
@@ -1,147 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <assert.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 5
-
-int SocketFD;
-
-int not_always_data = 0;
-
-unsigned int get_all_buf(int sock, char* output, unsigned int maxsize)
-{
- // select check for IO
- fd_set sett;
- FD_ZERO(&sett);
- assert(select(64, &sett, NULL, NULL, NULL) == 0); // empty set
- FD_SET(sock, &sett);
- assert(select(0, &sett, NULL, NULL, NULL) == 0); // max FD to check is 0
- assert(FD_ISSET(sock, &sett) == 0);
- FD_SET(sock, &sett);
- int select_says_yes = select(64, &sett, NULL, NULL, NULL);
-
- // ioctl check for IO
- int bytes;
- if (ioctl(sock, FIONREAD, &bytes) || bytes == 0) {
- not_always_data = 1;
- assert(FD_ISSET(sock, &sett) == 0);
- return 0;
- }
-
- assert(FD_ISSET(sock, &sett));
- assert(select_says_yes); // ioctl must agree with select
-
- char buffer[1024];
- int n;
- unsigned int offset = 0;
- while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) ||
- errno == EINTR) {
- if(n>0)
- {
- if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); }
- memcpy(output+offset, buffer, n);
- offset += n;
- }
- }
-
- if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
- fprintf(stderr, "error in get_all_buf! %d", errno);
- exit(EXIT_FAILURE);
- }
- return offset;
-}
-
-int done = 0;
-
-void iter(void *arg) {
- /* perform read write operations ... */
- static char out[1024*2];
- static int pos = 0;
- int n = get_all_buf(SocketFD, out+pos, 1024-pos);
- if (n) printf("read! %d\n", n);
- pos += n;
- if (pos >= EXPECTED_BYTES) {
- int i, sum = 0;
- for (i=0; i < pos; i++) {
- printf("%x\n", out[i]);
- sum += out[i];
- }
-
- shutdown(SocketFD, SHUT_RDWR);
-
- close(SocketFD);
-
- done = 1;
-
- printf("sum: %d\n", sum);
-
-#if EMSCRIPTEN
- //assert(not_always_data == 1);
-
- int result = sum;
- REPORT_RESULT();
-#endif
- }
-}
-
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 8991
-#else
- 8990
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_bi.c b/tests/websockets_bi.c
deleted file mode 100644
index fb60177b..00000000
--- a/tests/websockets_bi.c
+++ /dev/null
@@ -1,140 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 28
-
-#ifndef SOCKK
-#define SOCKK 8992
-#endif
-
-int SocketFD;
-
-unsigned int get_all_buf(int sock, char* output, unsigned int maxsize)
-{
- int bytes;
- if (ioctl(sock, FIONREAD, &bytes)) return 0;
- if (bytes == 0) return 0;
-
- char buffer[1024];
- int n;
- unsigned int offset = 0;
-#if TEST_FILE_OPS
- while((errno = 0, (n = read(sock, buffer, sizeof(buffer)))>0) ||
-#else
- while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) ||
-#endif
- errno == EINTR) {
- if(n>0)
- {
- if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); }
- memcpy(output+offset, buffer, n);
- offset += n;
- }
- }
-
- if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
- fprintf(stderr, "error in get_all_buf!");
- exit(EXIT_FAILURE);
- }
- return offset;
-}
-
-int done = 0;
-
-void iter(void *arg) {
- /* perform read write operations ... */
- static char out[1024*2];
- static int pos = 0;
- int n = get_all_buf(SocketFD, out+pos, 1024-pos);
- if (n) printf("read! %d\n", n);
- pos += n;
- if (pos >= EXPECTED_BYTES) {
- int i, sum = 0;
- for (i=0; i < pos; i++) {
- printf("%x\n", out[i]);
- sum += out[i];
- }
-
- shutdown(SocketFD, SHUT_RDWR);
-
- close(SocketFD);
-
- done = 1;
-
- printf("sum: %d\n", sum);
-
- emscripten_cancel_main_loop();
-
-#if EMSCRIPTEN
- int result = sum;
- REPORT_RESULT();
-#endif
- }
-}
-
-int main(void)
-{
- printf("hello from main page\n");
-
- struct sockaddr_in stSockAddr;
- int Res;
-#if !TEST_DGRAM
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-#else
- SocketFD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-#endif
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(SOCKK);
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_run_script("console.log('adding iframe');"
- "var iframe = document.createElement('iframe');"
- "iframe.src = 'side.html';"
- "document.body.appendChild(iframe);"
- "console.log('added.');");
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_bi_bigdata.c b/tests/websockets_bi_bigdata.c
deleted file mode 100644
index 2039f83c..00000000
--- a/tests/websockets_bi_bigdata.c
+++ /dev/null
@@ -1,137 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#include "websockets_bigdata.h"
-
-#define EXPECTED_BYTES DATA_SIZE
-
-int SocketFD;
-
-unsigned int get_all_buf(int sock, char* output, unsigned int maxsize)
-{
- int bytes;
- if (ioctl(sock, FIONREAD, &bytes)) return 0;
- if (bytes == 0) return 0;
-
- char buffer[EXPECTED_BYTES];
- int n;
- unsigned int offset = 0;
- while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) ||
- errno == EINTR) {
- if(n>0)
- {
- if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); }
- memcpy(output+offset, buffer, n);
- offset += n;
- }
- }
-
- if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
- fprintf(stderr, "error in get_all_buf!");
- exit(EXIT_FAILURE);
- }
- return offset;
-}
-
-int done = 0;
-
-void iter(void *arg) {
- /* perform read write operations ... */
- static char out[EXPECTED_BYTES];
- static int pos = 0;
- printf("so far %d, expecting up to %d\n", pos, EXPECTED_BYTES-pos);
- int n = get_all_buf(SocketFD, out+pos, EXPECTED_BYTES-pos);
- if (n) printf("read! %d\n", n);
- pos += n;
- if (pos >= EXPECTED_BYTES) {
- shutdown(SocketFD, SHUT_RDWR);
-
- close(SocketFD);
-
- done = 1;
-
- emscripten_cancel_main_loop();
-
-#if EMSCRIPTEN
- char *comp = generateData();
- int result = strcmp(comp, out);
- if (result != 0) {
- for (int i = 0; i < DATA_SIZE; i++) {
- printf("%d:%d\n", comp[i], out[i]);
- }
- }
- REPORT_RESULT();
-#endif
- }
-}
-
-int main(void)
-{
- printf("hello from main page\n");
-
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 3993
-#else
- 3992
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_run_script("console.log('adding iframe');"
- "var iframe = document.createElement('iframe');"
- "iframe.src = 'side.html';"
- "iframe.width = '100%';"
- "iframe.width = '40%';"
- "document.body.appendChild(iframe);"
- "console.log('added.');");
- emscripten_set_main_loop(iter, 3, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_bi_listener.c b/tests/websockets_bi_listener.c
deleted file mode 100644
index 6c3b17b1..00000000
--- a/tests/websockets_bi_listener.c
+++ /dev/null
@@ -1,151 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 28
-
-int ListenFD, SocketFD;
-
-unsigned int get_all_buf(int sock, char* output, unsigned int maxsize)
-{
- int bytes;
- if (ioctl(sock, FIONREAD, &bytes)) return 0;
- if (bytes == 0) return 0;
-
- char buffer[1024];
- int n;
- unsigned int offset = 0;
- while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) ||
- errno == EINTR) {
- if(n>0)
- {
- if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); }
- memcpy(output+offset, buffer, n);
- offset += n;
- }
- }
-
- if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
- fprintf(stderr, "error in get_all_buf!");
- exit(EXIT_FAILURE);
- }
- return offset;
-}
-
-int done = 0;
-
-void iter(void *arg) {
- /* perform read write operations ... */
- static char out[1024*2];
- static int pos = 0;
- int n = get_all_buf(SocketFD, out+pos, 1024-pos);
- if (n) printf("read! %d\n", n);
- pos += n;
- if (pos >= EXPECTED_BYTES) {
- int i, sum = 0;
- for (i=0; i < pos; i++) {
- printf("%x\n", out[i]);
- sum += out[i];
- }
-
- shutdown(SocketFD, SHUT_RDWR);
-
- close(SocketFD);
-
- done = 1;
-
- printf("sum: %d\n", sum);
-
-#if EMSCRIPTEN
- int result = sum;
- REPORT_RESULT();
- emscripten_cancel_main_loop();
-#endif
- }
-}
-
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- ListenFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == ListenFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 6993
-#else
- 6995
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(ListenFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(ListenFD);
- exit(EXIT_FAILURE);
- }
-
- printf("bind..\n");
-
- if (-1 == bind(ListenFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("bind failed");
- close(ListenFD);
- exit(EXIT_FAILURE);
- }
-
- printf("listen..\n");
-
- if (-1 == listen(ListenFD, 50)) {
- perror("listen failed");
- close(ListenFD);
- exit(EXIT_FAILURE);
- }
-
- printf("accept..\n");
-
- struct sockaddr_in stSockAddr2;
- socklen_t temp;
-
- if (-1 == (SocketFD = accept(ListenFD, (struct sockaddr *)&stSockAddr2, &temp))) {
- perror("accept failed");
- close(ListenFD);
- exit(EXIT_FAILURE);
- }
-
-#if EMSCRIPTEN
- emscripten_run_script("console.log('adding iframe');"
- "var iframe = document.createElement('iframe');"
- "iframe.src = 'side.html';"
- "document.body.appendChild(iframe);"
- "console.log('added.');");
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_bi_side.c b/tests/websockets_bi_side.c
deleted file mode 100644
index 1d557ed8..00000000
--- a/tests/websockets_bi_side.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 5
-
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
-#if !TEST_DGRAM
- int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-#else
- int SocketFD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-#endif
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(SOCKK);
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- printf("connect..\n");
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
-#if TEST_FILE_OPS
- printf("write..\n");
-
- char data[] = "hello from the other siide (fileops)\n";
- write(SocketFD, data, sizeof(data));
-#else
- printf("send..\n");
-
- char data[] = "hello from the other siide\n";
- send(SocketFD, data, sizeof(data), 0);
-#endif
-
- printf("stall..\n");
-
- //int bytes;
- //while (1) ioctl(SocketFD, FIONREAD, &bytes);
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_bi_side_bigdata.c b/tests/websockets_bi_side_bigdata.c
deleted file mode 100644
index 9b67fe4c..00000000
--- a/tests/websockets_bi_side_bigdata.c
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#include "websockets_bigdata.h"
-
-#define EXPECTED_BYTES 5
-
-void stall(void *arg) {
-}
-
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(SOCKK);
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- printf("connect..\n");
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- printf("send..\n");
-
- char *data = generateData();
- send(SocketFD, data, DATA_SIZE, 0);
-
- printf("stall..\n");
-
- emscripten_set_main_loop(stall, 1, 0);
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_bigdata.h b/tests/websockets_bigdata.h
deleted file mode 100644
index 17149ad6..00000000
--- a/tests/websockets_bigdata.h
+++ /dev/null
@@ -1,20 +0,0 @@
-
-#include <stdlib.h>
-
-#define DATA_SIZE (256*256*2)
-// 1500 fails
-
-char *generateData() {
- char *ret = malloc(256*256*2);
- char *curr = ret;
- for (int i = 0; i < 256; i++) {
- for (int j = 0; j < 256; j++) {
- *curr = i;
- curr++;
- *curr = j;
- curr++;
- }
- }
- return ret;
-}
-
diff --git a/tests/websockets_gethostbyname.c b/tests/websockets_gethostbyname.c
deleted file mode 100644
index 1580d9a7..00000000
--- a/tests/websockets_gethostbyname.c
+++ /dev/null
@@ -1,132 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 5
-
-int SocketFD;
-
-unsigned int get_all_buf(int sock, char* output, unsigned int maxsize)
-{
- int bytes;
- if (ioctl(sock, FIONREAD, &bytes)) return 0;
- if (bytes == 0) return 0;
-
- char buffer[1024];
- int n;
- unsigned int offset = 0;
- while((errno = 0, (n = recv(sock, buffer, sizeof(buffer), 0))>0) ||
- errno == EINTR) {
- if(n>0)
- {
- if (((unsigned int) n)+offset > maxsize) { fprintf(stderr, "too much data!"); exit(EXIT_FAILURE); }
- memcpy(output+offset, buffer, n);
- offset += n;
- }
- }
-
- if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
- fprintf(stderr, "error in get_all_buf!");
- exit(EXIT_FAILURE);
- }
- return offset;
-}
-
-int done = 0;
-
-void iter() {
- /* perform read write operations ... */
- static char out[1024*2];
- static int pos = 0;
- int n = get_all_buf(SocketFD, out+pos, 1024-pos);
- if (n) printf("read! %d\n", n);
- pos += n;
- if (pos >= EXPECTED_BYTES) {
- int i, sum = 0;
- for (i=0; i < pos; i++) {
- printf("%x\n", out[i]);
- sum += out[i];
- }
-
- shutdown(SocketFD, SHUT_RDWR);
-
- close(SocketFD);
-
- done = 1;
-
- printf("sum: %d\n", sum);
-
-#if EMSCRIPTEN
- int result = sum;
- REPORT_RESULT();
-#endif
- }
-}
-
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(7001);
-
- struct hostent *host0 = gethostbyname("test.com"); // increment hostname counter to check for possible but at 0,0 not differentiating low/high
- struct hostent *host = gethostbyname("localhost");
- char **addr_list = host->h_addr_list;
- int *addr = (int*)*addr_list;
- printf("raw addr: %d\n", *addr);
- char name[INET_ADDRSTRLEN];
- if (!inet_ntop(AF_INET, addr, name, sizeof(name))) {
- printf("could not figure out name\n");
- return 0;
- }
- printf("localhost has 'ip' of %s\n", name);
-
- Res = inet_pton(AF_INET, name, &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter();
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_partial.c b/tests/websockets_partial.c
deleted file mode 100644
index f71160b7..00000000
--- a/tests/websockets_partial.c
+++ /dev/null
@@ -1,127 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <assert.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-int SocketFD;
-int done = 0;
-int sum = 0;
-
-void iter(void *arg) {
- char buffer[1024];
- char packetLength;
- int n;
- int i;
-
- if (done) {
- return;
- }
-
- n = recv(SocketFD, buffer, 1, 0);
-
- if (n == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- return; //try again
- }
-
- fprintf(stderr, "unexcepted end of data");
- exit(EXIT_FAILURE);
- }
-
- if (n != 1) {
- fprintf(stderr, "should read 1 byte");
- exit(EXIT_FAILURE);
- }
-
- packetLength = buffer[0];
- n = recv(SocketFD, buffer, packetLength, 0);
-
- printf("got %d,%d\n", n, packetLength);
-
- if (n != packetLength) {
- fprintf(stderr, "lost packet data, expected: %d readed: %d", packetLength, n);
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; i < packetLength; ++i) {
- if (buffer[i] != i+1) {
- fprintf(stderr, "packet corrupted, expected: %d, actual: %d", i+1, buffer[i]);
- exit(EXIT_FAILURE);
- }
-
- sum += buffer[i];
- }
-
- if (packetLength == buffer[0]) { // \x01\x01 - end marker
- shutdown(SocketFD, SHUT_RDWR);
- close(SocketFD);
- done = 1;
-
- #if EMSCRIPTEN
- printf("sum: %d\n", sum);
- int result = sum;
- REPORT_RESULT();
- #endif
- }
-}
-
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 8991
-#else
- 8990
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_select.c b/tests/websockets_select.c
deleted file mode 100644
index b8ab9091..00000000
--- a/tests/websockets_select.c
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <assert.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 5
-
-int SocketFD;
-
-int done = 0;
-
-void iter(void *arg) {
- fd_set sett;
- FD_ZERO(&sett);
- FD_SET(SocketFD, &sett);
-
- // The error should happen here
- int select_says_yes = select(64, &sett, NULL, NULL, NULL);
- if( select_says_yes == -1 ){
- printf( "Connection to websocket server failed as expected." );
- perror( "Error message" );
- int result = 266;
- REPORT_RESULT();
- done = 1;
- }
-
- assert(!select_says_yes);
- done = 1;
-}
-
-// This is for testing a websocket connection to a closed server port.
-// The connect call will succeed (due to the asynchronous websocket
-// behavior) but once the underlying websocket system realized that
-// the connection cannot be established, the next select call will fail.
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 8995
-#else
- 8994
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- // This call should succeed (even if the server port is closed)
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_select_server_closes_connection.c b/tests/websockets_select_server_closes_connection.c
deleted file mode 100644
index 6ce6d311..00000000
--- a/tests/websockets_select_server_closes_connection.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <assert.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 5
-
-int SocketFD;
-
-int done = 0;
-
-void iter(void *arg) {
- static char readbuf[1024];
- static int readPos = 0;
-
- fd_set sett;
- FD_ZERO(&sett);
- FD_SET(SocketFD, &sett);
-
- if( readPos < 7 ){
- // still reading
- int selectRes = select(64, &sett, NULL, NULL, NULL);
-
- if( selectRes == 0 )
- return;
-
- if( selectRes == -1 ){
- perror( "Connection to websocket server failed" );
- exit(EXIT_FAILURE);
- }
- if( selectRes > 0 ){
- assert(FD_ISSET(SocketFD, &sett));
-
- int bytesRead = recv( SocketFD, readbuf+readPos, 7-readPos, 0 );
- readPos += bytesRead;
- }
- } else {
- // here the server should have closed the connection
- int selectRes = select(64, &sett, NULL, NULL, NULL);
-
- if( selectRes == 0 )
- return;
-
- if( selectRes == -1 ){
- perror( "Connection to websocket server failed as expected" );
- int result = 266;
- REPORT_RESULT();
- emscripten_cancel_main_loop();
- done = 1;
- }
-
- if( selectRes > 0 ){
- printf( "Error: socket should not show up on select call anymore.\n" );
- exit(EXIT_FAILURE);
- }
- }
-
- return;
-}
-
-// Scenario: the server sends data and closes the connection after 7 bytes.
-// This test should provoke the situation in which the underlying
-// tcp connection has been torn down already but there is still data
-// in the inQueue. The select call has to succeed as long the queue
-// still contains data and only then start to throw errors.
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 8995
-#else
- 8994
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- // This call should succeed (even if the server port is closed)
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tests/websockets_select_server_closes_connection_rw.c b/tests/websockets_select_server_closes_connection_rw.c
deleted file mode 100644
index dd0913bf..00000000
--- a/tests/websockets_select_server_closes_connection_rw.c
+++ /dev/null
@@ -1,213 +0,0 @@
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <assert.h>
-#if EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#define EXPECTED_BYTES 5
-
-int SocketFD;
-
-int done = 0;
-
-void iter(void *arg) {
- static int state = 0;
- static char writebuf[] = "01234567890123456789";
- static int writePos = 0;
- static char readbuf[1024];
- static int readPos = 0;
- int selectRes;
- ssize_t transferAmount;
- fd_set sett;
-
-
- switch( state ){
- case 0:
- // writing 10 bytes to the server
-
- // the socket in the read file descriptors has to result in a 0 return value
- // because the connection exists, but there is no data yet
- FD_ZERO( &sett );
- FD_SET(SocketFD, &sett);
- selectRes = select(64, &sett, NULL, NULL, NULL);
- if( selectRes != 0 ){
- printf( "case 0: read select != 0\n" );
- exit(EXIT_FAILURE);
- }
-
- // the socket in the write file descriptors has to result in either a 0 or 1
- // the connection either is setting up or is established and writing is possible
- FD_ZERO( &sett );
- FD_SET(SocketFD, &sett);
- selectRes = select(64, NULL, &sett, NULL, NULL);
- if( selectRes == -1 ){
- printf( "case 0: write select == -1\n" );
- exit(EXIT_FAILURE);
- }
- if( selectRes == 0 ){
- return;
- }
-
- // send a single byte
- transferAmount = send( SocketFD, writebuf+writePos, 1, 0 );
- writePos += transferAmount;
-
- // after 10 bytes switch to next state
- if( writePos >= 10 ){
- state = 1;
- }
- break;
-
- case 1:
- // wait until we can read one byte to make sure the server
- // has sent the data and then closed the connection
- FD_ZERO( &sett );
- FD_SET(SocketFD, &sett);
- selectRes = select(64, &sett, NULL, NULL, NULL);
- if( selectRes == -1 ){
- printf( "case 1: read selectRes == -1\n" );
- exit(EXIT_FAILURE);
- }
- if( selectRes == 0 )
- return;
-
- // read a single byte
- transferAmount = recv( SocketFD, readbuf+readPos, 1, 0 );
- readPos += transferAmount;
-
- // if successfully reading 1 byte, switch to next state
- if( readPos >= 1 ){
- state = 2;
- }
- break;
-
- case 2:
- // calling select with the socket in the write file descriptors has
- // to fail because the tcp network connection is already down
- FD_ZERO( &sett );
- FD_SET(SocketFD, &sett);
- selectRes = select(64, NULL, &sett, NULL, NULL);
- if( selectRes != -1 ){
- printf( "case 2: write selectRes != -1\n" );
- exit(EXIT_FAILURE);
- }
-
- // calling select with the socket in the read file descriptors
- // has to succeed because there is still data in the inQueue
- FD_ZERO( &sett );
- FD_SET(SocketFD, &sett);
- selectRes = select(64, &sett, NULL, NULL, NULL);
- if( selectRes != 1 ){
- printf( "case 2: read selectRes != 1\n" );
- exit(EXIT_FAILURE);
- }
- if( selectRes == 0 )
- return;
-
- // read a single byte
- transferAmount = recv( SocketFD, readbuf+readPos, 1, 0 );
- readPos += transferAmount;
-
- // with 10 bytes read the inQueue is empty => switch state
- if( readPos >= 10 ){
- state = 3;
- }
- break;
-
- case 3:
- // calling select with the socket in the read file descriptors
- // now also has to fail as the inQueue is empty
- FD_ZERO( &sett );
- FD_SET(SocketFD, &sett);
- selectRes = select(64, &sett, NULL, NULL, NULL);
- if( selectRes != -1 ){
- printf( "case 3: read selectRes != -1\n" );
- exit(EXIT_FAILURE);
- }
-
- // report back success, the 266 is just an arbitrary value without
- // deeper meaning
- int result = 266;
- REPORT_RESULT();
- break;
-
- default:
- printf( "Impossible state!\n" );
- exit(EXIT_FAILURE);
- break;
- }
-
- return;
-}
-
-// This test checks for an intended asymmetry in the behavior of the select function.
-// Scenario: the client sends data to the server. After 10 received bytes the
-// server sends 10 bytes on its own and immediately afterwards closes the connection.
-// This mimics a typical connect-request-response-disconnect situation.
-// After the server closed the connection select calls with the socket in the write file
-// descriptors have to fail as the tcp connection is already down and there is no way
-// anymore to send data.
-// Select calls with the socket in the read file descriptor list still have to succeed
-// as there are still 10 bytes to read from the inQueue. So, for the same socket the
-// select call behaves differently depending on whether the socket is listed in the
-// read or write file descriptors.
-int main(void)
-{
- struct sockaddr_in stSockAddr;
- int Res;
- SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (-1 == SocketFD)
- {
- perror("cannot create socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&stSockAddr, 0, sizeof(stSockAddr));
-
- stSockAddr.sin_family = AF_INET;
- stSockAddr.sin_port = htons(
-#if EMSCRIPTEN
- 8999
-#else
- 8998
-#endif
- );
- Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);
-
- if (0 > Res) {
- perror("error: first parameter is not a valid address family");
- close(SocketFD);
- exit(EXIT_FAILURE);
- } else if (0 == Res) {
- perror("char string (second parameter does not contain valid ipaddress)");
- close(SocketFD);
- exit(EXIT_FAILURE);
- }
-
- // This call should succeed (even if the server port is closed)
- if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) {
- perror("connect failed");
- close(SocketFD);
- exit(EXIT_FAILURE);
-
- }
-
-#if EMSCRIPTEN
- emscripten_set_main_loop(iter, 0, 0);
-#else
- while (!done) iter(NULL);
-#endif
-
- return EXIT_SUCCESS;
-}
-
diff --git a/tools/asm_module.py b/tools/asm_module.py
index bf7fa71d..226b66b8 100644
--- a/tools/asm_module.py
+++ b/tools/asm_module.py
@@ -84,7 +84,9 @@ class AsmModule():
for table in self.tables:
if table not in main.tables:
sig = table[table.rfind('_')+1:]
- all_sendings['invoke_%s' % sig] = shared.JS.make_invoke(sig, named=False)
+ func = 'invoke_%s' % sig
+ all_sendings[func] = func
+ main.pre_js += 'var %s = %s;\n' % (func, shared.JS.make_invoke(sig, named=False))
added_sending = True
# imports
diff --git a/tools/exec_llvm.py b/tools/exec_llvm.py
index 2685f9e4..ec7a8924 100755
--- a/tools/exec_llvm.py
+++ b/tools/exec_llvm.py
@@ -39,12 +39,12 @@ def path_from_root(*pathelems):
sys.path += [path_from_root('')]
from tools.shared import *
-Popen([LLVM_OPT, sys.argv[1], '-strip-debug', '-o=' + sys.argv[1]+'.clean.bc']).communicate()[0]
+Popen([LLVM_OPT, sys.argv[1], '-strip-debug', '-o', sys.argv[1]+'.clean.bc']).communicate()[0]
# Execute with empty environment - just like the JS script will have
Popen([LLVM_INTERPRETER, sys.argv[1]+'.clean.bc'] + sys.argv[2:], env={'HOME': '.'}).communicate()[0]
-#Popen([LLVM_COMPILER, '-march=c', sys.argv[1], '-o=' + sys.argv[1]+'.cbe.c']).communicate()[0]
+#Popen([LLVM_COMPILER, '-march=c', sys.argv[1], '-o', sys.argv[1]+'.cbe.c']).communicate()[0]
#Popen(['gcc', sys.argv[1]+'.cbe.c', '-lstdc++']).communicate()[0]
#Popen(['./a.out'] + sys.argv[2:]).communicate()[0]
diff --git a/tools/file_packager.py b/tools/file_packager.py
index 1a9d925b..33ccebad 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -40,7 +40,7 @@ TODO: You can also provide .crn files yourself, pre-crunched. With this o
'''
import os, sys, shutil, random, uuid, ctypes
-
+import posixpath
import shared
from shared import Compression, execute, suffix, unsuffixed
from subprocess import Popen, PIPE, STDOUT
@@ -216,7 +216,8 @@ for file_ in data_files:
file_['dstpath'] = file_['dstpath'].replace(os.path.sep, '/') # name in the filesystem, native and emulated
if file_['dstpath'].endswith('/'): # If user has submitted a directory name as the destination but omitted the destination filename, use the filename from source file
file_['dstpath'] = file_['dstpath'] + os.path.basename(file_['srcpath'])
- if file_['dstpath'].startswith('./'): file_['dstpath'] = file_['dstpath'][2:] # remove redundant ./ prefix
+ # make destination path always relative to the root
+ file_['dstpath'] = posixpath.normpath(os.path.join('/', file_['dstpath']))
if DEBUG:
print >> sys.stderr, 'Packaging file "' + file_['srcpath'] + '" to VFS in path "' + file_['dstpath'] + '".'
@@ -341,6 +342,8 @@ if has_preloaded:
counter = 0
for file_ in data_files:
filename = file_['dstpath']
+ dirname = os.path.dirname(filename)
+ basename = os.path.basename(filename)
if file_['mode'] == 'embed':
# Embed
data = map(ord, open(file_['srcpath'], 'rb').read())
@@ -356,7 +359,7 @@ for file_ in data_files:
str_data = str(chunk)
else:
str_data += '.concat(' + str(chunk) + ')'
- code += '''Module['FS_createDataFile']('/%s', '%s', %s, true, true);\n''' % (os.path.dirname(filename), os.path.basename(filename), str_data)
+ code += '''Module['FS_createDataFile']('%s', '%s', %s, true, true);\n''' % (dirname, basename, str_data)
elif file_['mode'] == 'preload':
# Preload
varname = 'filePreload%d' % counter
@@ -389,7 +392,7 @@ for file_ in data_files:
assert(arrayBuffer, 'Loading file %(filename)s failed.');
var byteArray = !arrayBuffer.subarray ? new Uint8Array(arrayBuffer) : arrayBuffer;
%(prepare)s
- Module['FS_createPreloadedFile']('/%(dirname)s', '%(basename)s', byteArray, true, true, function() {
+ Module['FS_createPreloadedFile']('%(dirname)s', '%(basename)s', byteArray, true, true, function() {
%(finish)s
}%(fail)s);
};
@@ -399,8 +402,8 @@ for file_ in data_files:
'request': 'DataRequest', # In the past we also supported XHRs here
'varname': varname,
'filename': filename,
- 'dirname': os.path.dirname(filename),
- 'basename': os.path.basename(filename),
+ 'dirname': dirname,
+ 'basename': basename,
'prepare': prepare,
'finish': finish,
'fail': '' if filename[-4:] not in AUDIO_SUFFIXES else ''', function() { Module['removeRunDependency']('fp %s') }''' % filename # workaround for chromium bug 124926 (still no audio with this, but at least we don't hang)
diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py
index 6fdec3a9..79136343 100644
--- a/tools/find_bigfuncs.py
+++ b/tools/find_bigfuncs.py
@@ -1,5 +1,5 @@
'''
-Simple tool to find big functions in an .ll file.
+Simple tool to find big functions in a js or ll file
'''
import os, sys, re
@@ -11,7 +11,7 @@ curr = None
data = []
for line in open(filename):
i += 1
- if line.startswith('function '):
+ if line.startswith(('function ', 'define ')):
start = i
curr = line
elif line.startswith('}') and curr:
diff --git a/tools/find_bigvars.py b/tools/find_bigvars.py
new file mode 100644
index 00000000..6bee5dd4
--- /dev/null
+++ b/tools/find_bigvars.py
@@ -0,0 +1,24 @@
+'''
+Simple tool to find functions with lots of vars.
+'''
+
+import os, sys, re
+
+filename = sys.argv[1]
+i = 0
+curr = None
+data = []
+size = 0
+for line in open(filename):
+ i += 1
+ if line.startswith('function '):
+ size = len(line.split(',')) # params
+ curr = line
+ elif line.strip().startswith('var '):
+ size += len(line.split(',')) + 1 # vars
+ elif line.startswith('}') and curr:
+ data.append([curr, size])
+ curr = None
+data.sort(lambda x, y: x[1] - y[1])
+print ''.join(['%6d : %s' % (x[1], x[0]) for x in data])
+
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 4192ddd1..e61317af 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -801,7 +801,10 @@ function simplifyExpressions(ast) {
// HEAP[x >> 2]
// very often. We can in some cases do the shift on the variable itself when it is set,
// to greatly reduce the number of shift operations.
-// TODO: when shifting a variable, if there are other uses, keep an unshifted version too, to prevent slowdowns?
+// XXX this optimization is deprecated and currently invalid: does not handle overflows
+// or non-aligned (round numbers, x >> 2 is a multiple of 4). Both are ok to assume
+// for pointers (undefined behavior otherwise), but invalid in general, and we do
+// no sufficiently-well distinguish the cases.
function optimizeShiftsInternal(ast, conservative) {
var MAX_SHIFTS = 3;
traverseGeneratedFunctions(ast, function(fun) {
@@ -3001,7 +3004,7 @@ function outline(ast) {
// Try to flatten out code as much as possible, to make outlining more feasible.
function flatten(func, asmData) {
- var minSize = sizeToOutline;
+ var minSize = extraInfo.sizeToOutline/4;
var helperId = 0;
function getHelper() {
while (1) {
@@ -3106,7 +3109,9 @@ function outline(ast) {
// Reserve an extra two spots per possible outlining: one for control flow var, the other for control flow data
// The control variables are zeroed out when calling an outlined function, and after using
// the value after they return.
- asmData.maxOutlinings = Math.round(3*measureSize(func)/extraInfo.sizeToOutline);
+ var size = measureSize(func);
+ asmData.maxOutlinings = Math.round(3*size/extraInfo.sizeToOutline);
+ asmData.intendedPieces = Math.ceil(size/extraInfo.sizeToOutline);
asmData.totalStackSize = stackSize + (stack.length + 2*asmData.maxOutlinings)*8;
asmData.controlStackPos = function(i) { return stackSize + (stack.length + i)*8 };
asmData.controlDataStackPos = function(i) { return stackSize + (stack.length + i)*8 + 4 };
@@ -3211,16 +3216,18 @@ function outline(ast) {
var CONTROL_BREAK = 1, CONTROL_BREAK_LABEL = 2, CONTROL_CONTINUE = 3, CONTROL_CONTINUE_LABEL = 4, CONTROL_RETURN_VOID = 5, CONTROL_RETURN_INT = 6, CONTROL_RETURN_DOUBLE = 7;
var sizeToOutline = null; // customized per function and as we make progress
- function calculateThreshold(func) {
- sizeToOutline = extraInfo.sizeToOutline;
+ function calculateThreshold(func, asmData) {
var size = measureSize(func);
- //var desiredChunks = Math.ceil(size/extraInfo.sizeToOutline);
- ////sizeToOutline = Math.round((extraInfo.sizeToOutline + (2*size/desiredChunks))/3);
- //sizeToOutline = Math.round(size/desiredChunks);
- printErr('trying to reduce the size of ' + func[1] + ' which is ' + size + ' (>= ' + extraInfo.sizeToOutline + '), aim for ' + sizeToOutline);
+ if (size <= extraInfo.sizeToOutline) {
+ sizeToOutline = Infinity;
+ printErr(' no point in trying to reduce the size of ' + func[1] + ' which is ' + size + ' <= ' + extraInfo.sizeToOutline);
+ } else {
+ sizeToOutline = Math.round(size/Math.max(2, asmData.intendedPieces--));
+ printErr('trying to reduce the size of ' + func[1] + ' which is ' + size + ' (>=? ' + extraInfo.sizeToOutline + '), aim for ' + sizeToOutline);
+ }
}
- var level = 0;
+ var level = 0, loops = 0;
var outliningParents = {}; // function name => parent it was outlined from
function doOutline(func, asmData, stats, start, end) {
@@ -3241,21 +3248,29 @@ function outline(ast) {
}
});
var reps = [];
- // wipe out control variable
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', 0])]);
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', 0])]); // XXX not really needed
- // add spills and reads before and after the call to the outlined code, and in the outlined code itself
- keys(setUnion(codeInfo.reads, codeInfo.writes)).forEach(function(v) {
+ // add spills
+ function orderFunc(x, y) {
+ return (asmData.stackPos[x] - asmData.stackPos[y]) || x.localeCompare(y);
+ }
+ var sortedReadsAndWrites = keys(setUnion(codeInfo.reads, codeInfo.writes)).sort(orderFunc);
+ var sortedWrites = keys(codeInfo.writes).sort(orderFunc);
+ sortedReadsAndWrites.forEach(function(v) {
if (!(v in owned)) {
reps.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
}
});
+ // wipe out control variable
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', 0])]);
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', 0])]); // XXX not really needed
+ // do the call
reps.push(['stat', ['call', ['name', newIdent], [['name', 'sp']]]]);
- for (var v in codeInfo.writes) {
+ // add unspills
+ sortedWrites.forEach(function(v) {
if (!(v in owned)) {
reps.push(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]);
}
- }
+ });
+
// Generate new function
if (codeInfo.hasReturn || codeInfo.hasReturnInt || codeInfo.hasReturnDouble || codeInfo.hasBreak || codeInfo.hasContinue) {
// we need to capture all control flow using a top-level labeled one-time loop in the outlined function
@@ -3389,16 +3404,17 @@ function outline(ast) {
}
}
// add spills and unspills in outlined code outside the OL loop
- keys(setUnion(codeInfo.reads, codeInfo.writes)).forEach(function(v) {
+ sortedReadsAndWrites.reverse();
+ sortedReadsAndWrites.forEach(function(v) {
if (!(v in owned)) {
code.unshift(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]);
}
});
- for (var v in codeInfo.writes) {
+ sortedWrites.forEach(function(v) {
if (!(v in owned)) {
code.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
}
- }
+ });
// finalize
var newFunc = ['defun', newIdent, ['sp'], code];
var newAsmData = { params: { sp: ASM_INT }, vars: {} };
@@ -3436,8 +3452,8 @@ function outline(ast) {
}
}
outliningParents[newIdent] = func[1];
- printErr('performed outline ' + [func[1], newIdent, 'code sizes (pre/post):', originalCodeSize, measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned))]);
- calculateThreshold(func);
+ printErr('performed outline ' + [func[1], newIdent, 'code sizes (pre/post):', originalCodeSize, measureSize(code), 'overhead (w/r):', setSize(setSub(codeInfo.writes, owned)), setSize(setSub(codeInfo.reads, owned)), ' owned: ', setSize(owned), ' left: ', setSize(asmData.vars), setSize(asmData.params), ' loopsDepth: ', loops]);
+ calculateThreshold(func, asmData);
return [newFunc];
}
@@ -3462,6 +3478,9 @@ function outline(ast) {
}
}
}
+ function done() {
+ return asmData.splitCounter >= asmData.maxOutlinings || measureSize(func) <= extraInfo.sizeToOutline;
+ }
while (1) {
i--;
calcMinIndex(); // TODO: optimize
@@ -3506,11 +3525,18 @@ function outline(ast) {
if (subRet && subRet.length > 0) ret.push.apply(ret, subRet);
}
return null; // do not recurse into children, outlineStatements will do so if necessary
+ } else if (type == 'while') {
+ loops++;
+ }
+ }, function(node, type) {
+ if (type == 'while') {
+ loops--;
}
});
if (ret.length > pre) {
// we outlined recursively, reset our state here
//printErr('successful outline in recursion ' + func[1] + ' due to recursive in level ' + level);
+ if (done()) break;
end = i-1;
sizeSeen = 0;
canRestart = true;
@@ -3550,6 +3576,7 @@ function outline(ast) {
if (newFuncs.length) {
ret.push.apply(ret, newFuncs);
}
+ if (done()) break;
sizeSeen = 0;
end = i-1;
canRestart = true;
@@ -3581,8 +3608,8 @@ function outline(ast) {
if (size >= extraInfo.sizeToOutline) {
aggressiveVariableElimination(func, asmData);
flatten(func, asmData);
- calculateThreshold(func);
analyzeFunction(func, asmData);
+ calculateThreshold(func, asmData);
var stats = getStatements(func);
var ret = outlineStatements(func, asmData, stats, 0.9*size);
assert(level == 0);
diff --git a/tools/nativize_llvm.py b/tools/nativize_llvm.py
index d9558c32..413c8d14 100755
--- a/tools/nativize_llvm.py
+++ b/tools/nativize_llvm.py
@@ -21,11 +21,11 @@ filename = sys.argv[1]
libs = sys.argv[2:] # e.g.: dl for dlopen/dlclose, util for openpty/forkpty
print 'bc => clean bc'
-Popen([LLVM_OPT, filename, '-strip-debug', '-o=' + filename + '.clean.bc']).communicate()[0]
+Popen([LLVM_OPT, filename, '-strip-debug', '-o', filename + '.clean.bc']).communicate()[0]
print 'bc => s'
for params in [[], ['-march=x86-64']]: # try x86, then x86-64 FIXME
print 'params', params
- Popen([LLVM_COMPILER] + params + [filename + '.clean.bc', '-o=' + filename + '.s']).communicate()[0]
+ Popen([LLVM_COMPILER] + params + [filename + '.clean.bc', '-o', filename + '.s']).communicate()[0]
print 's => o'
Popen(['as', filename + '.s', '-o', filename + '.o']).communicate()[0]
if os.path.exists(filename + '.o'): break
diff --git a/tools/response_file.py b/tools/response_file.py
index 312cda73..f19cf8af 100644
--- a/tools/response_file.py
+++ b/tools/response_file.py
@@ -6,8 +6,8 @@ def create_response_file(args, directory):
(response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True)
response_fd = os.fdopen(response_fd, "w")
#print >> sys.stderr, "Creating response file '%s'" % response_filename
- args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args)
- response_fd.write(' '.join(args))
+ args = map(lambda p: p.replace('\\', '\\\\').replace('"', '\\"'), args)
+ response_fd.write('"' + '" "'.join(args) + '"')
response_fd.close()
return response_filename
diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py
index 7ab89b48..14b45a20 100644
--- a/tools/settings_template_readonly.py
+++ b/tools/settings_template_readonly.py
@@ -16,7 +16,7 @@ V8_ENGINE = os.path.expanduser(os.getenv('V8') or 'd8') # executable
JAVA = 'java' # executable
-TEMP_DIR = '/tmp' # You will need to modify this on Windows
+TEMP_DIR = '{{{ TEMP }}}'
#CLOSURE_COMPILER = '..' # define this to not use the bundled version
diff --git a/tools/shared.py b/tools/shared.py
index c0df227d..0d0f20d4 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -200,18 +200,25 @@ if '\n' in EM_CONFIG:
else:
CONFIG_FILE = os.path.expanduser(EM_CONFIG)
if not os.path.exists(CONFIG_FILE):
+ # Note: repr is used to ensure the paths are escaped correctly on Windows.
+ # The full string is replaced so that the template stays valid Python.
config_file = open(path_from_root('tools', 'settings_template_readonly.py')).read().split('\n')
config_file = config_file[1:] # remove "this file will be copied..."
config_file = '\n'.join(config_file)
# autodetect some default paths
- config_file = config_file.replace('{{{ EMSCRIPTEN_ROOT }}}', __rootpath__)
+ config_file = config_file.replace('\'{{{ EMSCRIPTEN_ROOT }}}\'', repr(__rootpath__))
llvm_root = os.path.dirname(find_executable('llvm-dis') or '/usr/bin/llvm-dis')
- config_file = config_file.replace('{{{ LLVM_ROOT }}}', llvm_root)
+ config_file = config_file.replace('\'{{{ LLVM_ROOT }}}\'', repr(llvm_root))
node = find_executable('node') or find_executable('nodejs') or 'node'
- config_file = config_file.replace('{{{ NODE }}}', node)
+ config_file = config_file.replace('\'{{{ NODE }}}\'', repr(node))
python = find_executable('python2') or find_executable('python') or \
sys.executable or 'python'
- config_file = config_file.replace('{{{ PYTHON }}}', python)
+ config_file = config_file.replace('\'{{{ PYTHON }}}\'', repr(python))
+ if WINDOWS:
+ tempdir = os.environ.get('TEMP') or os.environ.get('TMP') or 'c:\\temp'
+ else:
+ tempdir = '/tmp'
+ config_file = config_file.replace('\'{{{ TEMP }}}\'', repr(tempdir))
# write
open(CONFIG_FILE, 'w').write(config_file)
@@ -283,7 +290,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.5.3'
+EMSCRIPTEN_VERSION = '1.5.5'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT
@@ -333,7 +340,7 @@ def check_sanity(force=False):
logging.critical('Node.js (%s) does not seem to work, check the paths in %s' % (NODE_JS, EM_CONFIG))
sys.exit(1)
- for cmd in [CLANG, LLVM_LINK, LLVM_AR, LLVM_OPT, LLVM_AS, LLVM_DIS, LLVM_NM]:
+ for cmd in [CLANG, LINK_CMD[0], LLVM_AR, LLVM_OPT, LLVM_AS, LLVM_DIS, LLVM_NM]:
if not os.path.exists(cmd) and not os.path.exists(cmd + '.exe'): # .exe extension required for Windows
logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG))
sys.exit(1)
@@ -360,12 +367,31 @@ def check_sanity(force=False):
# Tools/paths
-LLVM_ADD_VERSION = os.getenv('LLVM_ADD_VERSION')
-CLANG_ADD_VERSION = os.getenv('CLANG_ADD_VERSION')
+try:
+ LLVM_ADD_VERSION
+except NameError:
+ LLVM_ADD_VERSION = os.getenv('LLVM_ADD_VERSION')
+
+try:
+ CLANG_ADD_VERSION
+except NameError:
+ CLANG_ADD_VERSION = os.getenv('CLANG_ADD_VERSION')
+
+USING_PNACL_TOOLCHAIN = os.path.exists(os.path.join(LLVM_ROOT, 'pnacl-clang'))
+
+def modify_prefix(tool):
+ if USING_PNACL_TOOLCHAIN:
+ if tool.startswith('llvm-'):
+ tool = tool[5:]
+ tool = 'pnacl-' + tool
+ if WINDOWS:
+ tool += '.bat'
+ return tool
# Some distributions ship with multiple llvm versions so they add
# the version to the binaries, cope with that
def build_llvm_tool_path(tool):
+ tool = modify_prefix(tool)
if LLVM_ADD_VERSION:
return os.path.join(LLVM_ROOT, tool + "-" + LLVM_ADD_VERSION)
else:
@@ -374,6 +400,7 @@ def build_llvm_tool_path(tool):
# Some distributions ship with multiple clang versions so they add
# the version to the binaries, cope with that
def build_clang_tool_path(tool):
+ tool = modify_prefix(tool)
if CLANG_ADD_VERSION:
return os.path.join(LLVM_ROOT, tool + "-" + CLANG_ADD_VERSION)
else:
@@ -382,7 +409,11 @@ def build_clang_tool_path(tool):
CLANG_CC=os.path.expanduser(build_clang_tool_path('clang'))
CLANG_CPP=os.path.expanduser(build_clang_tool_path('clang++'))
CLANG=CLANG_CPP
-LLVM_LINK=build_llvm_tool_path('llvm-link')
+if USING_PNACL_TOOLCHAIN:
+ # The PNaCl toolchain doesn't have llvm-link, but we can fake it
+ LINK_CMD = [build_llvm_tool_path('llvm-ld'), '-nostdlib', '-r']
+else:
+ LINK_CMD = [build_llvm_tool_path('llvm-link')]
LLVM_AR=build_llvm_tool_path('llvm-ar')
LLVM_OPT=os.path.expanduser(build_llvm_tool_path('opt'))
LLVM_AS=os.path.expanduser(build_llvm_tool_path('llvm-as'))
@@ -519,6 +550,7 @@ if USE_EMSDK:
# allows projects to override them)
EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc',
'-Xclang', '-isystem' + path_from_root('system', 'local', 'include'),
+ '-Xclang', '-isystem' + path_from_root('system', 'include', 'compat'),
'-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'),
'-Xclang', '-isystem' + path_from_root('system', 'include'),
'-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'),
@@ -599,7 +631,7 @@ def line_splitter(data):
return out
-def limit_size(string, MAX=120*20):
+def limit_size(string, MAX=12000*20):
if len(string) < MAX: return string
return string[0:MAX/2] + '\n[..]\n' + string[-MAX/2:]
@@ -643,62 +675,89 @@ def expand_response(data):
# Settings. A global singleton. Not pretty, but nicer than passing |, settings| everywhere
-class Settings:
- @classmethod
- def reset(self):
- class Settings2:
- QUANTUM_SIZE = 4
- reset = Settings.reset
-
- # Given some emcc-type args (-O3, -s X=Y, etc.), fill Settings with the right settings
- @classmethod
- def load(self, args=[]):
- # Load the JS defaults into python
- settings = open(path_from_root('src', 'settings.js')).read().replace('var ', 'Settings.').replace('//', '#')
- exec settings in globals()
-
- # Apply additional settings. First -O, then -s
- for i in range(len(args)):
- if args[i].startswith('-O'):
- level = eval(args[i][2])
- Settings.apply_opt_level(level)
- for i in range(len(args)):
- if args[i] == '-s':
- exec 'Settings.' + args[i+1] in globals() # execute the setting
-
- # Transforms the Settings information into emcc-compatible args (-s X=Y, etc.). Basically
- # the reverse of load_settings, except for -Ox which is relevant there but not here
- @classmethod
- def serialize(self):
- ret = []
- for key, value in Settings.__dict__.iteritems():
- if key == key.upper(): # this is a hack. all of our settings are ALL_CAPS, python internals are not
- jsoned = json.dumps(value, sort_keys=True)
- ret += ['-s', key + '=' + jsoned]
- return ret
-
- @classmethod
- def apply_opt_level(self, opt_level, noisy=False):
- if opt_level >= 1:
- Settings.ASM_JS = 1
- Settings.ASSERTIONS = 0
- Settings.DISABLE_EXCEPTION_CATCHING = 1
- Settings.EMIT_GENERATED_FUNCTIONS = 1
- if opt_level >= 2:
- Settings.RELOOP = 1
- Settings.ALIASING_FUNCTION_POINTERS = 1
- if opt_level >= 3:
- # Aside from these, -O3 also runs closure compiler and llvm lto
- Settings.FORCE_ALIGNED_MEMORY = 1
- Settings.DOUBLE_MODE = 0
- Settings.PRECISE_I64_MATH = 0
- if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)')
-
- global Settings
- Settings = Settings2
- Settings.load() # load defaults
-
-Settings.reset()
+class Settings2(type):
+ class __impl:
+ attrs = {}
+
+ def __init__(self):
+ self.reset()
+
+ @classmethod
+ def reset(self):
+ self.attrs = { 'QUANTUM_SIZE': 4 }
+ self.load()
+
+ # Given some emcc-type args (-O3, -s X=Y, etc.), fill Settings with the right settings
+ @classmethod
+ def load(self, args=[]):
+ # Load the JS defaults into python
+ settings = open(path_from_root('src', 'settings.js')).read().replace('//', '#')
+ settings = re.sub(r'var ([\w\d]+)', r'self.attrs["\1"]', settings)
+ exec settings
+
+ # Apply additional settings. First -O, then -s
+ for i in range(len(args)):
+ if args[i].startswith('-O'):
+ level = eval(args[i][2])
+ self.apply_opt_level(level)
+ for i in range(len(args)):
+ if args[i] == '-s':
+ declare = re.sub(r'([\w\d]+)\s*=\s*(.+)', r'self.attrs["\1"]=\2;', args[i+1])
+ exec declare
+
+ # Transforms the Settings information into emcc-compatible args (-s X=Y, etc.). Basically
+ # the reverse of load_settings, except for -Ox which is relevant there but not here
+ @classmethod
+ def serialize(self):
+ ret = []
+ for key, value in self.attrs.iteritems():
+ if key == key.upper(): # this is a hack. all of our settings are ALL_CAPS, python internals are not
+ jsoned = json.dumps(value, sort_keys=True)
+ ret += ['-s', key + '=' + jsoned]
+ return ret
+
+ @classmethod
+ def apply_opt_level(self, opt_level, noisy=False):
+ if opt_level >= 1:
+ self.attrs['ASM_JS'] = 1
+ self.attrs['ASSERTIONS'] = 0
+ self.attrs['DISABLE_EXCEPTION_CATCHING'] = 1
+ self.attrs['EMIT_GENERATED_FUNCTIONS'] = 1
+ if opt_level >= 2:
+ self.attrs['RELOOP'] = 1
+ self.attrs['ALIASING_FUNCTION_POINTERS'] = 1
+ if opt_level >= 3:
+ # Aside from these, -O3 also runs closure compiler and llvm lto
+ self.attrs['FORCE_ALIGNED_MEMORY'] = 1
+ self.attrs['DOUBLE_MODE'] = 0
+ self.attrs['PRECISE_I64_MATH'] = 0
+ if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)')
+
+ def __getattr__(self, attr):
+ if attr in self.attrs:
+ return self.attrs[attr]
+ else:
+ raise AttributeError
+
+ def __setattr__(self, attr, value):
+ self.attrs[attr] = value
+
+ __instance = None
+
+ @staticmethod
+ def instance():
+ if Settings2.__instance is None:
+ Settings2.__instance = Settings2.__impl()
+ return Settings2.__instance
+
+ def __getattr__(self, attr):
+ return getattr(self.instance(), attr)
+
+ def __setattr__(self, attr, value):
+ return setattr(self.instance(), attr, value)
+
+class Settings(object):
+ __metaclass__ = Settings2
# Building
@@ -706,6 +765,7 @@ class Building:
COMPILER = CLANG
LLVM_OPTS = False
COMPILER_TEST_OPTS = [] # For use of the test runner
+ JS_ENGINE_OVERRIDE = None # Used to pass the JS engine override from runner.py -> test_benchmark.py
@staticmethod
def get_building_env(native=False):
@@ -876,7 +936,10 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
@staticmethod
def link(files, target, force_archive_contents=False):
actual_files = []
- unresolved_symbols = set(['main']) # tracking unresolveds is necessary for .a linking, see below. (and main is always a necessary symbol)
+ # Tracking unresolveds is necessary for .a linking, see below.
+ # Specify all possible entry points to seed the linking process.
+ # For a simple application, this would just be "main".
+ unresolved_symbols = set([func[1:] for func in Settings.EXPORTED_FUNCTIONS])
resolved_symbols = set()
temp_dirs = []
files = map(os.path.abspath, files)
@@ -944,7 +1007,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
logging.debug('emcc: llvm-linking: %s to %s', actual_files, target)
# check for too-long command line
- link_cmd = [LLVM_LINK] + actual_files + ['-o', target]
+ link_cmd = LINK_CMD + actual_files + ['-o', target]
# 8k is a bit of an arbitrary limit, but a reasonable one
# for max command line size before we use a respose file
response_file = None
@@ -952,7 +1015,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
logging.debug('using response file for llvm-link')
[response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR)
- link_cmd = [LLVM_LINK, "@" + response_file]
+ link_cmd = LINK_CMD + ["@" + response_file]
response_fh = os.fdopen(response_fd, 'w')
for arg in actual_files:
@@ -996,7 +1059,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
opts = Building.pick_llvm_opts(opts)
#opts += ['-debug-pass=Arguments']
logging.debug('emcc: LLVM opts: ' + str(opts))
- output = Popen([LLVM_OPT, filename] + opts + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_OPT, filename] + opts + ['-o', filename + '.opt.bc'], stdout=PIPE).communicate()[0]
assert os.path.exists(filename + '.opt.bc'), 'Failed to run llvm optimizations: ' + output
shutil.move(filename + '.opt.bc', filename)
@@ -1004,7 +1067,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
def llvm_opts(filename): # deprecated version, only for test runner. TODO: remove
if Building.LLVM_OPTS:
shutil.move(filename + '.o', filename + '.o.pre')
- output = Popen([LLVM_OPT, filename + '.o.pre'] + Building.LLVM_OPT_OPTS + ['-o=' + filename + '.o'], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_OPT, filename + '.o.pre'] + Building.LLVM_OPT_OPTS + ['-o', filename + '.o'], stdout=PIPE).communicate()[0]
assert os.path.exists(filename + '.o'), 'Failed to run llvm optimizations: ' + output
@staticmethod
@@ -1015,7 +1078,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
output_filename = input_filename + '.o.ll'
input_filename = input_filename + '.o'
try_delete(output_filename)
- output = Popen([LLVM_DIS, input_filename, '-o=' + output_filename], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_DIS, input_filename, '-o', output_filename], stdout=PIPE).communicate()[0]
assert os.path.exists(output_filename), 'Could not create .ll file: ' + output
return output_filename
@@ -1027,7 +1090,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
output_filename = input_filename + '.o'
input_filename = input_filename + '.o.ll'
try_delete(output_filename)
- output = Popen([LLVM_AS, input_filename, '-o=' + output_filename], stdout=PIPE).communicate()[0]
+ output = Popen([LLVM_AS, input_filename, '-o', output_filename], stdout=PIPE).communicate()[0]
assert os.path.exists(output_filename), 'Could not create bc file: ' + output
return output_filename
@@ -1048,6 +1111,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
for line in output.split('\n'):
if len(line) == 0: continue
parts = filter(lambda seg: len(seg) > 0, line.split(' '))
+ # pnacl-nm will print zero offsets for bitcode
+ if len(parts) == 3 and parts[0] == "00000000":
+ parts.pop(0)
if len(parts) == 2: # ignore lines with absolute offsets, these are not bitcode anyhow (e.g. |00000630 t d_source_name|)
status, symbol = parts
if status == 'U':
diff --git a/tools/source-maps/sourcemapper.js b/tools/source-maps/sourcemapper.js
index fa908900..06c9a227 100755
--- a/tools/source-maps/sourcemapper.js
+++ b/tools/source-maps/sourcemapper.js
@@ -16,6 +16,38 @@ function countLines(s) {
return count;
}
+// For a minor optimization, only do win32->unix normalization if we are actually on Windows,
+// which avoids redundantly scanning files if not needed.
+var isWindows = (process.platform === 'win32');
+
+var unixPathRe = new RegExp('\\\\', 'g');
+// Returns the given (possibly Windows) path p normalized to unix path separators '/'.
+function toUnixPath(p) {
+ if (isWindows) {
+ return p.replace(unixPathRe, '/');
+ } else {
+ return p;
+ }
+}
+
+var unixLineEndRe = new RegExp('\r\n', 'g');
+// Returns the given (possibly Windows) text data t normalized to unix line endings '\n'.
+function toUnixLineEnding(t) {
+ if (isWindows) {
+ return t.replace(unixLineEndRe, '\n');
+ } else {
+ return t;
+ }
+}
+
+// If path "p2" is a relative path, joins paths p1 and p2 to form "p1/p2". If p2 is an absolute path, "p2" is returned.
+function joinPath(p1, p2) {
+ if (p2[0] == '/' || (p2.length >= 3 && p2[1] == ':' && (p2[2] == '/' || p2[2] == '\\'))) // Is p2 an absolute path?
+ return p2;
+ else
+ return toUnixPath(path.join(p1, p2));
+}
+
/*
* Extracts the line (not block) comments from the generated function code and
* invokes commentHandler with (comment content, line number of comment). This
@@ -105,8 +137,7 @@ function generateMap(mappings, sourceRoot, mapFileBaseName, generatedLineOffset)
// avoid doing it unnecessarily
if (!(originalFileName in seenFiles)) {
seenFiles[originalFileName] = true;
- var rootedPath = originalFileName[0] === path.sep ?
- originalFileName : path.join(sourceRoot, originalFileName);
+ var rootedPath = joinPath(sourceRoot, originalFileName);
try {
generator.setSourceContent(originalFileName, fs.readFileSync(rootedPath, 'utf-8'));
} catch (e) {
@@ -144,15 +175,15 @@ if (require.main === module) {
} else {
var opts = parseArgs(process.argv.slice(2));
var fileName = opts._[0];
- var sourceRoot = opts.sourceRoot ? opts.sourceRoot : ".";
- var mapFileBaseName = opts.mapFileBaseName ? opts.mapFileBaseName : fileName;
+ var sourceRoot = opts.sourceRoot ? toUnixPath(opts.sourceRoot) : ".";
+ var mapFileBaseName = toUnixPath(opts.mapFileBaseName ? opts.mapFileBaseName : fileName);
var generatedLineOffset = opts.offset ? parseInt(opts.offset, 10) : 0;
- var generatedSource = fs.readFileSync(fileName, 'utf-8');
+ var generatedSource = toUnixLineEnding(fs.readFileSync(fileName, 'utf-8'));
var source = generatedSource;
var mappings = getMappings(generatedSource);
for (var i = 1, l = opts._.length; i < l; i ++) {
- var optimizedSource = fs.readFileSync(opts._[i], 'utf-8')
+ var optimizedSource = toUnixLineEnding(fs.readFileSync(opts._[i], 'utf-8'))
var optimizedMappings = getMappings(optimizedSource);
var newMappings = {};
// uglify processes the code between EMSCRIPTEN_START_FUNCS and
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index 5027f680..d8ea9446 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -5,7 +5,6 @@ function lin() {
c(1);
c(2);
c(3);
- c(4);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
lin$1(sp);
@@ -21,8 +20,6 @@ function lin2() {
while (1) {
c(1);
c(2);
- c(3);
- c(4);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
lin2$1(sp);
@@ -42,9 +39,14 @@ function lin3() {
c(3);
c(4);
c(5);
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- lin3$1(sp);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
HEAP32[sp + 8 >> 2] = 0;
HEAP32[sp + 12 >> 2] = 0;
lin3$0(sp);
@@ -70,9 +72,15 @@ function lin4() {
c(2);
c(3);
c(4);
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- lin4$1(sp);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
HEAP32[sp + 8 >> 2] = 0;
HEAP32[sp + 12 >> 2] = 0;
lin4$0(sp);
@@ -97,9 +105,15 @@ function lin5() {
c(2);
c(3);
c(4);
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- lin5$1(sp);
+ c(5);
+ c(6);
+ c(7);
+ c(8);
+ c(9);
+ c(10);
+ c(11);
+ c(12);
+ c(13);
HEAP32[sp + 8 >> 2] = 0;
HEAP32[sp + 12 >> 2] = 0;
lin5$0(sp);
@@ -120,13 +134,6 @@ function mix() {
sp = STACKTOP;
STACKTOP = STACKTOP + 168 | 0;
main : while (1) {
- c(1);
- c(2);
- c(3);
- c(4);
- c(5);
- c(6);
- c(7);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
mix$1(sp);
@@ -170,15 +177,14 @@ function vars(x, y) {
var sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 152 | 0;
- HEAP32[sp + 32 >> 2] = 0;
- HEAP32[sp + 36 >> 2] = 0;
+ c(1 + (x + y));
+ c(2 + y * x);
+ c(3 + (x + y));
+ c(4 + y * x);
HEAP32[sp + 8 >> 2] = x;
HEAPF32[sp + 16 >> 2] = y;
- vars$1(sp);
HEAP32[sp + 24 >> 2] = 0;
HEAP32[sp + 28 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = x;
- HEAPF32[sp + 16 >> 2] = y;
vars$0(sp);
STACKTOP = sp;
}
@@ -192,10 +198,11 @@ function vars2(x, y) {
b = y * x;
a = c(1 + a);
b = c(2 + b);
- HEAP32[sp + 40 >> 2] = 0;
- HEAP32[sp + 44 >> 2] = 0;
+ a = c(3 + a);
HEAP32[sp + 24 >> 2] = a;
HEAPF32[sp + 32 >> 2] = b;
+ HEAP32[sp + 40 >> 2] = 0;
+ HEAP32[sp + 44 >> 2] = 0;
vars2$0(sp);
a = HEAP32[sp + 24 >> 2] | 0;
b = +HEAPF32[sp + 32 >> 2];
@@ -207,18 +214,16 @@ function vars3(x, y) {
var a = 0, sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 160 | 0;
- HEAP32[sp + 40 >> 2] = 0;
- HEAP32[sp + 44 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = a;
+ a = x + y;
+ a = c(1 + a);
+ a = c(2 + y * x);
+ a = c(3 + a);
+ a = c(4 + y * x);
HEAP32[sp + 8 >> 2] = x;
HEAPF32[sp + 16 >> 2] = y;
- vars3$1(sp);
- a = HEAP32[sp + 24 >> 2] | 0;
+ HEAP32[sp + 24 >> 2] = a;
HEAP32[sp + 32 >> 2] = 0;
HEAP32[sp + 36 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = a;
- HEAPF32[sp + 16 >> 2] = y;
- HEAP32[sp + 8 >> 2] = x;
vars3$0(sp);
a = HEAP32[sp + 24 >> 2] | 0;
STACKTOP = sp;
@@ -230,20 +235,16 @@ function vars4(x, y) {
sp = STACKTOP;
STACKTOP = STACKTOP + 168 | 0;
a = x + y;
- HEAP32[sp + 48 >> 2] = 0;
- HEAP32[sp + 52 >> 2] = 0;
- HEAPF32[sp + 16 >> 2] = y;
+ b = y * x;
+ a = c(1 + a);
+ a = c(2 + a);
+ a = c(3 + a);
+ a = c(4 + a);
HEAP32[sp + 8 >> 2] = x;
HEAP32[sp + 24 >> 2] = a;
HEAPF32[sp + 32 >> 2] = b;
- vars4$1(sp);
- b = +HEAPF32[sp + 32 >> 2];
- a = HEAP32[sp + 24 >> 2] | 0;
HEAP32[sp + 40 >> 2] = 0;
HEAP32[sp + 44 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = a;
- HEAP32[sp + 8 >> 2] = x;
- HEAPF32[sp + 32 >> 2] = b;
vars4$0(sp);
a = HEAP32[sp + 24 >> 2] | 0;
b = +HEAPF32[sp + 32 >> 2];
@@ -255,20 +256,19 @@ function vars_w_stack(x, y) {
var a = 0, b = +0, sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 208 | 0;
- a = x + y;
- HEAP32[sp + 72 >> 2] = 0;
- HEAP32[sp + 76 >> 2] = 0;
- HEAPF32[sp + 32 >> 2] = y;
HEAP32[sp + 24 >> 2] = x;
+ HEAPF32[sp + 32 >> 2] = y;
HEAP32[sp + 40 >> 2] = a;
HEAPF32[sp + 48 >> 2] = b;
+ HEAP32[sp + 72 >> 2] = 0;
+ HEAP32[sp + 76 >> 2] = 0;
vars_w_stack$1(sp);
- b = +HEAPF32[sp + 48 >> 2];
a = HEAP32[sp + 40 >> 2] | 0;
- HEAP32[sp + 64 >> 2] = 0;
- HEAP32[sp + 68 >> 2] = 0;
+ b = +HEAPF32[sp + 48 >> 2];
HEAP32[sp + 40 >> 2] = a;
HEAPF32[sp + 48 >> 2] = b;
+ HEAP32[sp + 64 >> 2] = 0;
+ HEAP32[sp + 68 >> 2] = 0;
vars_w_stack$0(sp);
a = HEAP32[sp + 40 >> 2] | 0;
b = +HEAPF32[sp + 48 >> 2];
@@ -276,43 +276,53 @@ function vars_w_stack(x, y) {
function chain() {
var helper$0 = 0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 336 | 0;
+ STACKTOP = STACKTOP + 464 | 0;
helper$0 = 1;
- HEAP32[sp + 56 >> 2] = 0;
- HEAP32[sp + 60 >> 2] = 0;
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 1) {
+ print(1);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 2) {
+ print(2);
+ } else {
+ helper$0 = 1;
+ }
+ }
HEAP32[sp + 8 >> 2] = helper$0;
- chain$5(sp);
- helper$0 = HEAP32[sp + 8 >> 2] | 0;
HEAP32[sp + 48 >> 2] = 0;
HEAP32[sp + 52 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
chain$4(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
HEAP32[sp + 40 >> 2] = 0;
HEAP32[sp + 44 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
chain$3(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
HEAP32[sp + 32 >> 2] = 0;
HEAP32[sp + 36 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
chain$2(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
HEAP32[sp + 24 >> 2] = 0;
HEAP32[sp + 28 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
chain$1(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
chain$0(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
STACKTOP = sp;
}
function lin$0(sp) {
sp = sp | 0;
- c(13);
c(14);
c(15);
c(16);
@@ -323,6 +333,7 @@ function lin$0(sp) {
}
function lin$1(sp) {
sp = sp | 0;
+ c(4);
c(5);
c(6);
c(7);
@@ -331,10 +342,10 @@ function lin$1(sp) {
c(10);
c(11);
c(12);
+ c(13);
}
function lin2$0(sp) {
sp = sp | 0;
- c(13);
c(14);
c(15);
c(16);
@@ -345,6 +356,8 @@ function lin2$0(sp) {
}
function lin2$1(sp) {
sp = sp | 0;
+ c(3);
+ c(4);
c(5);
c(6);
c(7);
@@ -353,6 +366,7 @@ function lin2$1(sp) {
c(10);
c(11);
c(12);
+ c(13);
}
function lin3$0(sp) {
sp = sp | 0;
@@ -369,21 +383,9 @@ function lin3$0(sp) {
break OL;
} while (0);
}
-function lin3$1(sp) {
- sp = sp | 0;
- c(6);
- c(7);
- c(8);
- c(9);
- c(10);
- c(11);
- c(12);
- c(13);
-}
function lin4$0(sp) {
sp = sp | 0;
OL : do {
- c(13);
c(14);
c(15);
c(16);
@@ -395,21 +397,9 @@ function lin4$0(sp) {
break OL;
} while (0);
}
-function lin4$1(sp) {
- sp = sp | 0;
- c(5);
- c(6);
- c(7);
- c(8);
- c(9);
- c(10);
- c(11);
- c(12);
-}
function lin5$0(sp) {
sp = sp | 0;
OL : do {
- c(13);
c(14);
c(15);
c(16);
@@ -421,22 +411,9 @@ function lin5$0(sp) {
break OL;
} while (0);
}
-function lin5$1(sp) {
- sp = sp | 0;
- c(5);
- c(6);
- c(7);
- c(8);
- c(9);
- c(10);
- c(11);
- c(12);
-}
function mix$0(sp) {
sp = sp | 0;
OL : do {
- c(16);
- c(17);
HEAP32[sp + 8 >> 2] = 2;
HEAP32[sp + 12 >> 2] = 2;
break OL;
@@ -460,6 +437,13 @@ function mix$0(sp) {
}
function mix$1(sp) {
sp = sp | 0;
+ c(1);
+ c(2);
+ c(3);
+ c(4);
+ c(5);
+ c(6);
+ c(7);
c(8);
c(9);
c(10);
@@ -468,33 +452,24 @@ function mix$1(sp) {
c(13);
c(14);
c(15);
+ c(16);
+ c(17);
}
function vars$0(sp) {
sp = sp | 0;
var x = 0, y = +0;
- y = +HEAPF32[sp + 16 >> 2];
x = HEAP32[sp + 8 >> 2] | 0;
+ y = +HEAPF32[sp + 16 >> 2];
c(5 + (x + y));
c(6 + y * x);
c(7 + (x + y));
c(8 + y * x);
}
-function vars$1(sp) {
- sp = sp | 0;
- var x = 0, y = +0;
- y = +HEAPF32[sp + 16 >> 2];
- x = HEAP32[sp + 8 >> 2] | 0;
- c(1 + (x + y));
- c(2 + y * x);
- c(3 + (x + y));
- c(4 + y * x);
-}
function vars2$0(sp) {
sp = sp | 0;
- var a = 0, b = +0;
- b = +HEAPF32[sp + 32 >> 2];
+ var b = +0, a = 0;
a = HEAP32[sp + 24 >> 2] | 0;
- a = c(3 + a);
+ b = +HEAPF32[sp + 32 >> 2];
b = c(4 + b);
a = c(5 + a);
b = c(6 + b);
@@ -507,57 +482,28 @@ function vars3$0(sp) {
x = HEAP32[sp + 8 >> 2] | 0;
y = +HEAPF32[sp + 16 >> 2];
a = HEAP32[sp + 24 >> 2] | 0;
- a = c(4 + y * x);
a = c(5 + a);
a = c(6 + y * x);
a = c(7 + a);
HEAP32[sp + 24 >> 2] = a;
}
-function vars3$1(sp) {
- sp = sp | 0;
- var a = 0, x = 0, y = +0;
- y = +HEAPF32[sp + 16 >> 2];
- x = HEAP32[sp + 8 >> 2] | 0;
- a = HEAP32[sp + 24 >> 2] | 0;
- a = x + y;
- a = c(1 + a);
- a = c(2 + y * x);
- a = c(3 + a);
- HEAP32[sp + 24 >> 2] = a;
-}
function vars4$0(sp) {
sp = sp | 0;
var a = 0, x = 0, b = +0;
- b = +HEAPF32[sp + 32 >> 2];
x = HEAP32[sp + 8 >> 2] | 0;
a = HEAP32[sp + 24 >> 2] | 0;
- a = c(4 + a);
+ b = +HEAPF32[sp + 32 >> 2];
a = c(5 + a);
a = c(6 + a);
b = c(7 + a + x);
HEAP32[sp + 24 >> 2] = a;
HEAPF32[sp + 32 >> 2] = b;
}
-function vars4$1(sp) {
- sp = sp | 0;
- var y = +0, x = 0, a = 0, b = +0;
- b = +HEAPF32[sp + 32 >> 2];
- a = HEAP32[sp + 24 >> 2] | 0;
- x = HEAP32[sp + 8 >> 2] | 0;
- y = +HEAPF32[sp + 16 >> 2];
- b = y * x;
- a = c(1 + a);
- a = c(2 + a);
- a = c(3 + a);
- HEAPF32[sp + 32 >> 2] = b;
- HEAP32[sp + 24 >> 2] = a;
-}
function vars_w_stack$0(sp) {
sp = sp | 0;
var a = 0, b = +0;
- b = +HEAPF32[sp + 48 >> 2];
a = HEAP32[sp + 40 >> 2] | 0;
- a = c(4 + a);
+ b = +HEAPF32[sp + 48 >> 2];
a = c(5 + a);
a = c(6 + a);
b = c(7 + a);
@@ -567,17 +513,19 @@ function vars_w_stack$0(sp) {
}
function vars_w_stack$1(sp) {
sp = sp | 0;
- var y = +0, x = 0, a = 0, b = +0;
- b = +HEAPF32[sp + 48 >> 2];
- a = HEAP32[sp + 40 >> 2] | 0;
+ var a = 0, x = 0, y = +0, b = +0;
x = HEAP32[sp + 24 >> 2] | 0;
y = +HEAPF32[sp + 32 >> 2];
+ a = HEAP32[sp + 40 >> 2] | 0;
+ b = +HEAPF32[sp + 48 >> 2];
+ a = x + y;
b = y * x;
a = c(1 + a);
a = c(2 + a);
a = c(3 + a);
- HEAPF32[sp + 48 >> 2] = b;
+ a = c(4 + a);
HEAP32[sp + 40 >> 2] = a;
+ HEAPF32[sp + 48 >> 2] = b;
}
function chain$0(sp) {
sp = sp | 0;
@@ -585,9 +533,7 @@ function chain$0(sp) {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- if (x == 11) {
- print(11);
- } else if (x == 12) {
+ if (x == 12) {
print(12);
} else {
helper$0 = 1;
@@ -609,14 +555,20 @@ function chain$1(sp) {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- if (x == 9) {
- print(9);
- } else if (x == 10) {
+ if (x == 10) {
print(10);
} else {
helper$0 = 1;
}
}
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 11) {
+ print(11);
+ } else {
+ helper$0 = 1;
+ }
+ }
HEAP32[sp + 8 >> 2] = helper$0;
}
function chain$2(sp) {
@@ -625,14 +577,20 @@ function chain$2(sp) {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- if (x == 7) {
- print(7);
- } else if (x == 8) {
+ if (x == 8) {
print(8);
} else {
helper$0 = 1;
}
}
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 9) {
+ print(9);
+ } else {
+ helper$0 = 1;
+ }
+ }
HEAP32[sp + 8 >> 2] = helper$0;
}
function chain$3(sp) {
@@ -641,14 +599,20 @@ function chain$3(sp) {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- if (x == 5) {
- print(5);
- } else if (x == 6) {
+ if (x == 6) {
print(6);
} else {
helper$0 = 1;
}
}
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 7) {
+ print(7);
+ } else {
+ helper$0 = 1;
+ }
+ }
HEAP32[sp + 8 >> 2] = helper$0;
}
function chain$4(sp) {
@@ -659,24 +623,22 @@ function chain$4(sp) {
helper$0 = 0;
if (x == 3) {
print(3);
- } else if (x == 4) {
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 4) {
print(4);
} else {
helper$0 = 1;
}
}
- HEAP32[sp + 8 >> 2] = helper$0;
-}
-function chain$5(sp) {
- sp = sp | 0;
- var helper$0 = 0;
- helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- if (x == 1) {
- print(1);
- } else if (x == 2) {
- print(2);
+ if (x == 5) {
+ print(5);
} else {
helper$0 = 1;
}
diff --git a/tools/test-js-optimizer-asm-outline2-output.js b/tools/test-js-optimizer-asm-outline2-output.js
index 9f0be278..2658fda0 100644
--- a/tools/test-js-optimizer-asm-outline2-output.js
+++ b/tools/test-js-optimizer-asm-outline2-output.js
@@ -11,6 +11,8 @@ function linear() {
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
+ cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
+ cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
HEAP32[sp + 16 >> 2] = 0;
HEAP32[sp + 20 >> 2] = 0;
linear$1(sp);
@@ -50,27 +52,35 @@ function _free($mem) {
if (($mem + (-8 - $21 | 0) | 0) >>> 0 < $5 >>> 0) {
_abort();
}
- HEAP32[sp + 664 >> 2] = 0;
- HEAP32[sp + 668 >> 2] = 0;
- HEAP32[sp + 48 >> 2] = $25;
+ if (($25 | 0) == (HEAP32[25] | 0)) {
+ if ((HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & 3 | 0) != 3) {
+ $p_0 = $25;
+ $psize_0 = $26;
+ break;
+ }
+ HEAP32[22] = $26;
+ HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & -2;
+ HEAP32[$mem + ((-8 - $21 | 0) + 4) >> 2] = $26 | 1;
+ HEAP32[($mem + (($10 & -8) - 8) | 0) >> 2] = $26;
+ return;
+ }
HEAP32[sp + 8 >> 2] = $mem;
- HEAP32[sp + 24 >> 2] = $10;
- HEAP32[sp + 56 >> 2] = $26;
- HEAP32[sp + 40 >> 2] = $21;
HEAP32[sp + 16 >> 2] = $5;
- HEAP32[sp + 224 >> 2] = $p_0;
+ HEAP32[sp + 40 >> 2] = $21;
+ HEAP32[sp + 48 >> 2] = $25;
+ HEAP32[sp + 56 >> 2] = $26;
HEAP32[sp + 216 >> 2] = $psize_0;
+ HEAP32[sp + 224 >> 2] = $p_0;
+ HEAP32[sp + 696 >> 2] = 0;
+ HEAP32[sp + 700 >> 2] = 0;
_free$1(sp);
- $p_0 = HEAP32[sp + 224 >> 2] | 0;
$psize_0 = HEAP32[sp + 216 >> 2] | 0;
- tempValue = HEAP32[sp + 664 >> 2] | 0;
- tempInt = HEAP32[sp + 668 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 668 >> 2];
- HEAP32[sp + 664 >> 2] = 0;
- HEAP32[sp + 668 >> 2] = 0;
- if ((tempValue | 0) == 5) {
- return;
- }
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ tempValue = HEAP32[sp + 696 >> 2] | 0;
+ tempInt = HEAP32[sp + 700 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 700 >> 2];
+ HEAP32[sp + 696 >> 2] = 0;
+ HEAP32[sp + 700 >> 2] = 0;
if ((tempValue | 0) == 1) {
break;
}
@@ -104,21 +114,21 @@ function _free($mem) {
if (($194 & 1 | 0) == 0) {
_abort();
}
- HEAP32[sp + 672 >> 2] = 0;
- HEAP32[sp + 676 >> 2] = 0;
- HEAP32[sp + 240 >> 2] = $194;
+ HEAP32[sp + 8 >> 2] = $mem;
+ HEAP32[sp + 24 >> 2] = $10;
HEAP32[sp + 32 >> 2] = $16;
HEAP32[sp + 216 >> 2] = $psize_0;
HEAP32[sp + 224 >> 2] = $p_0;
HEAP32[sp + 232 >> 2] = $189;
- HEAP32[sp + 8 >> 2] = $mem;
- HEAP32[sp + 24 >> 2] = $10;
+ HEAP32[sp + 240 >> 2] = $194;
+ HEAP32[sp + 704 >> 2] = 0;
+ HEAP32[sp + 708 >> 2] = 0;
_free$2(sp);
- tempValue = HEAP32[sp + 672 >> 2] | 0;
- tempInt = HEAP32[sp + 676 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 676 >> 2];
- HEAP32[sp + 672 >> 2] = 0;
- HEAP32[sp + 676 >> 2] = 0;
+ tempValue = HEAP32[sp + 704 >> 2] | 0;
+ tempInt = HEAP32[sp + 708 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 708 >> 2];
+ HEAP32[sp + 704 >> 2] = 0;
+ HEAP32[sp + 708 >> 2] = 0;
if ((tempValue | 0) == 5) {
return;
}
@@ -137,7 +147,6 @@ function linear$0(sp) {
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
- cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
}
function linear$1(sp) {
sp = sp | 0;
@@ -153,31 +162,18 @@ function linear$1(sp) {
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
- cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
}
function _free$0(sp) {
sp = sp | 0;
- var $16 = 0, $220 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $227 = 0, $194 = 0, $233 = 0, $mem = 0, $10 = 0, $236 = 0, $_pre_phi305 = 0, $267 = 0, $270 = 0, $273 = 0, $294 = 0, $299 = 0, $R7_1 = 0, $R7_0 = 0, $RP9_0 = 0, $301 = 0, $302 = 0, $305 = 0, $306 = 0, $278 = 0, $320 = 0, $351 = 0, $364 = 0, $psize_1 = 0;
- $psize_1 = HEAP32[sp + 424 >> 2] | 0;
- $10 = HEAP32[sp + 24 >> 2] | 0;
+ var helper$3 = 0, $194 = 0, $233 = 0, $mem = 0, $10 = 0, $236 = 0, $16 = 0, $_pre_phi305 = 0, $267 = 0, $270 = 0, $273 = 0, helper$4 = 0, $294 = 0, $299 = 0, $R7_1 = 0, $R7_0 = 0, $RP9_0 = 0, $301 = 0, $302 = 0, $305 = 0, $306 = 0, $278 = 0, $320 = 0, $351 = 0, $364 = 0;
$mem = HEAP32[sp + 8 >> 2] | 0;
- $194 = HEAP32[sp + 240 >> 2] | 0;
- $189 = HEAP32[sp + 232 >> 2] | 0;
- $p_0 = HEAP32[sp + 224 >> 2] | 0;
- $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $10 = HEAP32[sp + 24 >> 2] | 0;
$16 = HEAP32[sp + 32 >> 2] | 0;
+ $194 = HEAP32[sp + 240 >> 2] | 0;
+ helper$3 = HEAP32[sp + 664 >> 2] | 0;
OL : do {
- if (($16 | 0) == (HEAP32[25] | 0)) {
- $220 = (HEAP32[22] | 0) + $psize_0 | 0;
- HEAP32[22] = $220;
- HEAP32[25] = $p_0;
- HEAP32[$p_0 + 4 >> 2] = $220 | 1;
- HEAP32[$189 + $220 >> 2] = $220;
- HEAP32[sp + 656 >> 2] = 5;
- break OL;
- }
- $227 = ($194 & -8) + $psize_0 | 0;
- L726 : do {
+ if (helper$3) {
+ helper$3 = 0;
if ($194 >>> 0 < 256) {
$233 = HEAP32[$mem + ($10 & -8) >> 2] | 0;
$236 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0;
@@ -194,7 +190,8 @@ function _free$0(sp) {
} while (0);
if (($236 | 0) == ($233 | 0)) {
HEAP32[20] = HEAP32[20] & (1 << ($194 >>> 3) ^ -1);
- break;
+ HEAP32[sp + 688 >> 2] = 1;
+ break OL;
}
do {
if (($236 | 0) == (120 + ($194 >>> 3 << 1 << 2) | 0 | 0)) {
@@ -213,69 +210,88 @@ function _free$0(sp) {
HEAP32[$233 + 12 >> 2] = $236;
HEAP32[$_pre_phi305 >> 2] = $233;
} else {
+ helper$3 = 1;
+ }
+ }
+ if (helper$3) {
+ helper$3 = 0;
+ if (1) {
$267 = $mem + (($10 & -8) - 8) | 0;
$270 = HEAP32[$mem + (($10 & -8) + 16) >> 2] | 0;
$273 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0;
do {
- if (($273 | 0) == ($267 | 0)) {
- $294 = HEAP32[($mem + (($10 & -8) + 12) | 0) >> 2] | 0;
- if (($294 | 0) == 0) {
- $299 = HEAP32[($mem + (($10 & -8) + 8) | 0) >> 2] | 0;
- if (($299 | 0) == 0) {
- $R7_1 = 0;
- break;
+ helper$4 = 1;
+ if (helper$4) {
+ helper$4 = 0;
+ if (($273 | 0) == ($267 | 0)) {
+ $294 = HEAP32[($mem + (($10 & -8) + 12) | 0) >> 2] | 0;
+ if (($294 | 0) == 0) {
+ $299 = HEAP32[($mem + (($10 & -8) + 8) | 0) >> 2] | 0;
+ if (($299 | 0) == 0) {
+ $R7_1 = 0;
+ break;
+ } else {
+ $R7_0 = $299;
+ $RP9_0 = $mem + (($10 & -8) + 8) | 0;
+ }
+ } else {
+ $R7_0 = $294;
+ $RP9_0 = $mem + (($10 & -8) + 12) | 0;
+ }
+ while (1) {
+ $301 = $R7_0 + 20 | 0;
+ $302 = HEAP32[$301 >> 2] | 0;
+ if (($302 | 0) != 0) {
+ $R7_0 = $302;
+ $RP9_0 = $301;
+ continue;
+ }
+ $305 = $R7_0 + 16 | 0;
+ $306 = HEAP32[$305 >> 2] | 0;
+ if (($306 | 0) == 0) {
+ break;
+ } else {
+ $R7_0 = $306;
+ $RP9_0 = $305;
+ }
+ }
+ if ($RP9_0 >>> 0 < (HEAP32[24] | 0) >>> 0) {
+ _abort();
} else {
- $R7_0 = $299;
- $RP9_0 = $mem + (($10 & -8) + 8) | 0;
+ HEAP32[$RP9_0 >> 2] = 0;
+ $R7_1 = $R7_0;
+ break;
}
} else {
- $R7_0 = $294;
- $RP9_0 = $mem + (($10 & -8) + 12) | 0;
+ helper$4 = 1;
}
- while (1) {
- $301 = $R7_0 + 20 | 0;
- $302 = HEAP32[$301 >> 2] | 0;
- if (($302 | 0) != 0) {
- $R7_0 = $302;
- $RP9_0 = $301;
- continue;
+ }
+ if (helper$4) {
+ helper$4 = 0;
+ if (1) {
+ $278 = HEAP32[$mem + ($10 & -8) >> 2] | 0;
+ if ($278 >>> 0 < (HEAP32[24] | 0) >>> 0) {
+ _abort();
}
- $305 = $R7_0 + 16 | 0;
- $306 = HEAP32[$305 >> 2] | 0;
- if (($306 | 0) == 0) {
+ if ((HEAP32[($278 + 12 | 0) >> 2] | 0) != ($267 | 0)) {
+ _abort();
+ }
+ if ((HEAP32[($273 + 8 | 0) >> 2] | 0) == ($267 | 0)) {
+ HEAP32[($278 + 12 | 0) >> 2] = $273;
+ HEAP32[($273 + 8 | 0) >> 2] = $278;
+ $R7_1 = $273;
break;
} else {
- $R7_0 = $306;
- $RP9_0 = $305;
+ _abort();
}
- }
- if ($RP9_0 >>> 0 < (HEAP32[24] | 0) >>> 0) {
- _abort();
- } else {
- HEAP32[$RP9_0 >> 2] = 0;
- $R7_1 = $R7_0;
- break;
- }
- } else {
- $278 = HEAP32[$mem + ($10 & -8) >> 2] | 0;
- if ($278 >>> 0 < (HEAP32[24] | 0) >>> 0) {
- _abort();
- }
- if ((HEAP32[($278 + 12 | 0) >> 2] | 0) != ($267 | 0)) {
- _abort();
- }
- if ((HEAP32[($273 + 8 | 0) >> 2] | 0) == ($267 | 0)) {
- HEAP32[($278 + 12 | 0) >> 2] = $273;
- HEAP32[($273 + 8 | 0) >> 2] = $278;
- $R7_1 = $273;
- break;
} else {
- _abort();
+ helper$4 = 1;
}
}
} while (0);
if (($270 | 0) == 0) {
- break;
+ HEAP32[sp + 688 >> 2] = 1;
+ break OL;
}
$320 = 384 + (HEAP32[($mem + (($10 & -8) + 20) | 0) >> 2] << 2) | 0;
do {
@@ -285,7 +301,9 @@ function _free$0(sp) {
break;
}
HEAP32[21] = HEAP32[21] & (1 << HEAP32[($mem + (($10 & -8) + 20) | 0) >> 2] ^ -1);
- break L726;
+ HEAP32[sp + 688 >> 2] = 2;
+ HEAP32[sp + 692 >> 2] = 2;
+ break OL;
} else {
if ($270 >>> 0 < (HEAP32[24] | 0) >>> 0) {
_abort();
@@ -296,7 +314,9 @@ function _free$0(sp) {
HEAP32[$270 + 20 >> 2] = $R7_1;
}
if (($R7_1 | 0) == 0) {
- break L726;
+ HEAP32[sp + 688 >> 2] = 2;
+ HEAP32[sp + 692 >> 2] = 2;
+ break OL;
}
}
} while (0);
@@ -318,56 +338,35 @@ function _free$0(sp) {
} while (0);
$364 = HEAP32[$mem + (($10 & -8) + 12) >> 2] | 0;
if (($364 | 0) == 0) {
- break;
+ HEAP32[sp + 688 >> 2] = 1;
+ break OL;
}
if ($364 >>> 0 < (HEAP32[24] | 0) >>> 0) {
_abort();
} else {
HEAP32[$R7_1 + 20 >> 2] = $364;
HEAP32[$364 + 24 >> 2] = $R7_1;
- break;
+ HEAP32[sp + 688 >> 2] = 1;
+ break OL;
}
+ } else {
+ helper$3 = 1;
}
- } while (0);
- HEAP32[$p_0 + 4 >> 2] = $227 | 1;
- HEAP32[$189 + $227 >> 2] = $227;
- if (($p_0 | 0) != (HEAP32[25] | 0)) {
- $psize_1 = $227;
- HEAP32[sp + 656 >> 2] = 1;
- break OL;
}
- HEAP32[22] = $227;
- HEAP32[sp + 656 >> 2] = 5;
- break OL;
} while (0);
- HEAP32[sp + 424 >> 2] = $psize_1;
+ HEAP32[sp + 664 >> 2] = helper$3;
}
function _free$1(sp) {
sp = sp | 0;
- var $25 = 0, $mem = 0, $10 = 0, $26 = 0, $21 = 0, $37 = 0, $40 = 0, $5 = 0, $_pre_phi307 = 0, $69 = 0, $72 = 0, $75 = 0, $95 = 0, $100 = 0, $R_1 = 0, $R_0 = 0, $RP_0 = 0, $102 = 0, $103 = 0, $106 = 0, $107 = 0, $80 = 0, $120 = 0, $151 = 0, $164 = 0, $p_0 = 0, $psize_0 = 0;
- $psize_0 = HEAP32[sp + 216 >> 2] | 0;
- $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ var $21 = 0, $37 = 0, $mem = 0, $40 = 0, $5 = 0, $25 = 0, $26 = 0, $_pre_phi307 = 0, $69 = 0, $72 = 0, $75 = 0, helper$1 = 0, $95 = 0, $100 = 0, $R_1 = 0, $R_0 = 0, $RP_0 = 0, $102 = 0, $103 = 0, $106 = 0, $107 = 0, $80 = 0, $120 = 0, $151 = 0, $164 = 0, $p_0 = 0, $psize_0 = 0;
+ $mem = HEAP32[sp + 8 >> 2] | 0;
$5 = HEAP32[sp + 16 >> 2] | 0;
$21 = HEAP32[sp + 40 >> 2] | 0;
- $26 = HEAP32[sp + 56 >> 2] | 0;
- $10 = HEAP32[sp + 24 >> 2] | 0;
- $mem = HEAP32[sp + 8 >> 2] | 0;
$25 = HEAP32[sp + 48 >> 2] | 0;
+ $26 = HEAP32[sp + 56 >> 2] | 0;
+ $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
OL : do {
- if (($25 | 0) == (HEAP32[25] | 0)) {
- if ((HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & 3 | 0) != 3) {
- $p_0 = $25;
- $psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 1;
- break OL;
- }
- HEAP32[22] = $26;
- HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & -2;
- HEAP32[$mem + ((-8 - $21 | 0) + 4) >> 2] = $26 | 1;
- HEAP32[($mem + (($10 & -8) - 8) | 0) >> 2] = $26;
- HEAP32[sp + 664 >> 2] = 5;
- break OL;
- }
if ($21 >>> 0 < 256) {
$37 = HEAP32[$mem + ((-8 - $21 | 0) + 8) >> 2] | 0;
$40 = HEAP32[$mem + ((-8 - $21 | 0) + 12) >> 2] | 0;
@@ -386,7 +385,7 @@ function _free$1(sp) {
HEAP32[20] = HEAP32[20] & (1 << ($21 >>> 3) ^ -1);
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 1;
+ HEAP32[sp + 696 >> 2] = 1;
break OL;
}
do {
@@ -407,74 +406,86 @@ function _free$1(sp) {
HEAP32[$_pre_phi307 >> 2] = $37;
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 1;
+ HEAP32[sp + 696 >> 2] = 1;
break OL;
}
$69 = $mem + (-8 - $21 | 0) | 0;
$72 = HEAP32[$mem + ((-8 - $21 | 0) + 24) >> 2] | 0;
$75 = HEAP32[$mem + ((-8 - $21 | 0) + 12) >> 2] | 0;
do {
- if (($75 | 0) == ($69 | 0)) {
- $95 = HEAP32[($mem + ((-8 - $21 | 0) + 20) | 0) >> 2] | 0;
- if (($95 | 0) == 0) {
- $100 = HEAP32[($mem + ((-8 - $21 | 0) + 16) | 0) >> 2] | 0;
- if (($100 | 0) == 0) {
- $R_1 = 0;
- break;
+ helper$1 = 1;
+ if (helper$1) {
+ helper$1 = 0;
+ if (($75 | 0) == ($69 | 0)) {
+ $95 = HEAP32[($mem + ((-8 - $21 | 0) + 20) | 0) >> 2] | 0;
+ if (($95 | 0) == 0) {
+ $100 = HEAP32[($mem + ((-8 - $21 | 0) + 16) | 0) >> 2] | 0;
+ if (($100 | 0) == 0) {
+ $R_1 = 0;
+ break;
+ } else {
+ $R_0 = $100;
+ $RP_0 = $mem + ((-8 - $21 | 0) + 16) | 0;
+ }
+ } else {
+ $R_0 = $95;
+ $RP_0 = $mem + ((-8 - $21 | 0) + 20) | 0;
+ }
+ while (1) {
+ $102 = $R_0 + 20 | 0;
+ $103 = HEAP32[$102 >> 2] | 0;
+ if (($103 | 0) != 0) {
+ $R_0 = $103;
+ $RP_0 = $102;
+ continue;
+ }
+ $106 = $R_0 + 16 | 0;
+ $107 = HEAP32[$106 >> 2] | 0;
+ if (($107 | 0) == 0) {
+ break;
+ } else {
+ $R_0 = $107;
+ $RP_0 = $106;
+ }
+ }
+ if ($RP_0 >>> 0 < $5 >>> 0) {
+ _abort();
} else {
- $R_0 = $100;
- $RP_0 = $mem + ((-8 - $21 | 0) + 16) | 0;
+ HEAP32[$RP_0 >> 2] = 0;
+ $R_1 = $R_0;
+ break;
}
} else {
- $R_0 = $95;
- $RP_0 = $mem + ((-8 - $21 | 0) + 20) | 0;
+ helper$1 = 1;
}
- while (1) {
- $102 = $R_0 + 20 | 0;
- $103 = HEAP32[$102 >> 2] | 0;
- if (($103 | 0) != 0) {
- $R_0 = $103;
- $RP_0 = $102;
- continue;
+ }
+ if (helper$1) {
+ helper$1 = 0;
+ if (1) {
+ $80 = HEAP32[$mem + ((-8 - $21 | 0) + 8) >> 2] | 0;
+ if ($80 >>> 0 < $5 >>> 0) {
+ _abort();
}
- $106 = $R_0 + 16 | 0;
- $107 = HEAP32[$106 >> 2] | 0;
- if (($107 | 0) == 0) {
+ if ((HEAP32[($80 + 12 | 0) >> 2] | 0) != ($69 | 0)) {
+ _abort();
+ }
+ if ((HEAP32[($75 + 8 | 0) >> 2] | 0) == ($69 | 0)) {
+ HEAP32[($80 + 12 | 0) >> 2] = $75;
+ HEAP32[($75 + 8 | 0) >> 2] = $80;
+ $R_1 = $75;
break;
} else {
- $R_0 = $107;
- $RP_0 = $106;
+ _abort();
}
- }
- if ($RP_0 >>> 0 < $5 >>> 0) {
- _abort();
} else {
- HEAP32[$RP_0 >> 2] = 0;
- $R_1 = $R_0;
- break;
- }
- } else {
- $80 = HEAP32[$mem + ((-8 - $21 | 0) + 8) >> 2] | 0;
- if ($80 >>> 0 < $5 >>> 0) {
- _abort();
- }
- if ((HEAP32[($80 + 12 | 0) >> 2] | 0) != ($69 | 0)) {
- _abort();
- }
- if ((HEAP32[($75 + 8 | 0) >> 2] | 0) == ($69 | 0)) {
- HEAP32[($80 + 12 | 0) >> 2] = $75;
- HEAP32[($75 + 8 | 0) >> 2] = $80;
- $R_1 = $75;
- break;
- } else {
- _abort();
+ helper$1 = 1;
}
}
} while (0);
if (($72 | 0) == 0) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 1;
+ HEAP32[sp + 696 >> 2] = 1;
break OL;
}
$120 = 384 + (HEAP32[($mem + ((-8 - $21 | 0) + 28) | 0) >> 2] << 2) | 0;
@@ -487,8 +498,8 @@ function _free$1(sp) {
HEAP32[21] = HEAP32[21] & (1 << HEAP32[($mem + ((-8 - $21 | 0) + 28) | 0) >> 2] ^ -1);
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 2;
- HEAP32[sp + 668 >> 2] = 2;
+ HEAP32[sp + 696 >> 2] = 2;
+ HEAP32[sp + 700 >> 2] = 2;
break OL;
} else {
if ($72 >>> 0 < (HEAP32[24] | 0) >>> 0) {
@@ -502,8 +513,8 @@ function _free$1(sp) {
if (($R_1 | 0) == 0) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 2;
- HEAP32[sp + 668 >> 2] = 2;
+ HEAP32[sp + 696 >> 2] = 2;
+ HEAP32[sp + 700 >> 2] = 2;
break OL;
}
}
@@ -528,7 +539,7 @@ function _free$1(sp) {
if (($164 | 0) == 0) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 1;
+ HEAP32[sp + 696 >> 2] = 1;
break OL;
}
if ($164 >>> 0 < (HEAP32[24] | 0) >>> 0) {
@@ -538,28 +549,28 @@ function _free$1(sp) {
HEAP32[$164 + 24 >> 2] = $R_1;
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 664 >> 2] = 1;
+ HEAP32[sp + 696 >> 2] = 1;
break OL;
}
} while (0);
- HEAP32[sp + 224 >> 2] = $p_0;
HEAP32[sp + 216 >> 2] = $psize_0;
+ HEAP32[sp + 224 >> 2] = $p_0;
}
function _free$2(sp) {
sp = sp | 0;
- var helper$1 = 0, $194 = 0, $16 = 0, $204 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $mem = 0, $10 = 0, $psize_1 = 0, $390 = 0, $396 = 0, $F16_0 = 0, $_pre_phi = 0, $404 = 0, $414 = 0, $415 = 0, $I18_0 = 0, $428 = 0, $436 = 0, $443 = 0, $447 = 0, $448 = 0, $463 = 0, $K19_0 = 0, $T_0 = 0, $472 = 0, $473 = 0, label = 0, $486 = 0, $487 = 0, $489 = 0, $501 = 0, $sp_0_in_i = 0, $sp_0_i = 0;
- $10 = HEAP32[sp + 24 >> 2] | 0;
+ var helper$2 = 0, $194 = 0, $16 = 0, $204 = 0, $psize_0 = 0, $p_0 = 0, $220 = 0, $189 = 0, $227 = 0, helper$3 = 0, $mem = 0, $10 = 0, $psize_1 = 0, $390 = 0, $396 = 0, $F16_0 = 0, $_pre_phi = 0, $404 = 0, $414 = 0, $415 = 0, $I18_0 = 0, $428 = 0, $436 = 0, $443 = 0, $447 = 0, $448 = 0, helper$5 = 0, $463 = 0, $K19_0 = 0, $T_0 = 0, $472 = 0, $473 = 0, label = 0, $486 = 0, $487 = 0, $489 = 0, $501 = 0, $sp_0_in_i = 0, $sp_0_i = 0;
$mem = HEAP32[sp + 8 >> 2] | 0;
- $189 = HEAP32[sp + 232 >> 2] | 0;
- $p_0 = HEAP32[sp + 224 >> 2] | 0;
- $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $10 = HEAP32[sp + 24 >> 2] | 0;
$16 = HEAP32[sp + 32 >> 2] | 0;
+ $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ $189 = HEAP32[sp + 232 >> 2] | 0;
$194 = HEAP32[sp + 240 >> 2] | 0;
OL : do {
do {
- helper$1 = 1;
- if (helper$1) {
- helper$1 = 0;
+ helper$2 = 1;
+ if (helper$2) {
+ helper$2 = 0;
if (($194 & 2 | 0) == 0) {
if (($16 | 0) == (HEAP32[26] | 0)) {
$204 = (HEAP32[23] | 0) + $psize_0 | 0;
@@ -571,50 +582,73 @@ function _free$2(sp) {
HEAP32[22] = 0;
}
if ($204 >>> 0 <= (HEAP32[27] | 0) >>> 0) {
- HEAP32[sp + 672 >> 2] = 5;
+ HEAP32[sp + 704 >> 2] = 5;
break OL;
}
_sys_trim(0) | 0;
- HEAP32[sp + 672 >> 2] = 5;
+ HEAP32[sp + 704 >> 2] = 5;
break OL;
}
- HEAP32[sp + 656 >> 2] = 0;
- HEAP32[sp + 660 >> 2] = 0;
- HEAP32[sp + 32 >> 2] = $16;
- HEAP32[sp + 216 >> 2] = $psize_0;
- HEAP32[sp + 224 >> 2] = $p_0;
- HEAP32[sp + 232 >> 2] = $189;
- HEAP32[sp + 240 >> 2] = $194;
- HEAP32[sp + 8 >> 2] = $mem;
- HEAP32[sp + 24 >> 2] = $10;
- HEAP32[sp + 424 >> 2] = $psize_1;
- _free$0(sp);
- $psize_1 = HEAP32[sp + 424 >> 2] | 0;
- tempValue = HEAP32[sp + 656 >> 2] | 0;
- tempInt = HEAP32[sp + 660 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 660 >> 2];
- HEAP32[sp + 656 >> 2] = 0;
- HEAP32[sp + 660 >> 2] = 0;
- if ((tempValue | 0) == 5) {
- HEAP32[sp + 672 >> 2] = 5;
+ if (($16 | 0) == (HEAP32[25] | 0)) {
+ $220 = (HEAP32[22] | 0) + $psize_0 | 0;
+ HEAP32[22] = $220;
+ HEAP32[25] = $p_0;
+ HEAP32[$p_0 + 4 >> 2] = $220 | 1;
+ HEAP32[$189 + $220 >> 2] = $220;
+ HEAP32[sp + 704 >> 2] = 5;
break OL;
}
- if ((tempValue | 0) == 1) {
+ $227 = ($194 & -8) + $psize_0 | 0;
+ L726 : do {
+ helper$3 = 1;
+ HEAP32[sp + 8 >> 2] = $mem;
+ HEAP32[sp + 24 >> 2] = $10;
+ HEAP32[sp + 32 >> 2] = $16;
+ HEAP32[sp + 240 >> 2] = $194;
+ HEAP32[sp + 664 >> 2] = helper$3;
+ HEAP32[sp + 688 >> 2] = 0;
+ HEAP32[sp + 692 >> 2] = 0;
+ _free$0(sp);
+ helper$3 = HEAP32[sp + 664 >> 2] | 0;
+ tempValue = HEAP32[sp + 688 >> 2] | 0;
+ tempInt = HEAP32[sp + 692 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 692 >> 2];
+ HEAP32[sp + 688 >> 2] = 0;
+ HEAP32[sp + 692 >> 2] = 0;
+ if ((tempValue | 0) == 1) {
+ break;
+ }
+ if ((tempValue | 0) == 2) {
+ switch (tempInt | 0) {
+ case 2:
+ {
+ break L726;
+ }
+ }
+ }
+ } while (0);
+ HEAP32[$p_0 + 4 >> 2] = $227 | 1;
+ HEAP32[$189 + $227 >> 2] = $227;
+ if (($p_0 | 0) != (HEAP32[25] | 0)) {
+ $psize_1 = $227;
break;
}
+ HEAP32[22] = $227;
+ HEAP32[sp + 704 >> 2] = 5;
+ break OL;
} else {
- helper$1 = 1;
+ helper$2 = 1;
}
}
- if (helper$1) {
- helper$1 = 0;
+ if (helper$2) {
+ helper$2 = 0;
if (1) {
HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = $194 & -2;
HEAP32[$p_0 + 4 >> 2] = $psize_0 | 1;
HEAP32[$189 + $psize_0 >> 2] = $psize_0;
$psize_1 = $psize_0;
} else {
- helper$1 = 1;
+ helper$2 = 1;
}
}
} while (0);
@@ -640,7 +674,7 @@ function _free$2(sp) {
HEAP32[$F16_0 + 12 >> 2] = $p_0;
HEAP32[$p_0 + 8 >> 2] = $F16_0;
HEAP32[$p_0 + 12 >> 2] = 120 + ($390 << 1 << 2) | 0;
- HEAP32[sp + 672 >> 2] = 5;
+ HEAP32[sp + 704 >> 2] = 5;
break OL;
}
$414 = $p_0;
@@ -665,60 +699,72 @@ function _free$2(sp) {
$447 = HEAP32[21] | 0;
$448 = 1 << $I18_0;
do {
- if (($447 & $448 | 0) == 0) {
- HEAP32[21] = $447 | $448;
- HEAP32[$443 >> 2] = $414;
- HEAP32[$p_0 + 24 >> 2] = $443;
- HEAP32[$p_0 + 12 >> 2] = $p_0;
- HEAP32[$p_0 + 8 >> 2] = $p_0;
- } else {
- if (($I18_0 | 0) == 31) {
- $463 = 0;
+ helper$5 = 1;
+ if (helper$5) {
+ helper$5 = 0;
+ if (($447 & $448 | 0) == 0) {
+ HEAP32[21] = $447 | $448;
+ HEAP32[$443 >> 2] = $414;
+ HEAP32[$p_0 + 24 >> 2] = $443;
+ HEAP32[$p_0 + 12 >> 2] = $p_0;
+ HEAP32[$p_0 + 8 >> 2] = $p_0;
} else {
- $463 = 25 - ($I18_0 >>> 1) | 0;
+ helper$5 = 1;
}
- $K19_0 = $psize_1 << $463;
- $T_0 = HEAP32[$443 >> 2] | 0;
- while (1) {
- if ((HEAP32[$T_0 + 4 >> 2] & -8 | 0) == ($psize_1 | 0)) {
- break;
- }
- $472 = $T_0 + 16 + ($K19_0 >>> 31 << 2) | 0;
- $473 = HEAP32[$472 >> 2] | 0;
- if (($473 | 0) == 0) {
- label = 569;
- break;
+ }
+ if (helper$5) {
+ helper$5 = 0;
+ if (1) {
+ if (($I18_0 | 0) == 31) {
+ $463 = 0;
} else {
- $K19_0 = $K19_0 << 1;
- $T_0 = $473;
+ $463 = 25 - ($I18_0 >>> 1) | 0;
}
- }
- if ((label | 0) == 569) {
- if ($472 >>> 0 < (HEAP32[24] | 0) >>> 0) {
+ $K19_0 = $psize_1 << $463;
+ $T_0 = HEAP32[$443 >> 2] | 0;
+ while (1) {
+ if ((HEAP32[$T_0 + 4 >> 2] & -8 | 0) == ($psize_1 | 0)) {
+ break;
+ }
+ $472 = $T_0 + 16 + ($K19_0 >>> 31 << 2) | 0;
+ $473 = HEAP32[$472 >> 2] | 0;
+ if (($473 | 0) == 0) {
+ label = 569;
+ break;
+ } else {
+ $K19_0 = $K19_0 << 1;
+ $T_0 = $473;
+ }
+ }
+ if ((label | 0) == 569) {
+ if ($472 >>> 0 < (HEAP32[24] | 0) >>> 0) {
+ _abort();
+ } else {
+ HEAP32[$472 >> 2] = $414;
+ HEAP32[$p_0 + 24 >> 2] = $T_0;
+ HEAP32[$p_0 + 12 >> 2] = $p_0;
+ HEAP32[$p_0 + 8 >> 2] = $p_0;
+ break;
+ }
+ }
+ $486 = $T_0 + 8 | 0;
+ $487 = HEAP32[$486 >> 2] | 0;
+ $489 = HEAP32[24] | 0;
+ if ($T_0 >>> 0 < $489 >>> 0) {
+ _abort();
+ }
+ if ($487 >>> 0 < $489 >>> 0) {
_abort();
} else {
- HEAP32[$472 >> 2] = $414;
- HEAP32[$p_0 + 24 >> 2] = $T_0;
- HEAP32[$p_0 + 12 >> 2] = $p_0;
- HEAP32[$p_0 + 8 >> 2] = $p_0;
+ HEAP32[$487 + 12 >> 2] = $414;
+ HEAP32[$486 >> 2] = $414;
+ HEAP32[$p_0 + 8 >> 2] = $487;
+ HEAP32[$p_0 + 12 >> 2] = $T_0;
+ HEAP32[$p_0 + 24 >> 2] = 0;
break;
}
- }
- $486 = $T_0 + 8 | 0;
- $487 = HEAP32[$486 >> 2] | 0;
- $489 = HEAP32[24] | 0;
- if ($T_0 >>> 0 < $489 >>> 0) {
- _abort();
- }
- if ($487 >>> 0 < $489 >>> 0) {
- _abort();
} else {
- HEAP32[$487 + 12 >> 2] = $414;
- HEAP32[$486 >> 2] = $414;
- HEAP32[$p_0 + 8 >> 2] = $487;
- HEAP32[$p_0 + 12 >> 2] = $T_0;
- HEAP32[$p_0 + 24 >> 2] = 0;
- break;
+ helper$5 = 1;
}
}
} while (0);
@@ -727,7 +773,7 @@ function _free$2(sp) {
if (($501 | 0) == 0) {
$sp_0_in_i = 536;
} else {
- HEAP32[sp + 672 >> 2] = 5;
+ HEAP32[sp + 704 >> 2] = 5;
break OL;
}
while (1) {
@@ -740,7 +786,7 @@ function _free$2(sp) {
}
HEAP32[28] = -1;
STACKTOP = sp;
- HEAP32[sp + 672 >> 2] = 5;
+ HEAP32[sp + 704 >> 2] = 5;
break OL;
} while (0);
}