summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--ChangeLog4
-rwxr-xr-xemcc120
-rwxr-xr-xemscripten.py6
-rw-r--r--src/compiler.js3
-rw-r--r--src/headless.js12
-rw-r--r--src/headlessCanvas.js1
-rw-r--r--src/library.js412
-rw-r--r--src/library_browser.js9
-rw-r--r--src/library_gl.js273
-rw-r--r--src/library_glew.js135
-rw-r--r--src/library_sdl.js64
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js67
-rw-r--r--src/postamble.js5
-rw-r--r--src/preamble.js36
-rw-r--r--src/relooper/Relooper.cpp27
-rw-r--r--src/relooper/Relooper.h4
-rw-r--r--src/relooper/test.txt4
-rw-r--r--src/runtime.js14
-rw-r--r--src/shell.js12
-rw-r--r--system/include/GL/glew.h841
-rw-r--r--system/include/libcxx/exception4
-rw-r--r--system/lib/libc.symbols33
-rw-r--r--system/lib/libc/gen/err.c49
-rw-r--r--system/lib/libc/gen/errx.c49
-rw-r--r--system/lib/libc/gen/verr.c58
-rw-r--r--system/lib/libc/gen/verrx.c51
-rw-r--r--system/lib/libc/gen/vwarn.c55
-rw-r--r--system/lib/libc/gen/vwarnx.c48
-rw-r--r--system/lib/libc/gen/warn.c49
-rw-r--r--system/lib/libc/gen/warnx.c49
-rw-r--r--system/lib/libc/musl/readme.txt4
-rw-r--r--system/lib/libc/musl/src/legacy/err.c67
-rw-r--r--system/lib/libc/musl/src/math/__cos.c71
-rw-r--r--system/lib/libc/musl/src/math/__sin.c64
-rw-r--r--system/lib/libc/musl/src/misc/getopt.c74
-rw-r--r--system/lib/libc/musl/src/misc/getopt_long.c59
-rw-r--r--system/lib/libc/musl/src/regex/fnmatch.c299
-rw-r--r--system/lib/libc/musl/src/stdio/__toread.c10
-rw-r--r--system/lib/libc/musl/src/stdio/__towrite.c18
-rw-r--r--system/lib/libc/musl/src/stdio/fputwc.c22
-rw-r--r--system/lib/libc/musl/src/stdio/fputws.c30
-rw-r--r--system/lib/libc/musl/src/stdio/vswprintf.c17
-rw-r--r--system/lib/libc/musl/src/stdlib/strtod.c24
-rw-r--r--system/lib/libc/stdlib/getopt_long.c511
-rw-r--r--system/lib/libc/stdlib/strtod.c305
-rw-r--r--system/lib/libcextra.symbols26
-rw-r--r--tests/cases/fptosi.ll28
-rw-r--r--tests/cases/fptosi.txt6
-rw-r--r--tests/cases/longjmp_tiny_invoke.ll6
-rw-r--r--tests/cases/longjmp_tiny_invoke_phi.ll4
-rw-r--r--tests/cases/longjmp_tiny_phi.ll2
-rw-r--r--tests/cases/longjmp_tiny_phi2.ll2
-rw-r--r--tests/core/fnmatch.c79
-rw-r--r--tests/core/fnmatch.out23
-rw-r--r--tests/core/test_alloca.in13
-rw-r--r--tests/core/test_exceptions_2.in (renamed from tests/core/test_exception_2.in)0
-rw-r--r--tests/core/test_exceptions_2.out (renamed from tests/core/test_exception_2.out)0
-rw-r--r--tests/core/test_exceptions_multi.in (renamed from tests/core/test_multiexception.in)6
-rw-r--r--tests/core/test_exceptions_multi.out (renamed from tests/core/test_multiexception.out)0
-rw-r--r--tests/core/test_exceptions_std.in (renamed from tests/core/test_std_exception.in)1
-rw-r--r--tests/core/test_exceptions_std.out2
-rw-r--r--tests/core/test_exceptions_typed.in (renamed from tests/exceptions/typed.cpp)0
-rw-r--r--tests/core/test_exceptions_typed.out (renamed from tests/exceptions/output.txt)0
-rw-r--r--tests/core/test_exceptions_white_list.in (renamed from tests/core/test_white_list_exception.in)0
-rw-r--r--tests/core/test_exceptions_white_list.out (renamed from tests/core/test_white_list_exception.out)0
-rw-r--r--tests/core/test_inlinejs3.in2
-rw-r--r--tests/core/test_nl_types.in8
-rw-r--r--tests/core/test_nl_types.out1
-rw-r--r--tests/core/test_std_exception.out1
-rw-r--r--tests/core/test_wprintf.c50
-rw-r--r--tests/core/test_wprintf.out35
-rw-r--r--tests/doublestart.c23
-rw-r--r--tests/glew.c51
-rwxr-xr-xtests/runner.py2
-rw-r--r--tests/test_benchmark.py12
-rw-r--r--tests/test_browser.py24
-rw-r--r--tests/test_core.py127
-rw-r--r--tests/test_other.py97
-rw-r--r--tests/utf32.cpp20
-rw-r--r--tools/eliminator/asm-eliminator-test-output.js506
-rw-r--r--tools/eliminator/asm-eliminator-test.js651
-rw-r--r--tools/js-optimizer.js1387
-rw-r--r--tools/js_optimizer.py7
-rw-r--r--tools/shared.py79
-rw-r--r--tools/test-js-optimizer-asm-regs-min-output.js5
-rw-r--r--tools/test-js-optimizer-asm-regs-min.js5
-rw-r--r--tools/test-js-optimizer-shiftsAggressive-output.js11
-rw-r--r--tools/test-js-optimizer-shiftsAggressive.js13
90 files changed, 5472 insertions, 1916 deletions
diff --git a/AUTHORS b/AUTHORS
index cc5dfb56..792fb523 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -117,3 +117,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Andre Weissflog <floooh@gmail.com>
* Alexandre Perrot <alexandre.perrot@gmail.com>
* Emerson José Silveira da Costa <emerson.costa@gmail.com>
+* Jari Vetoniemi <mailroxas@gmail.com>
+* Sindre Sorhus <sindresorhus@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index 8749f02f..9d1d85d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,12 +12,12 @@ Current trunk code
- To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see
https://github.com/kripken/emscripten/compare/1.8.2...incoming
-v1.8.2: 1/4/2013
+v1.8.2: 1/4/2014
------------------
- Fixed glGetFramebufferAttachmentParameteriv and an issue with glGetXXX when the returned value was null.
- Full list of changes: https://github.com/kripken/emscripten/compare/1.8.1...1.8.2
-v1.8.1: 1/3/2013
+v1.8.1: 1/3/2014
------------------
- Added support for WebGL hardware instancing extension.
- Improved fastcomp native LLVM backend support.
diff --git a/emcc b/emcc
index 8bfa0942..7460da61 100755
--- a/emcc
+++ b/emcc
@@ -146,7 +146,7 @@ Options that are modified or new in %s include:
This is the recommended setting when you want a
reasonably optimized build that is generated as
- quickly as possible (it is much faster than -O2).
+ quickly as possible (it builds much faster than -O2).
(Note: for details on the affects of different
opt levels, see apply_opt_level() in
@@ -158,20 +158,11 @@ Options that are modified or new in %s include:
time in return for the smallest and fastest
output.
- -O3 As -O2, plus dangerous optimizations that may
- break the generated code! This adds
+ -O3 As -O2, plus additional optimizations that can
+ take a significant amount of compilation time.
- -s FORCE_ALIGNED_MEMORY=1
- -s DOUBLE_MODE=0
- -s PRECISE_I64_MATH=0
- --closure 1
- --llvm-lto 3
-
- This is not recommended at all. A better idea
- is to try each of these separately on top of
- -O2 to see what works. See the wiki and
- src/settings.js (for the -s options) for more
- information.
+ For tips on optimizing your code, see
+ https://github.com/kripken/emscripten/wiki/Optimizing-Code
-s OPTION=VALUE JavaScript code generation option passed
into the emscripten compiler. For the
@@ -267,8 +258,7 @@ Options that are modified or new in %s include:
code size and may in some cases increase
runtime speed (although the opposite can also
occur). Note that it takes time to run, and
- may require some changes to the code. This
- is run by default in -O3.
+ may require some changes to the code.
In asm.js mode, closure will only be used on the
'shell' code around the compiled code (the
@@ -781,6 +771,14 @@ def filename_type_ending(filename):
suffix = filename_type_suffix(filename)
return '' if not suffix else ('.' + suffix)
+# Log out times for emcc stages
+log_time_last = time.time()
+def log_time(name):
+ global log_time_last
+ now = time.time()
+ logging.debug('emcc step "%s" took %.2f seconds' % (name, now - log_time_last))
+ log_time_last = now
+
try:
call = CXX if use_cxx else CC
@@ -1029,9 +1027,7 @@ try:
if js_opts is None: js_opts = opt_level >= 2
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
- if closure is None and opt_level == 3: closure = True
if llvm_lto is None and bind:
logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue
@@ -1196,7 +1192,6 @@ try:
shared.Settings.ASM_JS = 1
assert shared.Settings.ALLOW_MEMORY_GROWTH == 0, 'memory growth not supported in fastcomp yet'
assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp'
- assert shared.Settings.SAFE_HEAP == 0, 'safe heap not supported in fastcomp yet'
assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet'
assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp'
assert shared.Settings.RESERVED_FUNCTION_POINTERS == 0, 'reserved function pointers not supported in fastcomp'
@@ -1230,6 +1225,13 @@ try:
shared.Settings.CORRECT_OVERFLOWS = 1
assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode'
+ if shared.Settings.SAFE_HEAP and not js_opts:
+ logging.warning('asm.js+SAFE_HEAP requires js opts to be run (-O1 or above by default)')
+
+ if shared.Settings.ALLOW_MEMORY_GROWTH:
+ logging.error('Cannot enable ALLOW_MEMORY_GROWTH with asm.js, build with -s ASM_JS=0 if you need a growable heap');
+ sys.exit(1);
+
if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2:
debug_level = 4 # must keep debug info to do line-by-line operations
@@ -1295,6 +1297,8 @@ try:
temp_files = []
+ log_time('parse arguments and setup')
+
# First, generate LLVM bitcode. For each input file, we get base.o with bitcode
for input_file in input_files:
file_ending = filename_type_ending(input_file)
@@ -1334,6 +1338,8 @@ try:
logging.error(input_file + ': Unknown file suffix when compiling to LLVM bitcode!')
sys.exit(1)
+ log_time('bitcodeize inputs')
+
if not LEAVE_INPUTS_RAW:
assert len(temp_files) == len(input_files)
@@ -1380,6 +1386,8 @@ try:
shared.Building.link(temp_files, specified_target)
exit(0)
+ log_time('bitcodeize inputs')
+
## Continue on to create JavaScript
logging.debug('will generate JavaScript')
@@ -1440,15 +1448,6 @@ try:
libc_files = [
'dlmalloc.c',
os.path.join('libcxx', 'new.cpp'),
- os.path.join('libc', 'stdlib', 'getopt_long.c'),
- os.path.join('libc', 'gen', 'err.c'),
- os.path.join('libc', 'gen', 'errx.c'),
- os.path.join('libc', 'gen', 'warn.c'),
- os.path.join('libc', 'gen', 'warnx.c'),
- os.path.join('libc', 'gen', 'verr.c'),
- os.path.join('libc', 'gen', 'verrx.c'),
- os.path.join('libc', 'gen', 'vwarn.c'),
- os.path.join('libc', 'gen', 'vwarnx.c'),
]
musl_files = [
['internal', [
@@ -1462,6 +1461,7 @@ try:
['stdio', [
'__overflow.c',
'__toread.c',
+ '__towrite.c',
'__uflow.c',
]],
['stdlib', [
@@ -1511,6 +1511,9 @@ try:
['internal', [
'intscan.c',
]],
+ ['legacy', [
+ 'err.c',
+ ]],
['locale', [
'iconv.c',
'iswalnum_l.c',
@@ -1541,7 +1544,9 @@ try:
'wctype_l.c',
]],
['math', [
+ '__cos.c',
'__cosdf.c',
+ '__sin.c',
'__sindf.c',
'ilogb.c',
'ilogbf.c',
@@ -1563,6 +1568,10 @@ try:
'tgammaf.c',
'tgammal.c'
]],
+ ['misc', [
+ 'getopt.c',
+ 'getopt_long.c',
+ ]],
['multibyte', [
'btowc.c',
'mblen.c',
@@ -1581,6 +1590,7 @@ try:
'wctomb.c',
]],
['regex', [
+ 'fnmatch.c',
'regcomp.c',
'regerror.c',
'regexec.c',
@@ -1594,6 +1604,7 @@ try:
'vwprintf.c',
'wprintf.c',
'fputwc.c',
+ 'fputws.c',
]],
['stdlib', [
'ecvt.c',
@@ -1750,15 +1761,14 @@ try:
libfile = shared.Cache.get(name, create)
extra_files_to_link.append(libfile)
+ log_time('calculate system libraries')
+
# First, combine the bitcode files if there are several. We must also link if we have a singleton .a
if len(input_files) + len(extra_files_to_link) > 1 or \
(not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])):
linker_inputs = temp_files + extra_files_to_link
logging.debug('linking: ' + str(linker_inputs))
- t0 = time.time()
shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0)
- t1 = time.time()
- logging.debug(' linking took %.2f seconds' % (t1 - t0))
final = in_temp(target_basename + '.bc')
else:
if not LEAVE_INPUTS_RAW:
@@ -1768,19 +1778,16 @@ try:
final = in_temp(input_files[0])
shutil.copyfile(input_files[0], final)
+ log_time('link')
+
if DEBUG:
logging.debug('saving intermediate processing steps to %s' % shared.EMSCRIPTEN_TEMP_DIR)
intermediate_counter = 0
- intermediate_time = None
def save_intermediate(name=None, suffix='js'):
- global intermediate_counter, intermediate_time
+ global intermediate_counter
shutil.copyfile(final, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'emcc-%d%s.%s' % (intermediate_counter, '' if name is None else '-' + name, suffix)))
intermediate_counter += 1
- now = time.time()
- if intermediate_time:
- logging.debug(' step took %.2f seconds' % (now - intermediate_time))
- intermediate_time = now
if not LEAVE_INPUTS_RAW: save_intermediate('basebc', 'bc')
@@ -1841,6 +1848,8 @@ try:
final += '.adsimp.bc'
if DEBUG: save_intermediate('adsimp', 'bc')
+ log_time('post-link')
+
# Emscripten
logging.debug('LLVM => JS')
extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))]
@@ -1848,6 +1857,8 @@ try:
final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
if DEBUG: save_intermediate('original')
+ log_time('emscript (llvm=>js)')
+
# Embed and preload files
if len(preload_files) + len(embed_files) > 0:
logging.debug('setting up files')
@@ -1908,9 +1919,7 @@ try:
shared.try_delete(memfile)
def repl(m):
# handle chunking of the memory initializer
- s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0])
- s = s.replace('concat', ',')
- if s[-1] == ',': s = s[:-1]
+ s = m.groups(0)[0]
open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(','))))
if DEBUG:
# Copy into temp dir as well, so can be run there too
@@ -1921,6 +1930,7 @@ try:
src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1)
open(final + '.mem.js', 'w').write(src)
final += '.mem.js'
+ src = None
js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings
if DEBUG:
if os.path.exists(memfile):
@@ -1928,6 +1938,17 @@ try:
logging.debug('wrote memory initialization to %s' % memfile)
else:
logging.debug('did not see memory initialization')
+ elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE:
+ # not writing a binary init, but we can at least optimize them by splitting them up
+ src = open(final).read()
+ src = shared.JS.optimize_initializer(src)
+ if src is not None:
+ logging.debug('optimizing memory initialization')
+ open(final + '.mem.js', 'w').write(src)
+ final += '.mem.js'
+ src = None
+
+ log_time('source transforms')
# It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing
js_optimizer_queue = []
@@ -1989,15 +2010,20 @@ try:
if DEBUG: save_intermediate('closure')
if js_opts:
+ if shared.Settings.ASM_JS and shared.Settings.SAFE_HEAP: js_optimizer_queue += ['safeHeap']
+
if shared.Settings.OUTLINING_LIMIT > 0 and shared.Settings.ASM_JS:
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 shared.Settings.ASM_JS and opt_level >= 3 and shared.Settings.OUTLINING_LIMIT == 0:
+ js_optimizer_queue += ['registerizeHarder']
+ else:
+ 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 < 2 and shared.Settings.ASM_JS: js_optimizer_queue += ['minifyNames']
if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
if closure and shared.Settings.ASM_JS:
@@ -2007,10 +2033,12 @@ try:
flush_js_optimizer_queue()
+ log_time('js opts')
+
# Remove some trivial whitespace # TODO: do not run when compress has already been done on all parts of the code
- src = open(final).read()
- src = re.sub(r'\n+[ \n]*\n+', '\n', src)
- open(final, 'w').write(src)
+ #src = open(final).read()
+ #src = re.sub(r'\n+[ \n]*\n+', '\n', src)
+ #open(final, 'w').write(src)
def generate_source_map(map_file_base_name, offset=0):
jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'),
@@ -2113,6 +2141,8 @@ try:
# copy final JS to output
shutil.move(final, target)
+ log_time('final emitting')
+
if DEBUG: logging.debug('total time: %.2f seconds' % (time.time() - start_time))
finally:
diff --git a/emscripten.py b/emscripten.py
index befad8d5..725f573f 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -455,7 +455,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
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']
+ if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE']
if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8']
if settings['ASSERTIONS']:
basic_funcs += ['nullFunc']
@@ -725,7 +725,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
outfile: The file where the output is written.
"""
- assert(settings['ASM_JS']) # TODO: apply ASM_JS even in -O0 for fastcomp
+ assert(settings['ASM_JS'])
# Overview:
# * Run LLVM backend to emit JS. JS includes function bodies, memory initializer,
@@ -956,7 +956,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
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']
+ if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE']
if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8']
if settings['ASSERTIONS']:
basic_funcs += ['nullFunc']
diff --git a/src/compiler.js b/src/compiler.js
index e4ce1c88..17a8e83c 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -183,9 +183,6 @@ if (SAFE_HEAP) USE_BSS = 0; // must initialize heap for safe heap
// Settings sanity checks
assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4');
-if (ASM_JS) {
- assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap');
-}
assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals');
// Output some info and warnings based on settings
diff --git a/src/headless.js b/src/headless.js
index e5458641..5880c087 100644
--- a/src/headless.js
+++ b/src/headless.js
@@ -82,6 +82,16 @@ var window = {
}
listeners.push(func);
},
+ removeEventListener: function(id, func) {
+ var listeners = this.eventListeners[id];
+ if (!listeners) return;
+ for (var i = 0; i < listeners.length; i++) {
+ if (listeners[i] === func) {
+ listeners.splice(i, 1);
+ return;
+ }
+ }
+ },
callEventListeners: function(id) {
var listeners = this.eventListeners[id];
if (listeners) {
@@ -101,6 +111,7 @@ var document = {
headless: true,
eventListeners: {},
addEventListener: window.addEventListener,
+ removeEventListener: window.removeEventListener,
callEventListeners: window.callEventListeners,
getElementById: function(id) {
switch(id) {
@@ -144,6 +155,7 @@ var document = {
},
eventListeners: {},
addEventListener: document.addEventListener,
+ removeEventListener: document.removeEventListener,
callEventListeners: document.callEventListeners,
};
};
diff --git a/src/headlessCanvas.js b/src/headlessCanvas.js
index 4951aed8..6b0f9d47 100644
--- a/src/headlessCanvas.js
+++ b/src/headlessCanvas.js
@@ -600,6 +600,7 @@ function headlessCanvas() {
style: {},
eventListeners: {},
addEventListener: function(){},
+ removeEventListener: function(){},
requestFullScreen: function() {
document.fullscreenElement = document.getElementById('canvas');
window.setTimeout(function() {
diff --git a/src/library.js b/src/library.js
index 69569601..bc577e78 100644
--- a/src/library.js
+++ b/src/library.js
@@ -100,7 +100,7 @@ LibraryManager.library = {
return FS.handleFSError(e);
}
if (stream.position < 0 || stream.position >= entries.length) {
- {{{ makeSetValue('result', '0', '0', 'i8*') }}}
+ {{{ makeSetValue('result', '0', '0', 'i8*') }}};
return 0;
}
var id;
@@ -118,15 +118,15 @@ LibraryManager.library = {
FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link.
8; // DT_REG, regular file.
}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}}
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}};
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}};
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}};
for (var i = 0; i < name.length; i++) {
- {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}};
}
- {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}
- {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
+ {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}};
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}};
+ {{{ makeSetValue('result', '0', 'entry', 'i8*') }}};
stream.position++;
return 0;
},
@@ -149,8 +149,6 @@ LibraryManager.library = {
}
return {{{ makeGetValue(0, '_readdir.result', 'i8*') }}};
},
- __01readdir64_: 'readdir',
- // TODO: Check if we need to link any other aliases.
// ==========================================================================
// utime.h
@@ -207,13 +205,13 @@ LibraryManager.library = {
var length = i;
if (allSlashes) {
// All slashes result in a single slash.
- {{{ makeSetValue('path', '1', '0', 'i8') }}}
+ {{{ makeSetValue('path', '1', '0', 'i8') }}};
return [path, -1];
} else {
// Strip trailing slashes.
while (slashPositions.length &&
slashPositions[slashPositions.length - 1] == length - 1) {
- {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}}
+ {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}};
length--;
}
return [path, slashPositions.pop()];
@@ -227,16 +225,15 @@ LibraryManager.library = {
var result = ___libgenSplitName(path);
return result[0] + result[1] + 1;
},
- __xpg_basename: 'basename',
dirname__deps: ['__libgenSplitName'],
dirname: function(path) {
// char *dirname(char *path);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/dirname.html
var result = ___libgenSplitName(path);
if (result[1] == 0) {
- {{{ makeSetValue('result[0]', 1, '0', 'i8') }}}
+ {{{ makeSetValue('result[0]', 1, '0', 'i8') }}};
} else if (result[1] !== -1) {
- {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}}
+ {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}};
}
return result[0];
},
@@ -257,22 +254,22 @@ LibraryManager.library = {
{{{ makeSetValue('buf', C_STRUCTS.stat.st_dev, 'stat.dev', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_dev_padding, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_ino_truncated, 'stat.ino', 'i32') }}};
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_rdev_padding, '0', 'i32') }}};
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}};
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -395,14 +392,6 @@ LibraryManager.library = {
_umask.cmask = newMask;
return oldMask;
},
- stat64: 'stat',
- fstat64: 'fstat',
- lstat64: 'lstat',
- __01fstat64_: 'fstat',
- __01stat64_: 'stat',
- __01lstat64_: 'lstat',
-
- // TODO: Check if other aliases are needed.
// ==========================================================================
// sys/statvfs.h
@@ -414,17 +403,17 @@ LibraryManager.library = {
// int statvfs(const char *restrict path, struct statvfs *restrict buf);
// NOTE: None of the constants here are true. We're just returning safe and
// sane values.
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}} // ST_NOSUID
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}}; // ST_NOSUID
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}};
return 0;
},
fstatvfs__deps: ['statvfs'],
@@ -433,8 +422,6 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/009604499/functions/statvfs.html
return _statvfs(0, buf);
},
- __01statvfs64_: 'statvfs',
- __01fstatvfs64_: 'fstatvfs',
// ==========================================================================
// fcntl.h
@@ -515,7 +502,7 @@ LibraryManager.library = {
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
var offset = {{{ C_STRUCTS.flock.l_type }}};
// We're always unlocked.
- {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}
+ {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}};
return 0;
case {{{ cDefine('F_SETLK') }}}:
case {{{ cDefine('F_SETLKW') }}}:
@@ -571,6 +558,25 @@ LibraryManager.library = {
},
// ==========================================================================
+ // nl_types.h
+ // ==========================================================================
+
+ catopen: function(name, oflag) {
+ // nl_catd catopen (const char *name, int oflag)
+ return -1;
+ },
+
+ catgets: function(catd, set_id, msg_id, s) {
+ // char *catgets (nl_catd catd, int set_id, int msg_id, const char *s)
+ return s;
+ },
+
+ catclose: function(catd) {
+ // int catclose (nl_catd catd)
+ return 0;
+ },
+
+ // ==========================================================================
// poll.h
// ==========================================================================
@@ -594,7 +600,7 @@ LibraryManager.library = {
}
mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}};
if (mask) nonzero++;
- {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}}
+ {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}};
}
return nonzero;
},
@@ -1174,7 +1180,7 @@ LibraryManager.library = {
} else {
var length = Math.min(len, value.length);
for (var i = 0; i < length; i++) {
- {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}};
}
if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}}
return i;
@@ -1223,9 +1229,9 @@ LibraryManager.library = {
// int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
// http://linux.die.net/man/2/getresuid
// We have just one process/group/user, all with ID 0.
- {{{ makeSetValue('ruid', '0', '0', 'i32') }}}
- {{{ makeSetValue('euid', '0', '0', 'i32') }}}
- {{{ makeSetValue('suid', '0', '0', 'i32') }}}
+ {{{ makeSetValue('ruid', '0', '0', 'i32') }}};
+ {{{ makeSetValue('euid', '0', '0', 'i32') }}};
+ {{{ makeSetValue('suid', '0', '0', 'i32') }}};
return 0;
},
getresgid: 'getresuid',
@@ -1237,7 +1243,7 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
} else {
- {{{ makeSetValue('grouplist', '0', '0', 'i32') }}}
+ {{{ makeSetValue('grouplist', '0', '0', 'i32') }}};
return 1;
}
},
@@ -1270,10 +1276,10 @@ LibraryManager.library = {
}
var length = Math.min(namelen, host.length);
for (var i = 0; i < length; i++) {
- {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}};
}
if (namelen > length) {
- {{{ makeSetValue('name', 'i', '0', 'i8') }}}
+ {{{ makeSetValue('name', 'i', '0', 'i8') }}};
return 0;
} else {
___setErrNo(ERRNO_CODES.ENAMETOOLONG);
@@ -1390,8 +1396,8 @@ LibraryManager.library = {
for (var i = 0; i < nbytes; i += 2) {
var first = {{{ makeGetValue('src', 'i', 'i8') }}};
var second = {{{ makeGetValue('src', 'i + 1', 'i8') }}};
- {{{ makeSetValue('dest', 'i', 'second', 'i8') }}}
- {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}}
+ {{{ makeSetValue('dest', 'i', 'second', 'i8') }}};
+ {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}};
}
},
tcgetpgrp: function(fildes) {
@@ -1565,14 +1571,6 @@ LibraryManager.library = {
if (bytes != 0) self.alloc(bytes);
return ret; // Previous break location.
},
- open64: 'open',
- lseek64: 'lseek',
- ftruncate64: 'ftruncate',
- __01open64_: 'open',
- __01lseek64_: 'lseek',
- __01truncate64_: 'truncate',
- __01ftruncate64_: 'ftruncate',
- // TODO: Check if any other aliases are needed.
// ==========================================================================
// stdio.h
@@ -1804,7 +1802,7 @@ LibraryManager.library = {
break;
case 'X':
case 'x':
- {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}
+ {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}};
break;
case 'F':
case 'f':
@@ -1815,15 +1813,15 @@ LibraryManager.library = {
case 'E':
// fallthrough intended
if (long_) {
- {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}
+ {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}};
} else {
- {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}}
+ {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}};
}
break;
case 's':
var array = intArrayFromString(text);
for (var j = 0; j < array.length; j++) {
- {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}
+ {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}};
}
break;
}
@@ -2259,7 +2257,7 @@ LibraryManager.library = {
case 'n': {
// Write the length written so far to the next parameter.
var ptr = getNextArg('i32*');
- {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}}
+ {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}};
break;
}
case '%': {
@@ -2386,9 +2384,9 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.ESPIPE);
return -1;
}
- {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}
+ {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}};
var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0);
- {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}
+ {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}};
return 0;
},
fgets__deps: ['fgetc'],
@@ -2405,9 +2403,9 @@ LibraryManager.library = {
if (streamObj.error || (streamObj.eof && i == 0)) return 0;
else if (streamObj.eof) break;
}
- {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}}
+ {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}};
}
- {{{ makeSetValue('s', 'i', '0', 'i8') }}}
+ {{{ makeSetValue('s', 'i', '0', 'i8') }}};
return s;
},
gets__deps: ['fgets'],
@@ -2471,7 +2469,7 @@ LibraryManager.library = {
// int fputc(int c, FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
var chr = unSign(c & 0xFF);
- {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}}
+ {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}};
var ret = _write(stream, _fputc.ret, 1);
if (ret == -1) {
var streamObj = FS.getStream(stream);
@@ -2525,7 +2523,7 @@ LibraryManager.library = {
return 0;
}
while (streamObj.ungotten.length && bytesToRead > 0) {
- {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}}
+ {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}};
bytesToRead--;
bytesRead++;
}
@@ -2568,7 +2566,6 @@ LibraryManager.library = {
return 0;
},
fseeko: 'fseek',
- fseeko64: 'fseek',
fsetpos__deps: ['$FS', 'lseek', '__setErrNo', '$ERRNO_CODES'],
fsetpos: function(stream, pos) {
// int fsetpos(FILE *stream, const fpos_t *pos);
@@ -2605,7 +2602,6 @@ LibraryManager.library = {
}
},
ftello: 'ftell',
- ftello64: 'ftell',
fwrite__deps: ['$FS', 'write'],
fwrite: function(ptr, size, nitems, stream) {
// size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
@@ -2897,22 +2893,6 @@ LibraryManager.library = {
},
#endif
- fopen64: 'fopen',
- __01fopen64_: 'fopen',
- __01freopen64_: 'freopen',
- __01fseeko64_: 'fseek',
- __01ftello64_: 'ftell',
- __01tmpfile64_: 'tmpfile',
- __isoc99_fscanf: 'fscanf',
- // TODO: Check if any other aliases are needed.
- _IO_getc: 'getc',
- _IO_putc: 'putc',
- _ZNSo3putEc: 'putchar',
- _ZNSo5flushEv__deps: ['fflush', 'stdout'],
- _ZNSo5flushEv: function() {
- _fflush({{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}});
- },
-
// ==========================================================================
// sys/mman.h
// ==========================================================================
@@ -2950,7 +2930,6 @@ LibraryManager.library = {
_mmap.mappings[ptr] = { malloc: ptr, num: num, allocated: allocated };
return ptr;
},
- __01mmap64_: 'mmap',
munmap: function(start, num) {
if (!_mmap.mappings) _mmap.mappings = {};
@@ -3147,7 +3126,7 @@ LibraryManager.library = {
// Set end pointer.
if (endptr) {
- {{{ makeSetValue('endptr', 0, 'str', '*') }}}
+ {{{ makeSetValue('endptr', 0, 'str', '*') }}};
}
// Unsign if needed.
@@ -3233,7 +3212,7 @@ LibraryManager.library = {
// Set end pointer.
if (endptr) {
- {{{ makeSetValue('endptr', 0, 'str', '*') }}}
+ {{{ makeSetValue('endptr', 0, 'str', '*') }}};
}
try {
@@ -3327,7 +3306,7 @@ LibraryManager.library = {
poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC);
envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}},
'i8*', ALLOC_STATIC);
- {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}}
+ {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}};
{{{ makeSetValue(makeGlobalUse('_environ'), 0, 'envPtr', 'i8*') }}};
} else {
envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}};
@@ -3451,7 +3430,7 @@ LibraryManager.library = {
var limit = Math.min(nelem, 3);
var doubleSize = {{{ Runtime.getNativeTypeSize('double') }}};
for (var i = 0; i < limit; i++) {
- {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}}
+ {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}};
}
return limit;
},
@@ -3480,9 +3459,9 @@ LibraryManager.library = {
} else {
var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1.
for (var i = 0; i < size; i++) {
- {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}};
}
- {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}}
+ {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}};
return resolved_name;
}
},
@@ -3690,7 +3669,7 @@ LibraryManager.library = {
var padding = 0, curr = 0, i = 0;
while ((i|0) < (num|0)) {
curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}};
- {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}}
+ {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}};
padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0);
i = (i+1)|0;
}
@@ -3743,7 +3722,7 @@ LibraryManager.library = {
if ({{{ makeGetValue('pdest', 'len+i', 'i8') }}} == 0) break;
i ++;
if (i == num) {
- {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}}
+ {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}};
break;
}
}
@@ -3830,6 +3809,7 @@ LibraryManager.library = {
},
strnlen: function(ptr, num) {
+ num = num >>> 0;
for (var i = 0; i < num; i++) {
if ({{{ makeGetValue('ptr', 0, 'i8') }}} == 0) return i;
ptr++;
@@ -4110,7 +4090,7 @@ LibraryManager.library = {
var i16size = {{{ Runtime.getNativeTypeSize('i16') }}};
var arr = _malloc(values.length * i16size);
for (var i = 0; i < values.length; i++) {
- {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}}
+ {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}};
}
me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL);
}
@@ -4138,7 +4118,7 @@ LibraryManager.library = {
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
var arr = _malloc(values.length * i32size);
for (var i = 0; i < values.length; i++) {
- {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}
+ {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}};
}
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
}
@@ -4165,7 +4145,7 @@ LibraryManager.library = {
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
var arr = _malloc(values.length * i32size);
for (var i = 0; i < values.length; i++) {
- {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}
+ {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}};
}
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
}
@@ -4311,6 +4291,8 @@ LibraryManager.library = {
abort('trap!');
},
+ llvm_prefetch: function(){},
+
__assert_fail: function(condition, filename, line, func) {
ABORT = true;
throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
@@ -4367,9 +4349,9 @@ LibraryManager.library = {
#if EXCEPTION_DEBUG
Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + stackTrace());
#endif
- {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}}
- {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}}
- {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}};
+ {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}};
+ {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}};
if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
__ZSt18uncaught_exceptionv.uncaught_exception = 1;
} else {
@@ -4415,18 +4397,18 @@ LibraryManager.library = {
__THREW__ = 0;
#endif
// Clear type.
- {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}};
// Call destructor if one is registered then clear it.
var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'void*') }}};
if (destructor) {
Runtime.dynCall('vi', destructor, [ptr]);
- {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}};
}
// Free ptr if it isn't null.
if (ptr) {
___cxa_free_exception(ptr);
- {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}};
}
},
__cxa_get_exception_ptr__deps: ['llvm_eh_exception'],
@@ -4447,14 +4429,6 @@ LibraryManager.library = {
throw exception;
},
- _Unwind_Resume_or_Rethrow: function(ptr) {
- {{{ makeThrow('ptr') }}};
- },
- _Unwind_RaiseException: function(ptr) {
- {{{ makeThrow('ptr') }}};
- },
- _Unwind_DeleteException: function(ptr) {},
-
terminate: '__cxa_call_unexpected',
__gxx_personality_v0__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'],
@@ -4567,7 +4541,20 @@ LibraryManager.library = {
}
},
- _ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included
+ // Destructors for std::exception since we don't have them implemented in libcxx as we aren't using libcxxabi.
+ // These are also needed for the dlmalloc tests.
+ _ZNSt9exceptionD1Ev: function() {},
+ _ZNSt9exceptionD2Ev: function() {},
+
+ _ZNKSt9exception4whatEv__deps: ['_malloc'],
+ _ZNKSt9exception4whatEv: function() {
+ if (!__ZNKSt9exception4whatEv.buffer) {
+ var name = "std::exception";
+ __ZNKSt9exception4whatEv.buffer = _malloc(name.length + 1);
+ writeStringToMemory(name, __ZNKSt9exception4whatEv.buffer);
+ }
+ return __ZNKSt9exception4whatEv.buffer;
+ },
_ZNSt9type_infoD2Ev: function(){},
@@ -4837,11 +4824,11 @@ LibraryManager.library = {
cbrtl: 'cbrt',
modf: function(x, intpart) {
- {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}
+ {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}};
return x - {{{ makeGetValue('intpart', 0, 'double') }}};
},
modff: function(x, intpart) {
- {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}}
+ {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}};
return x - {{{ makeGetValue('intpart', 0, 'float') }}};
},
frexp: function(x, exp_addr) {
@@ -4857,7 +4844,7 @@ LibraryManager.library = {
if (exp_ === raw_exp) exp_ += 1;
sig = sign*x/Math.pow(2, exp_);
}
- {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}}
+ {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}};
return sig;
},
frexpf: 'frexp',
@@ -5365,7 +5352,7 @@ LibraryManager.library = {
time: function(ptr) {
var ret = Math.floor(Date.now()/1000);
if (ptr) {
- {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}}
+ {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}};
}
return ret;
},
@@ -5392,9 +5379,9 @@ LibraryManager.library = {
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}},
0).getTime() / 1000;
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}};
var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
return timestamp;
},
timelocal: 'mktime',
@@ -5407,15 +5394,15 @@ LibraryManager.library = {
gmtime_r__deps: ['__tm_timezone'],
gmtime_r: function(time, tmPtr) {
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}};
var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC
start.setUTCDate(1);
start.setUTCMonth(0);
@@ -5424,8 +5411,8 @@ LibraryManager.library = {
start.setUTCSeconds(0);
start.setUTCMilliseconds(0);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}};
return tmPtr;
},
@@ -5448,23 +5435,23 @@ LibraryManager.library = {
localtime_r: function(time, tmPtr) {
_tzset();
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}};
var start = new Date(date.getFullYear(), 0, 1);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}};
var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}};
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}};
return tmPtr;
},
@@ -5482,9 +5469,9 @@ LibraryManager.library = {
var timePart = formatted.match(/\d{2}:\d{2}:\d{2}/)[0];
formatted = datePart + timePart + ' ' + date.getFullYear() + '\n';
formatted.split('').forEach(function(chr, index) {
- {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}}
+ {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}};
});
- {{{ makeSetValue('buf', '25', '0', 'i8') }}}
+ {{{ makeSetValue('buf', '25', '0', 'i8') }}};
return buf;
},
@@ -5514,18 +5501,18 @@ LibraryManager.library = {
if (_tzset.called) return;
_tzset.called = true;
- {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}
+ {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}};
var winter = new Date(2000, 0, 1);
var summer = new Date(2000, 6, 1);
- {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}
+ {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}};
var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1];
var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
- {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}}
- {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}}
+ {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}};
+ {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}};
},
stime__deps: ['$ERRNO_CODES', '__setErrNo'],
@@ -6095,15 +6082,15 @@ LibraryManager.library = {
*/
var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0);
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}};
// we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F
// TODO: not sure that intArrayFromString handles all unicode characters correctly
@@ -6134,8 +6121,8 @@ LibraryManager.library = {
var seconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_sec, 'i32') }}};
var nanoseconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
if (rmtp !== 0) {
- {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}}
- {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}}
+ {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}};
+ {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}};
}
return _usleep((seconds * 1e6) + (nanoseconds / 1000));
},
@@ -6166,7 +6153,7 @@ LibraryManager.library = {
} else {
nsec = _emscripten_get_now_res();
}
- {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}}
+ {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}};
{{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, 'nsec', 'i32') }}} // resolution is milliseconds
return 0;
},
@@ -6250,9 +6237,6 @@ LibraryManager.library = {
label = label|0;
table = table|0;
var i = 0;
-#if ASSERTIONS
- if ((label|0) == 0) abort(121);
-#endif
setjmpId = (setjmpId+1)|0;
{{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}};
while ((i|0) < {{{ 2*MAX_SETJMPS }}}) {
@@ -6310,6 +6294,10 @@ LibraryManager.library = {
throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 };
#endif
},
+ emscripten_longjmp__deps: ['longjmp'],
+ emscripten_longjmp: function(env, value) {
+ _longjmp(env, value);
+ },
// ==========================================================================
// signal.h
@@ -6847,7 +6835,7 @@ LibraryManager.library = {
__setErrNo__postset: '___errno_state = Runtime.staticAlloc(4); {{{ makeSetValue("___errno_state", 0, 0, "i32") }}};',
__setErrNo: function(value) {
// For convenient setting and returning of errno.
- {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}}
+ {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}};
return value;
},
__errno_location__deps: ['__setErrNo'],
@@ -6871,15 +6859,14 @@ LibraryManager.library = {
// int setrlimit(int resource, const struct rlimit *rlp)
return 0;
},
- __01getrlimit64_: 'getrlimit',
// TODO: Implement for real. We just do time used, and no useful data
getrusage: function(resource, rlp) {
// int getrusage(int resource, struct rusage *rlp);
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}}
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}}
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}}
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}}
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}};
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}};
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}};
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}};
return 0;
},
@@ -6943,8 +6930,8 @@ LibraryManager.library = {
void **restrict stackaddr, size_t *restrict stacksize); */
/*FIXME: assumes that there is only one thread, and that attr is the
current thread*/
- {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}}
- {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}
+ {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}};
+ {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}};
return 0;
},
@@ -6962,7 +6949,7 @@ LibraryManager.library = {
if (key == 0) {
return ERRNO_CODES.EINVAL;
}
- {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}}
+ {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}};
// values start at 0
PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0;
PTHREAD_SPECIFIC_NEXT_KEY++;
@@ -7020,7 +7007,7 @@ LibraryManager.library = {
posix_memalign__deps: ['memalign'],
posix_memalign: function(memptr, alignment, size) {
var ptr = _memalign(alignment, size);
- {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}}
+ {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}};
return 0;
},
@@ -7062,7 +7049,7 @@ LibraryManager.library = {
if (addr === null) {
return 0;
}
- {{{ makeSetValue('inp', '0', 'addr', 'i32') }}}
+ {{{ makeSetValue('inp', '0', 'addr', 'i32') }}};
return 1;
},
@@ -7221,7 +7208,7 @@ LibraryManager.library = {
if (ret === null) {
return 0;
}
- {{{ makeSetValue('dst', '0', 'ret', 'i32') }}}
+ {{{ makeSetValue('dst', '0', 'ret', 'i32') }}};
return 1;
},
_inet_pton6_raw__deps: ['htons'],
@@ -7344,6 +7331,12 @@ LibraryManager.library = {
// netdb.h
// ==========================================================================
+ __h_errno_state: 'allocate(1, "i32", ALLOC_STATIC)',
+ __h_errno_location__deps: ['__h_errno_state'],
+ __h_errno_location: function() {
+ return ___h_errno_state;
+ },
+
// We can't actually resolve hostnames in the browser, so instead
// we're generating fake IP addresses with lookup_name that we can
// resolve later on with lookup_addr.
@@ -7399,6 +7392,7 @@ LibraryManager.library = {
gethostbyaddr: function (addr, addrlen, type) {
if (type !== {{{ cDefine('AF_INET') }}}) {
___setErrNo(ERRNO_CODES.EAFNOSUPPORT);
+ // TODO: set h_errno
return null;
}
addr = {{{ makeGetValue('addr', '0', 'i32') }}}; // addr is in_addr
@@ -7419,18 +7413,18 @@ LibraryManager.library = {
var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here
var nameBuf = _malloc(name.length+1);
writeStringToMemory(name, nameBuf);
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}};
var aliasesBuf = _malloc(4);
- {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}}
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}}
+ {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}};
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}};
var afinet = {{{ cDefine('AF_INET') }}};
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}}
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}};
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}};
var addrListBuf = _malloc(12);
- {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}}
- {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}}
- {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}}
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}}
+ {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}};
+ {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}};
+ {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}};
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}};
return ret;
},
@@ -9176,6 +9170,30 @@ LibraryManager.library = {
// misc shims for musl
__lockfile: function() { return 1 },
__unlockfile: function(){},
+
+ // misc definitions to avoid unnecessary unresolved symbols from fastcomp
+ emscripten_prep_setjmp: true,
+ emscripten_check_longjmp: true,
+ emscripten_get_longjmp_result: true,
+ emscripten_setjmp: true,
+ emscripten_preinvoke: true,
+ emscripten_postinvoke: true,
+ emscripten_resume: true,
+ emscripten_landingpad: true,
+ getHigh32: true,
+ setHigh32: true,
+ FtoILow: true,
+ FtoIHigh: true,
+ DtoILow: true,
+ DtoIHigh: true,
+ BDtoILow: true,
+ BDtoIHigh: true,
+ SItoF: true,
+ UItoF: true,
+ SItoD: true,
+ UItoD: true,
+ BItoD: true,
+ llvm_dbg_value: true,
};
function autoAddDeps(object, name) {
@@ -9188,7 +9206,7 @@ function autoAddDeps(object, name) {
}
// Add aborting stubs for various libc stuff needed by libc++
-['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) {
+['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach'].forEach(function(aborter) {
LibraryManager.library[aborter] = function aborting_stub() { throw 'TODO: ' + aborter };
});
diff --git a/src/library_browser.js b/src/library_browser.js
index d5e35339..458a8dd2 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -775,6 +775,15 @@ mergeInto(LibraryManager.library, {
return;
}
+ // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize
+ // VBO double-buffering and reduce GPU stalls.
+#if FULL_ES2
+ GL.newRenderingFrameStarted();
+#endif
+#if LEGACY_GL_EMULATION
+ GL.newRenderingFrameStarted();
+#endif
+
if (Module['preMainLoop']) {
Module['preMainLoop']();
}
diff --git a/src/library_gl.js b/src/library_gl.js
index a4da4220..3055309b 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -57,6 +57,7 @@ var LibraryGL = {
unpackAlignment: 4, // default alignment is 4 bytes
init: function() {
+ GL.createLog2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
Browser.moduleContextCreatedCallbacks.push(GL.initExtensions);
},
@@ -81,36 +82,58 @@ var LibraryGL = {
miniTempBuffer: null,
miniTempBufferViews: [0], // index i has the view of size i+1
- // Large temporary buffers
+ // When user GL code wants to render from client-side memory, we need to upload the vertex data to a temp VBO
+ // for rendering. Maintain a set of temp VBOs that are created-on-demand to appropriate sizes, and never destroyed.
+ // Also, for best performance the VBOs are double-buffered, i.e. every second frame we switch the set of VBOs we
+ // upload to, so that rendering from the previous frame is not disturbed by uploading from new data to it, which
+ // could cause a GPU-CPU pipeline stall.
+ // Note that index buffers are not double-buffered (at the moment) in this manner.
MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}},
- tempBufferIndexLookup: null,
- tempVertexBuffers: null,
- tempIndexBuffers: null,
+ tempVertexBuffers1: [],
+ tempVertexBufferCounters1: [],
+ tempVertexBuffers2: [],
+ tempVertexBufferCounters2: [],
+ // Maximum number of temp VBOs of one size to maintain, after that we start reusing old ones, which is safe but can give
+ // a performance impact. If CPU-GPU stalls are a problem, increasing this might help.
+ numTempVertexBuffersPerSize: 64, // (const)
+ tempIndexBuffers: [],
tempQuadIndexBuffer: null,
- generateTempBuffers: function(quads) {
- GL.tempBufferIndexLookup = new Uint8Array(GL.MAX_TEMP_BUFFER_SIZE+1);
- GL.tempVertexBuffers = [];
- GL.tempIndexBuffers = [];
- var last = -1, curr = -1;
- var size = 1;
- for (var i = 0; i <= GL.MAX_TEMP_BUFFER_SIZE; i++) {
- if (i > size) {
- size <<= 1;
+ // Precompute a lookup table for the function ceil(log2(x)), i.e. how many bits are needed to represent x, or,
+ // if x was rounded up to next pow2, which index is the single '1' bit at?
+ // Then log2ceilLookup[x] returns ceil(log2(x)).
+ log2ceilLookup: null,
+ createLog2ceilLookup: function(maxValue) {
+ GL.log2ceilLookup = new Uint8Array(maxValue+1);
+ var log2 = 0;
+ var pow2 = 1;
+ GL.log2ceilLookup[0] = 0;
+ for(var i = 1; i <= maxValue; ++i) {
+ if (i > pow2) {
+ pow2 <<= 1;
+ ++log2;
}
- if (size != last) {
- curr++;
- GL.tempVertexBuffers[curr] = GLctx.createBuffer();
- GLctx.bindBuffer(GLctx.ARRAY_BUFFER, GL.tempVertexBuffers[curr]);
- GLctx.bufferData(GLctx.ARRAY_BUFFER, size, GLctx.DYNAMIC_DRAW);
- GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null);
- GL.tempIndexBuffers[curr] = GLctx.createBuffer();
- GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[curr]);
- GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, size, GLctx.DYNAMIC_DRAW);
- GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, null);
- last = size;
+ GL.log2ceilLookup[i] = log2;
+ }
+ },
+
+ generateTempBuffers: function(quads) {
+ var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE];
+ GL.tempVertexBufferCounters1.length = GL.tempVertexBufferCounters2.length = largestIndex+1;
+ GL.tempVertexBuffers1.length = GL.tempVertexBuffers2.length = largestIndex+1;
+ GL.tempIndexBuffers.length = largestIndex+1;
+ for(var i = 0; i <= largestIndex; ++i) {
+ GL.tempIndexBuffers[i] = null; // Created on-demand
+ GL.tempVertexBufferCounters1[i] = GL.tempVertexBufferCounters2[i] = 0;
+ var ringbufferLength = GL.numTempVertexBuffersPerSize;
+ GL.tempVertexBuffers1[i] = [];
+ GL.tempVertexBuffers2[i] = [];
+ var ringbuffer1 = GL.tempVertexBuffers1[i];
+ var ringbuffer2 = GL.tempVertexBuffers2[i];
+ ringbuffer1.length = ringbuffer2.length = ringbufferLength;
+ for(var j = 0; j < ringbufferLength; ++j) {
+ ringbuffer1[j] = ringbuffer2[j] = null; // Created on-demand
}
- GL.tempBufferIndexLookup[i] = curr;
}
if (quads) {
@@ -140,6 +163,53 @@ var LibraryGL = {
}
},
+ getTempVertexBuffer: function getTempVertexBuffer(sizeBytes) {
+ var idx = GL.log2ceilLookup[sizeBytes];
+ var ringbuffer = GL.tempVertexBuffers1[idx];
+ var nextFreeBufferIndex = GL.tempVertexBufferCounters1[idx];
+ GL.tempVertexBufferCounters1[idx] = (GL.tempVertexBufferCounters1[idx]+1) & (GL.numTempVertexBuffersPerSize-1);
+ var vbo = ringbuffer[nextFreeBufferIndex];
+ if (vbo) {
+ return vbo;
+ }
+ var prevVBO = GLctx.getParameter(GLctx.ARRAY_BUFFER_BINDING);
+ ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer();
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, ringbuffer[nextFreeBufferIndex]);
+ GLctx.bufferData(GLctx.ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW);
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, prevVBO);
+ return ringbuffer[nextFreeBufferIndex];
+ },
+
+ getTempIndexBuffer: function getTempIndexBuffer(sizeBytes) {
+ var idx = GL.log2ceilLookup[sizeBytes];
+ var ibo = GL.tempIndexBuffers[idx];
+ if (ibo) {
+ return ibo;
+ }
+ var prevIBO = GLctx.getParameter(GLctx.ELEMENT_ARRAY_BUFFER_BINDING);
+ GL.tempIndexBuffers[idx] = GLctx.createBuffer();
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[idx]);
+ GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, prevIBO);
+ return GL.tempIndexBuffers[idx];
+ },
+
+ // Called at start of each new WebGL rendering frame. This swaps the doublebuffered temp VB memory pointers,
+ // so that every second frame utilizes different set of temp buffers. The aim is to keep the set of buffers
+ // being rendered, and the set of buffers being updated disjoint.
+ newRenderingFrameStarted: function newRenderingFrameStarted() {
+ var vb = GL.tempVertexBuffers1;
+ GL.tempVertexBuffers1 = GL.tempVertexBuffers2;
+ GL.tempVertexBuffers2 = vb;
+ vb = GL.tempVertexBufferCounters1;
+ GL.tempVertexBufferCounters1 = GL.tempVertexBufferCounters2;
+ GL.tempVertexBufferCounters2 = vb;
+ var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE];
+ for(var i = 0; i <= largestIndex; ++i) {
+ GL.tempVertexBufferCounters1[i] = 0;
+ }
+ },
+
// Find a token in a shader source string
findToken: function(source, token) {
function isIdentChar(ch) {
@@ -446,9 +516,6 @@ var LibraryGL = {
preDrawHandleClientVertexAttribBindings: function preDrawHandleClientVertexAttribBindings(count) {
GL.resetBufferBinding = false;
- var used = GL.usedTempBuffers;
- used.length = 0;
-
// TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib
for (var i = 0; i < GL.maxVertexAttribs; ++i) {
var cb = GL.clientBuffers[i];
@@ -457,15 +524,7 @@ var LibraryGL = {
GL.resetBufferBinding = true;
var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count);
- var index = GL.tempBufferIndexLookup[size];
- var buf;
- do {
-#if ASSERTIONS
- assert(index < GL.tempVertexBuffers.length);
-#endif
- buf = GL.tempVertexBuffers[index++];
- } while (used.indexOf(buf) >= 0);
- used.push(buf);
+ var buf = GL.getTempVertexBuffer(size);
GLctx.bindBuffer(GLctx.ARRAY_BUFFER, buf);
GLctx.bufferSubData(GLctx.ARRAY_BUFFER,
0,
@@ -2321,7 +2380,7 @@ var LibraryGL = {
// GL Immediate mode
// See comment in GLEmulation.init()
-#if FULL_ES2 == 0
+#if !FULL_ES2
$GLImmediate__postset: 'GLImmediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GLImmediate.init() });',
#endif
$GLImmediate__deps: ['$Browser', '$GL', '$GLEmulation'],
@@ -2742,14 +2801,6 @@ var LibraryGL = {
this.key0 = -1; // The key of this texture unit must be recomputed when rendering the next time.
GLImmediate.currentRenderer = null; // The currently used renderer must be re-evaluated at next render.
}
- this.traverseState = function(keyView) {
- if (this.key0 == -1) {
- this.recomputeKey();
- }
- keyView.next(this.key0);
- keyView.next(this.key1);
- keyView.next(this.key2);
- };
}
function CTexUnit() {
@@ -2758,26 +2809,55 @@ var LibraryGL = {
this.enabled_tex2D = false;
this.enabled_tex3D = false;
this.enabled_texCube = false;
+ this.texTypesEnabled = 0; // A bitfield combination of the four flags above, used for fast access to operations.
this.traverseState = function CTexUnit_traverseState(keyView) {
- var texUnitType = this.getTexType();
- keyView.next(texUnitType);
- if (!texUnitType) return;
- this.env.traverseState(keyView);
+ if (this.texTypesEnabled) {
+ if (this.env.key0 == -1) {
+ this.env.recomputeKey();
+ }
+ keyView.next(this.texTypesEnabled | (this.env.key0 << 4));
+ keyView.next(this.env.key1);
+ keyView.next(this.env.key2);
+ } else {
+ // For correctness, must traverse a zero value, theoretically a subsequent integer key could collide with this value otherwise.
+ keyView.next(0);
+ }
};
};
// Class impls:
CTexUnit.prototype.enabled = function CTexUnit_enabled() {
- return this.getTexType() != 0;
+ return this.texTypesEnabled;
}
CTexUnit.prototype.genPassLines = function CTexUnit_genPassLines(passOutputVar, passInputVar, texUnitID) {
if (!this.enabled()) {
return ["vec4 " + passOutputVar + " = " + passInputVar + ";"];
}
-
- return this.env.genPassLines(passOutputVar, passInputVar, texUnitID);
+ var lines = this.env.genPassLines(passOutputVar, passInputVar, texUnitID).join('\n');
+
+ var texLoadLines = '';
+ var texLoadRegex = /(texture.*?\(.*?\))/g;
+ var loadCounter = 0;
+ var load;
+
+ // As an optimization, merge duplicate identical texture loads to one var.
+ while(load = texLoadRegex.exec(lines)) {
+ var texLoadExpr = load[1];
+ var secondOccurrence = lines.slice(load.index+1).indexOf(texLoadExpr);
+ if (secondOccurrence != -1) { // And also has a second occurrence of same load expression..
+ // Create new var to store the common load.
+ var prefix = TEXENVJIT_NAMESPACE_PREFIX + 'env' + texUnitID + "_";
+ var texLoadVar = prefix + 'texload' + loadCounter++;
+ var texLoadLine = 'vec4 ' + texLoadVar + ' = ' + texLoadExpr + ';\n';
+ texLoadLines += texLoadLine + '\n'; // Store the generated texture load statements in a temp string to not confuse regex search in progress.
+ lines = lines.split(texLoadExpr).join(texLoadVar);
+ // Reset regex search, since we modified the string.
+ texLoadRegex = /(texture.*\(.*\))/g;
+ }
+ }
+ return [texLoadLines + lines];
}
CTexUnit.prototype.getTexType = function CTexUnit_getTexType() {
@@ -2898,13 +2978,18 @@ var LibraryGL = {
var alphaLines = this.genCombinerLines(false, alphaVar,
passInputVar, texUnitID,
this.alphaCombiner, this.alphaSrc, this.alphaOp);
+
+ // Generate scale, but avoid generating an identity op that multiplies by one.
+ var scaledColor = (this.colorScale == 1) ? colorVar : (colorVar + " * " + valToFloatLiteral(this.colorScale));
+ var scaledAlpha = (this.alphaScale == 1) ? alphaVar : (alphaVar + " * " + valToFloatLiteral(this.alphaScale));
+
var line = [
"vec4 " + passOutputVar,
" = ",
"vec4(",
- colorVar + " * " + valToFloatLiteral(this.colorScale),
+ scaledColor,
", ",
- alphaVar + " * " + valToFloatLiteral(this.alphaScale),
+ scaledAlpha,
")",
";",
].join("");
@@ -3084,12 +3169,7 @@ var LibraryGL = {
traverseState: function(keyView) {
for (var i = 0; i < s_texUnits.length; i++) {
- var texUnit = s_texUnits[i];
- var enabled = texUnit.enabled();
- keyView.next(enabled);
- if (enabled) {
- texUnit.traverseState(keyView);
- }
+ s_texUnits[i].traverseState(keyView);
}
},
@@ -3113,24 +3193,28 @@ var LibraryGL = {
if (!cur.enabled_tex1D) {
GLImmediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
cur.enabled_tex1D = true;
+ cur.texTypesEnabled |= 1;
}
break;
case GL_TEXTURE_2D:
if (!cur.enabled_tex2D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex2D = true;
+ cur.texTypesEnabled |= 2;
}
break;
case GL_TEXTURE_3D:
if (!cur.enabled_tex3D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex3D = true;
+ cur.texTypesEnabled |= 4;
}
break;
case GL_TEXTURE_CUBE_MAP:
if (!cur.enabled_texCube) {
GLImmediate.currentRenderer = null;
cur.enabled_texCube = true;
+ cur.texTypesEnabled |= 8;
}
break;
}
@@ -3143,24 +3227,28 @@ var LibraryGL = {
if (cur.enabled_tex1D) {
GLImmediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
cur.enabled_tex1D = false;
+ cur.texTypesEnabled &= ~1;
}
break;
case GL_TEXTURE_2D:
if (cur.enabled_tex2D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex2D = false;
+ cur.texTypesEnabled &= ~2;
}
break;
case GL_TEXTURE_3D:
if (cur.enabled_tex3D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex3D = false;
+ cur.texTypesEnabled &= ~4;
}
break;
case GL_TEXTURE_CUBE_MAP:
if (cur.enabled_texCube) {
GLImmediate.currentRenderer = null;
cur.enabled_texCube = false;
+ cur.texTypesEnabled &= ~8;
}
break;
}
@@ -3514,6 +3602,11 @@ var LibraryGL = {
GLImmediate.enabledClientAttributes[name] = true;
GLImmediate.setClientAttribute(name, size, type, 0, GLImmediate.rendererComponentPointer);
GLImmediate.rendererComponentPointer += size * GL.byteSizeByType[type - GL.byteSizeByTypeRoot];
+#if GL_FFP_ONLY
+ // We can enable the correct attribute stream index immediately here, since the same attribute in each shader
+ // will be bound to this same index.
+ GL.enableVertexAttribArray(name);
+#endif
} else {
GLImmediate.rendererComponents[name]++;
}
@@ -3535,7 +3628,6 @@ var LibraryGL = {
// we maintain a cache of renderers, optimized to not generate garbage
var attributes = GLImmediate.liveClientAttributes;
var cacheMap = GLImmediate.rendererCache;
- var temp;
var keyView = cacheMap.getStaticKeyView().reset();
// By attrib state:
@@ -3543,7 +3635,6 @@ var LibraryGL = {
for (var i = 0; i < attributes.length; i++) {
enabledAttributesKey |= 1 << attributes[i].name;
}
- keyView.next(enabledAttributesKey);
// By fog state:
var fogParam = 0;
@@ -3560,13 +3651,17 @@ var LibraryGL = {
break;
}
}
- keyView.next(fogParam);
+ keyView.next((enabledAttributesKey << 2) | fogParam);
+#if !GL_FFP_ONLY
// By cur program:
keyView.next(GL.currProgram);
if (!GL.currProgram) {
+#endif
GLImmediate.TexEnvJIT.traverseState(keyView);
+#if !GL_FFP_ONLY
}
+#endif
// If we don't already have it, create it.
var renderer = keyView.get();
@@ -3772,7 +3867,7 @@ var LibraryGL = {
this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, aTexCoordPrefix + i);
}
}
-
+ this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color');
if (!useCurrProgram) {
// Temporarily switch to the program so we can set our sampler uniforms early.
var prevBoundProg = GLctx.getParameter(GLctx.CURRENT_PROGRAM);
@@ -3784,6 +3879,9 @@ var LibraryGL = {
GLctx.uniform1i(texSamplerLoc, texUnitID);
}
}
+ // The default color attribute value is not the same as the default for all other attribute streams (0,0,0,1) but (1,1,1,1),
+ // so explicitly set it right at start.
+ GLctx.vertexAttrib4fv(this.colorLocation, [1,1,1,1]);
GLctx.useProgram(prevBoundProg);
}
@@ -3791,7 +3889,6 @@ var LibraryGL = {
for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
this.textureMatrixLocations[i] = GLctx.getUniformLocation(this.program, 'u_textureMatrix' + i);
}
- this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color');
this.normalLocation = GLctx.getAttribLocation(this.program, 'a_normal');
this.modelViewLocation = GLctx.getUniformLocation(this.program, 'u_modelView');
@@ -3822,7 +3919,7 @@ var LibraryGL = {
#if ASSERTIONS
assert(end <= GL.MAX_TEMP_BUFFER_SIZE, 'too much vertex data');
#endif
- arrayBuffer = GL.tempVertexBuffers[GL.tempBufferIndexLookup[end]];
+ arrayBuffer = GL.getTempVertexBuffer(end);
// TODO: consider using the last buffer we bound, if it was larger. downside is larger buffer, but we might avoid rebinding and preparing
} else {
arrayBuffer = GL.currArrayBuffer;
@@ -3884,11 +3981,9 @@ var LibraryGL = {
#if GL_FFP_ONLY
if (!GL.currArrayBuffer) {
GLctx.vertexAttribPointer(GLImmediate.VERTEX, posAttr.size, posAttr.type, false, GLImmediate.stride, posAttr.offset);
- GL.enableVertexAttribArray(GLImmediate.VERTEX);
if (this.hasNormal) {
var normalAttr = clientAttributes[GLImmediate.NORMAL];
GLctx.vertexAttribPointer(GLImmediate.NORMAL, normalAttr.size, normalAttr.type, true, GLImmediate.stride, normalAttr.offset);
- GL.enableVertexAttribArray(GLImmediate.NORMAL);
}
}
#else
@@ -3911,11 +4006,9 @@ var LibraryGL = {
var texAttr = clientAttributes[attribLoc];
if (texAttr.size) {
GLctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GLImmediate.stride, texAttr.offset);
- GL.enableVertexAttribArray(attribLoc);
} else {
// These two might be dangerous, but let's try them.
GLctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
- GL.disableVertexAttribArray(attribLoc);
}
}
#else
@@ -3950,21 +4043,18 @@ var LibraryGL = {
#if GL_FFP_ONLY
if (!GL.currArrayBuffer) {
GLctx.vertexAttribPointer(GLImmediate.COLOR, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset);
- GL.enableVertexAttribArray(GLImmediate.COLOR);
}
#else
GLctx.vertexAttribPointer(this.colorLocation, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset);
GLctx.enableVertexAttribArray(this.colorLocation);
#endif
- } else if (this.hasColor) {
-#if GL_FFP_ONLY
- GL.disableVertexAttribArray(GLImmediate.COLOR);
- GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor);
-#else
+ }
+#if !GL_FFP_ONLY
+ else if (this.hasColor) {
GLctx.disableVertexAttribArray(this.colorLocation);
GLctx.vertexAttrib4fv(this.colorLocation, GLImmediate.clientColor);
-#endif
}
+#endif
if (this.hasFog) {
if (this.fogColorLocation) GLctx.uniform4fv(this.fogColorLocation, GLEmulation.fogColor);
if (this.fogEndLocation) GLctx.uniform1f(this.fogEndLocation, GLEmulation.fogEnd);
@@ -3991,6 +4081,7 @@ var LibraryGL = {
}
if (!GL.currProgram) {
GLctx.useProgram(null);
+ GLImmediate.fixedFunctionProgram = 0;
}
if (!GL.currArrayBuffer) {
GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null);
@@ -4138,11 +4229,12 @@ var LibraryGL = {
if (!Module.useWebGL) return; // a 2D canvas may be currently used TODO: make sure we are actually called in that case
- GLImmediate.TexEnvJIT.init(GLctx);
-
// User can override the maximum number of texture units that we emulate. Using fewer texture units increases runtime performance
// slightly, so it is advantageous to choose as small value as needed.
GLImmediate.MAX_TEXTURES = Module['GL_MAX_TEXTURE_IMAGE_UNITS'] || GLctx.getParameter(GLctx.MAX_TEXTURE_IMAGE_UNITS);
+
+ GLImmediate.TexEnvJIT.init(GLctx, GLImmediate.MAX_TEXTURES);
+
GLImmediate.NUM_ATTRIBUTES = 3 /*pos+normal+color attributes*/ + GLImmediate.MAX_TEXTURES;
GLImmediate.clientAttributes = [];
GLEmulation.enabledClientAttribIndices = [];
@@ -4331,7 +4423,7 @@ var LibraryGL = {
#if ASSERTIONS
assert(numProvidedIndexes << 1 <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (a)');
#endif
- var indexBuffer = GL.tempIndexBuffers[GL.tempBufferIndexLookup[numProvidedIndexes << 1]];
+ var indexBuffer = GL.getTempIndexBuffer(numProvidedIndexes << 1);
GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, indexBuffer);
GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (numProvidedIndexes << 1)') }}});
ptr = 0;
@@ -4367,7 +4459,7 @@ var LibraryGL = {
GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null);
}
-#if GL_UNSAFE_OPTS == 0
+#if !GL_UNSAFE_OPTS
#if !GL_FFP_ONLY
renderer.cleanup();
#endif
@@ -4480,6 +4572,9 @@ var LibraryGL = {
GLImmediate.clientColor[1] = g;
GLImmediate.clientColor[2] = b;
GLImmediate.clientColor[3] = a;
+#if GL_FFP_ONLY
+ GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor);
+#endif
}
},
glColor4d: 'glColor4f',
@@ -4627,6 +4722,10 @@ var LibraryGL = {
GLImmediate.enabledClientAttributes[attrib] = true;
GLImmediate.totalEnabledClientAttributes++;
GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
+#if GL_FFP_ONLY
+ // In GL_FFP_ONLY mode, attributes are bound to the same index in each FFP emulation shader, so we can immediately apply the change here.
+ GL.enableVertexAttribArray(attrib);
+#endif
if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1;
GLImmediate.modifiedClientAttributes = true;
}
@@ -4643,6 +4742,10 @@ var LibraryGL = {
GLImmediate.enabledClientAttributes[attrib] = false;
GLImmediate.totalEnabledClientAttributes--;
GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
+#if GL_FFP_ONLY
+ // In GL_FFP_ONLY mode, attributes are bound to the same index in each FFP emulation shader, so we can immediately apply the change here.
+ GL.disableVertexAttribArray(attrib);
+#endif
if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap];
GLImmediate.modifiedClientAttributes = true;
}
@@ -4654,7 +4757,6 @@ var LibraryGL = {
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
GLctx.vertexAttribPointer(GLImmediate.VERTEX, size, type, false, stride, pointer);
- GL.enableVertexAttribArray(GLImmediate.VERTEX);
}
#endif
},
@@ -4664,7 +4766,6 @@ var LibraryGL = {
if (GL.currArrayBuffer) {
var loc = GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture;
GLctx.vertexAttribPointer(loc, size, type, false, stride, pointer);
- GL.enableVertexAttribArray(loc);
}
#endif
},
@@ -4673,7 +4774,6 @@ var LibraryGL = {
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
GLctx.vertexAttribPointer(GLImmediate.NORMAL, size, type, true, stride, pointer);
- GL.enableVertexAttribArray(GLImmediate.NORMAL);
}
#endif
},
@@ -4682,7 +4782,6 @@ var LibraryGL = {
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
GLctx.vertexAttribPointer(GLImmediate.COLOR, size, type, true, stride, pointer);
- GL.enableVertexAttribArray(GLImmediate.COLOR);
}
#endif
},
@@ -5099,7 +5198,7 @@ var LibraryGL = {
var buf;
if (!GL.currElementArrayBuffer) {
var size = GL.calcBufLength(1, type, 0, count);
- buf = GL.tempIndexBuffers[GL.tempBufferIndexLookup[size]];
+ buf = GL.getTempIndexBuffer(size);
GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, buf);
GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER,
0,
diff --git a/src/library_glew.js b/src/library_glew.js
new file mode 100644
index 00000000..f7da5f82
--- /dev/null
+++ b/src/library_glew.js
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * EMSCRIPTEN GLEW 1.10.0 emulation
+ *
+ * What it does:
+ * - Stubs init function.
+ * - GL Extensions support.
+ *
+ * Optional:
+ * - isLinaroFork variable to enable glew-es specific error strings.
+ * This is enabled by default, but should be disabled when upstream glew conflicts.
+ *
+ * Authors:
+ * - Jari Vetoniemi <mailroxas@gmail.com>
+ ******************************************************************************/
+
+var LibraryGLEW = {
+ $GLEW__deps: ['glGetString'],
+ $GLEW: {
+ isLinaroFork: 1,
+ extensions: null,
+
+ error: {
+ 0:null, // GLEW_OK || GLEW_NO_ERROR
+ 1:null, // GLEW_ERROR_NO_GL_VERSION
+ 2:null, // GLEW_ERROR_GL_VERSION_10_ONLY
+ 3:null, // GLEW_ERROR_GLX_VERSION_11_ONLY
+
+ 4:null, // GLEW_ERROR_NOT_GLES_VERSION
+ 5:null, // GLEW_ERROR_GLES_VERSION
+ 6:null, // GLEW_ERROR_NO_EGL_VERSION
+ 7:null, // GLEW_ERROR_EGL_VERSION_10_ONLY
+
+ 8:null, // Unknown error
+ },
+
+ version: {
+ 1:null, // GLEW_VERSION
+ 2:null, // GLEW_VERSION_MAJOR
+ 3:null, // GLEW_VERSION_MINOR
+ 4:null, // GLEW_VERSION_MICRO
+ },
+
+ errorStringConstantFromCode: function(error) {
+ if (GLEW.isLinaroFork) {
+ switch (error) {
+ case 4:return "OpenGL ES lib expected, found OpenGL lib"; // GLEW_ERROR_NOT_GLES_VERSION
+ case 5:return "OpenGL lib expected, found OpenGL ES lib"; // GLEW_ERROR_GLES_VERSION
+ case 6:return "Missing EGL version"; // GLEW_ERROR_NO_EGL_VERSION
+ case 7:return "EGL 1.1 and up are supported"; // GLEW_ERROR_EGL_VERSION_10_ONLY
+ default:break;
+ }
+ }
+
+ switch (error) {
+ case 0:return "No error"; // GLEW_OK || GLEW_NO_ERROR
+ case 1:return "Missing GL version"; // GLEW_ERROR_NO_GL_VERSION
+ case 2:return "GL 1.1 and up are supported"; // GLEW_ERROR_GL_VERSION_10_ONLY
+ case 3:return "GLX 1.2 and up are supported"; // GLEW_ERROR_GLX_VERSION_11_ONLY
+ default:return null;
+ }
+ },
+
+ errorString: function(error) {
+ if (!GLEW.error[error]) {
+ var string = GLEW.errorStringConstantFromCode(error);
+ if (!string) {
+ string = "Unknown error";
+ error = 8; // prevent array from growing more than this
+ }
+ GLEW.error[error] = allocate(intArrayFromString(string), 'i8', ALLOC_NORMAL);
+ }
+ return GLEW.error[error];
+ },
+
+ versionStringConstantFromCode: function(name) {
+ switch (name) {
+ case 1:return "1.10.0"; // GLEW_VERSION
+ case 2:return "1"; // GLEW_VERSION_MAJOR
+ case 3:return "10"; // GLEW_VERSION_MINOR
+ case 4:return "0"; // GLEW_VERSION_MICRO
+ default:return null;
+ }
+ },
+
+ versionString: function(name) {
+ if (!GLEW.version[name]) {
+ var string = GLEW.versionStringConstantFromCode(name);
+ if (!string)
+ return 0;
+ GLEW.version[name] = allocate(intArrayFromString(string), 'i8', ALLOC_NORMAL);
+ }
+ return GLEW.version[name];
+ },
+
+ extensionIsSupported: function(name) {
+ if (!GLEW.extensions) {
+ GLEW.extensions = Pointer_stringify(_glGetString(0x1F03)).split(' ');
+ }
+
+ if (GLEW.extensions.indexOf(name) != -1)
+ return 1;
+
+ // extensions from GLEmulations do not come unprefixed
+ // so, try with prefix
+ return (GLEW.extensions.indexOf("GL_" + name) != -1);
+ },
+ },
+
+ glewInit: function() { return 0; },
+
+ glewIsSupported: function(name) {
+ var exts = Pointer_stringify(name).split(' ');
+ for (i in exts) {
+ if (!GLEW.extensionIsSupported(exts[i]))
+ return 0;
+ }
+ return 1;
+ },
+
+ glewGetExtension: function(name) {
+ return GLEW.extensionIsSupported(Pointer_stringify(name));
+ },
+
+ glewGetErrorString: function(error) {
+ return GLEW.errorString(error);
+ },
+
+ glewGetString: function(name) {
+ return GLEW.versionString(name);
+ },
+
+};
+
+autoAddDeps(LibraryGLEW, '$GLEW');
+mergeInto(LibraryManager.library, LibraryGLEW);
diff --git a/src/library_sdl.js b/src/library_sdl.js
index fc38dd1c..80734d95 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -223,26 +223,26 @@ var LibrarySDL = {
var is_SDL_HWPALETTE = flags & 0x00200000;
var bpp = is_SDL_HWPALETTE ? 1 : 4;
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}} // SDL_Surface.flags
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}} // SDL_Surface.w
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}} // SDL_Surface.h
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now,
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}}; // SDL_Surface.flags
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}};// SDL_Surface.format TODO
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}}; // SDL_Surface.w
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}}; // SDL_Surface.h
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}}; // SDL_Surface.pitch, assuming RGBA or indexed for now,
// since that is what ImageData gives us in browsers
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}} // SDL_Surface.pixels
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}} // SDL_Surface.offset
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}}; // SDL_Surface.pixels
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}}; // SDL_Surface.offset
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}}
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}};
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}} // SDL_PIXELFORMAT_RGBA8888
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}} // TODO
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}};// SDL_PIXELFORMAT_RGBA8888
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}};// TODO
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}};
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}};
// Decide if we want to use WebGL or not
var useWebGL = (flags & 0x04000000) != 0; // SDL_OPENGL
@@ -592,19 +592,19 @@ var LibrarySDL = {
scan = SDL.scanCodes[key] || key;
}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}} // TODO
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}}; // TODO
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_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', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}};
break;
}
case 'keypress': {
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
// Not filling in windowID for now
var cStr = intArrayFromString(String.fromCharCode(event.charCode));
for (var i = 0; i < cStr.length; ++i) {
@@ -819,9 +819,9 @@ var LibrarySDL = {
SDL_Linked_Version: function() {
if (SDL.version === null) {
SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}});
- {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}}
- {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}}
- {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}}
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}};
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}};
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}};
}
return SDL.version;
},
@@ -879,11 +879,11 @@ var LibrarySDL = {
SDL_GetVideoInfo: function() {
// %struct.SDL_VideoInfo = type { i32, i32, %struct.SDL_PixelFormat*, i32, i32 } - 5 fields of quantum size
var ret = _malloc(5*Runtime.QUANTUM_SIZE);
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}} // TODO
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}} // TODO
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}}
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}}
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}}
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}}; // TODO
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}}; // TODO
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}};
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}};
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}};
return ret;
},
diff --git a/src/modules.js b/src/modules.js
index c0b98f6f..ad467ba7 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -424,7 +424,7 @@ var LibraryManager = {
load: function() {
if (this.library) return;
- var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.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', 'library_uuid.js'].concat(additionalLibraries);
+ var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.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', 'library_uuid.js', 'library_glew.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 b7f97a40..e09cd2e2 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -46,7 +46,11 @@ function preprocess(text) {
error('unsupported preprecessor op ' + op);
}
} else {
- showStack.push(ident in this && this[ident] > 0);
+ if (ident[0] === '!') {
+ showStack.push(!(this[ident.substr(1)] > 0));
+ } else {
+ showStack.push(ident in this && this[ident] > 0);
+ }
}
} else if (line[2] == 'n') { // include
var included = read(line.substr(line.indexOf(' ')+1));
@@ -1327,18 +1331,22 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
var printType = type;
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
if (printType[0] === '#') printType = printType.substr(1);
- return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type);
- } else {
- var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']';
- if (ASM_JS && (phase == 'funcs' || forceAsm)) {
- ret = asmCoercion(ret, type);
- }
- if (ASM_HEAP_LOG) {
- ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret,
- 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int'));
+ if (ASM_JS) {
+ if (!ignore) return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type);
+ // else fall through
+ } else {
+ return asmCoercion('SAFE_HEAP_LOAD(' + offset + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type);
}
- return ret;
}
+ var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']';
+ if (ASM_JS && (phase == 'funcs' || forceAsm)) {
+ ret = asmCoercion(ret, type);
+ }
+ if (ASM_HEAP_LOG) {
+ ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret,
+ 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int'));
+ }
+ return ret;
}
function makeGetValueAsm(ptr, pos, type, unsigned) {
@@ -1435,10 +1443,14 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
var printType = type;
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
if (printType[0] === '#') printType = printType.substr(1);
- return 'SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
- } else {
- return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep);
+ if (ASM_JS) {
+ if (!ignore) return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ')', type);
+ // else fall through
+ } else {
+ return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
+ }
}
+ return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep);
}
function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) {
@@ -1781,31 +1793,12 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization)
types = 'i8';
}
- // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime
- var chunkSize = JS_CHUNK_SIZE;
- function chunkify(array) {
- // break very large slabs into parts
- var ret = '';
- var index = 0;
- while (index < array.length) {
- ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : '');
- index += chunkSize;
- }
- return ret;
- }
- if (typeof slab == 'object' && slab.length > chunkSize) {
- slab = chunkify(slab);
- }
if (typeof types == 'object') {
while (types.length < slab.length) types.push(0);
}
- if (typeof types != 'string' && types.length > chunkSize) {
- types = chunkify(types);
- } else {
- types = JSON.stringify(types);
- }
+ types = JSON.stringify(types);
if (typeof slab == 'object') slab = '[' + slab.join(',') + ']';
- return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')';
+ return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ');';
}
function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
@@ -2150,9 +2143,9 @@ function makeRounding(value, bits, signed, floatConversion) {
}
}
// Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
- if (!correctRoundings() || !signed) return 'Math_floor(' + value + ')';
+ if (!correctRoundings() || !signed) return '(+Math_floor(' + value + '))';
// We are left with >32 bits
- return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR');
+ return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? +Math_floor(VALUE) : +Math_ceil(VALUE)', value, 'tempBigIntR');
}
}
diff --git a/src/postamble.js b/src/postamble.js
index d6c059b8..90a86474 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -121,12 +121,13 @@ function run(args) {
if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
function doRun() {
+ if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+ Module['calledRun'] = true;
+
ensureInitRuntime();
preMain();
- assert(!Module['calledRun']);
- Module['calledRun'] = true;
if (Module['_main'] && shouldRunNow) {
Module['callMain'](args);
}
diff --git a/src/preamble.js b/src/preamble.js
index ac6ee7b3..d415b87e 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -21,6 +21,7 @@ Module.print = Module.printErr = function(){};
#endif
#if SAFE_HEAP
+#if ASM_JS == 0
//========================================
// Debugging tools - Heap
//========================================
@@ -166,6 +167,41 @@ function SAFE_HEAP_FILL_HISTORY(from, to, type) {
}
//==========================================
+#else
+// ASM_JS safe heap
+
+function getSafeHeapType(bytes, isFloat) {
+ switch (bytes) {
+ case 1: return 'i8';
+ case 2: return 'i16';
+ case 4: return isFloat ? 'float' : 'i32';
+ case 8: return 'double';
+ default: assert(0);
+ }
+}
+
+function SAFE_HEAP_STORE(dest, value, bytes, isFloat) {
+#if SAFE_HEAP_LOG
+ Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat]);
+#endif
+ assert(dest > 0, 'segmentation fault');
+ assert(dest % bytes === 0);
+ setValue(dest, value, getSafeHeapType(bytes, isFloat), 1);
+}
+
+function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) {
+#if SAFE_HEAP_LOG
+ Module.print('SAFE_HEAP load: ' + [dest, bytes, isFloat, unsigned]);
+#endif
+ assert(dest > 0, 'segmentation fault');
+ assert(dest % bytes === 0);
+ var type = getSafeHeapType(bytes, isFloat);
+ var ret = getValue(dest, type, 1);
+ if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1);
+ return ret;
+}
+
+#endif
#endif
#if CHECK_HEAP_ALIGN
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp
index d5772c62..204986da 100644
--- a/src/relooper/Relooper.cpp
+++ b/src/relooper/Relooper.cpp
@@ -322,12 +322,26 @@ void MultipleShape::RenderLoopPostfix() {
void MultipleShape::Render(bool InLoop) {
RenderLoopPrefix();
- bool First = true;
+
+ // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here
+ typedef std::map<int, Shape*> IdShapeMap;
+ IdShapeMap IdMap;
for (BlockShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) {
+ int Id = iter->first->Id;
+ IdShapeMap::iterator Test = IdMap.find(Id);
+ if (Test != IdMap.end()) {
+ assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else
+ continue;
+ }
+ IdMap[iter->first->Id] = iter->second;
+ }
+
+ bool First = true;
+ for (IdShapeMap::iterator iter = IdMap.begin(); iter != IdMap.end(); iter++) {
if (AsmJS) {
- PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first->Id);
+ PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first);
} else {
- PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first->Id);
+ PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first);
}
First = false;
Indenter::Indent();
@@ -391,8 +405,8 @@ Relooper::~Relooper() {
for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i];
}
-void Relooper::AddBlock(Block *New) {
- New->Id = BlockIdCounter++;
+void Relooper::AddBlock(Block *New, int Id) {
+ New->Id = Id == -1 ? BlockIdCounter++ : Id;
Blocks.push_back(New);
}
@@ -446,8 +460,7 @@ void Relooper::Calculate(Block *Entry) {
for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) {
Block *Prior = *iter;
Block *Split = new Block(Original->Code, Original->BranchVar);
- Parent->AddBlock(Split);
- PrintDebug(" to %d\n", Split->Id);
+ Parent->AddBlock(Split, Original->Id);
Split->BranchesIn.insert(Prior);
Branch *Details = Prior->BranchesOut[Original];
Prior->BranchesOut[Split] = new Branch(Details->Condition, Details->Code);
diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h
index 6b9394db..85adf359 100644
--- a/src/relooper/Relooper.h
+++ b/src/relooper/Relooper.h
@@ -57,7 +57,7 @@ struct Block {
BlockBranchMap ProcessedBranchesOut;
BlockSet ProcessedBranchesIn;
Shape *Parent; // The shape we are directly inside
- int Id; // A unique identifier, defined when added to relooper
+ int Id; // A unique identifier, defined when added to relooper. Note that this uniquely identifies a *logical* block - if we split it, the two instances have the same content *and* the same Id
const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input)
const char *BranchVar; // If we have more than one branch out, the variable whose value determines where we go
bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable
@@ -191,7 +191,7 @@ struct Relooper {
Relooper();
~Relooper();
- void AddBlock(Block *New);
+ void AddBlock(Block *New, int Id=-1);
// Calculates the shapes
void Calculate(Block *Entry);
diff --git a/src/relooper/test.txt b/src/relooper/test.txt
index cb02b867..82b02ad7 100644
--- a/src/relooper/test.txt
+++ b/src/relooper/test.txt
@@ -91,7 +91,7 @@
}
default: {
var $x_1 = $x_0;
- label = 8;
+ label = 7;
break L1;
}
}
@@ -106,7 +106,7 @@
}
}
}
- if (label == 8) {
+ if (label == 7) {
// code 7
}
// code 4
diff --git a/src/runtime.js b/src/runtime.js
index cd3afb4b..4fcca56b 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -49,7 +49,7 @@ var RuntimeGenerator = {
stackExit: function(initial, force) {
if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return '';
var ret = '';
- if (SAFE_HEAP) {
+ if (SAFE_HEAP && !ASM_JS) {
ret += 'var i = sp; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }';
}
return ret += 'STACKTOP=sp';
@@ -393,7 +393,17 @@ var Runtime = {
for (var i = 0; i < numArgs; i++) {
args.push(String.fromCharCode(36) + i); // $0, $1 etc
}
- return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + Pointer_stringify(code) + ' })'); // new Function does not allow upvars in node
+ code = Pointer_stringify(code);
+ if (code[0] === '"') {
+ // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+ if (code.indexOf('"', 1) === code.length-1) {
+ code = code.substr(1, code.length-2);
+ } else {
+ // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+ abort('invalid EM_ASM input |' + code + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+ }
+ }
+ return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + code + ' })'); // new Function does not allow upvars in node
},
warnOnce: function(text) {
diff --git a/src/shell.js b/src/shell.js
index b41fbb51..84844c85 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -38,10 +38,10 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR
if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
// Note that we pollute the global namespace here, otherwise we break in node
- Module['print'] = function print(x) {
+ if (!Module['print']) Module['print'] = function print(x) {
process['stdout'].write(x + '\n');
};
- Module['printErr'] = function printErr(x) {
+ if (!Module['printErr']) Module['printErr'] = function printErr(x) {
process['stderr'].write(x + '\n');
};
@@ -71,7 +71,7 @@ if (ENVIRONMENT_IS_NODE) {
module['exports'] = Module;
}
else if (ENVIRONMENT_IS_SHELL) {
- Module['print'] = print;
+ if (!Module['print']) Module['print'] = print;
if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
if (typeof read != 'undefined') {
@@ -107,16 +107,16 @@ else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
}
if (typeof console !== 'undefined') {
- Module['print'] = function print(x) {
+ if (!Module['print']) Module['print'] = function print(x) {
console.log(x);
};
- Module['printErr'] = function printErr(x) {
+ if (!Module['printErr']) Module['printErr'] = function printErr(x) {
console.log(x);
};
} else {
// Probably a worker, and without console.log. We can do very little here...
var TRY_USE_DUMP = false;
- Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+ if (!Module['print']) 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
diff --git a/system/include/GL/glew.h b/system/include/GL/glew.h
index 324c6b29..8be23b60 100644
--- a/system/include/GL/glew.h
+++ b/system/include/GL/glew.h
@@ -1,6 +1,841 @@
+/* GLEW 1.10.0 emulation include header
+ * this include file provides neccessary stuff to function with most GLEW programs.
+ * library_glew.js is also provided to support extensions and error strings
+ *
+ * This file is based on GLEW (1.10.0) and linaro fork generated include files.
+ *
+ * What it lacks:
+ * - Some constants and function declarations that are in GLEW 1.10.0 might be missing.
+ * - The real glew-es fork also includes normal GL constants and function pointers, this does not.
+ *
+ * Authors:
+ * - Jari Vetoniemi <mailroxas@gmail.com>
+ */
-// Basically do nothing, just use existing symbols
+#ifndef __glew_h__
+#define __glew_h__
+#define __GLEW_H__
-#include "SDL/SDL_opengl.h"
-#define glewInit() {}
+/* linaro fork (glew-es) support */
+#ifndef GLEW_USE_LIB_ES11
+# define __GLEW_VERSION_ES11 0
+#else
+# define __GLEW_VERSION_ES11 1
+# include <SDL/SDL_opengles.h>
+#endif
+#ifndef GLEW_USE_LIB_ES20
+# define __GLEW_VERSION_ES20 0
+#else
+# define __GLEW_VERSION_ES20 1
+# include <SDL/SDL_opengles2.h>
+#endif
+
+#if !__GLEW_VERSION_ES11 && !__GLEW_VERSION_ES20
+# define __GLEW_NOT_ES 1
+# include <SDL/SDL_opengl.h>
+#else
+# define __GLEW_NOT_ES 0
+#endif
+
+/* report us up to GLEW_VERSION_2_1, when no GLEW_USE_LIB_ESXX is specified.
+ * in source, it's possible to #undef and redefine these constants, for
+ * better OpenGL path suitable for emscripten. */
+#define GLEW_VERSION_1_1 __GLEW_NOT_ES
+#define GLEW_VERSION_1_2 __GLEW_NOT_ES
+#define GLEW_VERSION_1_2_1 __GLEW_NOT_ES
+#define GLEW_VERSION_1_3 __GLEW_NOT_ES
+#define GLEW_VERSION_1_4 __GLEW_NOT_ES
+#define GLEW_VERSION_1_5 __GLEW_NOT_ES
+#define GLEW_VERSION_2_0 __GLEW_NOT_ES
+#define GLEW_VERSION_2_1 __GLEW_NOT_ES
+#define GLEW_VERSION_3_0 0
+#define GLEW_VERSION_3_1 0
+#define GLEW_VERSION_3_2 0
+#define GLEW_VERSION_3_3 0
+#define GLEW_VERSION_4_0 0
+#define GLEW_VERSION_4_1 0
+#define GLEW_VERSION_4_2 0
+#define GLEW_VERSION_4_3 0
+#define GLEW_VERSION_4_4 0
+
+/* linaro-fork (glew-es) version constants */
+#define GLEW_ES_VERSION_1_0 __GLEW_VERSION_ES11
+#define GLEW_ES_VERSION_2_0 __GLEW_VERSION_ES20
+
+/* string codes */
+#define GLEW_VERSION 1
+#define GLEW_VERSION_MAJOR 2
+#define GLEW_VERSION_MINOR 3
+#define GLEW_VERSION_MICRO 4
+
+/* error codes */
+#define GLEW_OK 0
+#define GLEW_NO_ERROR 0
+#define GLEW_ERROR_NO_GL_VERSION 1 /* missing GL version */
+#define GLEW_ERROR_GL_VERSION_10_ONLY 2 /* Need at least OpenGL 1.1 */
+#define GLEW_ERROR_GLX_VERSION_11_ONLY 3 /* Need at least GLX 1.2 */
+
+/* linaro-fork (glew-es) error codes */
+#define GLEW_ERROR_NOT_GLES_VERSION 4 /* Need to be OpenGL ES version */
+#define GLEW_ERROR_GLES_VERSION 5 /* Need to be desktop OpenGL version */
+#define GLEW_ERROR_NO_EGL_VERSION 6 /* missing EGL version */
+#define GLEW_ERROR_EGL_VERSION_10_ONLY 7 /* need at least EGL 1.1 */
+
+/* maps to glewGetExtension */
+#define GLEW_GET_VAR(x) glewGetExtension(#x)
+
+/* support GLEW constants, wrangling is done by SDL_opengl.h */
+#define GLEW_3DFX_multisample GLEW_GET_VAR(GL_3DFX_multisample)
+#define GLEW_3DFX_tbuffer GLEW_GET_VAR(GL_3DFX_tbuffer)
+#define GLEW_3DFX_texture_compression_FXT1 GLEW_GET_VAR(GL_3DFX_texture_compression_FXT1)
+#define GLEW_AMD_blend_minmax_factor GLEW_GET_VAR(GL_AMD_blend_minmax_factor)
+#define GLEW_AMD_conservative_depth GLEW_GET_VAR(GL_AMD_conservative_depth)
+#define GLEW_AMD_debug_output GLEW_GET_VAR(GL_AMD_debug_output)
+#define GLEW_AMD_depth_clamp_separate GLEW_GET_VAR(GL_AMD_depth_clamp_separate)
+#define GLEW_AMD_draw_buffers_blend GLEW_GET_VAR(GL_AMD_draw_buffers_blend)
+#define GLEW_AMD_interleaved_elements GLEW_GET_VAR(GL_AMD_interleaved_elements)
+#define GLEW_AMD_multi_draw_indirect GLEW_GET_VAR(GL_AMD_multi_draw_indirect)
+#define GLEW_AMD_name_gen_delete GLEW_GET_VAR(GL_AMD_name_gen_delete)
+#define GLEW_AMD_performance_monitor GLEW_GET_VAR(GL_AMD_performance_monitor)
+#define GLEW_AMD_pinned_memory GLEW_GET_VAR(GL_AMD_pinned_memory)
+#define GLEW_AMD_query_buffer_object GLEW_GET_VAR(GL_AMD_query_buffer_object)
+#define GLEW_AMD_sample_positions GLEW_GET_VAR(GL_AMD_sample_positions)
+#define GLEW_AMD_seamless_cubemap_per_texture GLEW_GET_VAR(GL_AMD_seamless_cubemap_per_texture)
+#define GLEW_AMD_shader_atomic_counter_ops GLEW_GET_VAR(GL_AMD_shader_atomic_counter_ops)
+#define GLEW_AMD_shader_stencil_export GLEW_GET_VAR(GL_AMD_shader_stencil_export)
+#define GLEW_AMD_shader_trinary_minmax GLEW_GET_VAR(GL_AMD_shader_trinary_minmax)
+#define GLEW_AMD_sparse_texture GLEW_GET_VAR(GL_AMD_sparse_texture)
+#define GLEW_AMD_stencil_operation_extended GLEW_GET_VAR(GL_AMD_stencil_operation_extended)
+#define GLEW_AMD_texture_texture4 GLEW_GET_VAR(GL_AMD_texture_texture4)
+#define GLEW_AMD_transform_feedback3_lines_triangles GLEW_GET_VAR(GL_AMD_transform_feedback3_lines_triangles)
+#define GLEW_AMD_vertex_shader_layer GLEW_GET_VAR(GL_AMD_vertex_shader_layer)
+#define GLEW_AMD_vertex_shader_tessellator GLEW_GET_VAR(GL_AMD_vertex_shader_tessellator)
+#define GLEW_AMD_vertex_shader_viewport_index GLEW_GET_VAR(GL_AMD_vertex_shader_viewport_index)
+#define GLEW_ANGLE_depth_texture GLEW_GET_VAR(GL_ANGLE_depth_texture)
+#define GLEW_ANGLE_framebuffer_blit GLEW_GET_VAR(GL_ANGLE_framebuffer_blit)
+#define GLEW_ANGLE_framebuffer_multisample GLEW_GET_VAR(GL_ANGLE_framebuffer_multisample)
+#define GLEW_ANGLE_instanced_arrays GLEW_GET_VAR(GL_ANGLE_instanced_arrays)
+#define GLEW_ANGLE_pack_reverse_row_order GLEW_GET_VAR(GL_ANGLE_pack_reverse_row_order)
+#define GLEW_ANGLE_program_binary GLEW_GET_VAR(GL_ANGLE_program_binary)
+#define GLEW_ANGLE_texture_compression_dxt1 GLEW_GET_VAR(GL_ANGLE_texture_compression_dxt1)
+#define GLEW_ANGLE_texture_compression_dxt3 GLEW_GET_VAR(GL_ANGLE_texture_compression_dxt3)
+#define GLEW_ANGLE_texture_compression_dxt5 GLEW_GET_VAR(GL_ANGLE_texture_compression_dxt5)
+#define GLEW_ANGLE_texture_usage GLEW_GET_VAR(GL_ANGLE_texture_usage)
+#define GLEW_ANGLE_timer_query GLEW_GET_VAR(GL_ANGLE_timer_query)
+#define GLEW_ANGLE_translated_shader_source GLEW_GET_VAR(GL_ANGLE_translated_shader_source)
+#define GLEW_APPLE_aux_depth_stencil GLEW_GET_VAR(GL_APPLE_aux_depth_stencil)
+#define GLEW_APPLE_client_storage GLEW_GET_VAR(GL_APPLE_client_storage)
+#define GLEW_APPLE_element_array GLEW_GET_VAR(GL_APPLE_element_array)
+#define GLEW_APPLE_fence GLEW_GET_VAR(GL_APPLE_fence)
+#define GLEW_APPLE_float_pixels GLEW_GET_VAR(GL_APPLE_float_pixels)
+#define GLEW_APPLE_flush_buffer_range GLEW_GET_VAR(GL_APPLE_flush_buffer_range)
+#define GLEW_APPLE_object_purgeable GLEW_GET_VAR(GL_APPLE_object_purgeable)
+#define GLEW_APPLE_pixel_buffer GLEW_GET_VAR(GL_APPLE_pixel_buffer)
+#define GLEW_APPLE_rgb_422 GLEW_GET_VAR(GL_APPLE_rgb_422)
+#define GLEW_APPLE_row_bytes GLEW_GET_VAR(GL_APPLE_row_bytes)
+#define GLEW_APPLE_specular_vector GLEW_GET_VAR(GL_APPLE_specular_vector)
+#define GLEW_APPLE_texture_range GLEW_GET_VAR(GL_APPLE_texture_range)
+#define GLEW_APPLE_transform_hint GLEW_GET_VAR(GL_APPLE_transform_hint)
+#define GLEW_APPLE_vertex_array_object GLEW_GET_VAR(GL_APPLE_vertex_array_object)
+#define GLEW_APPLE_vertex_array_range GLEW_GET_VAR(GL_APPLE_vertex_array_range)
+#define GLEW_APPLE_vertex_program_evaluators GLEW_GET_VAR(GL_APPLE_vertex_program_evaluators)
+#define GLEW_APPLE_ycbcr_422 GLEW_GET_VAR(GL_APPLE_ycbcr_422)
+#define GLEW_ARB_ES2_compatibility GLEW_GET_VAR(GL_ARB_ES2_compatibility)
+#define GLEW_ARB_ES3_compatibility GLEW_GET_VAR(GL_ARB_ES3_compatibility)
+#define GLEW_ARB_arrays_of_arrays GLEW_GET_VAR(GL_ARB_arrays_of_arrays)
+#define GLEW_ARB_base_instance GLEW_GET_VAR(GL_ARB_base_instance)
+#define GLEW_ARB_bindless_texture GLEW_GET_VAR(GL_ARB_bindless_texture)
+#define GLEW_ARB_blend_func_extended GLEW_GET_VAR(GL_ARB_blend_func_extended)
+#define GLEW_ARB_buffer_storage GLEW_GET_VAR(GL_ARB_buffer_storage)
+#define GLEW_ARB_cl_event GLEW_GET_VAR(GL_ARB_cl_event)
+#define GLEW_ARB_clear_buffer_object GLEW_GET_VAR(GL_ARB_clear_buffer_object)
+#define GLEW_ARB_clear_texture GLEW_GET_VAR(GL_ARB_clear_texture)
+#define GLEW_ARB_color_buffer_float GLEW_GET_VAR(GL_ARB_color_buffer_float)
+#define GLEW_ARB_compatibility GLEW_GET_VAR(GL_ARB_compatibility)
+#define GLEW_ARB_compressed_texture_pixel_storage GLEW_GET_VAR(GL_ARB_compressed_texture_pixel_storage)
+#define GLEW_ARB_compute_shader GLEW_GET_VAR(GL_ARB_compute_shader)
+#define GLEW_ARB_compute_variable_group_size GLEW_GET_VAR(GL_ARB_compute_variable_group_size)
+#define GLEW_ARB_conservative_depth GLEW_GET_VAR(GL_ARB_conservative_depth)
+#define GLEW_ARB_copy_buffer GLEW_GET_VAR(GL_ARB_copy_buffer)
+#define GLEW_ARB_copy_image GLEW_GET_VAR(GL_ARB_copy_image)
+#define GLEW_ARB_debug_output GLEW_GET_VAR(GL_ARB_debug_output)
+#define GLEW_ARB_depth_buffer_float GLEW_GET_VAR(GL_ARB_depth_buffer_float)
+#define GLEW_ARB_depth_clamp GLEW_GET_VAR(GL_ARB_depth_clamp)
+#define GLEW_ARB_depth_texture GLEW_GET_VAR(GL_ARB_depth_texture)
+#define GLEW_ARB_draw_buffers GLEW_GET_VAR(GL_ARB_draw_buffers)
+#define GLEW_ARB_draw_buffers_blend GLEW_GET_VAR(GL_ARB_draw_buffers_blend)
+#define GLEW_ARB_draw_elements_base_vertex GLEW_GET_VAR(GL_ARB_draw_elements_base_vertex)
+#define GLEW_ARB_draw_indirect GLEW_GET_VAR(GL_ARB_draw_indirect)
+#define GLEW_ARB_draw_instanced GLEW_GET_VAR(GL_ARB_draw_instanced)
+#define GLEW_ARB_enhanced_layouts GLEW_GET_VAR(GL_ARB_enhanced_layouts)
+#define GLEW_ARB_explicit_attrib_location GLEW_GET_VAR(GL_ARB_explicit_attrib_location)
+#define GLEW_ARB_explicit_uniform_location GLEW_GET_VAR(GL_ARB_explicit_uniform_location)
+#define GLEW_ARB_fragment_coord_conventions GLEW_GET_VAR(GL_ARB_fragment_coord_conventions)
+#define GLEW_ARB_fragment_layer_viewport GLEW_GET_VAR(GL_ARB_fragment_layer_viewport)
+#define GLEW_ARB_fragment_program GLEW_GET_VAR(GL_ARB_fragment_program)
+#define GLEW_ARB_fragment_program_shadow GLEW_GET_VAR(GL_ARB_fragment_program_shadow)
+#define GLEW_ARB_fragment_shader GLEW_GET_VAR(GL_ARB_fragment_shader)
+#define GLEW_ARB_framebuffer_no_attachments GLEW_GET_VAR(GL_ARB_framebuffer_no_attachments)
+#define GLEW_ARB_framebuffer_object GLEW_GET_VAR(GL_ARB_framebuffer_object)
+#define GLEW_ARB_framebuffer_sRGB GLEW_GET_VAR(GL_ARB_framebuffer_sRGB)
+#define GLEW_ARB_geometry_shader4 GLEW_GET_VAR(GL_ARB_geometry_shader4)
+#define GLEW_ARB_get_program_binary GLEW_GET_VAR(GL_ARB_get_program_binary)
+#define GLEW_ARB_gpu_shader5 GLEW_GET_VAR(GL_ARB_gpu_shader5)
+#define GLEW_ARB_gpu_shader_fp64 GLEW_GET_VAR(GL_ARB_gpu_shader_fp64)
+#define GLEW_ARB_half_float_pixel GLEW_GET_VAR(GL_ARB_half_float_pixel)
+#define GLEW_ARB_half_float_vertex GLEW_GET_VAR(GL_ARB_half_float_vertex)
+#define GLEW_ARB_imaging GLEW_GET_VAR(GL_ARB_imaging)
+#define GLEW_ARB_indirect_parameters GLEW_GET_VAR(GL_ARB_indirect_parameters)
+#define GLEW_ARB_instanced_arrays GLEW_GET_VAR(GL_ARB_instanced_arrays)
+#define GLEW_ARB_internalformat_query GLEW_GET_VAR(GL_ARB_internalformat_query)
+#define GLEW_ARB_internalformat_query2 GLEW_GET_VAR(GL_ARB_internalformat_query2)
+#define GLEW_ARB_invalidate_subdata GLEW_GET_VAR(GL_ARB_invalidate_subdata)
+#define GLEW_ARB_map_buffer_alignment GLEW_GET_VAR(GL_ARB_map_buffer_alignment)
+#define GLEW_ARB_map_buffer_range GLEW_GET_VAR(GL_ARB_map_buffer_range)
+#define GLEW_ARB_matrix_palette GLEW_GET_VAR(GL_ARB_matrix_palette)
+#define GLEW_ARB_multi_bind GLEW_GET_VAR(GL_ARB_multi_bind)
+#define GLEW_ARB_multi_draw_indirect GLEW_GET_VAR(GL_ARB_multi_draw_indirect)
+#define GLEW_ARB_multisample GLEW_GET_VAR(GL_ARB_multisample)
+#define GLEW_ARB_multitexture GLEW_GET_VAR(GL_ARB_multitexture)
+#define GLEW_ARB_occlusion_query GLEW_GET_VAR(GL_ARB_occlusion_query)
+#define GLEW_ARB_occlusion_query2 GLEW_GET_VAR(GL_ARB_occlusion_query2)
+#define GLEW_ARB_pixel_buffer_object GLEW_GET_VAR(GL_ARB_pixel_buffer_object)
+#define GLEW_ARB_point_parameters GLEW_GET_VAR(GL_ARB_point_parameters)
+#define GLEW_ARB_point_sprite GLEW_GET_VAR(GL_ARB_point_sprite)
+#define GLEW_ARB_program_interface_query GLEW_GET_VAR(GL_ARB_program_interface_query)
+#define GLEW_ARB_provoking_vertex GLEW_GET_VAR(GL_ARB_provoking_vertex)
+#define GLEW_ARB_query_buffer_object GLEW_GET_VAR(GL_ARB_query_buffer_object)
+#define GLEW_ARB_robust_buffer_access_behavior GLEW_GET_VAR(GL_ARB_robust_buffer_access_behavior)
+#define GLEW_ARB_robustness GLEW_GET_VAR(GL_ARB_robustness)
+#define GLEW_ARB_robustness_application_isolation GLEW_GET_VAR(GL_ARB_robustness_application_isolation)
+#define GLEW_ARB_robustness_share_group_isolation GLEW_GET_VAR(GL_ARB_robustness_share_group_isolation)
+#define GLEW_ARB_sample_shading GLEW_GET_VAR(GL_ARB_sample_shading)
+#define GLEW_ARB_sampler_objects GLEW_GET_VAR(GL_ARB_sampler_objects)
+#define GLEW_ARB_seamless_cube_map GLEW_GET_VAR(GL_ARB_seamless_cube_map)
+#define GLEW_ARB_seamless_cubemap_per_texture GLEW_GET_VAR(GL_ARB_seamless_cubemap_per_texture)
+#define GLEW_ARB_separate_shader_objects GLEW_GET_VAR(GL_ARB_separate_shader_objects)
+#define GLEW_ARB_shader_atomic_counters GLEW_GET_VAR(GL_ARB_shader_atomic_counters)
+#define GLEW_ARB_shader_bit_encoding GLEW_GET_VAR(GL_ARB_shader_bit_encoding)
+#define GLEW_ARB_shader_draw_parameters GLEW_GET_VAR(GL_ARB_shader_draw_parameters)
+#define GLEW_ARB_shader_group_vote GLEW_GET_VAR(GL_ARB_shader_group_vote)
+#define GLEW_ARB_shader_image_load_store GLEW_GET_VAR(GL_ARB_shader_image_load_store)
+#define GLEW_ARB_shader_image_size GLEW_GET_VAR(GL_ARB_shader_image_size)
+#define GLEW_ARB_shader_objects GLEW_GET_VAR(GL_ARB_shader_objects)
+#define GLEW_ARB_shader_precision GLEW_GET_VAR(GL_ARB_shader_precision)
+#define GLEW_ARB_shader_stencil_export GLEW_GET_VAR(GL_ARB_shader_stencil_export)
+#define GLEW_ARB_shader_storage_buffer_object GLEW_GET_VAR(GL_ARB_shader_storage_buffer_object)
+#define GLEW_ARB_shader_subroutine GLEW_GET_VAR(GL_ARB_shader_subroutine)
+#define GLEW_ARB_shader_texture_lod GLEW_GET_VAR(GL_ARB_shader_texture_lod)
+#define GLEW_ARB_shading_language_100 GLEW_GET_VAR(GL_ARB_shading_language_100)
+#define GLEW_ARB_shading_language_420pack GLEW_GET_VAR(GL_ARB_shading_language_420pack)
+#define GLEW_ARB_shading_language_include GLEW_GET_VAR(GL_ARB_shading_language_include)
+#define GLEW_ARB_shading_language_packing GLEW_GET_VAR(GL_ARB_shading_language_packing)
+#define GLEW_ARB_shadow GLEW_GET_VAR(GL_ARB_shadow)
+#define GLEW_ARB_shadow_ambient GLEW_GET_VAR(GL_ARB_shadow_ambient)
+#define GLEW_ARB_sparse_texture GLEW_GET_VAR(GL_ARB_sparse_texture)
+#define GLEW_ARB_stencil_texturing GLEW_GET_VAR(GL_ARB_stencil_texturing)
+#define GLEW_ARB_sync GLEW_GET_VAR(GL_ARB_sync)
+#define GLEW_ARB_tessellation_shader GLEW_GET_VAR(GL_ARB_tessellation_shader)
+#define GLEW_ARB_texture_border_clamp GLEW_GET_VAR(GL_ARB_texture_border_clamp)
+#define GLEW_ARB_texture_buffer_object GLEW_GET_VAR(GL_ARB_texture_buffer_object)
+#define GLEW_ARB_texture_buffer_object_rgb32 GLEW_GET_VAR(GL_ARB_texture_buffer_object_rgb32)
+#define GLEW_ARB_texture_buffer_range GLEW_GET_VAR(GL_ARB_texture_buffer_range)
+#define GLEW_ARB_texture_compression GLEW_GET_VAR(GL_ARB_texture_compression)
+#define GLEW_ARB_texture_compression_bptc GLEW_GET_VAR(GL_ARB_texture_compression_bptc)
+#define GLEW_ARB_texture_compression_rgtc GLEW_GET_VAR(GL_ARB_texture_compression_rgtc)
+#define GLEW_ARB_texture_cube_map GLEW_GET_VAR(GL_ARB_texture_cube_map)
+#define GLEW_ARB_texture_cube_map_array GLEW_GET_VAR(GL_ARB_texture_cube_map_array)
+#define GLEW_ARB_texture_env_add GLEW_GET_VAR(GL_ARB_texture_env_add)
+#define GLEW_ARB_texture_env_combine GLEW_GET_VAR(GL_ARB_texture_env_combine)
+#define GLEW_ARB_texture_env_crossbar GLEW_GET_VAR(GL_ARB_texture_env_crossbar)
+#define GLEW_ARB_texture_env_dot3 GLEW_GET_VAR(GL_ARB_texture_env_dot3)
+#define GLEW_ARB_texture_float GLEW_GET_VAR(GL_ARB_texture_float)
+#define GLEW_ARB_texture_gather GLEW_GET_VAR(GL_ARB_texture_gather)
+#define GLEW_ARB_texture_mirror_clamp_to_edge GLEW_GET_VAR(GL_ARB_texture_mirror_clamp_to_edge)
+#define GLEW_ARB_texture_mirrored_repeat GLEW_GET_VAR(GL_ARB_texture_mirrored_repeat)
+#define GLEW_ARB_texture_multisample GLEW_GET_VAR(GL_ARB_texture_multisample)
+#define GLEW_ARB_texture_non_power_of_two GLEW_GET_VAR(GL_ARB_texture_non_power_of_two)
+#define GLEW_ARB_texture_query_levels GLEW_GET_VAR(GL_ARB_texture_query_levels)
+#define GLEW_ARB_texture_query_lod GLEW_GET_VAR(GL_ARB_texture_query_lod)
+#define GLEW_ARB_texture_rectangle GLEW_GET_VAR(GL_ARB_texture_rectangle)
+#define GLEW_ARB_texture_rg GLEW_GET_VAR(GL_ARB_texture_rg)
+#define GLEW_ARB_texture_rgb10_a2ui GLEW_GET_VAR(GL_ARB_texture_rgb10_a2ui)
+#define GLEW_ARB_texture_stencil8 GLEW_GET_VAR(GL_ARB_texture_stencil8)
+#define GLEW_ARB_texture_storage GLEW_GET_VAR(GL_ARB_texture_storage)
+#define GLEW_ARB_texture_storage_multisample GLEW_GET_VAR(GL_ARB_texture_storage_multisample)
+#define GLEW_ARB_texture_swizzle GLEW_GET_VAR(GL_ARB_texture_swizzle)
+#define GLEW_ARB_texture_view GLEW_GET_VAR(GL_ARB_texture_view)
+#define GLEW_ARB_timer_query GLEW_GET_VAR(GL_ARB_timer_query)
+#define GLEW_ARB_transform_feedback2 GLEW_GET_VAR(GL_ARB_transform_feedback2)
+#define GLEW_ARB_transform_feedback3 GLEW_GET_VAR(GL_ARB_transform_feedback3)
+#define GLEW_ARB_transform_feedback_instanced GLEW_GET_VAR(GL_ARB_transform_feedback_instanced)
+#define GLEW_ARB_transpose_matrix GLEW_GET_VAR(GL_ARB_transpose_matrix)
+#define GLEW_ARB_uniform_buffer_object GLEW_GET_VAR(GL_ARB_uniform_buffer_object)
+#define GLEW_ARB_vertex_array_bgra GLEW_GET_VAR(GL_ARB_vertex_array_bgra)
+#define GLEW_ARB_vertex_array_object GLEW_GET_VAR(GL_ARB_vertex_array_object)
+#define GLEW_ARB_vertex_attrib_64bit GLEW_GET_VAR(GL_ARB_vertex_attrib_64bit)
+#define GLEW_ARB_vertex_attrib_binding GLEW_GET_VAR(GL_ARB_vertex_attrib_binding)
+#define GLEW_ARB_vertex_blend GLEW_GET_VAR(GL_ARB_vertex_blend)
+#define GLEW_ARB_vertex_buffer_object GLEW_GET_VAR(GL_ARB_vertex_buffer_object)
+#define GLEW_ARB_vertex_program GLEW_GET_VAR(GL_ARB_vertex_program)
+#define GLEW_ARB_vertex_shader GLEW_GET_VAR(GL_ARB_vertex_shader)
+#define GLEW_ARB_vertex_type_10f_11f_11f_rev GLEW_GET_VAR(GL_ARB_vertex_type_10f_11f_11f_rev)
+#define GLEW_ARB_vertex_type_2_10_10_10_rev GLEW_GET_VAR(GL_ARB_vertex_type_2_10_10_10_rev)
+#define GLEW_ARB_viewport_array GLEW_GET_VAR(GL_ARB_viewport_array)
+#define GLEW_ARB_window_pos GLEW_GET_VAR(GL_ARB_window_pos)
+#define GLEW_ATIX_point_sprites GLEW_GET_VAR(GL_ATIX_point_sprites)
+#define GLEW_ATIX_texture_env_combine3 GLEW_GET_VAR(GL_ATIX_texture_env_combine3)
+#define GLEW_ATIX_texture_env_route GLEW_GET_VAR(GL_ATIX_texture_env_route)
+#define GLEW_ATIX_vertex_shader_output_point_size GLEW_GET_VAR(GL_ATIX_vertex_shader_output_point_size)
+#define GLEW_ATI_draw_buffers GLEW_GET_VAR(GL_ATI_draw_buffers)
+#define GLEW_ATI_element_array GLEW_GET_VAR(GL_ATI_element_array)
+#define GLEW_ATI_envmap_bumpmap GLEW_GET_VAR(GL_ATI_envmap_bumpmap)
+#define GLEW_ATI_fragment_shader GLEW_GET_VAR(GL_ATI_fragment_shader)
+#define GLEW_ATI_map_object_buffer GLEW_GET_VAR(GL_ATI_map_object_buffer)
+#define GLEW_ATI_meminfo GLEW_GET_VAR(GL_ATI_meminfo)
+#define GLEW_ATI_pn_triangles GLEW_GET_VAR(GL_ATI_pn_triangles)
+#define GLEW_ATI_separate_stencil GLEW_GET_VAR(GL_ATI_separate_stencil)
+#define GLEW_ATI_shader_texture_lod GLEW_GET_VAR(GL_ATI_shader_texture_lod)
+#define GLEW_ATI_text_fragment_shader GLEW_GET_VAR(GL_ATI_text_fragment_shader)
+#define GLEW_ATI_texture_compression_3dc GLEW_GET_VAR(GL_ATI_texture_compression_3dc)
+#define GLEW_ATI_texture_env_combine3 GLEW_GET_VAR(GL_ATI_texture_env_combine3)
+#define GLEW_ATI_texture_float GLEW_GET_VAR(GL_ATI_texture_float)
+#define GLEW_ATI_texture_mirror_once GLEW_GET_VAR(GL_ATI_texture_mirror_once)
+#define GLEW_ATI_vertex_array_object GLEW_GET_VAR(GL_ATI_vertex_array_object)
+#define GLEW_ATI_vertex_attrib_array_object GLEW_GET_VAR(GL_ATI_vertex_attrib_array_object)
+#define GLEW_ATI_vertex_streams GLEW_GET_VAR(GL_ATI_vertex_streams)
+#define GLEW_EXT_422_pixels GLEW_GET_VAR(GL_EXT_422_pixels)
+#define GLEW_EXT_Cg_shader GLEW_GET_VAR(GL_EXT_Cg_shader)
+#define GLEW_EXT_abgr GLEW_GET_VAR(GL_EXT_abgr)
+#define GLEW_EXT_bgra GLEW_GET_VAR(GL_EXT_bgra)
+#define GLEW_EXT_bindable_uniform GLEW_GET_VAR(GL_EXT_bindable_uniform)
+#define GLEW_EXT_blend_color GLEW_GET_VAR(GL_EXT_blend_color)
+#define GLEW_EXT_blend_equation_separate GLEW_GET_VAR(GL_EXT_blend_equation_separate)
+#define GLEW_EXT_blend_func_separate GLEW_GET_VAR(GL_EXT_blend_func_separate)
+#define GLEW_EXT_blend_logic_op GLEW_GET_VAR(GL_EXT_blend_logic_op)
+#define GLEW_EXT_blend_minmax GLEW_GET_VAR(GL_EXT_blend_minmax)
+#define GLEW_EXT_blend_subtract GLEW_GET_VAR(GL_EXT_blend_subtract)
+#define GLEW_EXT_clip_volume_hint GLEW_GET_VAR(GL_EXT_clip_volume_hint)
+#define GLEW_EXT_cmyka GLEW_GET_VAR(GL_EXT_cmyka)
+#define GLEW_EXT_color_subtable GLEW_GET_VAR(GL_EXT_color_subtable)
+#define GLEW_EXT_compiled_vertex_array GLEW_GET_VAR(GL_EXT_compiled_vertex_array)
+#define GLEW_EXT_convolution GLEW_GET_VAR(GL_EXT_convolution)
+#define GLEW_EXT_coordinate_frame GLEW_GET_VAR(GL_EXT_coordinate_frame)
+#define GLEW_EXT_copy_texture GLEW_GET_VAR(GL_EXT_copy_texture)
+#define GLEW_EXT_cull_vertex GLEW_GET_VAR(GL_EXT_cull_vertex)
+#define GLEW_EXT_debug_label GLEW_GET_VAR(GL_EXT_debug_label)
+#define GLEW_EXT_debug_marker GLEW_GET_VAR(GL_EXT_debug_marker)
+#define GLEW_EXT_depth_bounds_test GLEW_GET_VAR(GL_EXT_depth_bounds_test)
+#define GLEW_EXT_direct_state_access GLEW_GET_VAR(GL_EXT_direct_state_access)
+#define GLEW_EXT_draw_buffers2 GLEW_GET_VAR(GL_EXT_draw_buffers2)
+#define GLEW_EXT_draw_instanced GLEW_GET_VAR(GL_EXT_draw_instanced)
+#define GLEW_EXT_draw_range_elements GLEW_GET_VAR(GL_EXT_draw_range_elements)
+#define GLEW_EXT_fog_coord GLEW_GET_VAR(GL_EXT_fog_coord)
+#define GLEW_EXT_fragment_lighting GLEW_GET_VAR(GL_EXT_fragment_lighting)
+#define GLEW_EXT_framebuffer_blit GLEW_GET_VAR(GL_EXT_framebuffer_blit)
+#define GLEW_EXT_framebuffer_multisample GLEW_GET_VAR(GL_EXT_framebuffer_multisample)
+#define GLEW_EXT_framebuffer_multisample_blit_scaled GLEW_GET_VAR(GL_EXT_framebuffer_multisample_blit_scaled)
+#define GLEW_EXT_framebuffer_object GLEW_GET_VAR(GL_EXT_framebuffer_object)
+#define GLEW_EXT_framebuffer_sRGB GLEW_GET_VAR(GL_EXT_framebuffer_sRGB)
+#define GLEW_EXT_geometry_shader4 GLEW_GET_VAR(GL_EXT_geometry_shader4)
+#define GLEW_EXT_gpu_program_parameters GLEW_GET_VAR(GL_EXT_gpu_program_parameters)
+#define GLEW_EXT_gpu_shader4 GLEW_GET_VAR(GL_EXT_gpu_shader4)
+#define GLEW_EXT_histogram GLEW_GET_VAR(GL_EXT_histogram)
+#define GLEW_EXT_index_array_formats GLEW_GET_VAR(GL_EXT_index_array_formats)
+#define GLEW_EXT_index_func GLEW_GET_VAR(GL_EXT_index_func)
+#define GLEW_EXT_index_material GLEW_GET_VAR(GL_EXT_index_material)
+#define GLEW_EXT_index_texture GLEW_GET_VAR(GL_EXT_index_texture)
+#define GLEW_EXT_light_texture GLEW_GET_VAR(GL_EXT_light_texture)
+#define GLEW_EXT_misc_attribute GLEW_GET_VAR(GL_EXT_misc_attribute)
+#define GLEW_EXT_multi_draw_arrays GLEW_GET_VAR(GL_EXT_multi_draw_arrays)
+#define GLEW_EXT_multisample GLEW_GET_VAR(GL_EXT_multisample)
+#define GLEW_EXT_packed_depth_stencil GLEW_GET_VAR(GL_EXT_packed_depth_stencil)
+#define GLEW_EXT_packed_float GLEW_GET_VAR(GL_EXT_packed_float)
+#define GLEW_EXT_packed_pixels GLEW_GET_VAR(GL_EXT_packed_pixels)
+#define GLEW_EXT_paletted_texture GLEW_GET_VAR(GL_EXT_paletted_texture)
+#define GLEW_EXT_pixel_buffer_object GLEW_GET_VAR(GL_EXT_pixel_buffer_object)
+#define GLEW_EXT_pixel_transform GLEW_GET_VAR(GL_EXT_pixel_transform)
+#define GLEW_EXT_pixel_transform_color_table GLEW_GET_VAR(GL_EXT_pixel_transform_color_table)
+#define GLEW_EXT_point_parameters GLEW_GET_VAR(GL_EXT_point_parameters)
+#define GLEW_EXT_polygon_offset GLEW_GET_VAR(GL_EXT_polygon_offset)
+#define GLEW_EXT_provoking_vertex GLEW_GET_VAR(GL_EXT_provoking_vertex)
+#define GLEW_EXT_rescale_normal GLEW_GET_VAR(GL_EXT_rescale_normal)
+#define GLEW_EXT_scene_marker GLEW_GET_VAR(GL_EXT_scene_marker)
+#define GLEW_EXT_secondary_color GLEW_GET_VAR(GL_EXT_secondary_color)
+#define GLEW_EXT_separate_shader_objects GLEW_GET_VAR(GL_EXT_separate_shader_objects)
+#define GLEW_EXT_separate_specular_color GLEW_GET_VAR(GL_EXT_separate_specular_color)
+#define GLEW_EXT_shader_image_load_store GLEW_GET_VAR(GL_EXT_shader_image_load_store)
+#define GLEW_EXT_shader_integer_mix GLEW_GET_VAR(GL_EXT_shader_integer_mix)
+#define GLEW_EXT_shadow_funcs GLEW_GET_VAR(GL_EXT_shadow_funcs)
+#define GLEW_EXT_shared_texture_palette GLEW_GET_VAR(GL_EXT_shared_texture_palette)
+#define GLEW_EXT_stencil_clear_tag GLEW_GET_VAR(GL_EXT_stencil_clear_tag)
+#define GLEW_EXT_stencil_two_side GLEW_GET_VAR(GL_EXT_stencil_two_side)
+#define GLEW_EXT_stencil_wrap GLEW_GET_VAR(GL_EXT_stencil_wrap)
+#define GLEW_EXT_subtexture GLEW_GET_VAR(GL_EXT_subtexture)
+#define GLEW_EXT_texture GLEW_GET_VAR(GL_EXT_texture)
+#define GLEW_EXT_texture3D GLEW_GET_VAR(GL_EXT_texture3D)
+#define GLEW_EXT_texture_array GLEW_GET_VAR(GL_EXT_texture_array)
+#define GLEW_EXT_texture_buffer_object GLEW_GET_VAR(GL_EXT_texture_buffer_object)
+#define GLEW_EXT_texture_compression_dxt1 GLEW_GET_VAR(GL_EXT_texture_compression_dxt1)
+#define GLEW_EXT_texture_compression_latc GLEW_GET_VAR(GL_EXT_texture_compression_latc)
+#define GLEW_EXT_texture_compression_rgtc GLEW_GET_VAR(GL_EXT_texture_compression_rgtc)
+#define GLEW_EXT_texture_compression_s3tc GLEW_GET_VAR(GL_EXT_texture_compression_s3tc)
+#define GLEW_EXT_texture_cube_map GLEW_GET_VAR(GL_EXT_texture_cube_map)
+#define GLEW_EXT_texture_edge_clamp GLEW_GET_VAR(GL_EXT_texture_edge_clamp)
+#define GLEW_EXT_texture_env GLEW_GET_VAR(GL_EXT_texture_env)
+#define GLEW_EXT_texture_env_add GLEW_GET_VAR(GL_EXT_texture_env_add)
+#define GLEW_EXT_texture_env_combine GLEW_GET_VAR(GL_EXT_texture_env_combine)
+#define GLEW_EXT_texture_env_dot3 GLEW_GET_VAR(GL_EXT_texture_env_dot3)
+#define GLEW_EXT_texture_filter_anisotropic GLEW_GET_VAR(GL_EXT_texture_filter_anisotropic)
+#define GLEW_EXT_texture_integer GLEW_GET_VAR(GL_EXT_texture_integer)
+#define GLEW_EXT_texture_lod_bias GLEW_GET_VAR(GL_EXT_texture_lod_bias)
+#define GLEW_EXT_texture_mirror_clamp GLEW_GET_VAR(GL_EXT_texture_mirror_clamp)
+#define GLEW_EXT_texture_object GLEW_GET_VAR(GL_EXT_texture_object)
+#define GLEW_EXT_texture_perturb_normal GLEW_GET_VAR(GL_EXT_texture_perturb_normal)
+#define GLEW_EXT_texture_rectangle GLEW_GET_VAR(GL_EXT_texture_rectangle)
+#define GLEW_EXT_texture_sRGB GLEW_GET_VAR(GL_EXT_texture_sRGB)
+#define GLEW_EXT_texture_sRGB_decode GLEW_GET_VAR(GL_EXT_texture_sRGB_decode)
+#define GLEW_EXT_texture_shared_exponent GLEW_GET_VAR(GL_EXT_texture_shared_exponent)
+#define GLEW_EXT_texture_snorm GLEW_GET_VAR(GL_EXT_texture_snorm)
+#define GLEW_EXT_texture_swizzle GLEW_GET_VAR(GL_EXT_texture_swizzle)
+#define GLEW_EXT_timer_query GLEW_GET_VAR(GL_EXT_timer_query)
+#define GLEW_EXT_transform_feedback GLEW_GET_VAR(GL_EXT_transform_feedback)
+#define GLEW_EXT_vertex_array GLEW_GET_VAR(GL_EXT_vertex_array)
+#define GLEW_EXT_vertex_array_bgra GLEW_GET_VAR(GL_EXT_vertex_array_bgra)
+#define GLEW_EXT_vertex_attrib_64bit GLEW_GET_VAR(GL_EXT_vertex_attrib_64bit)
+#define GLEW_EXT_vertex_shader GLEW_GET_VAR(GL_EXT_vertex_shader)
+#define GLEW_EXT_vertex_weighting GLEW_GET_VAR(GL_EXT_vertex_weighting)
+#define GLEW_EXT_x11_sync_object GLEW_GET_VAR(GL_EXT_x11_sync_object)
+#define GLEW_GREMEDY_frame_terminator GLEW_GET_VAR(GL_GREMEDY_frame_terminator)
+#define GLEW_GREMEDY_string_marker GLEW_GET_VAR(GL_GREMEDY_string_marker)
+#define GLEW_HP_convolution_border_modes GLEW_GET_VAR(GL_HP_convolution_border_modes)
+#define GLEW_HP_image_transform GLEW_GET_VAR(GL_HP_image_transform)
+#define GLEW_HP_occlusion_test GLEW_GET_VAR(GL_HP_occlusion_test)
+#define GLEW_HP_texture_lighting GLEW_GET_VAR(GL_HP_texture_lighting)
+#define GLEW_IBM_cull_vertex GLEW_GET_VAR(GL_IBM_cull_vertex)
+#define GLEW_IBM_multimode_draw_arrays GLEW_GET_VAR(GL_IBM_multimode_draw_arrays)
+#define GLEW_IBM_rasterpos_clip GLEW_GET_VAR(GL_IBM_rasterpos_clip)
+#define GLEW_IBM_static_data GLEW_GET_VAR(GL_IBM_static_data)
+#define GLEW_IBM_texture_mirrored_repeat GLEW_GET_VAR(GL_IBM_texture_mirrored_repeat)
+#define GLEW_IBM_vertex_array_lists GLEW_GET_VAR(GL_IBM_vertex_array_lists)
+#define GLEW_INGR_color_clamp GLEW_GET_VAR(GL_INGR_color_clamp)
+#define GLEW_INGR_interlace_read GLEW_GET_VAR(GL_INGR_interlace_read)
+#define GLEW_INTEL_fragment_shader_ordering GLEW_GET_VAR(GL_INTEL_fragment_shader_ordering)
+#define GLEW_INTEL_map_texture GLEW_GET_VAR(GL_INTEL_map_texture)
+#define GLEW_INTEL_parallel_arrays GLEW_GET_VAR(GL_INTEL_parallel_arrays)
+#define GLEW_INTEL_texture_scissor GLEW_GET_VAR(GL_INTEL_texture_scissor)
+#define GLEW_KHR_debug GLEW_GET_VAR(GL_KHR_debug)
+#define GLEW_KHR_texture_compression_astc_hdr GLEW_GET_VAR(GL_KHR_texture_compression_astc_hdr)
+#define GLEW_KHR_texture_compression_astc_ldr GLEW_GET_VAR(GL_KHR_texture_compression_astc_ldr)
+#define GLEW_KTX_buffer_region GLEW_GET_VAR(GL_KTX_buffer_region)
+#define GLEW_MESAX_texture_stack GLEW_GET_VAR(GL_MESAX_texture_stack)
+#define GLEW_MESA_pack_invert GLEW_GET_VAR(GL_MESA_pack_invert)
+#define GLEW_MESA_resize_buffers GLEW_GET_VAR(GL_MESA_resize_buffers)
+#define GLEW_MESA_window_pos GLEW_GET_VAR(GL_MESA_window_pos)
+#define GLEW_MESA_ycbcr_texture GLEW_GET_VAR(GL_MESA_ycbcr_texture)
+#define GLEW_NVX_conditional_render GLEW_GET_VAR(GL_NVX_conditional_render)
+#define GLEW_NVX_gpu_memory_info GLEW_GET_VAR(GL_NVX_gpu_memory_info)
+#define GLEW_NV_bindless_multi_draw_indirect GLEW_GET_VAR(GL_NV_bindless_multi_draw_indirect)
+#define GLEW_NV_bindless_texture GLEW_GET_VAR(GL_NV_bindless_texture)
+#define GLEW_NV_blend_equation_advanced GLEW_GET_VAR(GL_NV_blend_equation_advanced)
+#define GLEW_NV_blend_equation_advanced_coherent GLEW_GET_VAR(GL_NV_blend_equation_advanced_coherent)
+#define GLEW_NV_blend_square GLEW_GET_VAR(GL_NV_blend_square)
+#define GLEW_NV_compute_program5 GLEW_GET_VAR(GL_NV_compute_program5)
+#define GLEW_NV_conditional_render GLEW_GET_VAR(GL_NV_conditional_render)
+#define GLEW_NV_copy_depth_to_color GLEW_GET_VAR(GL_NV_copy_depth_to_color)
+#define GLEW_NV_copy_image GLEW_GET_VAR(GL_NV_copy_image)
+#define GLEW_NV_deep_texture3D GLEW_GET_VAR(GL_NV_deep_texture3D)
+#define GLEW_NV_depth_buffer_float GLEW_GET_VAR(GL_NV_depth_buffer_float)
+#define GLEW_NV_depth_clamp GLEW_GET_VAR(GL_NV_depth_clamp)
+#define GLEW_NV_depth_range_unclamped GLEW_GET_VAR(GL_NV_depth_range_unclamped)
+#define GLEW_NV_draw_texture GLEW_GET_VAR(GL_NV_draw_texture)
+#define GLEW_NV_evaluators GLEW_GET_VAR(GL_NV_evaluators)
+#define GLEW_NV_explicit_multisample GLEW_GET_VAR(GL_NV_explicit_multisample)
+#define GLEW_NV_fence GLEW_GET_VAR(GL_NV_fence)
+#define GLEW_NV_float_buffer GLEW_GET_VAR(GL_NV_float_buffer)
+#define GLEW_NV_fog_distance GLEW_GET_VAR(GL_NV_fog_distance)
+#define GLEW_NV_fragment_program GLEW_GET_VAR(GL_NV_fragment_program)
+#define GLEW_NV_fragment_program2 GLEW_GET_VAR(GL_NV_fragment_program2)
+#define GLEW_NV_fragment_program4 GLEW_GET_VAR(GL_NV_fragment_program4)
+#define GLEW_NV_fragment_program_option GLEW_GET_VAR(GL_NV_fragment_program_option)
+#define GLEW_NV_framebuffer_multisample_coverage GLEW_GET_VAR(GL_NV_framebuffer_multisample_coverage)
+#define GLEW_NV_geometry_program4 GLEW_GET_VAR(GL_NV_geometry_program4)
+#define GLEW_NV_geometry_shader4 GLEW_GET_VAR(GL_NV_geometry_shader4)
+#define GLEW_NV_gpu_program4 GLEW_GET_VAR(GL_NV_gpu_program4)
+#define GLEW_NV_gpu_program5 GLEW_GET_VAR(GL_NV_gpu_program5)
+#define GLEW_NV_gpu_program5_mem_extended GLEW_GET_VAR(GL_NV_gpu_program5_mem_extended)
+#define GLEW_NV_gpu_program_fp64 GLEW_GET_VAR(GL_NV_gpu_program_fp64)
+#define GLEW_NV_gpu_shader5 GLEW_GET_VAR(GL_NV_gpu_shader5)
+#define GLEW_NV_half_float GLEW_GET_VAR(GL_NV_half_float)
+#define GLEW_NV_light_max_exponent GLEW_GET_VAR(GL_NV_light_max_exponent)
+#define GLEW_NV_multisample_coverage GLEW_GET_VAR(GL_NV_multisample_coverage)
+#define GLEW_NV_multisample_filter_hint GLEW_GET_VAR(GL_NV_multisample_filter_hint)
+#define GLEW_NV_occlusion_query GLEW_GET_VAR(GL_NV_occlusion_query)
+#define GLEW_NV_packed_depth_stencil GLEW_GET_VAR(GL_NV_packed_depth_stencil)
+#define GLEW_NV_parameter_buffer_object GLEW_GET_VAR(GL_NV_parameter_buffer_object)
+#define GLEW_NV_parameter_buffer_object2 GLEW_GET_VAR(GL_NV_parameter_buffer_object2)
+#define GLEW_NV_path_rendering GLEW_GET_VAR(GL_NV_path_rendering)
+#define GLEW_NV_pixel_data_range GLEW_GET_VAR(GL_NV_pixel_data_range)
+#define GLEW_NV_point_sprite GLEW_GET_VAR(GL_NV_point_sprite)
+#define GLEW_NV_present_video GLEW_GET_VAR(GL_NV_present_video)
+#define GLEW_NV_primitive_restart GLEW_GET_VAR(GL_NV_primitive_restart)
+#define GLEW_NV_register_combiners GLEW_GET_VAR(GL_NV_register_combiners)
+#define GLEW_NV_register_combiners2 GLEW_GET_VAR(GL_NV_register_combiners2)
+#define GLEW_NV_shader_atomic_counters GLEW_GET_VAR(GL_NV_shader_atomic_counters)
+#define GLEW_NV_shader_atomic_float GLEW_GET_VAR(GL_NV_shader_atomic_float)
+#define GLEW_NV_shader_buffer_load GLEW_GET_VAR(GL_NV_shader_buffer_load)
+#define GLEW_NV_shader_storage_buffer_object GLEW_GET_VAR(GL_NV_shader_storage_buffer_object)
+#define GLEW_NV_tessellation_program5 GLEW_GET_VAR(GL_NV_tessellation_program5)
+#define GLEW_NV_texgen_emboss GLEW_GET_VAR(GL_NV_texgen_emboss)
+#define GLEW_NV_texgen_reflection GLEW_GET_VAR(GL_NV_texgen_reflection)
+#define GLEW_NV_texture_barrier GLEW_GET_VAR(GL_NV_texture_barrier)
+#define GLEW_NV_texture_compression_vtc GLEW_GET_VAR(GL_NV_texture_compression_vtc)
+#define GLEW_NV_texture_env_combine4 GLEW_GET_VAR(GL_NV_texture_env_combine4)
+#define GLEW_NV_texture_expand_normal GLEW_GET_VAR(GL_NV_texture_expand_normal)
+#define GLEW_NV_texture_multisample GLEW_GET_VAR(GL_NV_texture_multisample)
+#define GLEW_NV_texture_rectangle GLEW_GET_VAR(GL_NV_texture_rectangle)
+#define GLEW_NV_texture_shader GLEW_GET_VAR(GL_NV_texture_shader)
+#define GLEW_NV_texture_shader2 GLEW_GET_VAR(GL_NV_texture_shader2)
+#define GLEW_NV_texture_shader3 GLEW_GET_VAR(GL_NV_texture_shader3)
+#define GLEW_NV_transform_feedback GLEW_GET_VAR(GL_NV_transform_feedback)
+#define GLEW_NV_transform_feedback2 GLEW_GET_VAR(GL_NV_transform_feedback2)
+#define GLEW_NV_vdpau_interop GLEW_GET_VAR(GL_NV_vdpau_interop)
+#define GLEW_NV_vertex_array_range GLEW_GET_VAR(GL_NV_vertex_array_range)
+#define GLEW_NV_vertex_array_range2 GLEW_GET_VAR(GL_NV_vertex_array_range2)
+#define GLEW_NV_vertex_attrib_integer_64bit GLEW_GET_VAR(GL_NV_vertex_attrib_integer_64bit)
+#define GLEW_NV_vertex_buffer_unified_memory GLEW_GET_VAR(GL_NV_vertex_buffer_unified_memory)
+#define GLEW_NV_vertex_program GLEW_GET_VAR(GL_NV_vertex_program)
+#define GLEW_NV_vertex_program1_1 GLEW_GET_VAR(GL_NV_vertex_program1_1)
+#define GLEW_NV_vertex_program2 GLEW_GET_VAR(GL_NV_vertex_program2)
+#define GLEW_NV_vertex_program2_option GLEW_GET_VAR(GL_NV_vertex_program2_option)
+#define GLEW_NV_vertex_program3 GLEW_GET_VAR(GL_NV_vertex_program3)
+#define GLEW_NV_vertex_program4 GLEW_GET_VAR(GL_NV_vertex_program4)
+#define GLEW_NV_video_capture GLEW_GET_VAR(GL_NV_video_capture)
+#define GLEW_OES_byte_coordinates GLEW_GET_VAR(GL_OES_byte_coordinates)
+#define GLEW_OES_compressed_paletted_texture GLEW_GET_VAR(GL_OES_compressed_paletted_texture)
+#define GLEW_OES_read_format GLEW_GET_VAR(GL_OES_read_format)
+#define GLEW_OES_single_precision GLEW_GET_VAR(GL_OES_single_precision)
+#define GLEW_OML_interlace GLEW_GET_VAR(GL_OML_interlace)
+#define GLEW_OML_resample GLEW_GET_VAR(GL_OML_resample)
+#define GLEW_OML_subsample GLEW_GET_VAR(GL_OML_subsample)
+#define GLEW_PGI_misc_hints GLEW_GET_VAR(GL_PGI_misc_hints)
+#define GLEW_PGI_vertex_hints GLEW_GET_VAR(GL_PGI_vertex_hints)
+#define GLEW_REGAL_ES1_0_compatibility GLEW_GET_VAR(GL_REGAL_ES1_0_compatibility)
+#define GLEW_REGAL_ES1_1_compatibility GLEW_GET_VAR(GL_REGAL_ES1_1_compatibility)
+#define GLEW_REGAL_enable GLEW_GET_VAR(GL_REGAL_enable)
+#define GLEW_REGAL_error_string GLEW_GET_VAR(GL_REGAL_error_string)
+#define GLEW_REGAL_extension_query GLEW_GET_VAR(GL_REGAL_extension_query)
+#define GLEW_REGAL_log GLEW_GET_VAR(GL_REGAL_log)
+#define GLEW_REND_screen_coordinates GLEW_GET_VAR(GL_REND_screen_coordinates)
+#define GLEW_S3_s3tc GLEW_GET_VAR(GL_S3_s3tc)
+#define GLEW_SGIS_color_range GLEW_GET_VAR(GL_SGIS_color_range)
+#define GLEW_SGIS_detail_texture GLEW_GET_VAR(GL_SGIS_detail_texture)
+#define GLEW_SGIS_fog_function GLEW_GET_VAR(GL_SGIS_fog_function)
+#define GLEW_SGIS_generate_mipmap GLEW_GET_VAR(GL_SGIS_generate_mipmap)
+#define GLEW_SGIS_multisample GLEW_GET_VAR(GL_SGIS_multisample)
+#define GLEW_SGIS_pixel_texture GLEW_GET_VAR(GL_SGIS_pixel_texture)
+#define GLEW_SGIS_point_line_texgen GLEW_GET_VAR(GL_SGIS_point_line_texgen)
+#define GLEW_SGIS_sharpen_texture GLEW_GET_VAR(GL_SGIS_sharpen_texture)
+#define GLEW_SGIS_texture4D GLEW_GET_VAR(GL_SGIS_texture4D)
+#define GLEW_SGIS_texture_border_clamp GLEW_GET_VAR(GL_SGIS_texture_border_clamp)
+#define GLEW_SGIS_texture_edge_clamp GLEW_GET_VAR(GL_SGIS_texture_edge_clamp)
+#define GLEW_SGIS_texture_filter4 GLEW_GET_VAR(GL_SGIS_texture_filter4)
+#define GLEW_SGIS_texture_lod GLEW_GET_VAR(GL_SGIS_texture_lod)
+#define GLEW_SGIS_texture_select GLEW_GET_VAR(GL_SGIS_texture_select)
+#define GLEW_SGIX_async GLEW_GET_VAR(GL_SGIX_async)
+#define GLEW_SGIX_async_histogram GLEW_GET_VAR(GL_SGIX_async_histogram)
+#define GLEW_SGIX_async_pixel GLEW_GET_VAR(GL_SGIX_async_pixel)
+#define GLEW_SGIX_blend_alpha_minmax GLEW_GET_VAR(GL_SGIX_blend_alpha_minmax)
+#define GLEW_SGIX_clipmap GLEW_GET_VAR(GL_SGIX_clipmap)
+#define GLEW_SGIX_convolution_accuracy GLEW_GET_VAR(GL_SGIX_convolution_accuracy)
+#define GLEW_SGIX_depth_texture GLEW_GET_VAR(GL_SGIX_depth_texture)
+#define GLEW_SGIX_flush_raster GLEW_GET_VAR(GL_SGIX_flush_raster)
+#define GLEW_SGIX_fog_offset GLEW_GET_VAR(GL_SGIX_fog_offset)
+#define GLEW_SGIX_fog_texture GLEW_GET_VAR(GL_SGIX_fog_texture)
+#define GLEW_SGIX_fragment_specular_lighting GLEW_GET_VAR(GL_SGIX_fragment_specular_lighting)
+#define GLEW_SGIX_framezoom GLEW_GET_VAR(GL_SGIX_framezoom)
+#define GLEW_SGIX_interlace GLEW_GET_VAR(GL_SGIX_interlace)
+#define GLEW_SGIX_ir_instrument1 GLEW_GET_VAR(GL_SGIX_ir_instrument1)
+#define GLEW_SGIX_list_priority GLEW_GET_VAR(GL_SGIX_list_priority)
+#define GLEW_SGIX_pixel_texture GLEW_GET_VAR(GL_SGIX_pixel_texture)
+#define GLEW_SGIX_pixel_texture_bits GLEW_GET_VAR(GL_SGIX_pixel_texture_bits)
+#define GLEW_SGIX_reference_plane GLEW_GET_VAR(GL_SGIX_reference_plane)
+#define GLEW_SGIX_resample GLEW_GET_VAR(GL_SGIX_resample)
+#define GLEW_SGIX_shadow GLEW_GET_VAR(GL_SGIX_shadow)
+#define GLEW_SGIX_shadow_ambient GLEW_GET_VAR(GL_SGIX_shadow_ambient)
+#define GLEW_SGIX_sprite GLEW_GET_VAR(GL_SGIX_sprite)
+#define GLEW_SGIX_tag_sample_buffer GLEW_GET_VAR(GL_SGIX_tag_sample_buffer)
+#define GLEW_SGIX_texture_add_env GLEW_GET_VAR(GL_SGIX_texture_add_env)
+#define GLEW_SGIX_texture_coordinate_clamp GLEW_GET_VAR(GL_SGIX_texture_coordinate_clamp)
+#define GLEW_SGIX_texture_lod_bias GLEW_GET_VAR(GL_SGIX_texture_lod_bias)
+#define GLEW_SGIX_texture_multi_buffer GLEW_GET_VAR(GL_SGIX_texture_multi_buffer)
+#define GLEW_SGIX_texture_range GLEW_GET_VAR(GL_SGIX_texture_range)
+#define GLEW_SGIX_texture_scale_bias GLEW_GET_VAR(GL_SGIX_texture_scale_bias)
+#define GLEW_SGIX_vertex_preclip GLEW_GET_VAR(GL_SGIX_vertex_preclip)
+#define GLEW_SGIX_vertex_preclip_hint GLEW_GET_VAR(GL_SGIX_vertex_preclip_hint)
+#define GLEW_SGIX_ycrcb GLEW_GET_VAR(GL_SGIX_ycrcb)
+#define GLEW_SGI_color_matrix GLEW_GET_VAR(GL_SGI_color_matrix)
+#define GLEW_SGI_color_table GLEW_GET_VAR(GL_SGI_color_table)
+#define GLEW_SGI_texture_color_table GLEW_GET_VAR(GL_SGI_texture_color_table)
+#define GLEW_SUNX_constant_data GLEW_GET_VAR(GL_SUNX_constant_data)
+#define GLEW_SUN_convolution_border_modes GLEW_GET_VAR(GL_SUN_convolution_border_modes)
+#define GLEW_SUN_global_alpha GLEW_GET_VAR(GL_SUN_global_alpha)
+#define GLEW_SUN_mesh_array GLEW_GET_VAR(GL_SUN_mesh_array)
+#define GLEW_SUN_read_video_pixels GLEW_GET_VAR(GL_SUN_read_video_pixels)
+#define GLEW_SUN_slice_accum GLEW_GET_VAR(GL_SUN_slice_accum)
+#define GLEW_SUN_triangle_list GLEW_GET_VAR(GL_SUN_triangle_list)
+#define GLEW_SUN_vertex GLEW_GET_VAR(GL_SUN_vertex)
+#define GLEW_WIN_phong_shading GLEW_GET_VAR(GL_WIN_phong_shading)
+#define GLEW_WIN_specular_fog GLEW_GET_VAR(GL_WIN_specular_fog)
+#define GLEW_WIN_swap_hint GLEW_GET_VAR(GL_WIN_swap_hint)
+
+/* and from linaro glew-oes fork */
+#define GLEW_OES_byte_coordinates GLEW_GET_VAR(GL_OES_byte_coordinates)
+#define GLEW_OES_compressed_paletted_texture GLEW_GET_VAR(GL_OES_compressed_paletted_texture)
+#define GLEW_OES_read_format GLEW_GET_VAR(GL_OES_read_format)
+#define GLEW_OES_single_precision GLEW_GET_VAR(GL_OES_single_precision)
+#define GLEW_OES_EGL_image GLEW_GET_VAR(GL_OES_EGL_image)
+#define GLEW_OES_EGL_image_external GLEW_GET_VAR(GL_OES_EGL_image_external)
+#define GLEW_OES_EGL_sync GLEW_GET_VAR(GL_OES_EGL_sync)
+#define GLEW_OES_blend_equation_separate GLEW_GET_VAR(GL_OES_blend_equation_separate)
+#define GLEW_OES_blend_func_separate GLEW_GET_VAR(GL_OES_blend_func_separate)
+#define GLEW_OES_blend_subtract GLEW_GET_VAR(GL_OES_blend_subtract)
+#define GLEW_OES_compressed_ETC1_RGB8_texture GLEW_GET_VAR(GL_OES_compressed_ETC1_RGB8_texture)
+#define GLEW_OES_depth24 GLEW_GET_VAR(GL_OES_depth24)
+#define GLEW_OES_depth32 GLEW_GET_VAR(GL_OES_depth32)
+#define GLEW_OES_depth_texture GLEW_GET_VAR(GL_OES_depth_texture)
+#define GLEW_OES_depth_texture_cube_map GLEW_GET_VAR(GL_OES_depth_texture_cube_map)
+#define GLEW_OES_draw_texture GLEW_GET_VAR(GL_OES_draw_texture)
+#define GLEW_OES_element_index_uint GLEW_GET_VAR(GL_OES_element_index_uint)
+#define GLEW_OES_extended_matrix_palette GLEW_GET_VAR(GL_OES_extended_matrix_palette)
+#define GLEW_OES_fbo_render_mipmap GLEW_GET_VAR(GL_OES_fbo_render_mipmap)
+#define GLEW_OES_fragment_precision_high GLEW_GET_VAR(GL_OES_fragment_precision_high)
+#define GLEW_OES_framebuffer_object GLEW_GET_VAR(GL_OES_framebuffer_object)
+#define GLEW_OES_get_program_binary GLEW_GET_VAR(GL_OES_get_program_binary)
+#define GLEW_OES_mapbuffer GLEW_GET_VAR(GL_OES_mapbuffer)
+#define GLEW_OES_matrix_get GLEW_GET_VAR(GL_OES_matrix_get)
+#define GLEW_OES_matrix_palette GLEW_GET_VAR(GL_OES_matrix_palette)
+#define GLEW_OES_packed_depth_stencil GLEW_GET_VAR(GL_OES_packed_depth_stencil)
+#define GLEW_OES_point_size_array GLEW_GET_VAR(GL_OES_point_size_array)
+#define GLEW_OES_point_sprite GLEW_GET_VAR(GL_OES_point_sprite)
+#define GLEW_OES_required_internalformat GLEW_GET_VAR(GL_OES_required_internalformat)
+#define GLEW_OES_rgb8_rgba8 GLEW_GET_VAR(GL_OES_rgb8_rgba8)
+#define GLEW_OES_standard_derivatives GLEW_GET_VAR(GL_OES_standard_derivatives)
+#define GLEW_OES_stencil1 GLEW_GET_VAR(GL_OES_stencil1)
+#define GLEW_OES_stencil4 GLEW_GET_VAR(GL_OES_stencil4)
+#define GLEW_OES_stencil8 GLEW_GET_VAR(GL_OES_stencil8)
+#define GLEW_OES_surfaceless_context GLEW_GET_VAR(GL_OES_surfaceless_context)
+#define GLEW_OES_texture_3D GLEW_GET_VAR(GL_OES_texture_3D)
+#define GLEW_OES_texture_cube_map GLEW_GET_VAR(GL_OES_texture_cube_map)
+#define GLEW_OES_texture_env_crossbar GLEW_GET_VAR(GL_OES_texture_env_crossbar)
+#define GLEW_OES_texture_mirrored_repeat GLEW_GET_VAR(GL_OES_texture_mirrored_repeat)
+#define GLEW_OES_texture_npot GLEW_GET_VAR(GL_OES_texture_npot)
+#define GLEW_OES_vertex_array_object GLEW_GET_VAR(GL_OES_vertex_array_object)
+#define GLEW_OES_vertex_half_float GLEW_GET_VAR(GL_OES_vertex_half_float)
+#define GLEW_OES_vertex_type_10_10_10_2 GLEW_GET_VAR(GL_OES_vertex_type_10_10_10_2)
+
+/* some of the missing constants in SDL_opengl.h
+ * XXX: Most likely doesn't have all. */
+
+#ifndef GL_KHR_debug
+#define GL_KHR_debug 1
+
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
+#define GL_DEBUG_SOURCE_API 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION 0x824A
+#define GL_DEBUG_SOURCE_OTHER 0x824B
+#define GL_DEBUG_TYPE_ERROR 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
+#define GL_DEBUG_TYPE_OTHER 0x8251
+#define GL_DEBUG_TYPE_MARKER 0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
+#define GL_DEBUG_TYPE_POP_GROUP 0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
+#define GL_BUFFER 0x82E0
+#define GL_SHADER 0x82E1
+#define GL_PROGRAM 0x82E2
+#define GL_QUERY 0x82E3
+#define GL_PROGRAM_PIPELINE 0x82E4
+#define GL_SAMPLER 0x82E6
+#define GL_DISPLAY_LIST 0x82E7
+#define GL_MAX_LABEL_LENGTH 0x82E8
+#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES 0x9145
+#define GL_DEBUG_SEVERITY_HIGH 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
+#define GL_DEBUG_SEVERITY_LOW 0x9148
+#define GL_DEBUG_OUTPUT 0x92E0
+
+#endif /* GL_KHR_debug */
+
+#ifndef GL_ARB_shader_storage_buffer_object
+#define GL_ARB_shader_storage_buffer_object 1
+
+#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000
+#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
+#define GL_SHADER_STORAGE_BUFFER 0x90D2
+#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
+#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
+#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
+#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
+#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
+#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
+#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
+#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
+#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
+#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
+#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
+#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
+#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
+
+#endif /* GL_ARB_shader_storage_buffer_object */
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ARB_shader_atomic_counters 1
+
+#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
+#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+
+#endif /* GL_ARB_shader_atomic_counters */
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_ARB_shader_image_load_store 1
+
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+#define GL_UNIFORM_BARRIER_BIT 0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_COMMAND_BARRIER_BIT 0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_IMAGE_BINDING_NAME 0x8F3A
+#define GL_IMAGE_BINDING_LEVEL 0x8F3B
+#define GL_IMAGE_BINDING_LAYERED 0x8F3C
+#define GL_IMAGE_BINDING_LAYER 0x8F3D
+#define GL_IMAGE_BINDING_ACCESS 0x8F3E
+#define GL_IMAGE_1D 0x904C
+#define GL_IMAGE_2D 0x904D
+#define GL_IMAGE_3D 0x904E
+#define GL_IMAGE_2D_RECT 0x904F
+#define GL_IMAGE_CUBE 0x9050
+#define GL_IMAGE_BUFFER 0x9051
+#define GL_IMAGE_1D_ARRAY 0x9052
+#define GL_IMAGE_2D_ARRAY 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#define GL_IMAGE_2D_MULTISAMPLE 0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
+#define GL_INT_IMAGE_1D 0x9057
+#define GL_INT_IMAGE_2D 0x9058
+#define GL_INT_IMAGE_3D 0x9059
+#define GL_INT_IMAGE_2D_RECT 0x905A
+#define GL_INT_IMAGE_CUBE 0x905B
+#define GL_INT_IMAGE_BUFFER 0x905C
+#define GL_INT_IMAGE_1D_ARRAY 0x905D
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+#define GL_MAX_IMAGE_SAMPLES 0x906D
+#define GL_IMAGE_BINDING_FORMAT 0x906E
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+
+#endif /* GL_ARB_shader_image_load_store */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* API */
+#ifdef GLEW_MX
+
+#define glewContextInit(x) glewInit()
+#define glewContextIsSupported(x, y) glewIsSupported(y)
+
+#endif /* GLEW_MX */
+
+GLenum glewInit (void);
+GLboolean glewIsSupported (const char *name);
+#define glewIsExtensionSupported(x) glewIsSupported(x)
+
+//GLboolean glewExperimental;
+static GLboolean glewExperimental; // XXX Emscripten Added 'static' to work around a linkage issue. See https://github.com/kripken/emscripten/issues/2025
+
+GLboolean glewGetExtension (const char *name);
+const GLubyte * glewGetErrorString (GLenum error);
+const GLubyte * glewGetString (GLenum name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glew_h__ */
diff --git a/system/include/libcxx/exception b/system/include/libcxx/exception
index ddd75bd4..cad802e0 100644
--- a/system/include/libcxx/exception
+++ b/system/include/libcxx/exception
@@ -91,8 +91,8 @@ class _LIBCPP_EXCEPTION_ABI exception
{
public:
_LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {}
- virtual ~exception() _NOEXCEPT {} // XXX EMSCRIPTEN - implement in header
- virtual const char* what() const _NOEXCEPT { return "std::exception"; } // XXX EMSCRIPTEN - implement in header
+ virtual ~exception() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
};
class _LIBCPP_EXCEPTION_ABI bad_exception
diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols
index 04fb40d6..6f80ef90 100644
--- a/system/lib/libc.symbols
+++ b/system/lib/libc.symbols
@@ -41,32 +41,18 @@
W _ZnwjRKSt9nothrow_t
T __floatscan
T __overflow
- T __seek_on_exit
T __shgetc
T __shlim
W __strtod_l
W __strtof_l
W __strtold_l
T __toread
- W __towrite_used
+ T __towrite
T __uflow
- T _err
- T _errx
- T _verr
- T _verrx
- T _vwarn
- T _vwarnx
- T _warn
- T _warnx
T atof
W bulk_free
W calloc
- W err
- W errx
W free
- T getopt
- T getopt_long
- T getopt_long_only
W independent_calloc
W independent_comalloc
W mallinfo
@@ -80,11 +66,6 @@
W malloc_usable_size
W mallopt
W memalign
- C optarg
- D opterr
- D optind
- D optopt
- C optreset
W posix_memalign
W pvalloc
W realloc
@@ -92,15 +73,9 @@
T scalbn
T scalbnl
T strtod
- W strtod_l
+ T strtod_l
T strtof
- W strtof_l
+ T strtof_l
T strtold
- W strtold_l
+ T strtold_l
W valloc
- W verr
- W verrx
- W vwarn
- W vwarnx
- W warn
- W warnx
diff --git a/system/lib/libc/gen/err.c b/system/lib/libc/gen/err.c
deleted file mode 100644
index 218a3bfc..00000000
--- a/system/lib/libc/gen/err.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* $OpenBSD: err.c,v 1.11 2012/12/05 23:19:59 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#define __dead __attribute__((__noreturn__))
-
-/* PRINTFLIKE2 */
-__dead void
-_err(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _verr(eval, fmt, ap);
- va_end(ap);
-}
-
-/* PRINTFLIKE2 */
-__dead void
-err(int eval, const char *fmt, ...) __attribute__((weak, alias("_err")));
diff --git a/system/lib/libc/gen/errx.c b/system/lib/libc/gen/errx.c
deleted file mode 100644
index a16643c7..00000000
--- a/system/lib/libc/gen/errx.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* $OpenBSD: errx.c,v 1.10 2012/12/05 23:19:59 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#define __dead __attribute__((__noreturn__))
-
-/* PRINTFLIKE2 */
-__dead void
-_errx(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _verrx(eval, fmt, ap);
- va_end(ap);
-}
-
-/* PRINTFLIKE2 */
-__dead void
-errx(int eval, const char *fmt, ...) __attribute__((weak, alias("_errx")));
diff --git a/system/lib/libc/gen/verr.c b/system/lib/libc/gen/verr.c
deleted file mode 100644
index 90f5870f..00000000
--- a/system/lib/libc/gen/verr.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/* $OpenBSD: verr.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-extern char *__progname; /* Program name, from crt0. */
-
-#define __dead __attribute__((__noreturn__))
-
-__dead void
-_verr(int eval, const char *fmt, va_list ap)
-{
- int sverrno;
-
- sverrno = errno;
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL) {
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, ": ");
- }
- (void)fprintf(stderr, "%s\n", strerror(sverrno));
- exit(eval);
-}
-
-__dead void
-verr(int eval, const char *fmt, va_list ap) __attribute__((weak, alias("_verr")));
diff --git a/system/lib/libc/gen/verrx.c b/system/lib/libc/gen/verrx.c
deleted file mode 100644
index b712c65c..00000000
--- a/system/lib/libc/gen/verrx.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* $OpenBSD: verrx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-extern char *__progname; /* Program name, from crt0. */
-
-#define __dead __attribute__((__noreturn__))
-
-__dead void
-_verrx(int eval, const char *fmt, va_list ap)
-{
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL)
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- exit(eval);
-}
-
-__dead void
-verrx(int eval, const char *fmt, va_list ap) __attribute__((weak, alias("_verrx")));
diff --git a/system/lib/libc/gen/vwarn.c b/system/lib/libc/gen/vwarn.c
deleted file mode 100644
index 37acef35..00000000
--- a/system/lib/libc/gen/vwarn.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* $OpenBSD: vwarn.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-
-extern char *__progname; /* Program name, from crt0. */
-
-void
-_vwarn(const char *fmt, va_list ap)
-{
- int sverrno;
-
- sverrno = errno;
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL) {
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, ": ");
- }
- (void)fprintf(stderr, "%s\n", strerror(sverrno));
-}
-
-void
-vwarn(const char *fmt, va_list ap) __attribute__((weak, alias("_vwarn")));
-
diff --git a/system/lib/libc/gen/vwarnx.c b/system/lib/libc/gen/vwarnx.c
deleted file mode 100644
index a81a5a0d..00000000
--- a/system/lib/libc/gen/vwarnx.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $OpenBSD: vwarnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-extern char *__progname; /* Program name, from crt0. */
-
-void
-_vwarnx(const char *fmt, va_list ap)
-{
- (void)fprintf(stderr, "%s: ", __progname);
- if (fmt != NULL)
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
-}
-
-void
-vwarnx(const char *fmt, va_list ap) __attribute__((weak, alias("_vwarnx")));
-
diff --git a/system/lib/libc/gen/warn.c b/system/lib/libc/gen/warn.c
deleted file mode 100644
index c0dd2cd7..00000000
--- a/system/lib/libc/gen/warn.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* $OpenBSD: warn.c,v 1.10 2012/12/05 23:20:00 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#define __dead __attribute__((__noreturn__))
-
-/* PRINTFLIKE1 */
-void
-_warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _vwarn(fmt, ap);
- va_end(ap);
-}
-
-/* PRINTFLIKE1 */
-void
-warn(const char *fmt, ...) __attribute__((weak, alias("_warn")));
diff --git a/system/lib/libc/gen/warnx.c b/system/lib/libc/gen/warnx.c
deleted file mode 100644
index 7909cf2c..00000000
--- a/system/lib/libc/gen/warnx.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* $OpenBSD: warnx.c,v 1.9 2012/12/05 23:20:00 deraadt Exp $ */
-/*-
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <stdarg.h>
-
-#define __dead __attribute__((__noreturn__))
-
-/* PRINTFLIKE1 */
-void
-_warnx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _vwarnx(fmt, ap);
- va_end(ap);
-}
-
-/* PRINTFLIKE1 */
-void
-warnx(const char *fmt, ...) __attribute__((weak, alias("_warnx")));
diff --git a/system/lib/libc/musl/readme.txt b/system/lib/libc/musl/readme.txt
index 5e6f8389..9b9b6ad2 100644
--- a/system/lib/libc/musl/readme.txt
+++ b/system/lib/libc/musl/readme.txt
@@ -9,4 +9,6 @@ Differences from upstream musl include:
* We flag __assert_fail as _Noreturn.
* Disable FLOCK, FUNLOCK and FFINALLOCK
* Simplify fputwc to not rely on musl stream internals
-
+* signgam is no longer a weak alias of __signgam.
+* __toread and __towrite have had shutdown functionality removed.
+* Expand aliases for strto*_l() to short functions to remove warnings about incompatible pointer types.
diff --git a/system/lib/libc/musl/src/legacy/err.c b/system/lib/libc/musl/src/legacy/err.c
new file mode 100644
index 00000000..0d6ab524
--- /dev/null
+++ b/system/lib/libc/musl/src/legacy/err.c
@@ -0,0 +1,67 @@
+#include <err.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+extern char *__progname;
+
+void vwarn(const char *fmt, va_list ap)
+{
+ fprintf (stderr, "%s: ", __progname);
+ if (fmt) {
+ vfprintf(stderr, fmt, ap);
+ fputs (": ", stderr);
+ }
+ perror(0);
+}
+
+void vwarnx(const char *fmt, va_list ap)
+{
+ fprintf (stderr, "%s: ", __progname);
+ if (fmt) vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+}
+
+_Noreturn void verr(int status, const char *fmt, va_list ap)
+{
+ vwarn(fmt, ap);
+ exit(status);
+}
+
+_Noreturn void verrx(int status, const char *fmt, va_list ap)
+{
+ vwarnx(fmt, ap);
+ exit(status);
+}
+
+void warn(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarn(fmt, ap);
+ va_end(ap);
+}
+
+void warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+_Noreturn void err(int status, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verr(status, fmt, ap);
+ va_end(ap);
+}
+
+_Noreturn void errx(int status, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrx(status, fmt, ap);
+ va_end(ap);
+}
diff --git a/system/lib/libc/musl/src/math/__cos.c b/system/lib/libc/musl/src/math/__cos.c
new file mode 100644
index 00000000..46cefb38
--- /dev/null
+++ b/system/lib/libc/musl/src/math/__cos.c
@@ -0,0 +1,71 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+/*
+ * __cos( x, y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ *
+ * Algorithm
+ * 1. Since cos(-x) = cos(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ * 3. cos(x) is approximated by a polynomial of degree 14 on
+ * [0,pi/4]
+ * 4 14
+ * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ * where the remez error is
+ *
+ * | 2 4 6 8 10 12 14 | -58
+ * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
+ * | |
+ *
+ * 4 6 8 10 12 14
+ * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
+ * cos(x) ~ 1 - x*x/2 + r
+ * since cos(x+y) ~ cos(x) - sin(x)*y
+ * ~ cos(x) - x*y,
+ * a correction term is necessary in cos(x) and hence
+ * cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ * For better accuracy, rearrange to
+ * cos(x+y) ~ w + (tmp + (r-x*y))
+ * where w = 1 - x*x/2 and tmp is a tiny correction term
+ * (1 - x*x/2 == w + tmp exactly in infinite precision).
+ * The exactness of w + tmp in infinite precision depends on w
+ * and tmp having the same precision as x. If they have extra
+ * precision due to compiler bugs, then the extra precision is
+ * only good provided it is retained in all terms of the final
+ * expression for cos(). Retention happens in all cases tested
+ * under FreeBSD, so don't pessimize things by forcibly clipping
+ * any extra precision in w.
+ */
+
+#include "libm.h"
+
+static const double
+C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+double __cos(double x, double y)
+{
+ double_t hz,z,r,w;
+
+ z = x*x;
+ w = z*z;
+ r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
+ hz = 0.5*z;
+ w = 1.0-hz;
+ return w + (((1.0-w)-hz) + (z*r-x*y));
+}
diff --git a/system/lib/libc/musl/src/math/__sin.c b/system/lib/libc/musl/src/math/__sin.c
new file mode 100644
index 00000000..40309496
--- /dev/null
+++ b/system/lib/libc/musl/src/math/__sin.c
@@ -0,0 +1,64 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+/* __sin( x, y, iy)
+ * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
+ *
+ * Algorithm
+ * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
+ * 2. Callers must return sin(-0) = -0 without calling here since our
+ * odd polynomial is not evaluated in a way that preserves -0.
+ * Callers may do the optimization sin(x) ~ x for tiny x.
+ * 3. sin(x) is approximated by a polynomial of degree 13 on
+ * [0,pi/4]
+ * 3 13
+ * sin(x) ~ x + S1*x + ... + S6*x
+ * where
+ *
+ * |sin(x) 2 4 6 8 10 12 | -58
+ * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
+ * | x |
+ *
+ * 4. sin(x+y) = sin(x) + sin'(x')*y
+ * ~ sin(x) + (1-x*x/2)*y
+ * For better accuracy, let
+ * 3 2 2 2 2
+ * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ * then 3 2
+ * sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "libm.h"
+
+static const double
+S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+double __sin(double x, double y, int iy)
+{
+ double_t z,r,v,w;
+
+ z = x*x;
+ w = z*z;
+ r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6);
+ v = z*x;
+ if (iy == 0)
+ return x + v*(S1 + z*r);
+ else
+ return x - ((z*(0.5*y - v*r) - y) - v*S1);
+}
diff --git a/system/lib/libc/musl/src/misc/getopt.c b/system/lib/libc/musl/src/misc/getopt.c
new file mode 100644
index 00000000..f1a1639c
--- /dev/null
+++ b/system/lib/libc/musl/src/misc/getopt.c
@@ -0,0 +1,74 @@
+#include <unistd.h>
+#include <wchar.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "libc.h"
+
+char *optarg;
+int optind=1, opterr=1, optopt, __optpos, __optreset=0;
+
+#define optpos __optpos
+weak_alias(__optreset, optreset);
+
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+ int i;
+ wchar_t c, d;
+ int k, l;
+ char *optchar;
+
+ if (!optind || __optreset) {
+ __optreset = 0;
+ __optpos = 0;
+ optind = 1;
+ }
+
+ if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1])
+ return -1;
+ if (argv[optind][1] == '-' && !argv[optind][2])
+ return optind++, -1;
+
+ if (!optpos) optpos++;
+ if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
+ k = 1;
+ c = 0xfffd; /* replacement char */
+ }
+ optchar = argv[optind]+optpos;
+ optopt = c;
+ optpos += k;
+
+ if (!argv[optind][optpos]) {
+ optind++;
+ optpos = 0;
+ }
+
+ for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1);
+
+ if (d != c) {
+ if (optstring[0] != ':' && opterr) {
+ write(2, argv[0], strlen(argv[0]));
+ write(2, ": illegal option: ", 18);
+ write(2, optchar, k);
+ write(2, "\n", 1);
+ }
+ return '?';
+ }
+ if (optstring[i+1] == ':') {
+ if (optind >= argc) {
+ if (optstring[0] == ':') return ':';
+ if (opterr) {
+ write(2, argv[0], strlen(argv[0]));
+ write(2, ": option requires an argument: ", 31);
+ write(2, optchar, k);
+ write(2, "\n", 1);
+ }
+ return '?';
+ }
+ optarg = argv[optind++] + optpos;
+ optpos = 0;
+ }
+ return c;
+}
+
+weak_alias(getopt, __posix_getopt);
diff --git a/system/lib/libc/musl/src/misc/getopt_long.c b/system/lib/libc/musl/src/misc/getopt_long.c
new file mode 100644
index 00000000..4ef5a5c7
--- /dev/null
+++ b/system/lib/libc/musl/src/misc/getopt_long.c
@@ -0,0 +1,59 @@
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <getopt.h>
+#include <stdio.h>
+
+extern int __optpos, __optreset;
+
+static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
+{
+ if (!optind || __optreset) {
+ __optreset = 0;
+ __optpos = 0;
+ optind = 1;
+ }
+ if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1;
+ if ((longonly && argv[optind][1]) ||
+ (argv[optind][1] == '-' && argv[optind][2]))
+ {
+ int i;
+ for (i=0; longopts[i].name; i++) {
+ const char *name = longopts[i].name;
+ char *opt = argv[optind]+1;
+ if (*opt == '-') opt++;
+ for (; *name && *name == *opt; name++, opt++);
+ if (*name || (*opt && *opt != '=')) continue;
+ if (*opt == '=') {
+ if (!longopts[i].has_arg) continue;
+ optarg = opt+1;
+ } else {
+ if (longopts[i].has_arg == required_argument) {
+ if (!(optarg = argv[++optind]))
+ return ':';
+ } else optarg = NULL;
+ }
+ optind++;
+ if (idx) *idx = i;
+ if (longopts[i].flag) {
+ *longopts[i].flag = longopts[i].val;
+ return 0;
+ }
+ return longopts[i].val;
+ }
+ if (argv[optind][1] == '-') {
+ optind++;
+ return '?';
+ }
+ }
+ return getopt(argc, argv, optstring);
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 0);
+}
+
+int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 1);
+}
diff --git a/system/lib/libc/musl/src/regex/fnmatch.c b/system/lib/libc/musl/src/regex/fnmatch.c
new file mode 100644
index 00000000..ffd3ea0d
--- /dev/null
+++ b/system/lib/libc/musl/src/regex/fnmatch.c
@@ -0,0 +1,299 @@
+/*
+ * An implementation of what I call the "Sea of Stars" algorithm for
+ * POSIX fnmatch(). The basic idea is that we factor the pattern into
+ * a head component (which we match first and can reject without ever
+ * measuring the length of the string), an optional tail component
+ * (which only exists if the pattern contains at least one star), and
+ * an optional "sea of stars", a set of star-separated components
+ * between the head and tail. After the head and tail matches have
+ * been removed from the input string, the components in the "sea of
+ * stars" are matched sequentially by searching for their first
+ * occurrence past the end of the previous match.
+ *
+ * - Rich Felker, April 2012
+ */
+
+#include <string.h>
+#include <fnmatch.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define END -1
+#define UNMATCHABLE -2
+#define BRACKET -3
+#define QUESTION -4
+#define STAR -5
+
+static int str_next(const char *str, size_t n, size_t *step)
+{
+ if (!n) {
+ *step = 0;
+ return 0;
+ }
+ if (str[0] >= 128U) {
+ wchar_t wc;
+ int k = mbtowc(&wc, str, n);
+ if (k<0) {
+ *step = 1;
+ return -1;
+ }
+ *step = k;
+ return wc;
+ }
+ *step = 1;
+ return str[0];
+}
+
+static int pat_next(const char *pat, size_t m, size_t *step, int flags)
+{
+ int esc = 0;
+ if (!m || !*pat) {
+ *step = 0;
+ return END;
+ }
+ *step = 1;
+ if (pat[0]=='\\' && !(flags & FNM_NOESCAPE)) {
+ *step = 2;
+ pat++;
+ esc = 1;
+ goto escaped;
+ }
+ if (pat[0]=='[') {
+ size_t k = 1;
+ if (k<m) if (pat[k] == '^' || pat[k] == '!') k++;
+ if (k<m) if (pat[k] == ']') k++;
+ for (; k<m && pat[k] && pat[k]!=']'; k++) {
+ if (k+1<m && pat[k+1] && pat[k]=='[' && (pat[k+1]==':' || pat[k+1]=='.' || pat[k+1]=='=')) {
+ int z = pat[k+1];
+ k+=2;
+ if (k<m && pat[k]) k++;
+ while (k<m && pat[k] && (pat[k-1]!=z || pat[k]!=']')) k++;
+ if (k==m || !pat[k]) break;
+ }
+ }
+ if (k==m || !pat[k]) {
+ *step = 1;
+ return '[';
+ }
+ *step = k+1;
+ return BRACKET;
+ }
+ if (pat[0] == '*')
+ return STAR;
+ if (pat[0] == '?')
+ return QUESTION;
+escaped:
+ if (pat[0] >= 128U) {
+ wchar_t wc;
+ int k = mbtowc(&wc, pat, m);
+ if (k<0) {
+ *step = 0;
+ return UNMATCHABLE;
+ }
+ *step = k + esc;
+ return wc;
+ }
+ return pat[0];
+}
+
+static int match_bracket(const char *p, int k)
+{
+ wchar_t wc;
+ int inv = 0;
+ p++;
+ if (*p=='^' || *p=='!') {
+ inv = 1;
+ p++;
+ }
+ if (*p==']') {
+ if (k==']') return !inv;
+ p++;
+ } else if (*p=='-') {
+ if (k=='-') return !inv;
+ p++;
+ }
+ wc = p[-1];
+ for (; *p != ']'; p++) {
+ if (p[0]=='-' && p[1]!=']') {
+ wchar_t wc2;
+ int l = mbtowc(&wc2, p+1, 4);
+ if (l < 0) return 0;
+ if (wc<=wc2 && (unsigned)k-wc <= wc2-wc) return !inv;
+ p += l-1;
+ continue;
+ }
+ if (p[0]=='[' && (p[1]==':' || p[1]=='.' || p[1]=='=')) {
+ const char *p0 = p+2;
+ int z = p[1];
+ p+=3;
+ while (p[-1]!=z || p[0]!=']') p++;
+ if (z == ':' && p-1-p0 < 16) {
+ char buf[16];
+ memcpy(buf, p0, p-1-p0);
+ buf[p-1-p0] = 0;
+ if (iswctype(k, wctype(buf))) return !inv;
+ }
+ continue;
+ }
+ if (*p < 128U) {
+ wc = (unsigned char)*p;
+ } else {
+ int l = mbtowc(&wc, p, 4);
+ if (l < 0) return 0;
+ p += l-1;
+ }
+ if (wc==k) return !inv;
+ }
+ return inv;
+}
+
+static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n, int flags)
+{
+ const char *p, *ptail, *endpat;
+ const char *s, *stail, *endstr;
+ size_t pinc, sinc, tailcnt=0;
+ int c, k;
+
+ if (flags & FNM_PERIOD) {
+ if (*str == '.' && *pat != '.')
+ return FNM_NOMATCH;
+ }
+ for (;;) {
+ switch ((c = pat_next(pat, m, &pinc, flags))) {
+ case UNMATCHABLE:
+ return FNM_NOMATCH;
+ case STAR:
+ pat++;
+ m--;
+ break;
+ default:
+ k = str_next(str, n, &sinc);
+ if (k <= 0)
+ return (c==END) ? 0 : FNM_NOMATCH;
+ str += sinc;
+ n -= sinc;
+ if (c == BRACKET) {
+ if (!match_bracket(pat, k))
+ return FNM_NOMATCH;
+ } else if (c != QUESTION && k != c) {
+ return FNM_NOMATCH;
+ }
+ pat+=pinc;
+ m-=pinc;
+ continue;
+ }
+ break;
+ }
+
+ /* Compute real pat length if it was initially unknown/-1 */
+ m = strnlen(pat, m);
+ endpat = pat + m;
+
+ /* Find the last * in pat and count chars needed after it */
+ for (p=ptail=pat; p<endpat; p+=pinc) {
+ switch (pat_next(p, endpat-p, &pinc, flags)) {
+ case UNMATCHABLE:
+ return FNM_NOMATCH;
+ case STAR:
+ tailcnt=0;
+ ptail = p+1;
+ break;
+ default:
+ tailcnt++;
+ break;
+ }
+ }
+
+ /* Past this point we need not check for UNMATCHABLE in pat,
+ * because all of pat has already been parsed once. */
+
+ /* Compute real str length if it was initially unknown/-1 */
+ n = strnlen(str, n);
+ endstr = str + n;
+ if (n < tailcnt) return FNM_NOMATCH;
+
+ /* Find the final tailcnt chars of str, accounting for UTF-8.
+ * On illegal sequences we may get it wrong, but in that case
+ * we necessarily have a matching failure anyway. */
+ for (s=endstr; s>str && tailcnt; tailcnt--) {
+ if (s[-1] < 128U) s--;
+ else while ((unsigned char)*--s-0x80U<0x40 && s>str);
+ }
+ if (tailcnt) return FNM_NOMATCH;
+ stail = s;
+
+ /* Check that the pat and str tails match */
+ p = ptail;
+ for (;;) {
+ c = pat_next(p, endpat-p, &pinc, flags);
+ p += pinc;
+ if ((k = str_next(s, endstr-s, &sinc)) <= 0) {
+ if (c != END) return FNM_NOMATCH;
+ break;
+ }
+ s += sinc;
+ if (c == BRACKET) {
+ if (!match_bracket(p-pinc, k))
+ return FNM_NOMATCH;
+ } else if (c != QUESTION && k != c) {
+ return FNM_NOMATCH;
+ }
+ }
+
+ /* We're all done with the tails now, so throw them out */
+ endstr = stail;
+ endpat = ptail;
+
+ /* Match pattern components until there are none left */
+ while (pat<endpat) {
+ p = pat;
+ s = str;
+ for (;;) {
+ c = pat_next(p, endpat-p, &pinc, flags);
+ p += pinc;
+ /* Encountering * completes/commits a component */
+ if (c == STAR) {
+ pat = p;
+ str = s;
+ break;
+ }
+ k = str_next(s, endstr-s, &sinc);
+ if (!k)
+ return FNM_NOMATCH;
+ if (c == BRACKET) {
+ if (!match_bracket(p-pinc, k))
+ break;
+ } else if (c != QUESTION && k != c) {
+ break;
+ }
+ s += sinc;
+ }
+ if (c == STAR) continue;
+ /* If we failed, advance str, by 1 char if it's a valid
+ * char, or past all invalid bytes otherwise. */
+ k = str_next(str, endstr-str, &sinc);
+ if (k > 0) str += sinc;
+ else for (str++; str_next(str, endstr-str, &sinc)<0; str++);
+ }
+
+ return 0;
+}
+
+int fnmatch(const char *pat, const char *str, int flags)
+{
+ const char *s, *p;
+ size_t inc;
+ int c;
+ if (flags & FNM_PATHNAME) for (;;) {
+ for (s=str; *s && *s!='/'; s++);
+ for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc);
+ if (*s && *p!=*s) return FNM_NOMATCH;
+ if (fnmatch_internal(pat, p-pat, str, s-str, flags))
+ return FNM_NOMATCH;
+ if (!*s && c==END) return 0;
+ str = s+1;
+ pat = p+1;
+ }
+ return fnmatch_internal(pat, -1, str, -1, flags);
+}
diff --git a/system/lib/libc/musl/src/stdio/__toread.c b/system/lib/libc/musl/src/stdio/__toread.c
index 2e804f64..f00cc467 100644
--- a/system/lib/libc/musl/src/stdio/__toread.c
+++ b/system/lib/libc/musl/src/stdio/__toread.c
@@ -12,13 +12,3 @@ int __toread(FILE *f)
f->rpos = f->rend = f->buf;
return 0;
}
-
-static const int dummy = 0;
-weak_alias(dummy, __towrite_used);
-
-void __stdio_exit(void);
-
-void __seek_on_exit()
-{
- if (!__towrite_used) __stdio_exit();
-}
diff --git a/system/lib/libc/musl/src/stdio/__towrite.c b/system/lib/libc/musl/src/stdio/__towrite.c
new file mode 100644
index 00000000..3698d8b7
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/__towrite.c
@@ -0,0 +1,18 @@
+#include "stdio_impl.h"
+
+int __towrite(FILE *f)
+{
+ f->mode |= f->mode-1;
+ if (f->flags & (F_NOWR)) {
+ f->flags |= F_ERR;
+ return EOF;
+ }
+ /* Clear read buffer (easier than summoning nasal demons) */
+ f->rpos = f->rend = 0;
+
+ /* Activate write through the buffer. */
+ f->wpos = f->wbase = f->buf;
+ f->wend = f->buf + f->buf_size;
+
+ return 0;
+}
diff --git a/system/lib/libc/musl/src/stdio/fputwc.c b/system/lib/libc/musl/src/stdio/fputwc.c
index 11db2804..603fa615 100644
--- a/system/lib/libc/musl/src/stdio/fputwc.c
+++ b/system/lib/libc/musl/src/stdio/fputwc.c
@@ -8,23 +8,37 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f)
char mbc[MB_LEN_MAX];
int l;
+#if 0 // XXX EMSCRIPTEN
f->mode |= f->mode+1;
if (isascii(c)) {
-#if 0 // XXX EMSCRIPTEN
c = putc_unlocked(c, f);
} else if (f->wpos + MB_LEN_MAX < f->wend) {
l = wctomb((void *)f->wpos, c);
if (l < 0) c = WEOF;
else f->wpos += l;
-#else
- c = fputc(c, f);
-#endif
} else {
l = wctomb(mbc, c);
if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF;
}
return c;
+#else
+ if (isascii(c)) {
+ c = fputc(c, f);
+ } else {
+ l = wctomb(mbc, c);
+ if (l < 0) c = WEOF;
+ else {
+ for (int i = 0; i < l; i++) {
+ if (fputc(mbc[i], f) == EOF) {
+ c = WEOF;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ return c;
}
wint_t fputwc(wchar_t c, FILE *f)
diff --git a/system/lib/libc/musl/src/stdio/fputws.c b/system/lib/libc/musl/src/stdio/fputws.c
new file mode 100644
index 00000000..70e004c9
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/fputws.c
@@ -0,0 +1,30 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+
+int fputws(const wchar_t *restrict ws, FILE *restrict f)
+{
+ unsigned char buf[BUFSIZ];
+ size_t l=0;
+
+ FLOCK(f);
+
+#if 0 // XXX EMSCRIPTEN
+ f->mode |= f->mode+1;
+#endif
+
+ while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1)
+#if 0 // XXX EMSCRIPTEN
+ if (__fwritex(buf, l, f) < l) {
+#else
+ if (fwrite(buf, 1, l, f) < l) {
+#endif
+ FUNLOCK(f);
+ return -1;
+ }
+
+ FUNLOCK(f);
+
+ return l; /* 0 or -1 */
+}
+
+weak_alias(fputws, fputws_unlocked);
diff --git a/system/lib/libc/musl/src/stdio/vswprintf.c b/system/lib/libc/musl/src/stdio/vswprintf.c
index 7d237bae..e906f7ae 100644
--- a/system/lib/libc/musl/src/stdio/vswprintf.c
+++ b/system/lib/libc/musl/src/stdio/vswprintf.c
@@ -29,6 +29,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l)
int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_list ap)
{
+#if 0 // XXX EMSCRIPTEN
int r;
FILE f;
unsigned char buf[256];
@@ -50,4 +51,20 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis
r = vfwprintf(&f, fmt, ap);
sw_write(&f, 0, 0);
return r>=n ? -1 : r;
+#else
+ // XXX EMSCRIPTEN: use memfs through libc fs
+ // we write to a file, which is in multibyte, then we read, then expand to widechar
+ #define TEMPFILE "emscripten.vswprintf.temp.buffer"
+ FILE *f = fopen(TEMPFILE, "wb");
+ int r = vfwprintf(f, fmt, ap);
+ fclose(f);
+ f = fopen(TEMPFILE, "rb");
+ char buffer[r+1];
+ fread(buffer, 1, r, f);
+ fclose(f);
+ remove(TEMPFILE);
+ buffer[r] = 0;
+ r = mbstowcs(s, buffer, n);
+ return r>=n ? -1 : r;
+#endif
}
diff --git a/system/lib/libc/musl/src/stdlib/strtod.c b/system/lib/libc/musl/src/stdlib/strtod.c
index 461dcf85..35f640da 100644
--- a/system/lib/libc/musl/src/stdlib/strtod.c
+++ b/system/lib/libc/musl/src/stdlib/strtod.c
@@ -32,9 +32,21 @@ long double strtold(const char *restrict s, char **restrict p)
return strtox(s, p, 2);
}
-weak_alias(strtof, strtof_l);
-weak_alias(strtod, strtod_l);
-weak_alias(strtold, strtold_l);
-weak_alias(strtof, __strtof_l);
-weak_alias(strtod, __strtod_l);
-weak_alias(strtold, __strtold_l);
+float strtof_l(const char *restrict s, char **restrict p, struct __locale_struct *loc)
+{
+ return strtof(s, p);
+}
+
+double strtod_l(const char *restrict s, char **restrict p, struct __locale_struct *loc)
+{
+ return strtod(s, p);
+}
+
+long double strtold_l(const char *restrict s, char **restrict p, struct __locale_struct *loc)
+{
+ return strtold(s, p);
+}
+
+weak_alias(strtof_l, __strtof_l);
+weak_alias(strtod_l, __strtod_l);
+weak_alias(strtold_l, __strtold_l);
diff --git a/system/lib/libc/stdlib/getopt_long.c b/system/lib/libc/stdlib/getopt_long.c
deleted file mode 100644
index e149fe0a..00000000
--- a/system/lib/libc/stdlib/getopt_long.c
+++ /dev/null
@@ -1,511 +0,0 @@
-/* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */
-/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
-
-/*
- * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Dieter Baron and Thomas Klausner.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <errno.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-
-int opterr = 1; /* if error message should be printed */
-int optind = 1; /* index into parent argv vector */
-int optopt = '?'; /* character checked for validity */
-int optreset; /* reset getopt */
-char *optarg; /* argument associated with option */
-
-#define PRINT_ERROR ((opterr) && (*options != ':'))
-
-#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
-#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
-#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
-
-/* return values */
-#define BADCH (int)'?'
-#define BADARG ((*options == ':') ? (int)':' : (int)'?')
-#define INORDER (int)1
-
-#define EMSG ""
-
-static int getopt_internal(int, char * const *, const char *,
- const struct option *, int *, int);
-static int parse_long_options(char * const *, const char *,
- const struct option *, int *, int);
-static int gcd(int, int);
-static void permute_args(int, int, int, char * const *);
-
-static char *place = EMSG; /* option letter processing */
-
-/* XXX: set optreset to 1 rather than these two */
-static int nonopt_start = -1; /* first non option argument (for permute) */
-static int nonopt_end = -1; /* first option after non options (for permute) */
-
-/* Error messages */
-static const char recargchar[] = "option requires an argument -- %c";
-static const char recargstring[] = "option requires an argument -- %s";
-static const char ambig[] = "ambiguous option -- %.*s";
-static const char noarg[] = "option doesn't take an argument -- %.*s";
-static const char illoptchar[] = "unknown option -- %c";
-static const char illoptstring[] = "unknown option -- %s";
-
-/*
- * Compute the greatest common divisor of a and b.
- */
-static int
-gcd(int a, int b)
-{
- int c;
-
- c = a % b;
- while (c != 0) {
- a = b;
- b = c;
- c = a % b;
- }
-
- return (b);
-}
-
-/*
- * Exchange the block from nonopt_start to nonopt_end with the block
- * from nonopt_end to opt_end (keeping the same order of arguments
- * in each block).
- */
-static void
-permute_args(int panonopt_start, int panonopt_end, int opt_end,
- char * const *nargv)
-{
- int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
- char *swap;
-
- /*
- * compute lengths of blocks and number and size of cycles
- */
- nnonopts = panonopt_end - panonopt_start;
- nopts = opt_end - panonopt_end;
- ncycle = gcd(nnonopts, nopts);
- cyclelen = (opt_end - panonopt_start) / ncycle;
-
- for (i = 0; i < ncycle; i++) {
- cstart = panonopt_end+i;
- pos = cstart;
- for (j = 0; j < cyclelen; j++) {
- if (pos >= panonopt_end)
- pos -= nnonopts;
- else
- pos += nopts;
- swap = nargv[pos];
- /* LINTED const cast */
- ((char **) nargv)[pos] = nargv[cstart];
- /* LINTED const cast */
- ((char **)nargv)[cstart] = swap;
- }
- }
-}
-
-/*
- * parse_long_options --
- * Parse long options in argc/argv argument vector.
- * Returns -1 if short_too is set and the option does not match long_options.
- */
-static int
-parse_long_options(char * const *nargv, const char *options,
- const struct option *long_options, int *idx, int short_too)
-{
- char *current_argv, *has_equal;
- size_t current_argv_len;
- int i, match;
-
- current_argv = place;
- match = -1;
-
- optind++;
-
- if ((has_equal = strchr(current_argv, '=')) != NULL) {
- /* argument found (--option=arg) */
- current_argv_len = has_equal - current_argv;
- has_equal++;
- } else
- current_argv_len = strlen(current_argv);
-
- for (i = 0; long_options[i].name; i++) {
- /* find matching long option */
- if (strncmp(current_argv, long_options[i].name,
- current_argv_len))
- continue;
-
- if (strlen(long_options[i].name) == current_argv_len) {
- /* exact match */
- match = i;
- break;
- }
- /*
- * If this is a known short option, don't allow
- * a partial match of a single character.
- */
- if (short_too && current_argv_len == 1)
- continue;
-
- if (match == -1) /* partial match */
- match = i;
- else {
- /* ambiguous abbreviation */
- if (PRINT_ERROR)
- warnx(ambig, (int)current_argv_len,
- current_argv);
- optopt = 0;
- return (BADCH);
- }
- }
- if (match != -1) { /* option found */
- if (long_options[match].has_arg == no_argument
- && has_equal) {
- if (PRINT_ERROR)
- warnx(noarg, (int)current_argv_len,
- current_argv);
- /*
- * XXX: GNU sets optopt to val regardless of flag
- */
- if (long_options[match].flag == NULL)
- optopt = long_options[match].val;
- else
- optopt = 0;
- return (BADARG);
- }
- if (long_options[match].has_arg == required_argument ||
- long_options[match].has_arg == optional_argument) {
- if (has_equal)
- optarg = has_equal;
- else if (long_options[match].has_arg ==
- required_argument) {
- /*
- * optional argument doesn't use next nargv
- */
- optarg = nargv[optind++];
- }
- }
- if ((long_options[match].has_arg == required_argument)
- && (optarg == NULL)) {
- /*
- * Missing argument; leading ':' indicates no error
- * should be generated.
- */
- if (PRINT_ERROR)
- warnx(recargstring,
- current_argv);
- /*
- * XXX: GNU sets optopt to val regardless of flag
- */
- if (long_options[match].flag == NULL)
- optopt = long_options[match].val;
- else
- optopt = 0;
- --optind;
- return (BADARG);
- }
- } else { /* unknown option */
- if (short_too) {
- --optind;
- return (-1);
- }
- if (PRINT_ERROR)
- warnx(illoptstring, current_argv);
- optopt = 0;
- return (BADCH);
- }
- if (idx)
- *idx = match;
- if (long_options[match].flag) {
- *long_options[match].flag = long_options[match].val;
- return (0);
- } else
- return (long_options[match].val);
-}
-
-/*
- * getopt_internal --
- * Parse argc/argv argument vector. Called by user level routines.
- */
-static int
-getopt_internal(int nargc, char * const *nargv, const char *options,
- const struct option *long_options, int *idx, int flags)
-{
- char *oli; /* option letter list index */
- int optchar, short_too;
- static int posixly_correct = -1;
-
- if (options == NULL)
- return (-1);
-
- /*
- * XXX Some GNU programs (like cvs) set optind to 0 instead of
- * XXX using optreset. Work around this braindamage.
- */
- if (optind == 0)
- optind = optreset = 1;
-
- /*
- * Disable GNU extensions if POSIXLY_CORRECT is set or options
- * string begins with a '+'.
- */
- if (posixly_correct == -1 || optreset)
- posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
- if (*options == '-')
- flags |= FLAG_ALLARGS;
- else if (posixly_correct || *options == '+')
- flags &= ~FLAG_PERMUTE;
- if (*options == '+' || *options == '-')
- options++;
-
- optarg = NULL;
- if (optreset)
- nonopt_start = nonopt_end = -1;
-start:
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc) { /* end of argument vector */
- place = EMSG;
- if (nonopt_end != -1) {
- /* do permutation, if we have to */
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- optind -= nonopt_end - nonopt_start;
- }
- else if (nonopt_start != -1) {
- /*
- * If we skipped non-options, set optind
- * to the first of them.
- */
- optind = nonopt_start;
- }
- nonopt_start = nonopt_end = -1;
- return (-1);
- }
- if (*(place = nargv[optind]) != '-' ||
- (place[1] == '\0' && strchr(options, '-') == NULL)) {
- place = EMSG; /* found non-option */
- if (flags & FLAG_ALLARGS) {
- /*
- * GNU extension:
- * return non-option as argument to option 1
- */
- optarg = nargv[optind++];
- return (INORDER);
- }
- if (!(flags & FLAG_PERMUTE)) {
- /*
- * If no permutation wanted, stop parsing
- * at first non-option.
- */
- return (-1);
- }
- /* do permutation */
- if (nonopt_start == -1)
- nonopt_start = optind;
- else if (nonopt_end != -1) {
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- nonopt_start = optind -
- (nonopt_end - nonopt_start);
- nonopt_end = -1;
- }
- optind++;
- /* process next argument */
- goto start;
- }
- if (nonopt_start != -1 && nonopt_end == -1)
- nonopt_end = optind;
-
- /*
- * If we have "-" do nothing, if "--" we are done.
- */
- if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
- optind++;
- place = EMSG;
- /*
- * We found an option (--), so if we skipped
- * non-options, we have to permute.
- */
- if (nonopt_end != -1) {
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- optind -= nonopt_end - nonopt_start;
- }
- nonopt_start = nonopt_end = -1;
- return (-1);
- }
- }
-
- /*
- * Check long options if:
- * 1) we were passed some
- * 2) the arg is not just "-"
- * 3) either the arg starts with -- we are getopt_long_only()
- */
- if (long_options != NULL && place != nargv[optind] &&
- (*place == '-' || (flags & FLAG_LONGONLY))) {
- short_too = 0;
- if (*place == '-')
- place++; /* --foo long option */
- else if (*place != ':' && strchr(options, *place) != NULL)
- short_too = 1; /* could be short option too */
-
- optchar = parse_long_options(nargv, options, long_options,
- idx, short_too);
- if (optchar != -1) {
- place = EMSG;
- return (optchar);
- }
- }
-
- if ((optchar = (int)*place++) == (int)':' ||
- (optchar == (int)'-' && *place != '\0') ||
- (oli = strchr(options, optchar)) == NULL) {
- /*
- * If the user specified "-" and '-' isn't listed in
- * options, return -1 (non-option) as per POSIX.
- * Otherwise, it is an unknown option character (or ':').
- */
- if (optchar == (int)'-' && *place == '\0')
- return (-1);
- if (!*place)
- ++optind;
- if (PRINT_ERROR)
- warnx(illoptchar, optchar);
- optopt = optchar;
- return (BADCH);
- }
- if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
- /* -W long-option */
- if (*place) /* no space */
- /* NOTHING */;
- else if (++optind >= nargc) { /* no arg */
- place = EMSG;
- if (PRINT_ERROR)
- warnx(recargchar, optchar);
- optopt = optchar;
- return (BADARG);
- } else /* white space */
- place = nargv[optind];
- optchar = parse_long_options(nargv, options, long_options,
- idx, 0);
- place = EMSG;
- return (optchar);
- }
- if (*++oli != ':') { /* doesn't take argument */
- if (!*place)
- ++optind;
- } else { /* takes (optional) argument */
- optarg = NULL;
- if (*place) /* no white space */
- optarg = place;
- else if (oli[1] != ':') { /* arg not optional */
- if (++optind >= nargc) { /* no arg */
- place = EMSG;
- if (PRINT_ERROR)
- warnx(recargchar, optchar);
- optopt = optchar;
- return (BADARG);
- } else
- optarg = nargv[optind];
- }
- place = EMSG;
- ++optind;
- }
- /* dump back option letter */
- return (optchar);
-}
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- *
- * [eventually this will replace the BSD getopt]
- */
-int
-getopt(int nargc, char * const *nargv, const char *options)
-{
-
- /*
- * We don't pass FLAG_PERMUTE to getopt_internal() since
- * the BSD getopt(3) (unlike GNU) has never done this.
- *
- * Furthermore, since many privileged programs call getopt()
- * before dropping privileges it makes sense to keep things
- * as simple (and bug-free) as possible.
- */
- return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
-}
-
-/*
- * getopt_long --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long(int nargc, char * const *nargv, const char *options,
- const struct option *long_options, int *idx)
-{
-
- return (getopt_internal(nargc, nargv, options, long_options, idx,
- FLAG_PERMUTE));
-}
-
-/*
- * getopt_long_only --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long_only(int nargc, char * const *nargv, const char *options,
- const struct option *long_options, int *idx)
-{
-
- return (getopt_internal(nargc, nargv, options, long_options, idx,
- FLAG_PERMUTE|FLAG_LONGONLY));
-}
diff --git a/system/lib/libc/stdlib/strtod.c b/system/lib/libc/stdlib/strtod.c
deleted file mode 100644
index 7c441247..00000000
--- a/system/lib/libc/stdlib/strtod.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * strtod.c --
- *
- * Source code for the "strtod" library procedure.
- *
- * Copyright (c) 1988-1993 The Regents of the University of California.
- * Copyright (c) 1994 Sun Microsystems, Inc.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- * RCS: @(#) $Id$
- *
- * Taken from http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/missing/strtod.c
- */
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <locale.h>
-extern int errno;
-
-#ifndef __STDC__
-# ifdef __GNUC__
-# define const __const__
-# else
-# define const
-# endif
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-#ifndef NULL
-#define NULL 0
-#endif
-
-static int maxExponent = 511; /* Largest possible base 10 exponent. Any
- * exponent larger than this will already
- * produce underflow or overflow, so there's
- * no need to worry about additional digits.
- */
-static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
- 10., /* is 10^2^i. Used to convert decimal */
- 100., /* exponents into floating-point numbers. */
- 1.0e4,
- 1.0e8,
- 1.0e16,
- 1.0e32,
- 1.0e64,
- 1.0e128,
- 1.0e256
-};
-
-/*
- *----------------------------------------------------------------------
- *
- * strtod --
- *
- * This procedure converts a floating-point number from an ASCII
- * decimal representation to internal double-precision format.
- *
- * Results:
- * The return value is the double-precision floating-point
- * representation of the characters in string. If endPtr isn't
- * NULL, then *endPtr is filled in with the address of the
- * next character after the last one that was part of the
- * floating-point number.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-double
-strtod(string, endPtr)
- const char *string; /* A decimal ASCII floating-point number,
- * optionally preceded by white space.
- * Must have form "-I.FE-X", where I is the
- * integer part of the mantissa, F is the
- * fractional part of the mantissa, and X
- * is the exponent. Either of the signs
- * may be "+", "-", or omitted. Either I
- * or F may be omitted, or both. The decimal
- * point isn't necessary unless F is present.
- * The "E" may actually be an "e". E and X
- * may both be omitted (but not just one).
- */
- char **endPtr; /* If non-NULL, store terminating character's
- * address here. */
-{
- int sign, expSign = FALSE;
- double fraction, dblExp, *d;
- register const char *p;
- register int c;
- int exp = 0; /* Exponent read from "EX" field. */
- int fracExp = 0; /* Exponent that derives from the fractional
- * part. Under normal circumstatnces, it is
- * the negative of the number of digits in F.
- * However, if I is very long, the last digits
- * of I get dropped (otherwise a long I with a
- * large negative exponent could cause an
- * unnecessary overflow on I alone). In this
- * case, fracExp is incremented one for each
- * dropped digit. */
- int mantSize; /* Number of digits in mantissa. */
- int decPt; /* Number of mantissa digits BEFORE decimal
- * point. */
- const char *pExp; /* Temporarily holds location of exponent
- * in string. */
-
- /*
- * Strip off leading blanks and check for a sign.
- */
-
- p = string;
- while (isspace(*p)) {
- p += 1;
- }
- if (*p == '-') {
- sign = TRUE;
- p += 1;
- } else {
- if (*p == '+') {
- p += 1;
- }
- sign = FALSE;
- }
-
- /*
- * Count the number of digits in the mantissa (including the decimal
- * point), and also locate the decimal point.
- */
-
- decPt = -1;
- for (mantSize = 0; ; mantSize += 1)
- {
- c = *p;
- if (!isdigit(c)) {
- if ((c != '.') || (decPt >= 0)) {
- break;
- }
- decPt = mantSize;
- }
- p += 1;
- }
-
- /*
- * Now suck up the digits in the mantissa. Use two integers to
- * collect 9 digits each (this is faster than using floating-point).
- * If the mantissa has more than 18 digits, ignore the extras, since
- * they can't affect the value anyway.
- */
-
- pExp = p;
- p -= mantSize;
- if (decPt < 0) {
- decPt = mantSize;
- } else {
- mantSize -= 1; /* One of the digits was the point. */
- }
- if (mantSize > 18) {
- fracExp = decPt - 18;
- mantSize = 18;
- } else {
- fracExp = decPt - mantSize;
- }
- if (mantSize == 0) {
- fraction = 0.0;
- p = string;
- goto done;
- } else {
- int frac1, frac2;
- frac1 = 0;
- for ( ; mantSize > 9; mantSize -= 1)
- {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac1 = 10*frac1 + (c - '0');
- }
- frac2 = 0;
- for (; mantSize > 0; mantSize -= 1)
- {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac2 = 10*frac2 + (c - '0');
- }
- fraction = (1.0e9 * frac1) + frac2;
- }
-
- /*
- * Skim off the exponent.
- */
-
- p = pExp;
- if ((*p == 'E') || (*p == 'e')) {
- p += 1;
- if (*p == '-') {
- expSign = TRUE;
- p += 1;
- } else {
- if (*p == '+') {
- p += 1;
- }
- expSign = FALSE;
- }
- while (isdigit(*p)) {
- exp = exp * 10 + (*p - '0');
- p += 1;
- }
- }
- if (expSign) {
- exp = fracExp - exp;
- } else {
- exp = fracExp + exp;
- }
-
- /*
- * Generate a floating-point number that represents the exponent.
- * Do this by processing the exponent one bit at a time to combine
- * many powers of 2 of 10. Then combine the exponent with the
- * fraction.
- */
-
- if (exp < 0) {
- expSign = TRUE;
- exp = -exp;
- } else {
- expSign = FALSE;
- }
- if (exp > maxExponent) {
- exp = maxExponent;
- errno = ERANGE;
- }
- dblExp = 1.0;
- for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
- if (exp & 01) {
- dblExp *= *d;
- }
- }
- if (expSign) {
- fraction /= dblExp;
- } else {
- fraction *= dblExp;
- }
-
-done:
- if (endPtr != NULL) {
- *endPtr = (char *) p;
- }
-
- if (sign) {
- return -fraction;
- }
- return fraction;
-}
-
-/*
- * Implementations added for emscripten.
- */
-// XXX add real support for long double
-long double
-strtold(const char* nptr, char **endptr)
-{
- return (long double) strtod(nptr, endptr);
-}
-
-// use stdtod to handle strtof
-float
-strtof(const char* nptr, char **endptr)
-{
- return (float) strtod(nptr, endptr);
-}
-
-// XXX no locale support yet
-double
-strtod_l(const char* nptr, char **endptr, locale_t loc)
-{
- return strtod(nptr, endptr);
-}
-long double
-strtold_l(const char* nptr, char **endptr, locale_t loc)
-{
- return strtold(nptr, endptr);
-}
-
-double atof(const char* str)
-{
- return strtod(str, (char **) NULL);
-}
diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols
index c3475e1c..54176b1d 100644
--- a/system/lib/libcextra.symbols
+++ b/system/lib/libcextra.symbols
@@ -1,10 +1,16 @@
+ T __cos
T __cosdf
+ T __fputwc_unlocked
T __intscan
W __iswctype_l
T __lgamma_r
T __lgammaf_r
T __lgammal_r
T __memrchr
+ C __optpos
+ D __optreset
+ W __posix_getopt
+ T __sin
T __sindf
T __strchrnul
T __strxfrm_l
@@ -18,9 +24,16 @@
W __wctype_l
T btowc
T ecvt
+ T err
+ T errx
T fcvt
+ T fputwc
+ W fputwc_unlocked
T fwprintf
T gcvt
+ T getopt
+ T getopt_long
+ T getopt_long_only
T iconv
T iconv_close
T iconv_open
@@ -77,6 +90,12 @@
T memmem
T mempcpy
W memrchr
+ C optarg
+ D opterr
+ D optind
+ C optopt
+ W optreset
+ W putwc_unlocked
T regcomp
T regerror
T regexec
@@ -105,9 +124,15 @@
T towlower_l
T towupper
T towupper_l
+ T verr
+ T verrx
T vfwprintf
T vswprintf
+ T vwarn
+ T vwarnx
T vwprintf
+ T warn
+ T warnx
T wcpcpy
T wcpncpy
T wcrtomb
@@ -162,3 +187,4 @@
T wmemmove
T wmemset
T wprintf
+ T fnmatch
diff --git a/tests/cases/fptosi.ll b/tests/cases/fptosi.ll
new file mode 100644
index 00000000..71bc6af8
--- /dev/null
+++ b/tests/cases/fptosi.ll
@@ -0,0 +1,28 @@
+; ModuleID = '/dev/shm/tmp/src.cpp.o'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
+target triple = "le32-unknown-nacl"
+
+@.str = private unnamed_addr constant [8 x i8] c"*%.3f*\0A\00", align 1 ; [#uses=1 type=[8 x i8]*]
+@.str2 = private unnamed_addr constant [6 x i8] c"*%d*\0A\00", align 1 ; [#uses=1 type=[6 x i8]*]
+
+; [#uses=0]
+define i32 @main() {
+entry:
+ %f = fadd float 1.000, 0.500
+ %d = fadd double 3.333, 0.444
+ %fd = fpext float %f to double
+ %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([8 x i8]* @.str, i32 0, i32 0), double %fd) ; [#uses=0 type=i32]
+ %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([8 x i8]* @.str, i32 0, i32 0), double %d) ; [#uses=0 type=i32]
+ %fs = fptosi float %f to i64
+ %fu = fptoui float %f to i64
+ %ds = fptosi double %d to i64
+ %du = fptoui double %d to i64
+ %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %fs) ; [#uses=0 type=i32]
+ %call4 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %fu) ; [#uses=0 type=i32]
+ %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %ds) ; [#uses=0 type=i32]
+ %call6 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i64 %du) ; [#uses=0 type=i32]
+ ret i32 1
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
diff --git a/tests/cases/fptosi.txt b/tests/cases/fptosi.txt
new file mode 100644
index 00000000..eea925c4
--- /dev/null
+++ b/tests/cases/fptosi.txt
@@ -0,0 +1,6 @@
+*1.500*
+*3.777*
+*1*
+*1*
+*3*
+*3*
diff --git a/tests/cases/longjmp_tiny_invoke.ll b/tests/cases/longjmp_tiny_invoke.ll
index e1a72e00..6f856d49 100644
--- a/tests/cases/longjmp_tiny_invoke.ll
+++ b/tests/cases/longjmp_tiny_invoke.ll
@@ -9,7 +9,7 @@ target triple = "i386-pc-linux-gnu"
define i32 @main() {
%retval = alloca i32, align 4
store i32 0, i32* %retval
- %call = invoke i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice, !dbg !20
+ %call = invoke i32 @setjmp(i16* getelementptr inbounds ([20 x i16]* @_ZL3buf, i32 0, i32 0)) returns_twice
to label %allgood unwind label %awful
allgood:
@@ -29,9 +29,13 @@ if.end: ; preds = %if.else, %if.then
ret i32 0, !dbg !28
awful:
+ %Z = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ cleanup
ret i32 1
}
+declare i32 @__gxx_personality_v0(...)
+
declare i32 @setjmp(i16*) returns_twice
declare i32 @printf(i8*, ...)
diff --git a/tests/cases/longjmp_tiny_invoke_phi.ll b/tests/cases/longjmp_tiny_invoke_phi.ll
index 30c43339..0df3f924 100644
--- a/tests/cases/longjmp_tiny_invoke_phi.ll
+++ b/tests/cases/longjmp_tiny_invoke_phi.ll
@@ -35,6 +35,8 @@ if.end: ; preds = %if.else, %if.then
ret i32 0
awful:
+ %Z = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ cleanup
ret i32 1
}
@@ -44,3 +46,5 @@ declare i32 @printf(i8*, ...)
declare void @longjmp(i16*, i32)
+declare i32 @__gxx_personality_v0(...)
+
diff --git a/tests/cases/longjmp_tiny_phi.ll b/tests/cases/longjmp_tiny_phi.ll
index cced7cab..21b936dd 100644
--- a/tests/cases/longjmp_tiny_phi.ll
+++ b/tests/cases/longjmp_tiny_phi.ll
@@ -28,7 +28,7 @@ if.else: ; preds = %entry
br label %if.end
if.end: ; preds = %if.else, %if.then
- %aaa = phi i32 [ -1, %if.then ], [ 0, %if.else ], [ 1, %two ], [ 2, %entry ]
+ %aaa = phi i32 [ -1, %if.then ], [ 0, %if.else ]
%call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i32 %aaa), !dbg !26
ret i32 %aaa, !dbg !28
}
diff --git a/tests/cases/longjmp_tiny_phi2.ll b/tests/cases/longjmp_tiny_phi2.ll
index 1d7761c3..88312fc6 100644
--- a/tests/cases/longjmp_tiny_phi2.ll
+++ b/tests/cases/longjmp_tiny_phi2.ll
@@ -24,7 +24,7 @@ if.then: ; preds = %entry
br label %if.end, !dbg !25
if.end: ; preds = %if.else, %if.then
- %aaa = phi i32 [ -1, %if.then ], [ 1, %two ], [ 2, %entry ]
+ %aaa = phi i32 [ -1, %if.then ], [ 1, %two ]
%call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str2, i32 0, i32 0), i32 %aaa), !dbg !26
ret i32 %aaa, !dbg !28
}
diff --git a/tests/core/fnmatch.c b/tests/core/fnmatch.c
new file mode 100644
index 00000000..ebdb2009
--- /dev/null
+++ b/tests/core/fnmatch.c
@@ -0,0 +1,79 @@
+// Begin test_fnmatch.cpp
+#include <fnmatch.h>
+#include <iostream>
+#include <vector>
+#include <string>
+
+using namespace std;
+
+class TestCase {
+public:
+ TestCase(const string& pattern, const string& testString, int flags, int expected) :
+ pattern(pattern),
+ testString(testString),
+ flags(flags),
+ expected(expected)
+ {}
+ string pattern;
+ string testString;
+ int flags;
+ int expected;
+};
+
+int main()
+{
+ vector<TestCase> testCases;
+
+ testCases.push_back(TestCase("*","anything",0,0));
+ testCases.push_back(TestCase("*.txt","readme.txt",0,0));
+ testCases.push_back(TestCase("*.txt","readme.info",0,FNM_NOMATCH));
+ testCases.push_back(TestCase("*.t?t","readme.txt",0,0));
+ testCases.push_back(TestCase("*.t?t","readme.tot",0,0));
+ testCases.push_back(TestCase("*.t?t","readme.txxt",0,FNM_NOMATCH));
+ testCases.push_back(TestCase("[a-g]1","c1",0,0));
+ testCases.push_back(TestCase("[a-g]1","i1",0,FNM_NOMATCH));
+ testCases.push_back(TestCase("[!a-g]1","i1",0,0));
+ testCases.push_back(TestCase("a\\*","anything",0,FNM_NOMATCH));
+ testCases.push_back(TestCase("a\\*","a*",0,0));
+ testCases.push_back(TestCase("a\\*","a*",FNM_NOESCAPE,FNM_NOMATCH));
+ testCases.push_back(TestCase("a\\*","a\\*",FNM_NOESCAPE,0));
+ testCases.push_back(TestCase("*readme","/etc/readme",0,0));
+ testCases.push_back(TestCase("*readme","/etc/readme",FNM_PATHNAME,FNM_NOMATCH));
+ testCases.push_back(TestCase("/*/readme","/etc/readme",FNM_PATHNAME,0));
+ testCases.push_back(TestCase("*readme","/etc/.readme",0,0));
+ testCases.push_back(TestCase("*readme",".readme",FNM_PERIOD,FNM_NOMATCH));
+ testCases.push_back(TestCase("*.readme","/etc/.readme",FNM_PERIOD,0));
+ testCases.push_back(TestCase("*.readme","/etc/.readme",FNM_PERIOD|FNM_PATHNAME,FNM_NOMATCH));
+ testCases.push_back(TestCase("/*/.readme","/etc/.readme",FNM_PERIOD|FNM_PATHNAME,0));
+ testCases.push_back(TestCase("ReAdME","readme",0,FNM_NOMATCH));
+
+ bool pass = true;
+
+ for (vector<TestCase>::const_iterator it = testCases.begin(); it != testCases.end(); ++it)
+ {
+ int result = fnmatch(it->pattern.c_str(), it->testString.c_str(), it->flags);
+ if (result == it->expected)
+ cout << "Pass: ";
+ else
+ {
+ cout << "Fail: ";
+ pass = false;
+ }
+
+ cout << "fnmatch(" << it->pattern << ", " << it->testString << ", "
+ << it->flags << ") returned " << result << ", expected "
+ << it->expected << endl;
+ }
+
+ if (pass)
+ {
+ cout << "All tests passed." << endl;
+ return 0;
+ }
+ else
+ {
+ cout << "Some tests failed." << endl;
+ return 1;
+ }
+}
+
diff --git a/tests/core/fnmatch.out b/tests/core/fnmatch.out
new file mode 100644
index 00000000..303f7449
--- /dev/null
+++ b/tests/core/fnmatch.out
@@ -0,0 +1,23 @@
+Pass: fnmatch(*, anything, 0) returned 0, expected 0
+Pass: fnmatch(*.txt, readme.txt, 0) returned 0, expected 0
+Pass: fnmatch(*.txt, readme.info, 0) returned 1, expected 1
+Pass: fnmatch(*.t?t, readme.txt, 0) returned 0, expected 0
+Pass: fnmatch(*.t?t, readme.tot, 0) returned 0, expected 0
+Pass: fnmatch(*.t?t, readme.txxt, 0) returned 1, expected 1
+Pass: fnmatch([a-g]1, c1, 0) returned 0, expected 0
+Pass: fnmatch([a-g]1, i1, 0) returned 1, expected 1
+Pass: fnmatch([!a-g]1, i1, 0) returned 0, expected 0
+Pass: fnmatch(a\*, anything, 0) returned 1, expected 1
+Pass: fnmatch(a\*, a*, 0) returned 0, expected 0
+Pass: fnmatch(a\*, a*, 2) returned 1, expected 1
+Pass: fnmatch(a\*, a\*, 2) returned 0, expected 0
+Pass: fnmatch(*readme, /etc/readme, 0) returned 0, expected 0
+Pass: fnmatch(*readme, /etc/readme, 1) returned 1, expected 1
+Pass: fnmatch(/*/readme, /etc/readme, 1) returned 0, expected 0
+Pass: fnmatch(*readme, /etc/.readme, 0) returned 0, expected 0
+Pass: fnmatch(*readme, .readme, 4) returned 1, expected 1
+Pass: fnmatch(*.readme, /etc/.readme, 4) returned 0, expected 0
+Pass: fnmatch(*.readme, /etc/.readme, 5) returned 1, expected 1
+Pass: fnmatch(/*/.readme, /etc/.readme, 5) returned 0, expected 0
+Pass: fnmatch(ReAdME, readme, 0) returned 1, expected 1
+All tests passed.
diff --git a/tests/core/test_alloca.in b/tests/core/test_alloca.in
index bfad3324..d115880f 100644
--- a/tests/core/test_alloca.in
+++ b/tests/core/test_alloca.in
@@ -1,9 +1,14 @@
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
-int main() {
- char *pc;
- pc = (char *)alloca(5);
- printf("z:%d*%d*\n", pc > 0, (int)pc);
+int main(int argc, char **argv) {
+ char *pc, *pc2;
+ assert(argc == 1);
+ pc = (char *)alloca(4+argc);
+ assert(((int)pc) % 4 == 0);
+ pc2 = (char *)alloca(4+argc);
+ assert(((int)pc2) % 4 == 0);
+ printf("z:%d*%d*%d*\n", pc > 0, (int)pc, (int)pc2);
return 0;
}
diff --git a/tests/core/test_exception_2.in b/tests/core/test_exceptions_2.in
index 2eae3198..2eae3198 100644
--- a/tests/core/test_exception_2.in
+++ b/tests/core/test_exceptions_2.in
diff --git a/tests/core/test_exception_2.out b/tests/core/test_exceptions_2.out
index aa89c67d..aa89c67d 100644
--- a/tests/core/test_exception_2.out
+++ b/tests/core/test_exceptions_2.out
diff --git a/tests/core/test_multiexception.in b/tests/core/test_exceptions_multi.in
index 46acbbf3..5453d11c 100644
--- a/tests/core/test_multiexception.in
+++ b/tests/core/test_exceptions_multi.in
@@ -22,9 +22,9 @@ void setjmp_func(jmp_state* s, int level) {
s->jmp = c_jmp;
setjmp_func(s, level + 1);
}
- catch (int catched_eid) {
- printf("caught %d\n", catched_eid);
- if (catched_eid == c_jmp) {
+ catch (int caught_eid) {
+ printf("caught %d\n", caught_eid);
+ if (caught_eid == c_jmp) {
printf("setjmp exception execution path, level: %d, prev_jmp: %d\n",
level, prev_jmp);
if (prev_jmp != -1) {
diff --git a/tests/core/test_multiexception.out b/tests/core/test_exceptions_multi.out
index 33efe46e..33efe46e 100644
--- a/tests/core/test_multiexception.out
+++ b/tests/core/test_exceptions_multi.out
diff --git a/tests/core/test_std_exception.in b/tests/core/test_exceptions_std.in
index 4b5905d8..3b9f874b 100644
--- a/tests/core/test_std_exception.in
+++ b/tests/core/test_exceptions_std.in
@@ -7,6 +7,7 @@ int main() {
throw e;
}
catch (std::exception e) {
+ printf("what? %s\n", e.what());
printf("caught std::exception\n");
}
return 0;
diff --git a/tests/core/test_exceptions_std.out b/tests/core/test_exceptions_std.out
new file mode 100644
index 00000000..eddab21c
--- /dev/null
+++ b/tests/core/test_exceptions_std.out
@@ -0,0 +1,2 @@
+what? std::exception
+caught std::exception
diff --git a/tests/exceptions/typed.cpp b/tests/core/test_exceptions_typed.in
index a2b77fee..a2b77fee 100644
--- a/tests/exceptions/typed.cpp
+++ b/tests/core/test_exceptions_typed.in
diff --git a/tests/exceptions/output.txt b/tests/core/test_exceptions_typed.out
index 718f189a..718f189a 100644
--- a/tests/exceptions/output.txt
+++ b/tests/core/test_exceptions_typed.out
diff --git a/tests/core/test_white_list_exception.in b/tests/core/test_exceptions_white_list.in
index 2944f9fe..2944f9fe 100644
--- a/tests/core/test_white_list_exception.in
+++ b/tests/core/test_exceptions_white_list.in
diff --git a/tests/core/test_white_list_exception.out b/tests/core/test_exceptions_white_list.out
index 62e1a81c..62e1a81c 100644
--- a/tests/core/test_white_list_exception.out
+++ b/tests/core/test_exceptions_white_list.out
diff --git a/tests/core/test_inlinejs3.in b/tests/core/test_inlinejs3.in
index 3e1913ff..e21ed041 100644
--- a/tests/core/test_inlinejs3.in
+++ b/tests/core/test_inlinejs3.in
@@ -3,7 +3,7 @@
int main(int argc, char **argv) {
EM_ASM(Module.print('hello dere1'));
- EM_ASM(Module.print('hello dere2'););
+ EM_ASM("Module.print('hello dere2');");
for (int i = 0; i < 3; i++) {
EM_ASM(Module.print('hello dere3'); Module.print('hello dere' + 4););
}
diff --git a/tests/core/test_nl_types.in b/tests/core/test_nl_types.in
new file mode 100644
index 00000000..666920ee
--- /dev/null
+++ b/tests/core/test_nl_types.in
@@ -0,0 +1,8 @@
+#include <nl_types.h>
+#include <stdio.h>
+
+int main(int argc, char ** argv) {
+ nl_catd c = catopen("none", 0);
+ printf("Hello, %s.\n", catgets(c, 0, 0, "world"));
+ return catclose(c);
+}
diff --git a/tests/core/test_nl_types.out b/tests/core/test_nl_types.out
new file mode 100644
index 00000000..f75ba05f
--- /dev/null
+++ b/tests/core/test_nl_types.out
@@ -0,0 +1 @@
+Hello, world.
diff --git a/tests/core/test_std_exception.out b/tests/core/test_std_exception.out
deleted file mode 100644
index c1660de4..00000000
--- a/tests/core/test_std_exception.out
+++ /dev/null
@@ -1 +0,0 @@
-caught std::exception \ No newline at end of file
diff --git a/tests/core/test_wprintf.c b/tests/core/test_wprintf.c
index e938bf69..b5f8d6ab 100644
--- a/tests/core/test_wprintf.c
+++ b/tests/core/test_wprintf.c
@@ -1,7 +1,44 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
#include <wchar.h>
-int main()
+void PrintWide ( const wchar_t * format, ... )
{
+ wchar_t buffer[256];
+ memset(buffer, 0, 256);
+ va_list args;
+ va_start ( args, format );
+ wprintf(L"format starts with 0x%x\n", *(int*)format);
+ wprintf(L"fmt continues with 0x%x\n", *(((int*)format) + 1));
+ wprintf(L"fmt continues with 0x%x\n", *(((int*)format) + 2));
+ int r = vswprintf ( buffer, 256, format, args );
+ wprintf(L"vswprintf told us %d\n", r);
+ wprintf(L"vswoutput st-rts with 0x%x\n", *(int*)buffer);
+ wprintf(L"vsw continues with 0x%x\n", *(((int*)buffer) + 1));
+ wprintf(L"vsw continues with 0x%x\n", *(((int*)buffer) + 2));
+ wprintf(buffer);
+ va_end ( args );
+}
+
+int main ()
+{
+ FILE *f = fopen("test.dat", "wb");
+ int num = fwprintf(f, L"hello %d", 5);
+ wprintf(L"fwprintf told us %d\n", num);
+ fclose(f);
+ f = fopen("test.dat", "rb");
+ fseek(f, 0, SEEK_END);
+ int size = ftell(f);
+ fclose(f);
+ wprintf(L"file size is %d\n", size);
+
+ wchar_t str[] = L"test string has %d wide characters.\n";
+ wprintf(L"str starts with 0x%x\n", *(int*)str);
+ wprintf(L"str continues with 0x%x\n", *(((int*)str) + 1));
+ wprintf(L"str continues with 0x%x\n", *(((int*)str) + 2));
+ PrintWide ( str, wcslen(str) );
+
wprintf (L"Characters: %lc %lc \n", L'a', 65);
wprintf (L"Decimals: %d %ld\n", 1977, 650000L);
wprintf (L"Preceding with blanks: %10d \n", 1977);
@@ -10,6 +47,17 @@ int main()
wprintf (L"floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
wprintf (L"Width trick: %*d \n", 5, 10);
wprintf (L"%ls \n", L"A wide string");
+
+ wchar_t buffer [100];
+ memset(buffer, 0, sizeof(buffer));
+ int cx;
+ cx = swprintf(buffer, 100, L"The half of %d is %d", 80, 80/2);
+ wprintf(L"swprintf told us %d\n", cx);
+ for (int i = 0; i < 10; i++) wprintf(L"pre %d\n", ((int*)buffer)[i]);
+ swprintf (buffer+cx, 100-cx-1, L", and the half of that is %d.\n", 80/2/2);
+ for (int i = 0; i < 10; i++) wprintf(L"post %d\n", ((int*)buffer)[i]);
+ wprintf(buffer);
+
return 0;
}
diff --git a/tests/core/test_wprintf.out b/tests/core/test_wprintf.out
index f85abebb..e074743d 100644
--- a/tests/core/test_wprintf.out
+++ b/tests/core/test_wprintf.out
@@ -1,3 +1,16 @@
+fwprintf told us 7
+file size is 7
+str starts with 0x74
+str continues with 0x65
+str continues with 0x73
+format starts with 0x74
+fmt continues with 0x65
+fmt continues with 0x73
+vswprintf told us 36
+vswoutput st-rts with 0x74
+vsw continues with 0x65
+vsw continues with 0x73
+test string has 36 wide characters.
Characters: a A
Decimals: 1977 650000
Preceding with blanks: 1977
@@ -6,3 +19,25 @@ Some different radixes: 100 64 144 0x64 0144
floats: 3.14 +3e+00 3.141600E+00
Width trick: 10
A wide string
+swprintf told us 20
+pre 84
+pre 104
+pre 101
+pre 32
+pre 104
+pre 97
+pre 108
+pre 102
+pre 32
+pre 111
+post 84
+post 104
+post 101
+post 32
+post 104
+post 97
+post 108
+post 102
+post 32
+post 111
+The half of 80 is 40, and the half of that is 20.
diff --git a/tests/doublestart.c b/tests/doublestart.c
new file mode 100644
index 00000000..533e6308
--- /dev/null
+++ b/tests/doublestart.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <emscripten.h>
+
+int times = 0;
+
+void later(void* nada) {
+ int result = times;
+ REPORT_RESULT();
+}
+
+void main_loop(void) {
+ static int cnt = 0;
+ if (++cnt >= 10) emscripten_cancel_main_loop();
+}
+
+int main(void) {
+ emscripten_async_call(later, NULL, 2000);
+ times++;
+ printf("This should only appear once.\n");
+ emscripten_set_main_loop(main_loop, 10, 0);
+ return 0;
+}
+
diff --git a/tests/glew.c b/tests/glew.c
new file mode 100644
index 00000000..3bf93fd9
--- /dev/null
+++ b/tests/glew.c
@@ -0,0 +1,51 @@
+#include <GL/glew.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+/* for context creation */
+#include <SDL/SDL.h>
+
+int main()
+{
+ assert(SDL_Init(SDL_INIT_VIDEO) == 0);
+ assert(SDL_SetVideoMode(640, 480, 16, SDL_OPENGL) != NULL);
+
+ assert(glewInit() == GLEW_OK);
+ assert(glewGetString(0) == NULL);
+ assert(!strcmp((const char*)glewGetString(1), "1.10.0"));
+ assert(!strcmp((const char*)glewGetString(2), "1"));
+ assert(!strcmp((const char*)glewGetString(3), "10"));
+ assert(!strcmp((const char*)glewGetString(4), "0"));
+
+ for (int i = 0; i < 8; ++i) {
+ assert(glewGetErrorString(i) != NULL);
+ }
+
+ assert(glewGetExtension("EXT_unexistant") == 0);
+ assert(glewIsSupported("EXT_unexistant EXT_foobar") == 0);
+
+ /* we can't be sure about which extension exists, so lets do test on
+ * some of the common ones */
+ if (GLEW_EXT_texture_filter_anisotropic) {
+ assert(glewGetExtension("EXT_texture_filter_anisotropic") == 1);
+ assert(glewGetExtension("GL_EXT_texture_filter_anisotropic") == 1);
+ }
+
+ if (GLEW_EXT_framebuffer_object) {
+ assert(glewGetExtension("EXT_framebuffer_object") == 1);
+ assert(glewGetExtension("GL_EXT_framebuffer_object") == 1);
+ }
+
+ if (GLEW_EXT_texture_filter_anisotropic &&
+ GLEW_EXT_framebuffer_object) {
+ assert(glewIsSupported("EXT_texture_filter_anisotropic EXT_framebuffer_object") == 1);
+ assert(glewIsSupported("GL_EXT_texture_filter_anisotropic GL_EXT_framebuffer_object") == 1);
+ }
+
+#ifdef REPORT_RESULT
+ int result = 1;
+ REPORT_RESULT();
+#endif
+ return 0;
+}
diff --git a/tests/runner.py b/tests/runner.py
index 7f0cbaed..f59d5cb9 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -36,7 +36,7 @@ except:
# Core test runner class, shared between normal tests and benchmarks
checked_sanity = False
-test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm2f', 'asm2g', 'asm2x86', 's_0_0', 's_0_1']
+test_modes = ['default', 'o1', 'o2', 'asm1', 'asm2', 'asm3', 'asm2f', 'asm2g', 'asm2x86', 's_0_0', 's_0_1']
test_index = 0
class RunnerCore(unittest.TestCase):
diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py
index 21a47178..1bf1c1d5 100644
--- a/tests/test_benchmark.py
+++ b/tests/test_benchmark.py
@@ -51,20 +51,21 @@ class Benchmarker:
print
class NativeBenchmarker(Benchmarker):
- def __init__(self, name, cc, cxx):
+ def __init__(self, name, cc, cxx, args=['-O2']):
self.name = name
self.cc = cc
self.cxx = cxx
+ self.args = args
def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder):
self.parent = parent
if lib_builder: native_args = native_args + lib_builder(self.name, native=True, env_init={ 'CC': self.cc, 'CXX': self.cxx })
if not native_exec:
compiler = self.cxx if filename.endswith('cpp') else self.cc
- process = Popen([compiler, '-O2', '-fno-math-errno', filename, '-o', filename+'.native'] + shared_args + native_args, stdout=PIPE, stderr=parent.stderr_redirect)
+ process = Popen([compiler, '-fno-math-errno', filename, '-o', filename+'.native'] + self.args + shared_args + native_args, stdout=PIPE, stderr=parent.stderr_redirect)
output = process.communicate()
if process.returncode is not 0:
- print >> sys.stderr, "Building native executable with command '%s' failed with a return code %d!" % (' '.join([compiler, '-O2', filename, '-o', filename+'.native']), process.returncode)
+ print >> sys.stderr, "Building native executable with command failed"
print "Output: " + output[0]
else:
shutil.copyfile(native_exec, filename + '.native')
@@ -106,7 +107,7 @@ process(sys.argv[1])
final = os.path.dirname(filename) + os.path.sep + self.name+'_' + os.path.basename(filename) + '.js'
try_delete(final)
output = Popen([PYTHON, EMCC, filename, #'-O3',
- '-O2', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
+ '-O3', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
'--memory-init-file', '0', '--js-transform', 'python hardcode.py',
'-s', 'TOTAL_MEMORY=128*1024*1024',
#'--closure', '1',
@@ -124,6 +125,7 @@ try:
benchmarkers = [
#NativeBenchmarker('clang', CLANG_CC, CLANG),
NativeBenchmarker('clang-3.2', os.path.join(LLVM_3_2, 'clang'), os.path.join(LLVM_3_2, 'clang++')),
+ #NativeBenchmarker('clang-3.2-O3', os.path.join(LLVM_3_2, 'clang'), os.path.join(LLVM_3_2, 'clang++'), ['-O3']),
#NativeBenchmarker('clang-3.3', os.path.join(LLVM_3_3, 'clang'), os.path.join(LLVM_3_3, 'clang++')),
#NativeBenchmarker('clang-3.4', os.path.join(LLVM_3_4, 'clang'), os.path.join(LLVM_3_4, 'clang++')),
#NativeBenchmarker('gcc', 'gcc', 'g++'),
@@ -472,7 +474,7 @@ class benchmark(RunnerCore):
def lua(self, benchmark, expected, output_parser=None, args_processor=None):
shutil.copyfile(path_from_root('tests', 'lua', benchmark + '.lua'), benchmark + '.lua')
def lib_builder(name, native, env_init):
- ret = self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=native, cache_name_extra=name, env_init=env_init)
+ ret = self.get_library('lua_native' if native else 'lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=native, cache_name_extra=name, env_init=env_init)
if native: return ret
shutil.copyfile(ret[0], ret[0] + '.bc')
ret[0] += '.bc'
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 27dffff2..02bcecbd 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -683,6 +683,9 @@ If manually bisecting:
def test_sdl_canvas(self):
self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1'])
+ # some extra coverage
+ self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', '-O0', 'SAFE_HEAP=1'])
+ self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-s', '-O2', 'SAFE_HEAP=1'])
def test_sdl_canvas_proxy(self):
def post():
@@ -1602,6 +1605,10 @@ keydown(100);keyup(100); // trigger the end
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_ffp_only(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', '-s', 'GL_FFP_ONLY=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')
@@ -1749,4 +1756,21 @@ keydown(100);keyup(100); // trigger the end
# Now run test in browser
self.btest(path_from_root('tests', 'uuid', 'test.c'), '1')
+ def test_glew(self):
+ self.btest(path_from_root('tests', 'glew.c'), expected='1')
+ self.btest(path_from_root('tests', 'glew.c'), args=['-s', 'LEGACY_GL_EMULATION=1'], expected='1')
+ self.btest(path_from_root('tests', 'glew.c'), args=['-DGLEW_MX'], expected='1')
+ self.btest(path_from_root('tests', 'glew.c'), args=['-s', 'LEGACY_GL_EMULATION=1', '-DGLEW_MX'], expected='1')
+
+ def test_doublestart_bug(self):
+ open('pre.js', 'w').write(r'''
+if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
+if (!Module['preRun']) Module['preRun'] = [];
+Module["preRun"].push(function () {
+ Module['addRunDependency']('test_run_dependency');
+ Module['removeRunDependency']('test_run_dependency');
+});
+''')
+
+ self.btest('doublestart.c', args=['--pre-js', 'pre.js', '-o', 'test.html'], expected='1')
diff --git a/tests/test_core.py b/tests/test_core.py
index d7bebdc6..d25847d7 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -1117,74 +1117,48 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_longjmp(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
- test_path = path_from_root('tests', 'core', 'test_longjmp')
- src, output = (test_path + s for s in ('.in', '.out'))
-
- self.do_run_from_file(src, output)
+ test_path = path_from_root('tests', 'core', 'test_longjmp')
+ src, output = (test_path + s for s in ('.in', '.out'))
+ self.do_run_from_file(src, output)
def test_longjmp2(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
test_path = path_from_root('tests', 'core', 'test_longjmp2')
src, output = (test_path + s for s in ('.in', '.out'))
-
self.do_run_from_file(src, output)
def test_longjmp3(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
test_path = path_from_root('tests', 'core', 'test_longjmp3')
src, output = (test_path + s for s in ('.in', '.out'))
-
self.do_run_from_file(src, output)
def test_longjmp4(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
test_path = path_from_root('tests', 'core', 'test_longjmp4')
src, output = (test_path + s for s in ('.in', '.out'))
-
self.do_run_from_file(src, output)
def test_longjmp_funcptr(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
test_path = path_from_root('tests', 'core', 'test_longjmp_funcptr')
src, output = (test_path + s for s in ('.in', '.out'))
-
self.do_run_from_file(src, output)
def test_longjmp_repeat(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
- Settings.MAX_SETJMPS = 1
-
- test_path = path_from_root('tests', 'core', 'test_longjmp_repeat')
- src, output = (test_path + s for s in ('.in', '.out'))
-
- self.do_run_from_file(src, output)
+ Settings.MAX_SETJMPS = 1
+ test_path = path_from_root('tests', 'core', 'test_longjmp_repeat')
+ src, output = (test_path + s for s in ('.in', '.out'))
+ self.do_run_from_file(src, output)
def test_longjmp_stacked(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
test_path = path_from_root('tests', 'core', 'test_longjmp_stacked')
src, output = (test_path + s for s in ('.in', '.out'))
-
self.do_run_from_file(src, output)
-
def test_longjmp_exc(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
test_path = path_from_root('tests', 'core', 'test_longjmp_exc')
src, output = (test_path + s for s in ('.in', '.out'))
-
self.do_run_from_file(src, output)
def test_setjmp_many(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+ if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp: make MAX_SETJMPS take effect')
src = r'''
#include <stdio.h>
@@ -1269,7 +1243,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
}
catch (MyException & e)
{
- std::cout << "Catched...";
+ std::cout << "Caught...";
}
try
@@ -1278,7 +1252,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
}
catch (MyException e)
{
- std::cout << "Catched...";
+ std::cout << "Caught...";
}
return 0;
@@ -1288,26 +1262,25 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
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...')
+ self.do_run(src, 'Throw...Construct...Caught...Destruct...Throw...Construct...Copy...Caught...Destruct...Destruct...')
- def test_exception_2(self):
+ def test_exceptions_2(self):
if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
Settings.DISABLE_EXCEPTION_CATCHING = 0
- test_path = path_from_root('tests', 'core', 'test_exception_2')
+ test_path = path_from_root('tests', 'core', 'test_exceptions_2')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
-
- def test_white_list_exception(self):
+ def test_exceptions_white_list(self):
if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
Settings.DISABLE_EXCEPTION_CATCHING = 2
Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified
- test_path = path_from_root('tests', 'core', 'test_white_list_exception')
+ test_path = path_from_root('tests', 'core', 'test_exceptions_white_list')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
@@ -1315,7 +1288,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
Settings.DISABLE_EXCEPTION_CATCHING = 0
Settings.EXCEPTION_CATCHING_WHITELIST = []
- def test_uncaught_exception(self):
+ def test_exceptions_uncaught(self):
if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
Settings.DISABLE_EXCEPTION_CATCHING = 0
@@ -1354,29 +1327,27 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
'''
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):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
+ def test_exceptions_typed(self):
Settings.DISABLE_EXCEPTION_CATCHING = 0
+ Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
- test_path = path_from_root('tests', 'core', 'test_multiexception')
+ test_path = path_from_root('tests', 'core', 'test_exceptions_typed')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
- def test_std_exception(self):
+ def test_exceptions_multi(self):
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ test_path = path_from_root('tests', 'core', 'test_exceptions_multi')
+ src, output = (test_path + s for s in ('.in', '.out'))
+ self.do_run_from_file(src, output)
+
+ def test_exceptions_std(self):
if self.emcc_args is None: return self.skip('requires emcc')
Settings.DISABLE_EXCEPTION_CATCHING = 0
self.emcc_args += ['-s', 'SAFE_HEAP=0']
- test_path = path_from_root('tests', 'core', 'test_std_exception')
+ test_path = path_from_root('tests', 'core', 'test_exceptions_std')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
@@ -1486,7 +1457,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
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')
+ if os.environ.get('EMCC_FAST_COMPILER') == '1' and '-O2' not in self.emcc_args: return self.skip('todo in non-jsopts-enabled fastcomp')
Settings.SAFE_HEAP = 1
@@ -1606,6 +1577,8 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_alloca(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('non-ta2 may have unaligned allocas')
+
test_path = path_from_root('tests', 'core', 'test_alloca')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -3703,6 +3676,12 @@ ok
self.do_run_from_file(src, output)
+ def test_fnmatch(self):
+ if self.emcc_args is None: return self.skip('requires linking in libc++')
+ test_path = path_from_root('tests', 'core', 'fnmatch')
+ src, output = (test_path + s for s in ('.c', '.out'))
+ self.do_run_from_file(src, output)
+
def test_sscanf(self):
if self.emcc_args is None: return self.skip('needs emcc for libc')
if not self.is_le32(): return self.skip('le32 needed for accurate math')
@@ -4085,7 +4064,6 @@ def process(filename):
def test_utf32(self):
if self.emcc_args is None: return self.skip('need libc for wcslen()')
if not self.is_le32(): return self.skip('this test uses inline js, which requires le32')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.')
self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.', args=['-fshort-wchar'])
@@ -4284,6 +4262,12 @@ def process(filename):
self.do_run_from_file(src, output)
+ def test_nl_types(self):
+ test_path = path_from_root('tests', 'core', 'test_nl_types')
+ src, output = (test_path + s for s in ('.in', '.out'))
+
+ self.do_run_from_file(src, output)
+
def test_799(self):
src = open(path_from_root('tests', '799.cpp'), 'r').read()
self.do_run(src, '''Set PORT family: 0, port: 3979
@@ -4620,6 +4604,7 @@ return malloc(size);
assert 'asm1' in test_modes
if self.run_name == 'asm1':
generated = open('src.cpp.o.js').read()
+ generated = re.sub(r'\n+[ \n]*\n+', '\n', generated)
main = generated[generated.find('function runPostSets'):]
main = main[:main.find('\n}')]
assert main.count('\n') == 7, 'must not emit too many postSets: %d' % main.count('\n')
@@ -4642,6 +4627,8 @@ return malloc(size);
self.do_run_from_file(src, output)
def test_simd3(self):
+ return self.skip('FIXME: this appears to be broken')
+
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
@@ -4670,7 +4657,6 @@ return malloc(size);
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')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
for aggro in ([0, 1] if Settings.ASM_JS and '-O2' in self.emcc_args else [0]):
print aggro
@@ -4691,7 +4677,6 @@ return malloc(size);
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 os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
assert 'asm2g' in test_modes
if self.run_name == 'asm2g':
@@ -4837,7 +4822,6 @@ def process(filename):
def test_poppler(self):
if self.emcc_args is None: return self.skip('very slow, we only do this in emcc runs')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
Settings.CORRECT_OVERFLOWS = 1
Settings.CORRECT_SIGNS = 1
@@ -4999,7 +4983,9 @@ def process(filename):
def clean(text):
text = text.replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('\n\n', '\n').replace('{\n}', '{}')
return '\n'.join(sorted(text.split('\n')))
- self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code!
+ sizes = len(open('release.js').read()), len(open('debug%d.js' % debug).read())
+ print >> sys.stderr, debug, 'sizes', sizes
+ assert abs(sizes[0] - sizes[1]) < 0.0001*sizes[0] # we can't check on identical output, compilation is not 100% deterministic (order of switch elements, etc.), but size should be ~identical
print >> sys.stderr, 'debug check %d passed too' % debug
try:
@@ -5057,7 +5043,7 @@ def process(filename):
'structphiparam', 'callwithstructural_ta2', 'callwithstructural64_ta2', 'structinparam', # pnacl limitations in ExpandStructRegs
'2xi40', # pnacl limitations in ExpandGetElementPtr
'legalizer_ta2', '514_ta2', # pnacl limitation in not legalizing i104, i96, etc.
- 'longjmp_tiny', 'longjmp_tiny_invoke', 'longjmp_tiny_phi', 'longjmp_tiny_phi2', 'longjmp_tiny_invoke_phi', 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME
+ 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME
'sillyfuncast2', 'sillybitcast', 'atomicrmw_unaligned' # TODO XXX
]: continue
if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2:
@@ -5968,7 +5954,7 @@ def process(filename):
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')
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args or '-O3' in self.emcc_args: return self.skip('optimizations remove LLVM debug info')
src = '''
#include <stdio.h>
@@ -5999,7 +5985,6 @@ def process(filename):
def test_source_map(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip("doesn't pass without typed arrays")
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
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')
@@ -6046,6 +6031,7 @@ def process(filename):
# optimizer can deal with both types.
out_file = re.sub(' *//@.*$', '', out_file, flags=re.MULTILINE)
def clean(code):
+ code = re.sub(r'\n+[ \n]*\n+', '\n', code)
code = code.replace('{\n}', '{}')
return '\n'.join(sorted(code.split('\n')))
self.assertIdentical(clean(no_maps_file), clean(out_file))
@@ -6083,7 +6069,6 @@ def process(filename):
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')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
src = '''
#include <stdio.h>
@@ -6108,7 +6093,7 @@ def process(filename):
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']]:
+ if m['originalLine'] == 5 and '__cxa_throw' in lines[m['generatedLine']-1]: # -1 to fix 0-start vs 1-start
return
assert False, 'Must label throw statements with line numbers'
@@ -6358,7 +6343,7 @@ def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0,
if self.emcc_args is not None:
Settings.load(self.emcc_args)
Building.LLVM_OPTS = 0
- if '-O2' in self.emcc_args:
+ if '-O2' in self.emcc_args or '-O3' 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:
@@ -6412,8 +6397,12 @@ o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0", "-s", "J
# asm.js
asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1"])
asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])
+asm3 = make_run("asm3", compiler=CLANG, emcc_args=["-O3"])
asm2f = make_run("asm2f", compiler=CLANG, emcc_args=["-O2", "-s", "PRECISE_F32=1"])
-asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "CHECK_HEAP_ALIGN=1"])
+if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "SAFE_HEAP=1"])
+else:
+ asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "CHECK_HEAP_ALIGN=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
diff --git a/tests/test_other.py b/tests/test_other.py
index f91b4683..53128391 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -134,13 +134,13 @@ Options that are modified or new in %s include:
(['-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),
+ (['-o', 'something.js', '-O3', '-s', 'ASM_JS=0'], 3, None, 0, 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),
+ (['-o', 'something.bc', '-O3'], 3, ['-O3', '-s', 'ASM_JS=0'], 0, 0),
(['-O1', '-o', 'something.bc'], 1, [], 0, 0),
]:
print params, opt_level, bc_params, closure, has_malloc
@@ -157,7 +157,6 @@ Options that are modified or new in %s include:
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
@@ -196,7 +195,6 @@ Options that are modified or new in %s include:
(['-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', '-g2'], 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'),
@@ -284,9 +282,33 @@ f.close()
if WINDOWS:
generators = ['MinGW Makefiles', 'NMake Makefiles']
else:
- generators = ['Unix Makefiles']
-
- make_commands = { 'MinGW Makefiles': ['mingw32-make'], 'NMake Makefiles': ['nmake', '/NOLOGO'], 'Unix Makefiles': ['make'] }
+ generators = ['Unix Makefiles', 'Ninja', 'Eclipse CDT4 - Ninja']
+
+ def nmake_detect_error(configuration):
+ if Building.which(configuration['build'][0]):
+ return None
+ else:
+ return 'Skipping NMake test for CMake support, since nmake was not found in PATH. Run this test in Visual Studio command prompt to easily access nmake.'
+
+ def check_makefile(configuration, dirname):
+ assert os.path.exists(dirname + '/Makefile'), 'CMake call did not produce a Makefile!'
+
+ configurations = { 'MinGW Makefiles' : { 'prebuild': check_makefile,
+ 'build' : ['mingw32-make'],
+
+ },
+ 'NMake Makefiles' : { 'detect' : nmake_detect_error,
+ 'prebuild': check_makefile,
+ 'build' : ['nmake', '/NOLOGO'],
+ },
+ 'Unix Makefiles' : { 'prebuild': check_makefile,
+ 'build' : ['make'],
+ },
+ 'Ninja' : { 'build' : ['ninja'],
+ },
+ 'Eclipse CDT4 - Ninja': { 'build' : ['ninja'],
+ }
+ }
if os.name == 'nt':
emconfigure = path_from_root('emconfigure.bat')
@@ -294,11 +316,37 @@ f.close()
emconfigure = path_from_root('emconfigure')
for generator in generators:
- if generator == 'NMake Makefiles' and not Building.which('nmake'):
- print >> sys.stderr, 'Skipping NMake test for CMake support, since nmake was not found in PATH. Run this test in Visual Studio command prompt to easily access nmake.'
+ conf = configurations[generator]
+
+ make = conf['build']
+
+ try:
+ detector = conf['detect']
+ except KeyError:
+ detector = None
+
+ if detector:
+ error = detector(conf)
+ elif len(make) == 1 and not Building.which(make[0]):
+ # Use simple test if applicable
+ error = 'Skipping %s test for CMake support, since it could not be detected.' % generator
+ else:
+ error = None
+
+ if error:
+ logging.warning(error)
continue
- make = make_commands[generator]
+ try:
+ prebuild = conf['prebuild']
+ except KeyError:
+ prebuild = None
+
+ try:
+ postbuild = conf['postbuild']
+ except KeyError:
+ postbuild = None
+
cmake_cases = ['target_js', 'target_html']
cmake_outputs = ['test_cmake.js', 'hello_world_gles.html']
for i in range(0, 2):
@@ -331,7 +379,9 @@ f.close()
logging.error('Failed command: ' + ' '.join(cmd))
logging.error('Result:\n' + ret[1])
raise Exception('cmake call failed!')
- assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
+
+ if prebuild:
+ prebuild(configuration, tempdirname)
# Build
cmd = make + (['VERBOSE=1'] if verbose_level >= 3 else [])
@@ -344,6 +394,9 @@ f.close()
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]
+ if postbuild:
+ postbuild(configuration, tempdirname)
+
# 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]
@@ -1721,7 +1774,7 @@ f.close()
(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']),
+ ['asm', 'registerize', 'minifyLocals']),
(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(),
@@ -1736,6 +1789,8 @@ f.close()
['asm', 'outline']),
(path_from_root('tools', 'test-js-optimizer-asm-minlast.js'), open(path_from_root('tools', 'test-js-optimizer-asm-minlast-output.js')).read(),
['asm', 'minifyWhitespace', 'last']),
+ (path_from_root('tools', 'test-js-optimizer-shiftsAggressive.js'), open(path_from_root('tools', 'test-js-optimizer-shiftsAggressive-output.js')).read(),
+ ['asm', 'aggressiveVariableElimination']),
]:
print input
output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0]
@@ -2219,7 +2274,6 @@ mergeInto(LibraryManager.library, {
process.communicate()
assert(os.path.isfile(outdir + 'hello_world.obj'))
-
def test_doublestart_bug(self):
open('code.cpp', 'w').write(r'''
#include <stdio.h>
@@ -2251,3 +2305,20 @@ Module["preRun"].push(function () {
assert output.count('This should only appear once.') == 1, '\n'+output
+ def test_module_print(self):
+ open('code.cpp', 'w').write(r'''
+#include <stdio.h>
+int main(void) {
+ printf("123456789\n");
+ return 0;
+}
+''')
+
+ open('pre.js', 'w').write(r'''
+var Module = { print: function(x) { throw '<{(' + x + ')}>' } };
+''')
+
+ Popen([PYTHON, EMCC, 'code.cpp', '--pre-js', 'pre.js']).communicate()
+ output = run_js(os.path.join(self.get_dir(), 'a.out.js'), stderr=PIPE, full_output=True, engine=NODE_JS)
+ assert r'<{(123456789)}>' in output, output
+
diff --git a/tests/utf32.cpp b/tests/utf32.cpp
index 6b75b244..d00338a6 100644
--- a/tests/utf32.cpp
+++ b/tests/utf32.cpp
@@ -16,11 +16,11 @@ int main() {
if (sizeof(wchar_t) == 4) {
utf32 *memory = new utf32[wstr.length()+1];
- asm("var str = Module.UTF32ToString(%0);"
- "Module.print(str);"
- "Module.stringToUTF32(str, %1);"
- :
- : "r"(wstr.c_str()), "r"(memory));
+ EM_ASM_INT({
+ var str = Module.UTF32ToString($0);
+ Module.print(str);
+ Module.stringToUTF32(str, $1);
+ }, wstr.c_str(), memory);
// Compare memory to confirm that the string is intact after taking a route through JS side.
const utf32 *srcPtr = reinterpret_cast<const utf32 *>(wstr.c_str());
@@ -33,11 +33,11 @@ int main() {
} else { // sizeof(wchar_t) == 2, and we're building with -fshort-wchar.
utf16 *memory = new utf16[2*wstr.length()+1];
- asm("var str = Module.UTF16ToString(%0);"
- "Module.print(str);"
- "Module.stringToUTF16(str, %1);"
- :
- : "r"(wstr.c_str()), "r"(memory));
+ EM_ASM_INT({
+ var str = Module.UTF16ToString($0);
+ Module.print(str);
+ Module.stringToUTF16(str, $1);
+ }, wstr.c_str(), memory);
// Compare memory to confirm that the string is intact after taking a route through JS side.
const utf16 *srcPtr = reinterpret_cast<const utf16 *>(wstr.c_str());
diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js
index a344fc35..7a8baef2 100644
--- a/tools/eliminator/asm-eliminator-test-output.js
+++ b/tools/eliminator/asm-eliminator-test-output.js
@@ -304,4 +304,510 @@ function binary(x) {
memset(f(x)) | 0;
+dmemset(f(x));
}
+function cute($this, $outImage) {
+ $this = $this | 0;
+ $outImage = $outImage | 0;
+ var $retval = 0, $outImage_addr = 0, $width = 0, $height = 0, $bit_depth = 0, $color_type = 0, $data = 0, $bpl = 0, $y = 0, $i = 0, $y76 = 0, $p = 0, $end = 0, $this1 = 0, $call = 0, $call7 = 0, $call8 = 0, $3 = 0, $call17 = 0, $10 = 0, $call32 = 0, $call33 = 0, $17$0 = 0, $call34 = 0, $add_ptr = 0, $32 = 0, $call42 = 0, $35 = 0, $call45 = 0, $41 = 0, $call51 = 0, $43 = 0, $call55 = 0, $call57 = 0, $49 = 0, $call72 = 0, $call75 = 0, label = 0, setjmpLabel = 0, setjmpTable = 0, sp = 0;
+ sp = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ label = 1;
+ setjmpLabel = 0;
+ setjmpTable = STACKTOP;
+ STACKTOP = STACKTOP + 168 | 0;
+ HEAP32[setjmpTable >> 2] = 0;
+ while (1) switch (label | 0) {
+ case 1:
+ $width = sp | 0;
+ $height = sp + 8 | 0;
+ $bit_depth = sp + 16 | 0;
+ $color_type = sp + 24 | 0;
+ $outImage_addr = $outImage;
+ $this1 = $this;
+ if ((HEAP32[($this1 + 32 | 0) >> 2] | 0 | 0) == 3) {
+ label = 2;
+ break;
+ } else {
+ label = 3;
+ break;
+ }
+ case 2:
+ $retval = 0;
+ label = 37;
+ break;
+ case 3:
+ if ((HEAP32[($this1 + 32 | 0) >> 2] | 0 | 0) == 0) {
+ label = 4;
+ break;
+ } else {
+ label = 6;
+ break;
+ }
+ case 4:
+ $call = invoke_ii(900, $this1 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ if ($call) {
+ label = 6;
+ break;
+ } else {
+ label = 5;
+ break;
+ }
+ case 5:
+ HEAP32[($this1 + 32 | 0) >> 2] = 3;
+ $retval = 0;
+ label = 37;
+ break;
+ case 6:
+ HEAP32[($this1 + 28 | 0) >> 2] = 0;
+ $call7 = invoke_iiii(30, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, 2638 | 0, 156 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $call8 = _saveSetjmp($call7 | 0 | 0, label, setjmpTable) | 0;
+ label = 38;
+ break;
+ case 38:
+ if (($call8 | 0) != 0) {
+ label = 7;
+ break;
+ } else {
+ label = 10;
+ break;
+ }
+ case 7:
+ invoke_viii(640, $this1 + 16 | 0 | 0, $this1 + 20 | 0 | 0, $this1 + 24 | 0 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $3 = HEAP32[($this1 + 28 | 0) >> 2] | 0;
+ if (($3 | 0) == 0) {
+ label = 9;
+ break;
+ } else {
+ label = 8;
+ break;
+ }
+ case 8:
+ invoke_vi(926, $3 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 9;
+ break;
+ case 9:
+ HEAP32[($this1 + 16 | 0) >> 2] = 0;
+ HEAP32[($this1 + 32 | 0) >> 2] = 3;
+ $retval = 0;
+ label = 37;
+ break;
+ case 10:
+ invoke_viiif(2, $outImage_addr | 0, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0, +(+HEAPF32[($this1 | 0) >> 2]));
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $call17 = invoke_ii(832, $outImage_addr | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ if ($call17) {
+ label = 11;
+ break;
+ } else {
+ label = 14;
+ break;
+ }
+ case 11:
+ invoke_viii(640, $this1 + 16 | 0 | 0, $this1 + 20 | 0 | 0, $this1 + 24 | 0 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $10 = HEAP32[($this1 + 28 | 0) >> 2] | 0;
+ if (($10 | 0) == 0) {
+ label = 13;
+ break;
+ } else {
+ label = 12;
+ break;
+ }
+ case 12:
+ invoke_vi(926, $10 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 13;
+ break;
+ case 13:
+ HEAP32[($this1 + 16 | 0) >> 2] = 0;
+ HEAP32[($this1 + 32 | 0) >> 2] = 3;
+ $retval = 0;
+ label = 37;
+ break;
+ case 14:
+ invoke_iiiiiiiiii(2, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0, $width | 0, $height | 0, $bit_depth | 0, $color_type | 0, 0 | 0, 0 | 0, 0 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $call32 = invoke_ii(850, $outImage_addr | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $data = $call32;
+ $call33 = invoke_ii(284, $outImage_addr | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $bpl = $call33;
+ $17$0 = invoke_iii(860, HEAP32[$height >> 2] | 0 | 0, 4 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $call34 = invoke_ii(550, (tempRet0 ? -1 : $17$0) | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ HEAP32[($this1 + 28 | 0) >> 2] = $call34;
+ $y = 0;
+ label = 15;
+ break;
+ case 15:
+ if ($y >>> 0 < (HEAP32[$height >> 2] | 0) >>> 0) {
+ label = 16;
+ break;
+ } else {
+ label = 18;
+ break;
+ }
+ case 16:
+ $add_ptr = $data + (Math_imul($y, $bpl) | 0) | 0;
+ HEAP32[((HEAP32[($this1 + 28 | 0) >> 2] | 0) + ($y << 2) | 0) >> 2] = $add_ptr;
+ label = 17;
+ break;
+ case 17:
+ $y = $y + 1 | 0;
+ label = 15;
+ break;
+ case 18:
+ invoke_vii(858, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 28 | 0) >> 2] | 0 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $32 = $outImage_addr;
+ $call42 = invoke_iii(690, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_vii(1890, $32 | 0, $call42 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $35 = $outImage_addr;
+ $call45 = invoke_iii(256, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 20 | 0) >> 2] | 0 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_vii(2126, $35 | 0, $call45 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ HEAP32[($this1 + 32 | 0) >> 2] = 2;
+ invoke_vii(36, HEAP32[($this1 + 16 | 0) >> 2] | 0 | 0, HEAP32[($this1 + 24 | 0) >> 2] | 0 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_vii(2752, $this1 | 0, HEAP32[($this1 + 24 | 0) >> 2] | 0 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $i = 0;
+ label = 19;
+ break;
+ case 19:
+ $41 = $i;
+ $call51 = invoke_ii(618, $this1 + 12 | 0 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ if (($41 | 0) < ($call51 - 1 | 0 | 0)) {
+ label = 20;
+ break;
+ } else {
+ label = 22;
+ break;
+ }
+ case 20:
+ $43 = $outImage_addr;
+ $call55 = invoke_iii(502, $this1 + 12 | 0 | 0, $i | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $call57 = invoke_iii(502, $this1 + 12 | 0 | 0, $i + 1 | 0 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_viii(550, $43 | 0, $call55 | 0, $call57 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 21;
+ break;
+ case 21:
+ $i = $i + 2 | 0;
+ label = 19;
+ break;
+ case 22:
+ invoke_viii(640, $this1 + 16 | 0 | 0, $this1 + 20 | 0 | 0, $this1 + 24 | 0 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $49 = HEAP32[($this1 + 28 | 0) >> 2] | 0;
+ if (($49 | 0) == 0) {
+ label = 24;
+ break;
+ } else {
+ label = 23;
+ break;
+ }
+ case 23:
+ invoke_vi(926, $49 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 24;
+ break;
+ case 24:
+ HEAP32[($this1 + 16 | 0) >> 2] = 0;
+ HEAP32[($this1 + 32 | 0) >> 2] = 0;
+ if ((HEAP32[$color_type >> 2] | 0 | 0) == 3) {
+ label = 25;
+ break;
+ } else {
+ label = 36;
+ break;
+ }
+ case 25:
+ $call72 = invoke_ii(926, $outImage_addr | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ if (($call72 | 0) == 3) {
+ label = 26;
+ break;
+ } else {
+ label = 36;
+ break;
+ }
+ case 26:
+ $call75 = invoke_ii(860, $outImage_addr | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $y76 = 0;
+ label = 27;
+ break;
+ case 27:
+ if (($y76 | 0) < (HEAP32[$height >> 2] | 0 | 0)) {
+ label = 28;
+ break;
+ } else {
+ label = 35;
+ break;
+ }
+ case 28:
+ $p = $data + (Math_imul($y76, $bpl) | 0) | 0;
+ $end = $p + (HEAP32[$width >> 2] | 0) | 0;
+ label = 29;
+ break;
+ case 29:
+ if ($p >>> 0 < $end >>> 0) {
+ label = 30;
+ break;
+ } else {
+ label = 33;
+ break;
+ }
+ case 30:
+ if (((HEAP8[$p] | 0) & 255 | 0) >= ($call75 | 0)) {
+ label = 31;
+ break;
+ } else {
+ label = 32;
+ break;
+ }
+ case 31:
+ HEAP8[$p] = 0;
+ label = 32;
+ break;
+ case 32:
+ $p = $p + 1 | 0;
+ label = 29;
+ break;
+ case 33:
+ label = 34;
+ break;
+ case 34:
+ $y76 = $y76 + 1 | 0;
+ label = 27;
+ break;
+ case 35:
+ label = 36;
+ break;
+ case 36:
+ $retval = 1;
+ label = 37;
+ break;
+ case 37:
+ STACKTOP = sp;
+ return $retval | 0;
+ case -1:
+ if ((setjmpLabel | 0) == 6) {
+ $call8 = threwValue;
+ label = 38;
+ }
+ __THREW__ = threwValue = 0;
+ break;
+ }
+ return 0;
+}
diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js
index 4b45e4d4..ad1ed05e 100644
--- a/tools/eliminator/asm-eliminator-test.js
+++ b/tools/eliminator/asm-eliminator-test.js
@@ -378,5 +378,654 @@ function binary(x) {
z = f(x);
+dmemset(z);
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary"]
+function cute($this, $outImage) {
+ $this = $this | 0;
+ $outImage = $outImage | 0;
+ var $retval = 0, $this_addr = 0, $outImage_addr = 0, $width = 0, $height = 0, $bit_depth = 0, $color_type = 0, $data = 0, $bpl = 0, $y = 0, $i = 0, $color_table_size = 0, $y76 = 0, $p = 0, $end = 0, $this1 = 0, $state = 0, $0 = 0, $cmp = 0, $state2 = 0;
+ var $1 = 0, $cmp3 = 0, $call = 0, $state5 = 0, $row_pointers = 0, $png_ptr = 0, $2 = 0, $call7 = 0, $arraydecay = 0, $call8 = 0, $tobool = 0, $png_ptr10 = 0, $info_ptr = 0, $end_info = 0, $row_pointers11 = 0, $3 = 0, $isnull = 0, $4 = 0, $png_ptr12 = 0, $state13 = 0;
+ var $5 = 0, $png_ptr15 = 0, $6 = 0, $info_ptr16 = 0, $7 = 0, $gamma = 0, $8 = +0, $9 = 0, $call17 = 0, $png_ptr19 = 0, $info_ptr20 = 0, $end_info21 = 0, $row_pointers22 = 0, $10 = 0, $isnull23 = 0, $11 = 0, $png_ptr26 = 0, $state27 = 0, $png_ptr29 = 0, $12 = 0;
+ var $info_ptr30 = 0, $13 = 0, $call31 = 0, $14 = 0, $call32 = 0, $15 = 0, $call33 = 0, $16 = 0, $17$0 = 0, $17$1 = 0, $18 = 0, $19 = 0, $20 = 0, $call34 = 0, $21 = 0, $row_pointers35 = 0, $22 = 0, $23 = 0, $cmp36 = 0, $24 = 0;
+ var $25 = 0, $26 = 0, $mul = 0, $add_ptr = 0, $27 = 0, $row_pointers37 = 0, $28 = 0, $arrayidx = 0, $29 = 0, $inc = 0, $png_ptr38 = 0, $30 = 0, $row_pointers39 = 0, $31 = 0, $32 = 0, $png_ptr40 = 0, $33 = 0, $info_ptr41 = 0, $34 = 0, $call42 = 0;
+ var $35 = 0, $png_ptr43 = 0, $36 = 0, $info_ptr44 = 0, $37 = 0, $call45 = 0, $state46 = 0, $png_ptr47 = 0, $38 = 0, $end_info48 = 0, $39 = 0, $end_info49 = 0, $40 = 0, $41 = 0, $readTexts = 0, $42 = 0, $call51 = 0, $sub = 0, $cmp52 = 0, $43 = 0;
+ var $readTexts54 = 0, $44 = 0, $45 = 0, $call55 = 0, $readTexts56 = 0, $46 = 0, $47 = 0, $add = 0, $call57 = 0, $48 = 0, $add59 = 0, $png_ptr61 = 0, $info_ptr62 = 0, $end_info63 = 0, $row_pointers64 = 0, $49 = 0, $isnull65 = 0, $50 = 0, $png_ptr68 = 0, $state69 = 0;
+ var $51 = 0, $cmp70 = 0, $52 = 0, $call72 = 0, $cmp73 = 0, $53 = 0, $call75 = 0, $54 = 0, $55 = 0, $cmp78 = 0, $56 = 0, $57 = 0, $58 = 0, $mul80 = 0, $add_ptr81 = 0, $59 = 0, $60 = 0, $add_ptr82 = 0, $61 = 0, $62 = 0;
+ var $cmp83 = 0, $63 = 0, $64 = 0, $conv = 0, $65 = 0, $cmp84 = 0, $66 = 0, $67 = 0, $incdec_ptr = 0, $68 = 0, $inc88 = 0, $69 = 0, label = 0, setjmpLabel = 0, setjmpTable = 0;
+ var sp = 0;
+ sp = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ label = 1;
+ setjmpLabel = 0;
+ setjmpTable = STACKTOP;
+ STACKTOP = STACKTOP + 168 | 0;
+ HEAP32[setjmpTable >> 2] = 0;
+ while (1) switch (label | 0) {
+ case 1:
+ $width = sp | 0;
+ $height = sp + 8 | 0;
+ $bit_depth = sp + 16 | 0;
+ $color_type = sp + 24 | 0;
+ $this_addr = $this;
+ $outImage_addr = $outImage;
+ $this1 = $this_addr;
+ $state = $this1 + 32 | 0;
+ $0 = HEAP32[$state >> 2] | 0;
+ $cmp = ($0 | 0) == 3;
+ if ($cmp) {
+ label = 2;
+ break;
+ } else {
+ label = 3;
+ break;
+ }
+ case 2:
+ $retval = 0;
+ label = 37;
+ break;
+ case 3:
+ $state2 = $this1 + 32 | 0;
+ $1 = HEAP32[$state2 >> 2] | 0;
+ $cmp3 = ($1 | 0) == 0;
+ if ($cmp3) {
+ label = 4;
+ break;
+ } else {
+ label = 6;
+ break;
+ }
+ case 4:
+ $call = invoke_ii(900, $this1 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ if ($call) {
+ label = 6;
+ break;
+ } else {
+ label = 5;
+ break;
+ }
+ case 5:
+ $state5 = $this1 + 32 | 0;
+ HEAP32[$state5 >> 2] = 3;
+ $retval = 0;
+ label = 37;
+ break;
+ case 6:
+ $row_pointers = $this1 + 28 | 0;
+ HEAP32[$row_pointers >> 2] = 0;
+ $png_ptr = $this1 + 16 | 0;
+ $2 = HEAP32[$png_ptr >> 2] | 0;
+ $call7 = invoke_iiii(30, $2 | 0, 2638 | 0, 156 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $arraydecay = $call7 | 0;
+ $call8 = _saveSetjmp($arraydecay | 0, label, setjmpTable) | 0;
+ label = 38;
+ break;
+ case 38:
+ $tobool = ($call8 | 0) != 0;
+ if ($tobool) {
+ label = 7;
+ break;
+ } else {
+ label = 10;
+ break;
+ }
+ case 7:
+ $png_ptr10 = $this1 + 16 | 0;
+ $info_ptr = $this1 + 20 | 0;
+ $end_info = $this1 + 24 | 0;
+ invoke_viii(640, $png_ptr10 | 0, $info_ptr | 0, $end_info | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $row_pointers11 = $this1 + 28 | 0;
+ $3 = HEAP32[$row_pointers11 >> 2] | 0;
+ $isnull = ($3 | 0) == 0;
+ if ($isnull) {
+ label = 9;
+ break;
+ } else {
+ label = 8;
+ break;
+ }
+ case 8:
+ $4 = $3;
+ invoke_vi(926, $4 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 9;
+ break;
+ case 9:
+ $png_ptr12 = $this1 + 16 | 0;
+ HEAP32[$png_ptr12 >> 2] = 0;
+ $state13 = $this1 + 32 | 0;
+ HEAP32[$state13 >> 2] = 3;
+ $retval = 0;
+ label = 37;
+ break;
+ case 10:
+ $5 = $outImage_addr;
+ $png_ptr15 = $this1 + 16 | 0;
+ $6 = HEAP32[$png_ptr15 >> 2] | 0;
+ $info_ptr16 = $this1 + 20 | 0;
+ $7 = HEAP32[$info_ptr16 >> 2] | 0;
+ $gamma = $this1 | 0;
+ $8 = +HEAPF32[$gamma >> 2];
+ invoke_viiif(2, $5 | 0, $6 | 0, $7 | 0, +$8);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $9 = $outImage_addr;
+ $call17 = invoke_ii(832, $9 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ if ($call17) {
+ label = 11;
+ break;
+ } else {
+ label = 14;
+ break;
+ }
+ case 11:
+ $png_ptr19 = $this1 + 16 | 0;
+ $info_ptr20 = $this1 + 20 | 0;
+ $end_info21 = $this1 + 24 | 0;
+ invoke_viii(640, $png_ptr19 | 0, $info_ptr20 | 0, $end_info21 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $row_pointers22 = $this1 + 28 | 0;
+ $10 = HEAP32[$row_pointers22 >> 2] | 0;
+ $isnull23 = ($10 | 0) == 0;
+ if ($isnull23) {
+ label = 13;
+ break;
+ } else {
+ label = 12;
+ break;
+ }
+ case 12:
+ $11 = $10;
+ invoke_vi(926, $11 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 13;
+ break;
+ case 13:
+ $png_ptr26 = $this1 + 16 | 0;
+ HEAP32[$png_ptr26 >> 2] = 0;
+ $state27 = $this1 + 32 | 0;
+ HEAP32[$state27 >> 2] = 3;
+ $retval = 0;
+ label = 37;
+ break;
+ case 14:
+ $png_ptr29 = $this1 + 16 | 0;
+ $12 = HEAP32[$png_ptr29 >> 2] | 0;
+ $info_ptr30 = $this1 + 20 | 0;
+ $13 = HEAP32[$info_ptr30 >> 2] | 0;
+ $call31 = invoke_iiiiiiiiii(2, $12 | 0, $13 | 0, $width | 0, $height | 0, $bit_depth | 0, $color_type | 0, 0 | 0, 0 | 0, 0 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $14 = $outImage_addr;
+ $call32 = invoke_ii(850, $14 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $data = $call32;
+ $15 = $outImage_addr;
+ $call33 = invoke_ii(284, $15 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $bpl = $call33;
+ $16 = HEAP32[$height >> 2] | 0;
+ $17$0 = invoke_iii(860, $16 | 0, 4 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $17$1 = tempRet0;
+ $18 = $17$1;
+ $19 = $17$0;
+ $20 = $18 ? -1 : $19;
+ $call34 = invoke_ii(550, $20 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $21 = $call34;
+ $row_pointers35 = $this1 + 28 | 0;
+ HEAP32[$row_pointers35 >> 2] = $21;
+ $y = 0;
+ label = 15;
+ break;
+ case 15:
+ $22 = $y;
+ $23 = HEAP32[$height >> 2] | 0;
+ $cmp36 = $22 >>> 0 < $23 >>> 0;
+ if ($cmp36) {
+ label = 16;
+ break;
+ } else {
+ label = 18;
+ break;
+ }
+ case 16:
+ $24 = $data;
+ $25 = $y;
+ $26 = $bpl;
+ $mul = Math_imul($25, $26) | 0;
+ $add_ptr = $24 + $mul | 0;
+ $27 = $y;
+ $row_pointers37 = $this1 + 28 | 0;
+ $28 = HEAP32[$row_pointers37 >> 2] | 0;
+ $arrayidx = $28 + ($27 << 2) | 0;
+ HEAP32[$arrayidx >> 2] = $add_ptr;
+ label = 17;
+ break;
+ case 17:
+ $29 = $y;
+ $inc = $29 + 1 | 0;
+ $y = $inc;
+ label = 15;
+ break;
+ case 18:
+ $png_ptr38 = $this1 + 16 | 0;
+ $30 = HEAP32[$png_ptr38 >> 2] | 0;
+ $row_pointers39 = $this1 + 28 | 0;
+ $31 = HEAP32[$row_pointers39 >> 2] | 0;
+ invoke_vii(858, $30 | 0, $31 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $32 = $outImage_addr;
+ $png_ptr40 = $this1 + 16 | 0;
+ $33 = HEAP32[$png_ptr40 >> 2] | 0;
+ $info_ptr41 = $this1 + 20 | 0;
+ $34 = HEAP32[$info_ptr41 >> 2] | 0;
+ $call42 = invoke_iii(690, $33 | 0, $34 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_vii(1890, $32 | 0, $call42 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $35 = $outImage_addr;
+ $png_ptr43 = $this1 + 16 | 0;
+ $36 = HEAP32[$png_ptr43 >> 2] | 0;
+ $info_ptr44 = $this1 + 20 | 0;
+ $37 = HEAP32[$info_ptr44 >> 2] | 0;
+ $call45 = invoke_iii(256, $36 | 0, $37 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_vii(2126, $35 | 0, $call45 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $state46 = $this1 + 32 | 0;
+ HEAP32[$state46 >> 2] = 2;
+ $png_ptr47 = $this1 + 16 | 0;
+ $38 = HEAP32[$png_ptr47 >> 2] | 0;
+ $end_info48 = $this1 + 24 | 0;
+ $39 = HEAP32[$end_info48 >> 2] | 0;
+ invoke_vii(36, $38 | 0, $39 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $end_info49 = $this1 + 24 | 0;
+ $40 = HEAP32[$end_info49 >> 2] | 0;
+ invoke_vii(2752, $this1 | 0, $40 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $i = 0;
+ label = 19;
+ break;
+ case 19:
+ $41 = $i;
+ $readTexts = $this1 + 12 | 0;
+ $42 = $readTexts;
+ $call51 = invoke_ii(618, $42 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $sub = $call51 - 1 | 0;
+ $cmp52 = ($41 | 0) < ($sub | 0);
+ if ($cmp52) {
+ label = 20;
+ break;
+ } else {
+ label = 22;
+ break;
+ }
+ case 20:
+ $43 = $outImage_addr;
+ $readTexts54 = $this1 + 12 | 0;
+ $44 = $readTexts54;
+ $45 = $i;
+ $call55 = invoke_iii(502, $44 | 0, $45 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $readTexts56 = $this1 + 12 | 0;
+ $46 = $readTexts56;
+ $47 = $i;
+ $add = $47 + 1 | 0;
+ $call57 = invoke_iii(502, $46 | 0, $add | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ invoke_viii(550, $43 | 0, $call55 | 0, $call57 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 21;
+ break;
+ case 21:
+ $48 = $i;
+ $add59 = $48 + 2 | 0;
+ $i = $add59;
+ label = 19;
+ break;
+ case 22:
+ $png_ptr61 = $this1 + 16 | 0;
+ $info_ptr62 = $this1 + 20 | 0;
+ $end_info63 = $this1 + 24 | 0;
+ invoke_viii(640, $png_ptr61 | 0, $info_ptr62 | 0, $end_info63 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $row_pointers64 = $this1 + 28 | 0;
+ $49 = HEAP32[$row_pointers64 >> 2] | 0;
+ $isnull65 = ($49 | 0) == 0;
+ if ($isnull65) {
+ label = 24;
+ break;
+ } else {
+ label = 23;
+ break;
+ }
+ case 23:
+ $50 = $49;
+ invoke_vi(926, $50 | 0);
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ label = 24;
+ break;
+ case 24:
+ $png_ptr68 = $this1 + 16 | 0;
+ HEAP32[$png_ptr68 >> 2] = 0;
+ $state69 = $this1 + 32 | 0;
+ HEAP32[$state69 >> 2] = 0;
+ $51 = HEAP32[$color_type >> 2] | 0;
+ $cmp70 = ($51 | 0) == 3;
+ if ($cmp70) {
+ label = 25;
+ break;
+ } else {
+ label = 36;
+ break;
+ }
+ case 25:
+ $52 = $outImage_addr;
+ $call72 = invoke_ii(926, $52 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $cmp73 = ($call72 | 0) == 3;
+ if ($cmp73) {
+ label = 26;
+ break;
+ } else {
+ label = 36;
+ break;
+ }
+ case 26:
+ $53 = $outImage_addr;
+ $call75 = invoke_ii(860, $53 | 0) | 0;
+ if ((__THREW__ | 0) != 0 & (threwValue | 0) != 0) {
+ setjmpLabel = _testSetjmp(HEAP32[__THREW__ >> 2] | 0, setjmpTable) | 0;
+ if ((setjmpLabel | 0) > 0) {
+ label = -1;
+ break;
+ } else return 0 | 0;
+ }
+ __THREW__ = threwValue = 0;
+ $color_table_size = $call75;
+ $y76 = 0;
+ label = 27;
+ break;
+ case 27:
+ $54 = $y76;
+ $55 = HEAP32[$height >> 2] | 0;
+ $cmp78 = ($54 | 0) < ($55 | 0);
+ if ($cmp78) {
+ label = 28;
+ break;
+ } else {
+ label = 35;
+ break;
+ }
+ case 28:
+ $56 = $data;
+ $57 = $y76;
+ $58 = $bpl;
+ $mul80 = Math_imul($57, $58) | 0;
+ $add_ptr81 = $56 + $mul80 | 0;
+ $p = $add_ptr81;
+ $59 = $p;
+ $60 = HEAP32[$width >> 2] | 0;
+ $add_ptr82 = $59 + $60 | 0;
+ $end = $add_ptr82;
+ label = 29;
+ break;
+ case 29:
+ $61 = $p;
+ $62 = $end;
+ $cmp83 = $61 >>> 0 < $62 >>> 0;
+ if ($cmp83) {
+ label = 30;
+ break;
+ } else {
+ label = 33;
+ break;
+ }
+ case 30:
+ $63 = $p;
+ $64 = HEAP8[$63] | 0;
+ $conv = $64 & 255;
+ $65 = $color_table_size;
+ $cmp84 = ($conv | 0) >= ($65 | 0);
+ if ($cmp84) {
+ label = 31;
+ break;
+ } else {
+ label = 32;
+ break;
+ }
+ case 31:
+ $66 = $p;
+ HEAP8[$66] = 0;
+ label = 32;
+ break;
+ case 32:
+ $67 = $p;
+ $incdec_ptr = $67 + 1 | 0;
+ $p = $incdec_ptr;
+ label = 29;
+ break;
+ case 33:
+ label = 34;
+ break;
+ case 34:
+ $68 = $y76;
+ $inc88 = $68 + 1 | 0;
+ $y76 = $inc88;
+ label = 27;
+ break;
+ case 35:
+ label = 36;
+ break;
+ case 36:
+ $retval = 1;
+ label = 37;
+ break;
+ case 37:
+ $69 = $retval;
+ STACKTOP = sp;
+ return $69 | 0;
+ case -1:
+ if ((setjmpLabel | 0) == 6) {
+ $call8 = threwValue;
+ label = 38;
+ }
+ __THREW__ = threwValue = 0;
+ break;
+ }
+ return 0;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute"]
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 5324e15c..b35da99d 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1603,6 +1603,7 @@ function normalizeAsm(func) {
node = node[1];
var name = node[2][1];
if (func[2] && func[2].indexOf(name) < 0) break; // not an assign into a parameter, but a global
+ if (name in data.params) break; // already done that param, must be starting function body
data.params[name] = detectAsmCoercion(node[3]);
stats[i] = emptyNode();
i++;
@@ -1773,9 +1774,7 @@ function ensureMinifiedNames(n) { // make sure the nth index in minifiedNames ex
}
}
-// Very simple 'registerization', coalescing of variables into a smaller number,
-// as part of minification. Globals-level minification began in a previous pass,
-// we receive extraInfo which tells us how to rename globals. (Only in asm.js.)
+// Very simple 'registerization', coalescing of variables into a smaller number.
//
// We do not optimize when there are switches, so this pass only makes sense with
// relooping.
@@ -1811,6 +1810,7 @@ function registerize(ast) {
// Replace all var definitions with assignments; we will add var definitions at the top after we registerize
// We also mark local variables - i.e., having a var definition
var localVars = {};
+ var allVars = {};
var hasSwitch = false; // we cannot optimize variables if there is a switch, unless in asm mode
traverse(fun, function(node, type) {
if (type === 'var') {
@@ -1823,74 +1823,25 @@ function registerize(ast) {
}
} else if (type === 'switch') {
hasSwitch = true;
+ } else if (type === 'name') {
+ allVars[node[1]] = 1;
}
});
vacuum(fun);
- if (extraInfo && extraInfo.globals) {
- assert(asm);
- var usedGlobals = {};
- var nextLocal = 0;
- // Minify globals using the mapping we were given
- traverse(fun, function(node, type) {
- if (type === 'name') {
- var name = node[1];
- var minified = extraInfo.globals[name];
- if (minified) {
- assert(!localVars[name], name); // locals must not shadow globals, or else we don't know which is which
- if (localVars[minified]) {
- // trying to minify a global into a name used locally. rename all the locals
- var newName = '$_newLocal_' + (nextLocal++);
- assert(!localVars[newName]);
- if (params[minified]) {
- params[newName] = 1;
- delete params[minified];
- }
- localVars[newName] = 1;
- delete localVars[minified];
- asmData.vars[newName] = asmData.vars[minified];
- delete asmData.vars[minified];
- asmData.params[newName] = asmData.params[minified];
- delete asmData.params[minified];
- traverse(fun, function(node, type) {
- if (type === 'name' && node[1] === minified) {
- node[1] = newName;
- }
- });
- if (fun[2]) {
- for (var i = 0; i < fun[2].length; i++) {
- if (fun[2][i] === minified) fun[2][i] = newName;
- }
- }
- }
- node[1] = minified;
- usedGlobals[minified] = 1;
- }
- }
- });
- if (fun[1] in extraInfo.globals) { // if fun was created by a previous optimization pass, it will not be here
- fun[1] = extraInfo.globals[fun[1]];
- assert(fun[1]);
- }
- var nextRegName = 0;
- }
var regTypes = {};
function getNewRegName(num, name) {
- if (!asm) return 'r' + num;
- var type = asmData.vars[name];
- if (!extraInfo || !extraInfo.globals) {
- var ret = (type ? 'd' : 'i') + num;
+ var ret;
+ if (!asm) {
+ ret = 'r' + num;
+ } else {
+ var type = asmData.vars[name];
+ ret = (type ? 'd' : 'i') + num;
regTypes[ret] = type;
- return ret;
}
- // find the next free minified name that is not used by a global that shows up in this function
- while (1) {
- ensureMinifiedNames(nextRegName);
- var ret = minifiedNames[nextRegName++];
- if (!usedGlobals[ret]) {
- regTypes[ret] = type;
- return ret;
- }
+ if (ret in allVars) {
+ assert(ret in localVars, 'register shadows non-local name');
}
+ return ret;
}
// Find the # of uses of each variable.
// While doing so, check if all a variable's uses are dominated in a simple
@@ -2111,37 +2062,1070 @@ function registerize(ast) {
}
}
denormalizeAsm(fun, finalAsmData);
- if (extraInfo && extraInfo.globals) {
- // minify in asm var definitions, that denormalizeAsm just generated
- function minify(value) {
- if (value && value[0] === 'call' && value[1][0] === 'name') {
- var name = value[1][1];
- var minified = extraInfo.globals[name];
- if (minified) {
- value[1][1] = minified;
+ }
+ });
+}
+
+
+// Assign variables to 'registers', coalescing them onto a smaller number of shared
+// variables.
+//
+// This does the same job as 'registerize' above, but burns a lot more cycles trying
+// to reduce the total number of register variables. Key points about the operation:
+//
+// * we decompose the AST into a flow graph and perform a full liveness
+// analysis, to determine which variables are live at each point.
+//
+// * variables that are live concurrently are assigned to different registers.
+//
+// * variables that are linked via 'x=y' style statements are assigned the same
+// register if possible, so that the redundant assignment can be removed.
+// (e.g. assignments used to pass state around through loops).
+//
+// * any code that cannot be reached through the flow-graph is removed.
+// (e.g. redundant break statements like 'break L123; break;').
+//
+// * any assignments that we can prove are not subsequently used are removed.
+// (e.g. unnecessary assignments to the 'label' variable).
+//
+function registerizeHarder(ast) {
+ assert(asm);
+
+ traverseGeneratedFunctions(ast, function(fun) {
+
+ var asmData = normalizeAsm(fun);
+
+ var localVars = asmData.vars;
+ for (var name in asmData.params) {
+ localVars[name] = asmData.params[name];
+ }
+
+ // Utilities for allocating register variables.
+ // We need distinct register pools for each type of variable.
+
+ var allRegsByType = [{}, {}, {}];
+ var regPrefixByType = ['i', 'd', 'f'];
+ var nextReg = 1;
+
+ function createReg(forName) {
+ // Create a new register of type suitable for the given variable name.
+ var allRegs = allRegsByType[localVars[forName]];
+ reg = nextReg++;
+ allRegs[reg] = regPrefixByType[localVars[forName]] + reg;
+ return reg;
+ }
+
+ // Traverse the tree in execution order and synthesize a basic flow-graph.
+ // It's convenient to build a kind of "dual" graph where the nodes identify
+ // the junctions between blocks at which control-flow may branch, and each
+ // basic block is an edge connecting two such junctions.
+ // For each junction we store:
+ // * set of blocks that originate at the junction
+ // * set of blocks that terminate at the junction
+ // For each block we store:
+ // * a single entry junction
+ // * a single exit junction
+ // * any preconditions satisfied at entry to the block
+ // * a 'use' and 'kill' set of names for the block
+ // * full sequence of 'name' and 'assign' nodes in the block
+ // * whether each such node appears as part of a larger expression
+ // (and therefore cannot be safely eliminated)
+
+ var junctions = [];
+ var blocks = [];
+ var currEntryJunction = null;
+ var nextBasicBlock = null;
+ var isInExpr = 0;
+ var activeLabels = [{}];
+ var nextLoopLabel = null;
+
+ var ENTRY_JUNCTION = 0;
+ var EXIT_JUNCTION = 1;
+ var ENTRY_BLOCK = 0;
+
+ function addJunction() {
+ // Create a new junction, without inserting it into the graph.
+ // This is useful for e.g. pre-allocating an exit node.
+ var id = junctions.length;
+ junctions[id] = {id: id, inblocks: {}, outblocks: {}};
+ return id;
+ }
+
+ function markJunction(id) {
+ // Mark current traversal location as a junction.
+ // This makes a new basic block exiting at this position.
+ if (id === undefined || id === null) {
+ id = addJunction();
+ }
+ joinJunction(id);
+ return id;
+ }
+
+ function setJunction(id) {
+ // Set the next entry junction to the given id.
+ // This can be used to enter at a previously-declared point.
+ assert(nextBasicBlock.nodes.length === 0, 'refusing to abandon an in-progress basic block')
+ currEntryJunction = id;
+ }
+
+ function joinJunction(id) {
+ // Complete the pending basic block by exiting at this position.
+ // This can be used to exit at a previously-declared point.
+ if (currEntryJunction !== null) {
+ nextBasicBlock.id = blocks.length;
+ nextBasicBlock.entry = currEntryJunction;
+ nextBasicBlock.exit = id;
+ junctions[currEntryJunction].outblocks[nextBasicBlock.id] = 1;
+ junctions[id].inblocks[nextBasicBlock.id] = 1;
+ blocks.push(nextBasicBlock);
+ }
+ nextBasicBlock = { id: null, entry: null, exit: null, pre: {}, nodes: [], isexpr: [], use: {}, kill: {} };
+ currEntryJunction = id;
+ return id;
+ }
+
+ function pushActiveLabels(onContinue, onBreak) {
+ // Push the target junctions for continuing/breaking a loop.
+ // This should be called before traversing into a loop.
+ var newLabels = copy(activeLabels[activeLabels.length-1]);
+ newLabels[null] = [onContinue, onBreak];
+ if (nextLoopLabel) {
+ newLabels[nextLoopLabel] = [onContinue, onBreak];
+ nextLoopLabel = null;
+ }
+ activeLabels.push(newLabels);
+ }
+
+ function popActiveLabels() {
+ // Pop the target junctions for continuing/breaking a loop.
+ // This should be called after traversing into a loop.
+ activeLabels.pop();
+ }
+
+ function markNonLocalJump(type, label) {
+ // Complete a block via 'return', 'break' or 'continue'.
+ // This joins the targetted junction and then sets the current junction to null.
+ // Any code traversed before we get back an existing junction is dead code.
+ if (type === 'return') {
+ joinJunction(EXIT_JUNCTION);
+ } else {
+ label = label ? label : null;
+ var targets = activeLabels[activeLabels.length-1][label];
+ assert(targets, 'jump to unknown label');
+ if (type === 'continue') {
+ joinJunction(targets[0]);
+ } else if (type === 'break') {
+ joinJunction(targets[1]);
+ } else {
+ assert(false, 'unknown jump node type');
+ }
+ }
+ setJunction(null);
+ }
+
+ function addUseNode(node) {
+ // Mark a use of the given name node in the current basic block.
+ assert(node[0] === 'name', 'not a use node');
+ var name = node[1];
+ if (name in localVars) {
+ nextBasicBlock.nodes.push(node);
+ nextBasicBlock.isexpr.push(isInExpr);
+ if (!nextBasicBlock.kill[name]) {
+ nextBasicBlock.use[name] = 1;
+ }
+ }
+ }
+
+ function addKillNode(node) {
+ // Mark an assignment to the given name node in the current basic block.
+ assert(node[0] === 'assign', 'not a kill node');
+ assert(node[1] === true, 'not a kill node');
+ assert(node[2][0] === 'name', 'not a kill node');
+ var name = node[2][1];
+ if (name in localVars) {
+ nextBasicBlock.nodes.push(node);
+ nextBasicBlock.isexpr.push(isInExpr);
+ nextBasicBlock.kill[name] = 1;
+ }
+ }
+
+ function lookThroughCasts(node) {
+ // Look through value-preserving casts, like "x | 0" => "x"
+ if (node[0] === 'binary' && node[1] === '|') {
+ if (node[3][0] === 'num' && node[3][1] === 0) {
+ return lookThroughCasts(node[2]);
+ }
+ }
+ return node;
+ }
+
+ function addPreCondTrue(node) {
+ // Add pre-conditions implied by truth of the
+ // given node to the current basic block.
+ assert(nextBasicBlock.nodes.length === 0, 'cant add preconditions to an in-progress basic block')
+ if (node[0] === 'binary' && node[1] === '==') {
+ var lhs = lookThroughCasts(node[2]);
+ var rhs = lookThroughCasts(node[3]);
+ if (lhs[0] === 'name' && rhs[0] === 'num') {
+ nextBasicBlock.pre[lhs[1]] = ['==', rhs[1]];
+ }
+ }
+ }
+
+ function addPreCondFalse(node) {
+ // Add pre-conditions implied by falsehood of the
+ // given node to the current basic block.
+ assert(nextBasicBlock.nodes.length === 0, 'cant add preconditions to an in-progress basic block')
+ if (node[0] === 'binary' && node[1] === '==') {
+ var lhs = lookThroughCasts(node[2]);
+ var rhs = lookThroughCasts(node[3]);
+ if (lhs[0] === 'name' && rhs[0] === 'num') {
+ nextBasicBlock.pre[lhs[1]] = ['!=', rhs[1]];
+ }
+ }
+ }
+
+ function isTrueNode(node) {
+ // Check if the given node is statically truthy.
+ return (node[0] === 'num' && node[1] != 0);
+ }
+
+ function isFalseNode(node) {
+ // Check if the given node is statically falsy.
+ return (node[0] === 'num' && node[1] == 0);
+ }
+
+ function morphNode(node, newNode) {
+ // In-place morph a node into some other type of node.
+ var i = 0;
+ while (i < node.length && i < newNode.length) {
+ node[i] = newNode[i];
+ i++;
+ }
+ while (i < newNode.length) {
+ node.push(newNode[i]);
+ i++;
+ }
+ if (node.length > newNode.length) {
+ node.length = newNode.length;
+ }
+ }
+
+ function buildFlowGraph(node) {
+ // Recursive function to build up the flow-graph.
+ // It walks the tree in execution order, calling the above state-management
+ // functions at appropriate points in the traversal.
+ var type = node[0];
+
+ // Any code traversed without an active entry junction must be dead,
+ // as the resulting block could never be entered. Let's remove it.
+ if (currEntryJunction === null && junctions.length > 0) {
+ morphNode(node, ['block', []]);
+ return;
+ }
+
+ // Traverse each node type according to its particular control-flow semantics.
+ switch (type) {
+ case 'defun':
+ var jEntry = markJunction();
+ assert(jEntry === ENTRY_JUNCTION);
+ var jExit = addJunction();
+ assert(jExit === EXIT_JUNCTION);
+ for (var i = 0; i < node[3].length; i++) {
+ buildFlowGraph(node[3][i]);
+ }
+ joinJunction(jExit);
+ break;
+ case 'if':
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ isInExpr--;
+ var jEnter = markJunction();
+ addPreCondTrue(node[1]);
+ if (node[2]) {
+ buildFlowGraph(node[2]);
+ }
+ var jExit = markJunction();
+ setJunction(jEnter);
+ addPreCondFalse(node[1]);
+ if (node[3]) {
+ buildFlowGraph(node[3]);
+ }
+ joinJunction(jExit);
+ break;
+ case 'conditional':
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ var jEnter = markJunction();
+ addPreCondTrue(node[1]);
+ if (node[2]) {
+ buildFlowGraph(node[2]);
+ }
+ var jExit = markJunction();
+ setJunction(jEnter);
+ addPreCondFalse(node[1]);
+ if (node[3]) {
+ buildFlowGraph(node[3]);
+ }
+ joinJunction(jExit);
+ isInExpr--;
+ break;
+ case 'while':
+ // Special-case "while (1) {}" to use fewer junctions,
+ // since emscripten generates a lot of these.
+ if (isTrueNode(node[1])) {
+ var jLoop = markJunction();
+ var jExit = addJunction();
+ pushActiveLabels(jLoop, jExit);
+ buildFlowGraph(node[2]);
+ popActiveLabels();
+ joinJunction(jLoop);
+ setJunction(jExit);
+ } else {
+ var jCond = markJunction();
+ var jLoop = addJunction();
+ var jExit = addJunction();
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ isInExpr--;
+ joinJunction(jLoop);
+ pushActiveLabels(jCond, jExit);
+ addPreCondTrue(node[1]);
+ buildFlowGraph(node[2]);
+ popActiveLabels();
+ joinJunction(jCond);
+ // An empty basic-block linking condition exit to loop exit.
+ setJunction(jLoop);
+ joinJunction(jExit);
+ }
+ break;
+ case 'do':
+ // Special-case "do {} while (1)" and "do {} while (0)" to use
+ // fewer junctions, since emscripten generates a lot of these.
+ if (isFalseNode(node[1])) {
+ var jExit = addJunction();
+ pushActiveLabels(jExit, jExit);
+ buildFlowGraph(node[2]);
+ popActiveLabels();
+ joinJunction(jExit);
+ } else if (isTrueNode(node[1])) {
+ var jLoop = markJunction();
+ var jExit = addJunction();
+ pushActiveLabels(jLoop, jExit);
+ buildFlowGraph(node[2]);
+ popActiveLabels();
+ joinJunction(jLoop);
+ setJunction(jExit);
+ } else {
+ var jLoop = markJunction();
+ var jCond = addJunction();
+ var jCondExit = addJunction();
+ var jExit = addJunction();
+ pushActiveLabels(jCond, jExit);
+ buildFlowGraph(node[2]);
+ popActiveLabels();
+ joinJunction(jCond);
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ isInExpr--;
+ joinJunction(jCondExit);
+ joinJunction(jLoop);
+ setJunction(jCondExit);
+ joinJunction(jExit)
+ }
+ break;
+ case 'for':
+ var jTest = addJunction();
+ var jBody = addJunction();
+ var jStep = addJunction();
+ var jExit = addJunction();
+ buildFlowGraph(node[1]);
+ joinJunction(jTest);
+ isInExpr++;
+ buildFlowGraph(node[2]);
+ isInExpr--;
+ joinJunction(jBody);
+ pushActiveLabels(jStep, jExit);
+ buildFlowGraph(node[4]);
+ popActiveLabels();
+ joinJunction(jStep);
+ buildFlowGraph(node[3]);
+ joinJunction(jTest);
+ setJunction(jBody);
+ joinJunction(jExit);
+ break;
+ case 'label':
+ assert(node[2][0] in BREAK_CAPTURERS, 'label on non-loop, non-switch statement')
+ nextLoopLabel = node[1];
+ buildFlowGraph(node[2]);
+ break;
+ case 'switch':
+ // This is horrific. It need to capture the default flow-through
+ // logic of sequential case bodies, as well as the theoretical
+ // sequential evaluation of each case clause.
+ // TODO: simplify based on asmjs switch-statement restrictions.
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ isInExpr--;
+ var jCheckExit = markJunction();
+ var jExit = addJunction();
+ pushActiveLabels(null, jExit);
+ // Process all cases as a sequential chain of checks.
+ // Process all case bodies as one big flow-through statement.
+ // They might break themselves out of it but this implements the
+ // default fall-through case logic.
+ var hasDefault = false;
+ var jPrevCaseExit = jCheckExit;
+ var jPrevBodyExit = jCheckExit;
+ for (var i=0; i<node[2].length; i++) {
+ // In the general case we'll need a basic block for the case clause.
+ // Try to avoid it for common, simple, non-var-using cases.
+ if (!node[2][i][0]) {
+ hasDefault = true;
+ } else {
+ if (node[2][i][0][0] !== 'num') {
+ setJunction(jPrevCaseExit);
+ isInExpr++;
+ buildFlowGraph(node[2][i][0]);
+ isInExpr--;
+ jPrevCaseExit = markJunction();
+ }
+ }
+ // The next case body flows from the exit of the prev one,
+ // or may be entered directly from the case statement exit.
+ setJunction(jPrevCaseExit);
+ if (jPrevBodyExit !== jCheckExit) {
+ joinJunction(jPrevBodyExit);
+ }
+ for (var j = 0; j < node[2][i][1].length; j++) {
+ buildFlowGraph(node[2][i][1][j]);
}
+ jPrevBodyExit = markJunction();
}
+ markJunction(jExit);
+ // If there was no default case, we also need an empty block
+ // linking straight from entry to exit.
+ if (!hasDefault && jCheckExit !== jPrevBodyExit) {
+ setJunction(jCheckExit);
+ joinJunction(jExit);
+ }
+ popActiveLabels()
+ break;
+ case 'return':
+ if (node[1]) {
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ isInExpr--;
+ }
+ markNonLocalJump(type);
+ break;
+ case 'break':
+ case 'continue':
+ markNonLocalJump(type, node[1]);
+ break;
+ case 'assign':
+ isInExpr++;
+ buildFlowGraph(node[3]);
+ isInExpr--;
+ if (node[1] === true && node[2][0] === 'name') {
+ addKillNode(node);
+ } else {
+ buildFlowGraph(node[2]);
+ }
+ break;
+ case 'name':
+ addUseNode(node);
+ break;
+ case 'block':
+ case 'toplevel':
+ if (node[1]) {
+ for (var i = 0; i < node[1].length; i++) {
+ buildFlowGraph(node[1][i]);
+ }
+ }
+ break;
+ case 'stat':
+ buildFlowGraph(node[1]);
+ break;
+ case 'unary-prefix':
+ case 'unary-postfix':
+ isInExpr++;
+ buildFlowGraph(node[2]);
+ isInExpr--;
+ break;
+ case 'binary':
+ isInExpr++;
+ buildFlowGraph(node[2]);
+ buildFlowGraph(node[3]);
+ isInExpr--;
+ break;
+ case 'call':
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ if (node[2]) {
+ for (var i = 0; i < node[2].length; i++) {
+ buildFlowGraph(node[2][i]);
+ }
+ }
+ isInExpr--;
+ break;
+ case 'seq':
+ case 'sub':
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ buildFlowGraph(node[2]);
+ isInExpr--;
+ break;
+ case 'dot':
+ case 'throw':
+ isInExpr++;
+ buildFlowGraph(node[1]);
+ isInExpr--;
+ break;
+ case 'num':
+ case 'string':
+ case 'var':
+ break;
+ default:
+ printErr(JSON.stringify(node));
+ assert(false, 'unsupported node type: ' + type);
+ }
+ }
+ buildFlowGraph(fun);
+
+ assert(setSize(junctions[ENTRY_JUNCTION].inblocks) === 0, 'function entry must have no incoming blocks');
+ assert(setSize(junctions[EXIT_JUNCTION].outblocks) === 0, 'function exit must have no outgoing blocks');
+ assert(blocks[ENTRY_BLOCK].entry === ENTRY_JUNCTION, 'block zero must be the initial block');
+
+ // Fix up implicit jumps done by assigning to the 'label' variable.
+ // If a block ends with an assignment to 'label' and there's another block
+ // with that value of 'label' as precondition, we tweak the flow graph so
+ // that the former jumps straight to the later.
+
+ var labelledBlocks = {};
+ var labelledJumps = [];
+ FINDLABELLEDBLOCKS:
+ for (var i = 0; i < blocks.length; i++) {
+ var block = blocks[i];
+ // Does it have a specific label value as precondition?
+ var labelCond = block.pre['label'];
+ if (labelCond && labelCond[0] === '==') {
+ // If there are multiple blocks with the same label, all bets are off.
+ // This seems to happen sometimes for short blocks that end with a return.
+ if (labelCond[1] in labelledBlocks) {
+ labelledBlocks = {};
+ labelledJumps = [];
+ break FINDLABELLEDBLOCKS;
}
- var stats = fun[3];
- for (var i = 0; i < stats.length; i++) {
- var line = stats[i];
- if (i >= fun[2].length && line[0] !== 'var') break; // when we pass the arg and var coercions, break
- if (line[0] === 'stat') {
- assert(line[1][0] === 'assign');
- minify(line[1][3]);
+ labelledBlocks[labelCond[1]] = block;
+ }
+ // Does it assign a specific label value at exit?
+ if ('label' in block.kill) {
+ var finalNode = block.nodes[block.nodes.length - 1];
+ if (finalNode[0] === 'assign' && finalNode[2][1] === 'label') {
+ // If labels are computed dynamically then all bets are off.
+ // This can happen due to indirect branching in llvm output.
+ if (finalNode[3][0] !== 'num') {
+ labelledBlocks = {};
+ labelledJumps = [];
+ break FINDLABELLEDBLOCKS;
+ }
+ labelledJumps.push([finalNode[3][1], block]);
+ } else {
+ // If label is assigned a non-zero value elsewhere in the block
+ // then all bets are off. This can happen e.g. due to outlining
+ // saving/restoring label to the stack.
+ for (var j = 0; j < block.nodes.length - 1; j++) {
+ if (block.nodes[j][0] === 'assign' && block.nodes[j][2][1] === 'label') {
+ if (block.nodes[j][3][0] !== 'num' && block.nodes[j][3][1] !== 0) {
+ labelledBlocks = {};
+ labelledJumps = [];
+ break FINDLABELLEDBLOCKS;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (var labelVal in labelledBlocks) {
+ var block = labelledBlocks[labelVal];
+ // Disconnect it from the graph, and create a
+ // new junction for jumps targetting this label.
+ delete junctions[block.entry].outblocks[block.id];
+ block.entry = addJunction();
+ junctions[block.entry].outblocks[block.id] = 1;
+ // Add a fake use of 'label' to keep it alive in predecessor.
+ block.use['label'] = 1;
+ block.nodes.unshift(['name', 'label']);
+ block.isexpr.unshift(1);
+ }
+ for (var i = 0; i < labelledJumps.length; i++) {
+ var labelVal = labelledJumps[i][0];
+ var block = labelledJumps[i][1];
+ var targetBlock = labelledBlocks[labelVal];
+ if (targetBlock) {
+ // Redirect its exit to entry of the target block.
+ delete junctions[block.exit].inblocks[block.id];
+ block.exit = targetBlock.entry;
+ junctions[block.exit].inblocks[block.id] = 1;
+ }
+ }
+ labelledBlocks = null;
+ labelledJumps = null;
+
+ // Do a backwards data-flow analysis to determine the set of live
+ // variables at each junction, and to use this information to eliminate
+ // any unused assignments.
+ // We run two nested phases. The inner phase builds the live set for each
+ // junction. The outer phase uses this to try to eliminate redundant
+ // stores in each basic block, which might in turn affect liveness info.
+
+ function analyzeJunction(junc) {
+ // Update the live set for this junction.
+ var live = {};
+ for (var b in junc.outblocks) {
+ var block = blocks[b];
+ var liveSucc = junctions[block.exit].live || {};
+ for (var name in liveSucc) {
+ if (!(name in block.kill)) {
+ live[name] = 1;
+ }
+ }
+ for (var name in block.use) {
+ live[name] = 1;
+ }
+ }
+ junc.live = live;
+ }
+
+ function analyzeBlock(block) {
+ // Update information about the behaviour of the block.
+ // This includes the standard 'use' and 'kill' information,
+ // plus a 'link' set naming values that flow through from entry
+ // to exit, possibly changing names via simple 'x=y' assignments.
+ // As we go, we eliminate assignments if the variable is not
+ // subsequently used.
+ var live = copy(junctions[block.exit].live);
+ var use = {};
+ var kill = {};
+ var link = {};
+ var lastUseLoc = {};
+ var firstDeadLoc = {};
+ var lastKillLoc = {};
+ for (var name in live) {
+ link[name] = name;
+ lastUseLoc[name] = block.nodes.length;
+ firstDeadLoc[name] = block.nodes.length;
+ }
+ for (var j = block.nodes.length - 1; j >=0 ; j--) {
+ var node = block.nodes[j];
+ if (node[0] === 'name') {
+ var name = node[1];
+ live[name] = 1;
+ use[name] = j;
+ if (lastUseLoc[name] === undefined) {
+ lastUseLoc[name] = j;
+ firstDeadLoc[name] = j;
+ }
+ } else {
+ var name = node[2][1];
+ // We only keep assignments if they will be subsequently used.
+ if (name in live) {
+ kill[name] = 1;
+ delete use[name];
+ delete live[name];
+ firstDeadLoc[name] = j;
+ if (lastUseLoc[name] === undefined) {
+ lastUseLoc[name] = j;
+ }
+ if (lastKillLoc[name] === undefined) {
+ lastKillLoc[name] = j;
+ }
+ // If it's an "x=y" and "y" is not live, then we can create a
+ // flow-through link from "y" to "x". If not then there's no
+ // flow-through link for "x".
+ var oldLink = link[name];
+ if (oldLink) {
+ delete link[name];
+ if (node[3][0] === 'name') {
+ if (node[3][1] in localVars) {
+ link[node[3][1]] = oldLink;
+ }
+ }
+ }
+ } else {
+ // The result of this assignment is never used, so delete it.
+ // We may need to keep the RHS for its value or its side-effects.
+ function removeUnusedNodes(j, n) {
+ for (var name in lastUseLoc) {
+ lastUseLoc[name] -= n;
+ }
+ for (var name in lastKillLoc) {
+ lastKillLoc[name] -= n;
+ }
+ for (var name in firstDeadLoc) {
+ firstDeadLoc[name] -= n;
+ }
+ block.nodes.splice(j, n);
+ block.isexpr.splice(j, n);
+ }
+ if (block.isexpr[j] || hasSideEffects(node[3])) {
+ morphNode(node, node[3]);
+ removeUnusedNodes(j, 1);
+ } else {
+ var numUsesInExpr = 0;
+ traverse(node[3], function(node, type) {
+ if (type === 'name' && node[1] in localVars) {
+ numUsesInExpr++;
+ }
+ });
+ morphNode(node, ['block', []]);
+ j = j - numUsesInExpr;
+ removeUnusedNodes(j, 1 + numUsesInExpr);
+ }
+ }
+ }
+ }
+ block.use = use;
+ block.kill = kill;
+ block.link = link;
+ block.lastUseLoc = lastUseLoc;
+ block.firstDeadLoc = firstDeadLoc;
+ block.lastKillLoc = lastKillLoc;
+ }
+
+ var jWorklistMap = { EXIT_JUNCTION: 1 };
+ var jWorklist = [EXIT_JUNCTION];
+ var bWorklistMap = {};
+ var bWorklist = [];
+
+ // Be sure to visit every junction at least once.
+ // This avoids missing some vars because we disconnected them
+ // when processing the labelled jumps.
+ for (var i = junctions.length - 1; i >= EXIT_JUNCTION; i--) {
+ jWorklistMap[i] = 1;
+ jWorklist.push(i);
+ }
+
+ while (jWorklist.length > 0) {
+ // Iterate on just the junctions until we get stable live sets.
+ // The first run of this loop will grow the live sets to their maximal size.
+ // Subsequent runs will shrink them based on eliminated in-block uses.
+ while (jWorklist.length > 0) {
+ var junc = junctions[jWorklist.pop()];
+ delete jWorklistMap[junc.id];
+ var oldLive = junc.live || null;
+ analyzeJunction(junc);
+ if (!sortedJsonCompare(oldLive, junc.live)) {
+ // Live set changed, updated predecessor blocks and junctions.
+ for (var b in junc.inblocks) {
+ if (!(b in bWorklistMap)) {
+ bWorklistMap[b] = 1;
+ bWorklist.push(b);
+ }
+ var jPred = blocks[b].entry;
+ if (!(jPred in jWorklistMap)) {
+ jWorklistMap[jPred] = 1;
+ jWorklist.push(jPred);
+ }
+ }
+ }
+ }
+ // Now update the blocks based on the calculated live sets.
+ while (bWorklist.length > 0) {
+ var block = blocks[bWorklist.pop()];
+ delete bWorklistMap[block.id];
+ var oldUse = block.use;
+ analyzeBlock(block);
+ if (!sortedJsonCompare(oldUse, block.use)) {
+ // The use set changed, re-process the entry junction.
+ if (!(block.entry in jWorklistMap)) {
+ jWorklistMap[block.entry] = 1;
+ jWorklist.push(block.entry);
+ }
+ }
+ }
+ }
+
+ // Insist that all function parameters are alive at function entry.
+ // This ensures they will be assigned independent registers, even
+ // if they happen to be unused.
+
+ for (var name in asmData.params) {
+ junctions[ENTRY_JUNCTION].live[name] = 1;
+ }
+
+ // For variables that are live at one or more junctions, we assign them
+ // a consistent register for the entire scope of the function. Find pairs
+ // of variable that cannot use the same register (the "conflicts") as well
+ // as pairs of variables that we'd like to have share the same register
+ // (the "links").
+
+ var junctionVariables = {};
+
+ function initializeJunctionVariable(name) {
+ junctionVariables[name] = { conf: {}, link: {}, excl: {}, reg: null };
+ }
+
+ for (var i = 0; i < junctions.length; i++) {
+ var junc = junctions[i];
+ for (var name in junc.live) {
+ if (!junctionVariables[name]) initializeJunctionVariable(name);
+ // It conflicts with all other names live at this junction.
+ for (var otherName in junc.live) {
+ if (otherName == name) continue;
+ junctionVariables[name].conf[otherName] = 1;
+ }
+ for (var b in junc.outblocks) {
+ // It conflits with any output vars of successor blocks,
+ // if they're assigned before it goes dead in that block.
+ block = blocks[b];
+ var jSucc = junctions[block.exit];
+ for (var otherName in jSucc.live) {
+ if (junc.live[otherName]) continue;
+ if (block.lastKillLoc[otherName] < block.firstDeadLoc[name]) {
+ if (!junctionVariables[otherName]) initializeJunctionVariable(otherName);
+ junctionVariables[name].conf[otherName] = 1;
+ junctionVariables[otherName].conf[name] = 1;
+ }
+ }
+ // It links with any linkages in the outgoing blocks.
+ var linkName = block.link[name];
+ if (linkName && linkName !== name) {
+ if (!junctionVariables[linkName]) initializeJunctionVariable(linkName);
+ junctionVariables[name].link[linkName] = 1;
+ junctionVariables[linkName].link[name] = 1;
+ }
+ }
+ }
+ }
+
+ // Attempt to sort the junction variables to heuristically reduce conflicts.
+ // Simple starting point: handle the most-conflicted variables first.
+ // This seems to work pretty well.
+
+ var sortedJunctionVariables = keys(junctionVariables);
+ sortedJunctionVariables.sort(function(name1, name2) {
+ var jv1 = junctionVariables[name1];
+ var jv2 = junctionVariables[name2];
+ if (jv1.numConfs === undefined) {
+ jv1.numConfs = setSize(jv1.conf);
+ }
+ if (jv2.numConfs === undefined) {
+ jv2.numConfs = setSize(jv2.conf);
+ }
+ return jv2.numConfs - jv1.numConfs;
+ });
+
+ // We can now assign a register to each junction variable.
+ // Process them in order, trying available registers until we find
+ // one that works, and propagating the choice to linked/conflicted
+ // variables as we go.
+
+ function tryAssignRegister(name, reg) {
+ // Try to assign the given register to the given variable,
+ // and propagate that choice throughout the graph.
+ // Returns true if successful, false if there was a conflict.
+ var jv = junctionVariables[name];
+ if (jv.reg !== null) {
+ return jv.reg === reg;
+ }
+ if (jv.excl[reg]) {
+ return false;
+ }
+ jv.reg = reg;
+ // Exclude use of this register at all conflicting variables.
+ for (var confName in jv.conf) {
+ junctionVariables[confName].excl[reg] = 1;
+ }
+ // Try to propagate it into linked variables.
+ // It's not an error if we can't.
+ for (var linkName in jv.link) {
+ tryAssignRegister(linkName, reg);
+ }
+ return true;
+ }
+
+ NEXTVARIABLE:
+ for (var i = 0; i < sortedJunctionVariables.length; i++) {
+ var name = sortedJunctionVariables[i];
+ // It may already be assigned due to linked-variable propagation.
+ if (junctionVariables[name].reg !== null) {
+ continue NEXTVARIABLE;
+ }
+ // Try to use existing registers first.
+ var allRegs = allRegsByType[localVars[name]];
+ for (var reg in allRegs) {
+ if (tryAssignRegister(name, reg)) {
+ continue NEXTVARIABLE;
+ }
+ }
+ // They're all taken, create a new one.
+ tryAssignRegister(name, createReg(name));
+ }
+
+ // Each basic block can now be processed in turn.
+ // There may be internal-use-only variables that still need a register
+ // assigned, but they can be treated just for this block. We know
+ // that all inter-block variables are in a good state thanks to
+ // junction variable consistency.
+
+ for (var i = 0; i < blocks.length; i++) {
+ var block = blocks[i];
+ if (block.nodes.length === 0) continue;
+ var jEnter = junctions[block.entry];
+ var jExit = junctions[block.exit];
+ // Calculate the full internal liveness states for this block.
+ var liveness = [{}];
+ for (var name in jExit.live) {
+ liveness[0][name] = 1;
+ }
+ for (var j=block.nodes.length-1; j>=0; j--) {
+ var node = block.nodes[j];
+ liveness.unshift(copy(liveness[0]));
+ if (node[0] === 'assign') {
+ var name = node[2][1];
+ delete liveness[0][name];
+ } else if (node[0] === 'name') {
+ var name = node[1];
+ liveness[0][name] = 1;
+ } else {
+ assert(false, 'unexpected node type: ' + node[0]);
+ }
+ }
+ assert(liveness.length == block.nodes.length + 1);
+ assert(setSize(setSub(liveness[0], jEnter.live)) == 0);
+ // Mark the point at which each output reg gets assigned.
+ // Variables that live past this point must not be assigned
+ // to that register.
+ var outputAssignLoc = {};
+ var outputVars = {};
+ for (var name in jExit.live) {
+ var reg = junctionVariables[name].reg;
+ assert(reg !== null, 'output variable doesnt have a register');
+ outputAssignLoc[reg] = block.lastKillLoc[name];
+ outputVars[reg] = name;
+ }
+ // Scan through in execution order, allocating registers on demand.
+ // Be careful to avoid conflicts with the output registers.
+ // We consume free registers in last-used order, which helps to
+ // eliminate "x=y" assignments that are the last use of "y".
+ var assignedRegs = {};
+ var freeRegsByType = copy(allRegsByType);
+ // Begin with all live vars assigned per the entry-point.
+ for (var name in liveness[0]) {
+ var reg = junctionVariables[name].reg;
+ assert(reg !== null, 'input variable doesnt have a register');
+ assignedRegs[name] = reg;
+ delete freeRegsByType[localVars[name]][reg];
+ }
+ for (var j = 0; j < freeRegsByType.length; j++) {
+ freeRegsByType[j] = keys(freeRegsByType[j]);
+ }
+ // Scan through the nodes in sequence, modifying each node in-place
+ // and freeing registers according to the calculated liveness info.
+ for (var j = 0; j < block.nodes.length; j++) {
+ var node = block.nodes[j];
+ var name = node[0] === 'assign' ? node[2][1] : node[1];
+ var allRegs = allRegsByType[localVars[name]];
+ var freeRegs = freeRegsByType[localVars[name]];
+ var reg = assignedRegs[name];
+ if (node[0] === 'name') {
+ // A use. It should already be in a register.
+ assert(liveness[j][name], 'use node, but name was not alive?')
+ assert(reg, 'live variable did not have a reg?')
+ node[1] = allRegs[reg];
+ } else {
+ // A kill. This should assign it a new register.
+ assert(!liveness[j][name], 'kill node, but name was alive?')
+ assert(!reg, 'non-live variable still had a reg?')
+ if (name in jExit.live && j === block.lastKillLoc[name]) {
+ // Assignment to an output variable, must use pre-assigned reg.
+ reg = junctionVariables[name].reg;
+ assignedRegs[name] = reg;
+ for (var k = freeRegs.length - 1; k >= 0; k--) {
+ if (freeRegs[k] === reg) {
+ freeRegs.splice(k, 1);
+ break;
+ }
+ }
} else {
- assert(line[0] === 'var');
- var pairs = line[1];
- for (var j = 0; j < pairs.length; j++) {
- minify(pairs[j][1]);
+ // Try to use one of the existing free registers.
+ // It must not conflict with an output register.
+ for (var k = freeRegs.length - 1; k >= 0; k--) {
+ reg = freeRegs[k];
+ // Check for conflict with output registers.
+ if (block.lastUseLoc[name] > outputAssignLoc[reg]) {
+ if (name !== outputVars[reg]) {
+ continue;
+ }
+ }
+ // Found one!
+ assignedRegs[name] = reg;
+ freeRegs.splice(k, 1);
+ break;
+ }
+ // If we didn't find a suitable register, create a new one.
+ if (!assignedRegs[name]) {
+ reg = createReg(name);
+ assignedRegs[name] = reg;
}
}
+ // Modify assignment to use the new name.
+ // If we happen to create a "x=x" type do-nothing assignment,
+ // we can safely morph it into a no-op.
+ node[2][1] = allRegs[reg];
+ if (node[3][0] === 'name' && node[3][1] === node[2][1]) {
+ morphNode(node, ['block', []]);
+ }
}
+ // Free the reg if it's not live in the next step.
+ if (!liveness[j+1][name]) {
+ delete assignedRegs[name];
+ freeRegs.push(reg);
+ }
+ }
+ }
+
+ // Assign registers to function params based on entry junction
+
+ var paramRegs = {}
+ if (fun[2]) {
+ for (var i = 0; i < fun[2].length; i++) {
+ var allRegs = allRegsByType[localVars[fun[2][i]]];
+ fun[2][i] = allRegs[junctionVariables[fun[2][i]].reg];
+ paramRegs[fun[2][i]] = 1;
+ }
+ }
+
+ // That's it!
+ // Re-construct the function with appropriate variable definitions.
+
+ var finalAsmData = {
+ params: {},
+ vars: {},
+ inlines: asmData.inlines,
+ };
+ for (var i = 1; i < nextReg; i++) {
+ var reg;
+ for (var type=0; type<allRegsByType.length; type++) {
+ reg = allRegsByType[type][i];
+ if (reg) break;
+ }
+ if (!paramRegs[reg]) {
+ finalAsmData.vars[reg] = type;
+ } else {
+ finalAsmData.params[reg] = type;
}
}
+ denormalizeAsm(fun, finalAsmData);
+
+ vacuum(fun);
+
});
}
+
// Eliminator aka Expressionizer
//
// The goal of this pass is to eliminate unneeded variables (which represent one of the infinite registers in the LLVM
@@ -2322,7 +3306,7 @@ function eliminate(ast, memSafe) {
var memoryInvalidated = false;
var callsInvalidated = false;
function track(name, value, defNode) { // add a potential that has just been defined to the tracked list, we hope to eliminate it
- var usesGlobals = false, usesMemory = false, deps = {}, doesCall = false;
+ var usesGlobals = false, usesMemory = false, deps = {}, doesCall = false, hasDeps = false;
var ignoreName = false; // one-time ignorings of names, as first op in sub and call
traverse(value, function(node, type) {
if (type === 'name') {
@@ -2333,6 +3317,7 @@ function eliminate(ast, memSafe) {
}
if (!(name in potentials)) { // deps do not matter for potentials - they are defined once, so no complexity
deps[name] = 1;
+ hasDeps = true;
}
} else {
ignoreName = false;
@@ -2354,6 +3339,7 @@ function eliminate(ast, memSafe) {
usesMemory: usesMemory,
defNode: defNode,
deps: deps,
+ hasDeps: hasDeps,
doesCall: doesCall
};
globalsInvalidated = false;
@@ -2426,7 +3412,7 @@ function eliminate(ast, memSafe) {
function traverseInOrder(node, ignoreSub, ignoreName) {
if (abort) return;
//nesting++; // printErr-related
- //printErr(spaces(2*(nesting+1)) + 'trav: ' + JSON.stringify(node).substr(0, 50) + ' : ' + keys(tracked) + ' : ' + [allowTracking, ignoreSub, ignoreName]);
+ //printErr(JSON.stringify(node).substr(0, 50) + ' : ' + keys(tracked) + ' : ' + [allowTracking, ignoreSub, ignoreName]);
var type = node[0];
if (type === 'assign') {
var target = node[2];
@@ -2602,6 +3588,8 @@ function eliminate(ast, memSafe) {
traverseInOrder(node[3]);
} else if (type === 'switch') {
traverseInOrder(node[1]);
+ var originalTracked = {};
+ for (var o in tracked) originalTracked[o] = 1;
var cases = node[2];
for (var i = 0; i < cases.length; i++) {
var c = cases[i];
@@ -2610,6 +3598,15 @@ function eliminate(ast, memSafe) {
for (var j = 0; j < stats.length; j++) {
traverseInOrder(stats[j]);
}
+ // We cannot track from one switch case into another, undo all new trackings TODO: general framework here, use in if-else as well
+ for (var t in tracked) {
+ if (!(t in originalTracked)) {
+ var info = tracked[t];
+ if (info.usesGlobals || info.usesMemory || info.hasDeps) {
+ delete tracked[t];
+ }
+ }
+ }
}
} else {
if (!(type in ABORTING_ELIMINATOR_SCAN_NODES)) {
@@ -2900,6 +3897,111 @@ function minifyGlobals(ast) {
suffix = '// EXTRA_INFO:' + JSON.stringify(minified);
}
+
+function minifyLocals(ast) {
+ assert(asm)
+ assert(extraInfo && extraInfo.globals)
+
+ traverseGeneratedFunctions(ast, function(fun, type) {
+
+ // Analyse the asmjs to figure out local variable names,
+ // but operate on the original source tree so that we don't
+ // miss any global names in e.g. variable initializers.
+ var asmData = normalizeAsm(fun); denormalizeAsm(fun, asmData); // TODO: we can avoid modifying at all here - we just need a list of local vars+params
+ var newNames = {};
+ var usedNames = {};
+
+ // Find all the globals that we need to minify using
+ // pre-assigned names. Don't actually minify them yet
+ // as that might interfere with local variable names.
+ function isLocalName(name) {
+ return name in asmData.vars || name in asmData.params;
+ }
+ traverse(fun, function(node, type) {
+ if (type === 'name') {
+ var name = node[1];
+ if (!isLocalName(name)) {
+ var minified = extraInfo.globals[name];
+ if (minified){
+ newNames[name] = minified;
+ usedNames[minified] = 1;
+ }
+ }
+ }
+ });
+
+ // The first time we encounter a local name, we assign it a
+ // minified name that's not currently in use. Allocating on
+ // demand means they're processed in a predicatable order,
+ // which is very handy for testing/debugging purposes.
+ var nextMinifiedName = 0;
+ function getNextMinifiedName() {
+ var minified;
+ while (1) {
+ ensureMinifiedNames(nextMinifiedName);
+ minified = minifiedNames[nextMinifiedName++];
+ // TODO: we can probably remove !isLocalName here
+ if (!usedNames[minified] && !isLocalName(minified)) {
+ return minified;
+ }
+ }
+ }
+
+ // We can also minify loop labels, using a separate namespace
+ // to the variable declarations.
+ var newLabels = {};
+ var nextMinifiedLabel = 0;
+ function getNextMinifiedLabel() {
+ ensureMinifiedNames(nextMinifiedLabel);
+ return minifiedNames[nextMinifiedLabel++];
+ }
+
+ // Traverse and minify all names.
+ if (fun[1] in extraInfo.globals) {
+ fun[1] = extraInfo.globals[fun[1]];
+ assert(fun[1]);
+ }
+ if (fun[2]) {
+ for (var i = 0; i < fun[2].length; i++) {
+ var minified = getNextMinifiedName();
+ newNames[fun[2][i]] = minified;
+ fun[2][i] = minified;
+ }
+ }
+ traverse(fun[3], function(node, type) {
+ if (type === 'name') {
+ var name = node[1];
+ var minified = newNames[name];
+ if (minified) {
+ node[1] = minified;
+ } else if (isLocalName(name)) {
+ minified = getNextMinifiedName();
+ newNames[name] = minified;
+ node[1] = minified;
+ }
+ } else if (type === 'var') {
+ node[1].forEach(function(defn) {
+ var name = defn[0];
+ if (!(name in newNames)) {
+ newNames[name] = getNextMinifiedName();
+ }
+ defn[0] = newNames[name];
+ });
+ } else if (type === 'label') {
+ if (!newLabels[node[1]]) {
+ newLabels[node[1]] = getNextMinifiedLabel();
+ }
+ node[1] = newLabels[node[1]];
+ } else if (type === 'break' || type === 'continue') {
+ if (node[1]) {
+ node[1] = newLabels[node[1]];
+ }
+ }
+ });
+
+ });
+}
+
// Relocation pass for a shared module (for the functions part of the module)
//
// 1. Replace function names with alternate names as defined (to avoid colliding with
@@ -3117,8 +4219,8 @@ function aggressiveVariableEliminationInternal(func, asmData) {
var name = node[1];
if (name in trivials) {
var value = values[name];
- if (!value) throw 'missing value: ' + [func[1], name, values[name]] + ' - faulty reliance on asm zero-init?';
- return copy(value); // must copy, or else the same object can be used multiple times
+ if (value) return copy(value); // must copy, or else the same object can be used multiple times
+ else return emptyNode();
}
}
});
@@ -3866,6 +4968,113 @@ function outline(ast) {
});
}
+function safeHeap(ast) {
+ function fixPtr(ptr, heap) {
+ switch (heap) {
+ case 'HEAP8': case 'HEAPU8': break;
+ case 'HEAP16': case 'HEAPU16': {
+ if (ptr[0] === 'binary') {
+ assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 1);
+ ptr = ptr[2]; // skip the shift
+ } else {
+ ptr = ['binary', '*', ptr, ['num', 2]]; // was unshifted, convert to absolute address
+ }
+ break;
+ }
+ case 'HEAP32': case 'HEAPU32': {
+ if (ptr[0] === 'binary') {
+ assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 2);
+ ptr = ptr[2]; // skip the shift
+ } else {
+ ptr = ['binary', '*', ptr, ['num', 4]]; // was unshifted, convert to absolute address
+ }
+ break;
+ }
+ case 'HEAPF32': {
+ if (ptr[0] === 'binary') {
+ assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 2);
+ ptr = ptr[2]; // skip the shift
+ } else {
+ ptr = ['binary', '*', ptr, ['num', 4]]; // was unshifted, convert to absolute address
+ }
+ break;
+ }
+ case 'HEAPF64': {
+ if (ptr[0] === 'binary') {
+ assert(ptr[1] === '>>' && ptr[3][0] === 'num' && ptr[3][1] === 3);
+ ptr = ptr[2]; // skip the shift
+ } else {
+ ptr = ['binary', '*', ptr, ['num', 8]]; // was unshifted, convert to absolute address
+ }
+ break;
+ }
+ default: throw 'bad heap ' + heap;
+ }
+ ptr = ['binary', '|', ptr, ['num', 0]];
+ return ptr;
+ }
+ traverseGenerated(ast, function(node, type) {
+ if (type === 'assign') {
+ if (node[1] === true && node[2][0] === 'sub') {
+ var heap = node[2][1][1];
+ var ptr = fixPtr(node[2][2], heap);
+ var value = node[3];
+ // SAFE_HEAP_STORE(ptr, value, bytes, isFloat)
+ switch (heap) {
+ case 'HEAP8': case 'HEAPU8': {
+ return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 1], ['num', '0']]];
+ }
+ case 'HEAP16': case 'HEAPU16': {
+ return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 2], ['num', '0']]];
+ }
+ case 'HEAP32': case 'HEAPU32': {
+ return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_INT), ['num', 4], ['num', '0']]];
+ }
+ case 'HEAPF32': {
+ return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 4], ['num', '1']]];
+ }
+ case 'HEAPF64': {
+ return ['call', ['name', 'SAFE_HEAP_STORE'], [ptr, makeAsmCoercion(value, ASM_DOUBLE), ['num', 8], ['num', '1']]];
+ }
+ default: throw 'bad heap ' + heap;
+ }
+ }
+ } else if (type === 'sub') {
+ var heap = node[1][1];
+ if (heap[0] !== 'H') return;
+ var ptr = fixPtr(node[2], heap);
+ // SAFE_HEAP_LOAD(ptr, bytes, isFloat)
+ switch (heap) {
+ case 'HEAP8': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT);
+ }
+ case 'HEAPU8': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT);
+ }
+ case 'HEAP16': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT);
+ }
+ case 'HEAPU16': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT);
+ }
+ case 'HEAP32': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT);
+ }
+ case 'HEAPU32': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT);
+ }
+ case 'HEAPF32': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE);
+ }
+ case 'HEAPF64': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE);
+ }
+ default: throw 'bad heap ' + heap;
+ }
+ }
+ });
+}
+
// Last pass utilities
// Change +5 to DOT$ZERO(5). We then textually change 5 to 5.0 (uglify's ast cannot differentiate between 5 and 5.0 directly)
@@ -3956,6 +5165,7 @@ function asmLastOpts(ast) {
var minifyWhitespace = false, printMetadata = true, asm = false, last = false;
var passes = {
+ // passes
dumpAst: dumpAst,
dumpSrc: dumpSrc,
unGlobalize: unGlobalize,
@@ -3967,12 +5177,17 @@ var passes = {
hoistMultiples: hoistMultiples,
loopOptimizer: loopOptimizer,
registerize: registerize,
+ registerizeHarder: registerizeHarder,
eliminate: eliminate,
eliminateMemSafe: eliminateMemSafe,
aggressiveVariableElimination: aggressiveVariableElimination,
minifyGlobals: minifyGlobals,
+ minifyLocals: minifyLocals,
relocate: relocate,
outline: outline,
+ safeHeap: safeHeap,
+
+ // flags
minifyWhitespace: function() { minifyWhitespace = true },
noPrintMetadata: function() { printMetadata = false },
asm: function() { asm = true },
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index d5b1df27..e030b707 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -26,7 +26,7 @@ class Minifier:
'''
asm.js minification support. We calculate minification of
globals here, then pass that into the parallel js-optimizer.js runners which
- during registerize perform minification of locals.
+ perform minification of locals.
'''
def __init__(self, js, js_engine):
@@ -117,9 +117,9 @@ def run_on_js(filename, passes, js_engine, jcache, source_map=False, extra_info=
know_generated = suffix or start_funcs >= 0
- minify_globals = 'registerizeAndMinify' in passes and 'asm' in passes
+ minify_globals = 'minifyNames' in passes and 'asm' in passes
if minify_globals:
- passes = map(lambda p: p if p != 'registerizeAndMinify' else 'registerize', passes)
+ passes = map(lambda p: p if p != 'minifyNames' else 'minifyLocals', passes)
start_asm = js.find(start_asm_marker)
end_asm = js.rfind(end_asm_marker)
assert (start_asm >= 0) == (end_asm >= 0)
@@ -342,6 +342,7 @@ EMSCRIPTEN_FUNCS();
return filename
def run(filename, passes, js_engine=shared.NODE_JS, jcache=False, source_map=False, extra_info=None):
+ js_engine = shared.listify(js_engine)
return temp_files.run_and_clean(lambda: run_on_js(filename, passes, js_engine, jcache, source_map, extra_info))
if __name__ == '__main__':
diff --git a/tools/shared.py b/tools/shared.py
index 5f7e591c..e28a66c3 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -345,7 +345,7 @@ def find_temp_directory():
# 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.8.9'
+EMSCRIPTEN_VERSION = '1.9.3'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version()
@@ -809,12 +809,6 @@ class Settings2(type):
self.attrs['DISABLE_EXCEPTION_CATCHING'] = 1
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:
@@ -1568,7 +1562,7 @@ JCache = cache.JCache(Cache)
chunkify = cache.chunkify
class JS:
- memory_initializer_pattern = '/\* memory initializer \*/ allocate\(([\d,\.concat\(\)\[\]\\n ]+)"i8", ALLOC_NONE, ([\dRuntime\.GLOBAL_BASEH+]+)\)'
+ memory_initializer_pattern = '/\* memory initializer \*/ allocate\(\[([\d, ]+)\], "i8", ALLOC_NONE, ([\d+Runtime\.GLOBAL_BASEH]+)\);'
no_memory_initializer_pattern = '/\* no memory initializer \*/'
memory_staticbump_pattern = 'STATICTOP = STATIC_BASE \+ (\d+);'
@@ -1652,6 +1646,75 @@ class JS:
while x % by != 0: x += 1
return x
+ INITIALIZER_CHUNK_SIZE = 10240
+
+ @staticmethod
+ def collect_initializers(src):
+ ret = []
+ max_offset = -1
+ for init in re.finditer(JS.memory_initializer_pattern, src):
+ contents = init.group(1).split(',')
+ offset = sum([int(x) if x[0] != 'R' else 0 for x in init.group(2).split('+')])
+ ret.append((offset, contents))
+ assert offset > max_offset
+ max_offset = offset
+ return ret
+
+ @staticmethod
+ def split_initializer(contents):
+ # given a memory initializer (see memory_initializer_pattern), split it up into multiple initializers to avoid long runs of zeros or a single overly-large allocator
+ ret = []
+ l = len(contents)
+ maxx = JS.INITIALIZER_CHUNK_SIZE
+ i = 0
+ start = 0
+ while 1:
+ if i - start >= maxx or (i > start and i == l):
+ #print >> sys.stderr, 'new', start, i-start
+ ret.append((start, contents[start:i]))
+ start = i
+ if i == l: break
+ if contents[i] != '0':
+ i += 1
+ else:
+ # look for a sequence of zeros
+ j = i + 1
+ while j < l and contents[j] == '0': j += 1
+ if j-i > maxx/10 or j-start >= maxx:
+ #print >> sys.stderr, 'skip', start, i-start, j-start
+ ret.append((start, contents[start:i])) # skip over the zeros starting at i and ending at j
+ start = j
+ i = j
+ return ret
+
+ @staticmethod
+ def replace_initializers(src, inits):
+ class State:
+ first = True
+ def rep(m):
+ if not State.first: return ''
+ # write out all the new initializers in place of the first old one
+ State.first = False
+ def gen_init(init):
+ offset, contents = init
+ return '/* memory initializer */ allocate([%s], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE%s);' % (
+ ','.join(contents),
+ '' if offset == 0 else ('+%d' % offset)
+ )
+ return '\n'.join(map(gen_init, inits))
+ return re.sub(JS.memory_initializer_pattern, rep, src)
+
+ @staticmethod
+ def optimize_initializer(src):
+ inits = JS.collect_initializers(src)
+ if len(inits) == 0: return None
+ assert len(inits) == 1
+ init = inits[0]
+ offset, contents = init
+ assert offset == 0 # offset 0, singleton
+ if len(contents) <= JS.INITIALIZER_CHUNK_SIZE: return None
+ return JS.replace_initializers(src, JS.split_initializer(contents))
+
# Compression of code and data for smaller downloads
class Compression:
on = False
diff --git a/tools/test-js-optimizer-asm-regs-min-output.js b/tools/test-js-optimizer-asm-regs-min-output.js
index 3955e48a..748b8e0a 100644
--- a/tools/test-js-optimizer-asm-regs-min-output.js
+++ b/tools/test-js-optimizer-asm-regs-min-output.js
@@ -33,4 +33,9 @@ function cl(b) {
a(c);
i1(b);
}
+function cl(b) {
+ b = b | 0;
+ b = b + 4;
+ a(b);
+}
diff --git a/tools/test-js-optimizer-asm-regs-min.js b/tools/test-js-optimizer-asm-regs-min.js
index a5b9427e..65d8d429 100644
--- a/tools/test-js-optimizer-asm-regs-min.js
+++ b/tools/test-js-optimizer-asm-regs-min.js
@@ -33,5 +33,10 @@ function collideLocal(i1) {
aGlobal(a); // multiple collisions, a and i1
bGlobal(i1);
}
+function collideLocal(i1) {
+ i1 = i1 | 0;
+ i1 = i1 + 4; // statement is of similar shape to a param coercion
+ aGlobal(i1);
+}
// EMSCRIPTEN_GENERATED_FUNCTIONS
// EXTRA_INFO: { "names": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "i1", "cl"], "globals": { "aGlobal": "a", "bGlobal": "i1", "collideLocal": "cl" } }
diff --git a/tools/test-js-optimizer-shiftsAggressive-output.js b/tools/test-js-optimizer-shiftsAggressive-output.js
new file mode 100644
index 00000000..5b429786
--- /dev/null
+++ b/tools/test-js-optimizer-shiftsAggressive-output.js
@@ -0,0 +1,11 @@
+function __ZNSt3__111__call_onceERVmPvPFvS2_E($flag, $arg, $func) {
+ $flag = $flag | 0;
+ $arg = $arg | 0;
+ $func = $func | 0;
+ var $2 = 0;
+ $2 = cheez();
+ whee1($flag + 1 | 0);
+ whee2($flag + 1 | 0);
+ whee3($flag + 1 | 0);
+}
+
diff --git a/tools/test-js-optimizer-shiftsAggressive.js b/tools/test-js-optimizer-shiftsAggressive.js
new file mode 100644
index 00000000..4218d04c
--- /dev/null
+++ b/tools/test-js-optimizer-shiftsAggressive.js
@@ -0,0 +1,13 @@
+function __ZNSt3__111__call_onceERVmPvPFvS2_E($flag,$arg,$func){
+ $flag=($flag)|0;
+ $arg=($arg)|0;
+ $func=($func)|0;
+ var $1=0,$2=0,$3=0;
+ $1;
+ $2 = cheez();
+ $3 = $flag + 1 | 0;
+ whee1($3);
+ whee2($3);
+ whee3($3);
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["__ZNSt3__111__call_onceERVmPvPFvS2_E"]