summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-01-15 17:01:19 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-01-15 17:01:19 -0800
commitc42b937808924f6b922b29d2e0fd1fe1d1b0411c (patch)
tree4027d435b6638a7e72b9519990298fb9314ecc96
parent8478d6aee54d6c52de16d8c58309534afbf5bf9e (diff)
parente5ccf17e84e7a5102bf9e05ffef01e6672b4c15a (diff)
Merge branch 'incoming'
-rw-r--r--AUTHORS4
-rw-r--r--ChangeLog35
-rwxr-xr-xemcc104
-rwxr-xr-xemscripten.py12
-rw-r--r--src/closure-externs.js110
-rw-r--r--src/intertyper.js2
-rw-r--r--src/jsifier.js15
-rw-r--r--src/library.js26
-rw-r--r--src/library_browser.js30
-rw-r--r--src/library_fs.js4
-rw-r--r--src/library_gl.js1549
-rw-r--r--src/library_glew.js135
-rw-r--r--src/library_glut.js4
-rw-r--r--src/library_sdl.js34
-rw-r--r--src/library_uuid.js140
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js26
-rw-r--r--src/postamble.js10
-rw-r--r--src/preamble.js3
-rw-r--r--src/relooper/Relooper.cpp74
-rw-r--r--src/relooper/Relooper.h17
-rw-r--r--src/relooper/fuzzer.py14
-rw-r--r--src/relooper/test.cpp28
-rw-r--r--src/relooper/test.txt49
-rw-r--r--src/settings.js3
-rw-r--r--src/struct_info.json12
-rw-r--r--system/include/GL/glew.h839
-rw-r--r--system/include/libcxx/__config22
-rw-r--r--system/include/libcxx/__undef_min_max6
-rw-r--r--system/include/libcxx/experimental/dynarray (renamed from system/include/libcxx/dynarray)13
-rw-r--r--system/include/libcxx/experimental/optional (renamed from system/include/libcxx/optional)20
-rw-r--r--system/include/libcxx/ext/__hash2
-rw-r--r--system/include/libcxx/iomanip4
-rw-r--r--system/include/libcxx/memory39
-rw-r--r--system/include/libcxx/new6
-rw-r--r--system/include/libcxx/readme.txt2
-rw-r--r--system/include/libcxx/support/ibm/support.h2
-rw-r--r--system/include/libcxx/support/win32/locale_win32.h2
-rw-r--r--system/include/libcxx/support/win32/support.h1
-rw-r--r--system/include/libcxx/type_traits4
-rw-r--r--system/include/libcxx/utility4
-rw-r--r--system/include/uuid/uuid.h35
-rw-r--r--system/lib/libc.symbols50
-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.txt5
-rw-r--r--system/lib/libc/musl/src/internal/floatscan.c496
-rw-r--r--system/lib/libc/musl/src/internal/floatscan.h8
-rw-r--r--system/lib/libc/musl/src/internal/intscan.c99
-rw-r--r--system/lib/libc/musl/src/internal/intscan.h8
-rw-r--r--system/lib/libc/musl/src/internal/libm.h169
-rw-r--r--system/lib/libc/musl/src/internal/shgetc.c27
-rw-r--r--system/lib/libc/musl/src/internal/shgetc.h9
-rw-r--r--system/lib/libc/musl/src/internal/stdio_impl.h6
-rw-r--r--system/lib/libc/musl/src/legacy/err.c67
-rw-r--r--system/lib/libc/musl/src/locale/strcasecmp_l.c7
-rw-r--r--system/lib/libc/musl/src/locale/strncasecmp_l.c7
-rw-r--r--system/lib/libc/musl/src/math/__cos.c71
-rw-r--r--system/lib/libc/musl/src/math/__cosdf.c35
-rw-r--r--system/lib/libc/musl/src/math/__sin.c64
-rw-r--r--system/lib/libc/musl/src/math/__sindf.c36
-rw-r--r--system/lib/libc/musl/src/math/ilogb.c26
-rw-r--r--system/lib/libc/musl/src/math/ilogbf.c26
-rw-r--r--system/lib/libc/musl/src/math/ilogbl.c55
-rw-r--r--system/lib/libc/musl/src/math/ldexp.c6
-rw-r--r--system/lib/libc/musl/src/math/ldexpf.c6
-rw-r--r--system/lib/libc/musl/src/math/ldexpl.c6
-rw-r--r--system/lib/libc/musl/src/math/lgamma.c9
-rw-r--r--system/lib/libc/musl/src/math/lgamma_r.c314
-rw-r--r--system/lib/libc/musl/src/math/lgammaf.c9
-rw-r--r--system/lib/libc/musl/src/math/lgammaf_r.c249
-rw-r--r--system/lib/libc/musl/src/math/lgammal.c386
-rw-r--r--system/lib/libc/musl/src/math/logb.c17
-rw-r--r--system/lib/libc/musl/src/math/logbf.c10
-rw-r--r--system/lib/libc/musl/src/math/logbl.c16
-rw-r--r--system/lib/libc/musl/src/math/scalbn.c31
-rw-r--r--system/lib/libc/musl/src/math/scalbnf.c31
-rw-r--r--system/lib/libc/musl/src/math/scalbnl.c36
-rw-r--r--system/lib/libc/musl/src/math/signgam.c4
-rw-r--r--system/lib/libc/musl/src/math/tgamma.c222
-rw-r--r--system/lib/libc/musl/src/math/tgammaf.c6
-rw-r--r--system/lib/libc/musl/src/math/tgammal.c275
-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/stdio/__overflow.c10
-rw-r--r--system/lib/libc/musl/src/stdio/__toread.c14
-rw-r--r--system/lib/libc/musl/src/stdio/__towrite.c18
-rw-r--r--system/lib/libc/musl/src/stdio/__uflow.c11
-rw-r--r--system/lib/libc/musl/src/stdio/fputwc.c53
-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/atof.c6
-rw-r--r--system/lib/libc/musl/src/stdlib/strtod.c52
-rw-r--r--system/lib/libc/musl/src/stdlib/wcstod.c64
-rw-r--r--system/lib/libc/musl/src/stdlib/wcstol.c82
-rw-r--r--system/lib/libc/musl/src/string/memccpy.c32
-rw-r--r--system/lib/libc/musl/src/string/memmem.c148
-rw-r--r--system/lib/libc/musl/src/string/mempcpy.c6
-rw-r--r--system/lib/libc/musl/src/string/memrchr.c12
-rw-r--r--system/lib/libc/musl/src/string/strcasestr.c9
-rw-r--r--system/lib/libc/musl/src/string/strchrnul.c27
-rw-r--r--system/lib/libc/musl/src/string/strlcat.c9
-rw-r--r--system/lib/libc/musl/src/string/strlcpy.c32
-rw-r--r--system/lib/libc/musl/src/string/strsep.c13
-rw-r--r--system/lib/libc/musl/src/string/strverscmp.c42
-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.symbols74
-rw-r--r--system/lib/libcxx/exception.cpp2
-rw-r--r--system/lib/libcxx/locale.cpp2
-rw-r--r--system/lib/libcxx/new.cpp2
-rw-r--r--system/lib/libcxx/optional.cpp6
-rw-r--r--system/lib/libcxx/random.cpp2
-rw-r--r--system/lib/libcxx/readme.txt2
-rw-r--r--system/lib/libcxx/support/win32/locale_win32.cpp10
-rw-r--r--system/lib/libcxx/symbols2
-rw-r--r--system/lib/libcxxabi/CREDITS.TXT28
-rw-r--r--system/lib/libcxxabi/LICENSE.TXT4
-rw-r--r--system/lib/libcxxabi/include/cxa_demangle.h167
-rw-r--r--system/lib/libcxxabi/include/libunwind.h486
-rw-r--r--system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h487
-rw-r--r--system/lib/libcxxabi/include/unwind.h217
-rwxr-xr-xsystem/lib/libcxxabi/lib/buildit6
-rw-r--r--system/lib/libcxxabi/readme.txt2
-rw-r--r--system/lib/libcxxabi/src/Unwind/AddressSpace.hpp430
-rw-r--r--system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp693
-rw-r--r--system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp888
-rw-r--r--system/lib/libcxxabi/src/Unwind/DwarfParser.hpp713
-rw-r--r--system/lib/libcxxabi/src/Unwind/Registers.hpp1568
-rw-r--r--system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c468
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp1063
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c268
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindLevel1.c495
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S329
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S301
-rw-r--r--system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp205
-rw-r--r--system/lib/libcxxabi/src/Unwind/assembly.h44
-rw-r--r--system/lib/libcxxabi/src/Unwind/config.h108
-rw-r--r--system/lib/libcxxabi/src/Unwind/dwarf2.h237
-rw-r--r--system/lib/libcxxabi/src/Unwind/libunwind.cpp353
-rw-r--r--system/lib/libcxxabi/src/Unwind/libunwind_ext.h38
-rw-r--r--system/lib/libcxxabi/src/Unwind/unwind_ext.h37
-rw-r--r--system/lib/libcxxabi/src/cxa_default_handlers.cpp120
-rw-r--r--system/lib/libcxxabi/src/cxa_demangle.cpp13415
-rw-r--r--system/lib/libcxxabi/src/cxa_exception.cpp2
-rw-r--r--system/lib/libcxxabi/src/cxa_exception.hpp18
-rw-r--r--system/lib/libcxxabi/src/cxa_new_delete.cpp36
-rw-r--r--system/lib/libcxxabi/src/private_typeinfo.cpp20
-rw-r--r--system/lib/libcxxabi/src/stdexcept.cpp16
-rw-r--r--system/lib/libcxxabi/symbols3
-rw-r--r--tests/cases/breakinthemiddle2.ll8
-rw-r--r--tests/cases/breakinthemiddle3.ll29
-rw-r--r--tests/cases/gepaddoverflow.ll37
-rw-r--r--tests/cases/gepaddoverflow.txt1
-rw-r--r--tests/cases/invokeundef.ll5
-rw-r--r--tests/cases/switch64_ta2.ll44
-rw-r--r--tests/cases/switch64_ta2.txt2
-rw-r--r--tests/cases/switch64b_ta2.ll54
-rw-r--r--tests/cases/switch64b_ta2.txt3
-rw-r--r--tests/core/test_literal_negative_zero.in27
-rw-r--r--tests/core/test_literal_negative_zero.out6
-rw-r--r--tests/core/test_wprintf.c63
-rw-r--r--tests/core/test_wprintf.out43
-rw-r--r--tests/doublestart.c23
-rw-r--r--tests/glew.c51
-rw-r--r--tests/math/lgamma.in105
-rw-r--r--tests/math/lgamma.out18
-rw-r--r--tests/openal_buffers.c4
-rwxr-xr-xtests/poppler/configure4
-rw-r--r--tests/poppler/configure.ac4
-rw-r--r--tests/printf/output.txt1
-rw-r--r--tests/printf/output_i64_1.txt1
-rw-r--r--tests/printf/test.c1
-rwxr-xr-xtests/runner.py5
-rw-r--r--tests/sdl_canvas.c2
-rw-r--r--tests/test_benchmark.py57
-rw-r--r--tests/test_browser.py65
-rw-r--r--tests/test_core.py63
-rw-r--r--tests/test_other.py51
-rw-r--r--tests/test_webgl_context_attributes_common.c6
-rw-r--r--tests/uuid/test.c69
-rw-r--r--tools/js-optimizer.js333
-rw-r--r--tools/js_optimizer.py33
-rwxr-xr-xtools/nativize_llvm.py2
-rw-r--r--tools/shared.py21
-rw-r--r--tools/test-js-optimizer-shiftsAggressive-output.js11
-rw-r--r--tools/test-js-optimizer-shiftsAggressive.js13
193 files changed, 20627 insertions, 12396 deletions
diff --git a/AUTHORS b/AUTHORS
index 6cf860ab..d47b3199 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -114,3 +114,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Vasilis Kalintiris <ehostunreach@gmail.com>
* Adam C. Clifton <adam@hulkamaniac.com>
* Volo Zyko <volo.zyko@gmail.com>
+* 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>
diff --git a/ChangeLog b/ChangeLog
index cab1d74a..8749f02f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,7 +10,40 @@ Not all changes are documented here. In particular, new features, user-oriented
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.7.8...incoming
+ https://github.com/kripken/emscripten/compare/1.8.2...incoming
+
+v1.8.2: 1/4/2013
+------------------
+ - 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
+------------------
+ - Added support for WebGL hardware instancing extension.
+ - Improved fastcomp native LLVM backend support.
+ - Added support for #include filename.js to JS libraries.
+ - Deprecated --compression emcc command line parameter that manually compressed output JS files, due to performance issues. Instead, it is best to rely on the web server to serve compressed JS files.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.8.0...1.8.1
+
+v1.8.0: 12/28/2013
+------------------
+ - Fix two issues with function outliner and relooper.
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.7.9...1.8.0
+
+v1.7.9: 12/27/2013
+------------------
+ - Added new command line parameter --em-config that allows specifying a custom location for the .emscripten configuration file.
+ - Reintroduced relaxed asm.js heap sizes, which no longer need to be power of 2, but a multiple of 16MB is sufficient.
+ - Added emrun command line tool that allows launching .html pages from command line on desktop and Android as if they were native applications. See https://groups.google.com/forum/#!topic/emscripten-discuss/t2juu3q1H8E . Adds --emrun compiler link flag.
+ - Began initial work on the "fastcomp" compiler toolchain, a rewrite of the previous JS LLVM AST parsing and codegen via a native LLVM backend.
+ - Added --exclude-file command line flag to emcc and a matching --exclude command line flag to file packager, which allows specifying files and directories that should be excluded while packaging a VFS data blob.
+ - Improved GLES2 and EGL support libraries to be more spec-conformant.
+ - Optimized legacy GL emulation code path. Added new GL_FFP_ONLY optimization path to fixed function pipeline emulation.
+ - Added new core functions emscripten_log() and emscripten_get_callstack() that allow printing out log messages with demangled and source-mapped callstack information.
+ - Improved BSD Sockets support. Implemented getprotobyname() for BSD Sockets library.
+ - Fixed issues with simd support.
+ - Various bugfixes: #1573, #1846, #1886, #1908, #1918, #1930, #1931, #1942, #1948, ..
+ - Full list of changes: https://github.com/kripken/emscripten/compare/1.7.8...1.7.9
v1.7.8: 11/19/2013
------------------
diff --git a/emcc b/emcc
index 621cb340..f425ff4d 100755
--- a/emcc
+++ b/emcc
@@ -687,7 +687,7 @@ if os.environ.get('EMMAKEN_CXX'):
CC_ADDITIONAL_ARGS = shared.COMPILER_OPTS
EMMAKEN_CFLAGS = os.environ.get('EMMAKEN_CFLAGS')
-if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += shlex.split(EMMAKEN_CFLAGS)
+if EMMAKEN_CFLAGS: sys.argv += shlex.split(EMMAKEN_CFLAGS)
# ---------------- Utilities ---------------
@@ -1194,9 +1194,6 @@ try:
if fastcomp:
shared.Settings.ASM_JS = 1
- if shared.Settings.DISABLE_EXCEPTION_CATCHING == 0:
- logging.warning('disabling exception catching since not supported in fastcomp yet')
- shared.Settings.DISABLE_EXCEPTION_CATCHING = 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'
@@ -1210,11 +1207,16 @@ try:
assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp'
assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp'
assert shared.Settings.TARGET_LE32 == 1, 'fastcomp requires le32'
+ assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2'
assert not bind, 'embind not supported in fastcomp yet'
if jcache:
logging.warning('jcache is not supported in fastcomp (you should not need it anyhow), disabling')
jcache = False
+ fastcomp_opts = ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt']
+ if not shared.Settings.DISABLE_EXCEPTION_CATCHING:
+ fastcomp_opts += ['-enable-emscripten-cxx-exceptions']
+
if shared.Settings.ASM_JS:
assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above'
@@ -1438,18 +1440,26 @@ 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'),
- os.path.join('libc', 'stdlib', 'strtod.c'),
]
musl_files = [
+ ['internal', [
+ 'floatscan.c',
+ 'shgetc.c',
+ ]],
+ ['math', [
+ 'scalbn.c',
+ 'scalbnl.c',
+ ]],
+ ['stdio', [
+ '__overflow.c',
+ '__toread.c',
+ '__towrite.c',
+ '__uflow.c',
+ ]],
+ ['stdlib', [
+ 'atof.c',
+ 'strtod.c',
+ ]]
]
for directory, sources in musl_files:
libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources]
@@ -1490,6 +1500,12 @@ try:
'wctrans.c',
'wcwidth.c',
]],
+ ['internal', [
+ 'intscan.c',
+ ]],
+ ['legacy', [
+ 'err.c',
+ ]],
['locale', [
'iconv.c',
'iswalnum_l.c',
@@ -1505,7 +1521,9 @@ try:
'iswspace_l.c',
'iswupper_l.c',
'iswxdigit_l.c',
+ 'strcasecmp_l.c',
'strfmon.c',
+ 'strncasecmp_l.c',
'strxfrm.c',
'towctrans_l.c',
'towlower_l.c',
@@ -1517,6 +1535,35 @@ try:
'wctrans_l.c',
'wctype_l.c',
]],
+ ['math', [
+ '__cos.c',
+ '__cosdf.c',
+ '__sin.c',
+ '__sindf.c',
+ 'ilogb.c',
+ 'ilogbf.c',
+ 'ilogbl.c',
+ 'ldexp.c',
+ 'ldexpf.c',
+ 'ldexpl.c',
+ 'logb.c',
+ 'logbf.c',
+ 'logbl.c',
+ 'lgamma.c',
+ 'lgamma_r.c',
+ 'lgammaf.c',
+ 'lgammaf_r.c',
+ 'lgammal.c',
+ 'scalbnf.c',
+ 'signgam.c',
+ 'tgamma.c',
+ 'tgammaf.c',
+ 'tgammal.c'
+ ]],
+ ['misc', [
+ 'getopt.c',
+ 'getopt_long.c',
+ ]],
['multibyte', [
'btowc.c',
'mblen.c',
@@ -1547,13 +1594,27 @@ try:
'vswprintf.c',
'vwprintf.c',
'wprintf.c',
+ 'fputwc.c',
+ 'fputws.c',
]],
['stdlib', [
'ecvt.c',
'fcvt.c',
'gcvt.c',
+ 'wcstod.c',
+ 'wcstol.c',
]],
['string', [
+ 'memccpy.c',
+ 'memmem.c',
+ 'mempcpy.c',
+ 'memrchr.c',
+ 'strcasestr.c',
+ 'strchrnul.c',
+ 'strlcat.c',
+ 'strlcpy.c',
+ 'strsep.c',
+ 'strverscmp.c',
'wcpcpy.c',
'wcpncpy.c',
'wcscasecmp.c',
@@ -1743,7 +1804,6 @@ try:
# At minimum remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it)
link_opts += shared.Building.get_safe_internalize() + ['-globaldce']
-
if (not save_bc and not fastcomp) or AUTODEBUG:
# let llvm opt directly emit ll, to skip writing and reading all the bitcode
link_opts += ['-S']
@@ -1753,13 +1813,13 @@ try:
else:
if fastcomp and not save_bc:
# Simplify LLVM bitcode for fastcomp
- link_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt']
+ link_opts += fastcomp_opts
shared.Building.llvm_opt(final, link_opts)
if DEBUG: save_intermediate('linktime', 'bc')
if save_bc:
shutil.copyfile(final, save_bc)
if fastcomp:
- shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc')
+ shared.Building.llvm_opt(final, fastcomp_opts, final + '.adsimp.bc')
final += '.adsimp.bc'
if DEBUG: save_intermediate('adsimp', 'bc')
@@ -1779,7 +1839,7 @@ try:
# Simplify bitcode after autodebug
if fastcomp and (AUTODEBUG or LEAVE_INPUTS_RAW):
- shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc')
+ shared.Building.llvm_opt(final, fastcomp_opts, final + '.adsimp.bc')
final += '.adsimp.bc'
if DEBUG: save_intermediate('adsimp', 'bc')
@@ -1915,6 +1975,9 @@ try:
js_optimizer_queue += [get_eliminate()]
+ if shared.Settings.AGGRESSIVE_VARIABLE_ELIMINATION:
+ js_optimizer_queue += ['aggressiveVariableElimination']
+
if opt_level >= 2:
js_optimizer_queue += ['simplifyExpressions']
@@ -1973,6 +2036,11 @@ try:
if debug_level >= 4:
generate_source_map(target)
shutil.move(final, js_target)
+ # TODO: use an async blob, which would allow code rewriting on the client:
+ # var blob = new Blob([codeString]);
+ # var script = document.createElement('script');
+ # script.src = URL.createObjectURL(blob);
+ # document.body.appendChild(script);
script_tag = '''<script async type="text/javascript" src="%s"></script>''' % base_js_target
html.write(shell.replace('{{{ SCRIPT }}}', script_tag))
else:
diff --git a/emscripten.py b/emscripten.py
index 42db0803..befad8d5 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -804,6 +804,9 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
map(lambda x: x[1:], metadata['implementedFunctions'])
)
) + map(lambda x: x[1:], metadata['externs'])
+ if metadata['simd']:
+ settings['SIMD'] = 1
+ settings['ASM_JS'] = 2
# Save settings to a file to work around v8 issue 1579
settings_file = temp_files.get('.txt').name
@@ -869,6 +872,11 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
for key in metadata['implementedFunctions'] + forwarded_json['Functions']['implementedFunctions'].keys(): # XXX perf
if key in all_exported_functions or export_all or (export_bindings and key.startswith('_emscripten_bind')):
exported_implemented_functions.add(key)
+ implemented_functions = set(metadata['implementedFunctions'])
+
+ # Add named globals
+ named_globals = '\n'.join(['var %s = %s;' % (k, v) for k, v in metadata['namedGlobals'].iteritems()])
+ pre = pre.replace('// === Body ===', '// === Body ===\n' + named_globals + '\n')
#if DEBUG: outfile.write('// pre\n')
outfile.write(pre)
@@ -918,7 +926,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
Counter.j += 1
newline = Counter.j % 30 == 29
if item == '0': return bad if not newline else (bad + '\n')
- if item not in metadata['implementedFunctions']:
+ if item not in implemented_functions:
# this is imported into asm, we must wrap it
call_ident = item
if call_ident in metadata['redirects']: call_ident = metadata['redirects'][call_ident]
@@ -1018,7 +1026,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
pass
# If no named globals, only need externals
global_vars = metadata['externs'] #+ forwarded_json['Variables']['globals']
- global_funcs = list(set(['_' + key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2]).difference(set(global_vars)).difference(set(metadata['implementedFunctions'])))
+ global_funcs = list(set(['_' + key for key, value in forwarded_json['Functions']['libraryFunctions'].iteritems() if value != 2]).difference(set(global_vars)).difference(implemented_functions))
def math_fix(g):
return g if not g.startswith('Math_') else g.split('_')[1]
asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global.' + g + ';\n' for g in maths]) + \
diff --git a/src/closure-externs.js b/src/closure-externs.js
new file mode 100644
index 00000000..a82aa669
--- /dev/null
+++ b/src/closure-externs.js
@@ -0,0 +1,110 @@
+/**
+ * This file contains definitions for things that we'd really rather the closure compiler *didn't* minify.
+ * See http://code.google.com/p/closure-compiler/wiki/FAQ#How_do_I_write_an_externs_file
+ * See also the discussion here: https://github.com/kripken/emscripten/issues/1979
+ *
+ * The closure_compiler() method in tools/shared.py refers to this file when calling closure.
+ */
+
+// Closure externs used by library_uuid.js
+
+/**
+ * @param {Array} typedArray
+ */
+crypto.getRandomValues = function(typedArray) {};
+
+/**
+ BEGIN_NODE_INCLUDE
+ var crypto = require('crypto');
+ END_NODE_INCLUDE
+ */
+
+/**
+ * @type {Object.<string,*>}
+ */
+var crypto = {};
+
+/**
+ * @param {number} size
+ * @param {function(Error, buffer.Buffer)} callback
+ */
+crypto.randomBytes = function(size, callback) {};
+
+
+// Closure externs used by library_sockfs.js
+
+/**
+ BEGIN_NODE_INCLUDE
+ var ws = require('ws');
+ END_NODE_INCLUDE
+ */
+
+/**
+ * @type {Object.<string,*>}
+ */
+var ws = {};
+
+/**
+ * @param {string} event
+ * @param {function()} callback
+ */
+ws.on = function(event, callback) {};
+
+/**
+ * @param {Object} data
+ * @param {Object} flags
+ * @param {function()=} callback
+ */
+ws.send = function(data, flags, callback) {};
+
+/**
+* @type {boolean}
+*/
+ws.binaryType;
+
+/**
+ * @type {Object.<string,*>}
+ */
+var wss = ws.Server;
+
+/**
+ * @param {string} event
+ * @param {function()} callback
+ */
+wss.on = function(event, callback) {};
+
+/**
+ * @param {function()} callback
+ */
+wss.broadcast = function(callback) {};
+
+/**
+* @type {Object.<string,*>}
+*/
+wss._socket;
+
+/**
+* @type {string}
+*/
+wss.url;
+
+/**
+* @type {string}
+*/
+wss._socket.remoteAddress;
+
+/**
+* @type {number}
+*/
+wss._socket.remotePort;
+
+/**
+* @type {Object.<string,*>}
+*/
+var flags = {};
+/**
+* @type {boolean}
+*/
+flags.binary;
+
+
diff --git a/src/intertyper.js b/src/intertyper.js
index b34d0c08..10822e48 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -241,7 +241,7 @@ function intertyper(lines, sidePass, baseLineNums) {
if (mainPass && /^}.*/.test(line)) {
inFunction = false;
if (mainPass) {
- var func = funcHeaderHandler({ tokens: tokenize(currFunctionLines[0], currFunctionLineNum) });
+ var func = funcHeaderHandler({ tokens: tokenize(currFunctionLines[0]) });
if (SKIP_STACK_IN_SMALL && /emscripten_autodebug/.exec(func.ident)) {
warnOnce('Disabling SKIP_STACK_IN_SMALL because we are apparently processing autodebugger data');
diff --git a/src/jsifier.js b/src/jsifier.js
index 58dc4653..726a5eda 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -18,7 +18,7 @@ var INDENTATION = ' ';
var functionStubSigs = {};
// JSifier
-function JSify(data, functionsOnly, givenFunctions) {
+function JSify(data, functionsOnly) {
//B.start('jsifier');
var mainPass = !functionsOnly;
@@ -109,7 +109,7 @@ function JSify(data, functionsOnly, givenFunctions) {
dprint('unparsedFunctions','====================\n// Processing function batch of ' + currBaseLineNums.length +
' functions, ' + currFuncLines.length + ' lines, functions left: ' + data.unparsedFunctions.length);
if (DEBUG_MEMORY) MemoryDebugger.tick('pre-func');
- JSify(analyzer(intertyper(currFuncLines, true, currBaseLineNums), true), true, Functions);
+ JSify(analyzer(intertyper(currFuncLines, true, currBaseLineNums), true), true);
if (DEBUG_MEMORY) MemoryDebugger.tick('post-func');
}
currFuncLines = currBaseLineNums = null; // Do not hold on to anything from inside that loop (JS function scoping..)
@@ -215,6 +215,9 @@ function JSify(data, functionsOnly, givenFunctions) {
function parseConst(value, type, ident) {
var constant = makeConst(value, type);
+ // Sadly, we've thrown away type information in makeConst, so we're not
+ // passing correct type info to parseNumerical which works around this
+ // lack.
constant = flatten(constant).map(function(x) { return parseNumerical(x) })
return constant;
}
@@ -625,8 +628,8 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
- if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
if (!ASM_JS) {
+ if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
func.JS += INDENTATION + 'var label=0;\n';
}
@@ -878,8 +881,8 @@ function JSify(data, functionsOnly, givenFunctions) {
function makeAssign(item) {
var valueJS = item.JS;
item.JS = '';
- if (CLOSURE_ANNOTATIONS) item.JS += '/** @type {number} */ ';
if (!ASM_JS || item.intertype != 'alloca' || item.funcData.variables[item.assignTo].impl == VAR_EMULATED) { // asm only needs non-allocas
+ if (CLOSURE_ANNOTATIONS) item.JS += '/** @type {number} */ ';
item.JS += ((ASM_JS || item.overrideSSA) ? '' : 'var ') + toNiceIdent(item.assignTo);
}
var value = parseNumerical(valueJS);
@@ -1796,7 +1799,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
});
}
- JSify(globalsData, true, Functions);
+ JSify(globalsData, true);
globalsData = null;
data.unparsedGlobalss = null;
@@ -1871,7 +1874,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included');
print('var i64Math = null;');
}
- if (Types.usesSIMD) {
+ if (Types.usesSIMD || SIMD) {
print(read('simd.js'));
}
diff --git a/src/library.js b/src/library.js
index 354e5549..69569601 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1950,9 +1950,9 @@ LibraryManager.library = {
}
// Handle precision.
- var precisionSet = false;
+ var precisionSet = false, precision = -1;
if (next == {{{ charCode('.') }}}) {
- var precision = 0;
+ precision = 0;
precisionSet = true;
textIndex++;
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
@@ -1969,8 +1969,10 @@ LibraryManager.library = {
}
}
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
- } else {
- var precision = 6; // Standard default.
+ }
+ if (precision === -1) {
+ precision = 6; // Standard default.
+ precisionSet = false;
}
// Handle integer sizes. WARNING: These assume a 32-bit architecture!
@@ -4455,6 +4457,7 @@ LibraryManager.library = {
terminate: '__cxa_call_unexpected',
+ __gxx_personality_v0__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'],
__gxx_personality_v0: function() {
},
@@ -4827,15 +4830,6 @@ LibraryManager.library = {
llvm_log_f64: 'Math_log',
llvm_exp_f32: 'Math_exp',
llvm_exp_f64: 'Math_exp',
- ldexp: function(x, exp_) {
- return x * Math.pow(2, exp_);
- },
- ldexpf: 'ldexp',
- scalb: 'ldexp',
- scalbn: 'ldexp',
- scalbnf: 'ldexp',
- scalbln: 'ldexp',
- scalblnf: 'ldexp',
cbrt: function(x) {
return Math.pow(x, 1/3);
},
@@ -9178,6 +9172,10 @@ LibraryManager.library = {
tempRet0 = 0;
return (high >>> (bits - 32))|0;
},
+
+ // misc shims for musl
+ __lockfile: function() { return 1 },
+ __unlockfile: function(){},
};
function autoAddDeps(object, name) {
@@ -9190,7 +9188,7 @@ function autoAddDeps(object, name) {
}
// Add aborting stubs for various libc stuff needed by libc++
-['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose', 'fputwc', '__lockfile', '__unlockfile'].forEach(function(aborter) {
+['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose'].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 b368c6ac..458a8dd2 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -319,7 +319,7 @@ mergeInto(LibraryManager.library, {
}, false);
}
if (setInModule) {
- Module.ctx = ctx;
+ GLctx = Module.ctx = ctx;
Module.useWebGL = useWebGL;
Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
Browser.init();
@@ -478,19 +478,30 @@ mergeInto(LibraryManager.library, {
// in the coordinates.
var rect = Module["canvas"].getBoundingClientRect();
var x, y;
+
+ // Neither .scrollX or .pageXOffset are defined in a spec, but
+ // we prefer .scrollX because it is currently in a spec draft.
+ // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+ var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+ var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+#if ASSERTIONS
+ // If this assert lands, it's likely because the browser doesn't support scrollX or pageXOffset
+ // and we have no viable fallback.
+ assert((typeof scrollX !== 'undefined') && (typeof scrollY !== 'undefined'), 'Unable to retrieve scroll position, mouse positions likely broken.');
+#endif
if (event.type == 'touchstart' ||
event.type == 'touchend' ||
event.type == 'touchmove') {
var t = event.touches.item(0);
if (t) {
- x = t.pageX - (window.scrollX + rect.left);
- y = t.pageY - (window.scrollY + rect.top);
+ x = t.pageX - (scrollX + rect.left);
+ y = t.pageY - (scrollY + rect.top);
} else {
return;
}
} else {
- x = event.pageX - (window.scrollX + rect.left);
- y = event.pageY - (window.scrollY + rect.top);
+ x = event.pageX - (scrollX + rect.left);
+ y = event.pageY - (scrollY + rect.top);
}
// the canvas might be CSS-scaled compared to its backbuffer;
@@ -764,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_fs.js b/src/library_fs.js
index 1e7856aa..e6b060f6 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -1102,7 +1102,9 @@ mergeInto(LibraryManager.library, {
}
}
this.message = ERRNO_MESSAGES[errno];
- this.stack = stackTrace();
+#if ASSERTIONS
+ if (this.stack) this.stack = demangleAll(this.stack);
+#endif
};
FS.ErrnoError.prototype = new Error();
FS.ErrnoError.prototype.constructor = FS.ErrnoError;
diff --git a/src/library_gl.js b/src/library_gl.js
index 075d7cb5..61ca8957 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -4,7 +4,7 @@
*/
var LibraryGL = {
- $GL__postset: 'GL.init()',
+ $GL__postset: 'var GLctx; GL.init()',
$GL: {
#if GL_DEBUG
debug: true,
@@ -22,9 +22,13 @@ var LibraryGL = {
#if FULL_ES2
clientBuffers: [],
+ currArrayBuffer: 0,
+ currElementArrayBuffer: 0,
#endif
+#if LEGACY_GL_EMULATION
currArrayBuffer: 0,
currElementArrayBuffer: 0,
+#endif
byteSizeByTypeRoot: 0x1400, // GL_BYTE
byteSizeByType: [
@@ -53,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);
},
@@ -77,42 +82,64 @@ 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] = Module.ctx.createBuffer();
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.tempVertexBuffers[curr]);
- Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW);
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null);
- GL.tempIndexBuffers[curr] = Module.ctx.createBuffer();
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[curr]);
- Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, size, Module.ctx.DYNAMIC_DRAW);
- Module.ctx.bindBuffer(Module.ctx.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) {
// GL_QUAD indexes can be precalculated
- GL.tempQuadIndexBuffer = Module.ctx.createBuffer();
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer);
+ GL.tempQuadIndexBuffer = GLctx.createBuffer();
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer);
var numIndexes = GL.MAX_TEMP_BUFFER_SIZE >> 1;
var quadIndexes = new Uint16Array(numIndexes);
var i = 0, v = 0;
@@ -131,8 +158,55 @@ var LibraryGL = {
if (i >= numIndexes) break;
v += 4;
}
- Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER, quadIndexes, Module.ctx.STATIC_DRAW);
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null);
+ GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, quadIndexes, GLctx.STATIC_DRAW);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, null);
+ }
+ },
+
+ 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;
}
},
@@ -182,13 +256,13 @@ var LibraryGL = {
source += frag;
}
// Let's see if we need to enable the standard derivatives extension
- type = Module.ctx.getShaderParameter(GL.shaders[shader], 0x8B4F /* GL_SHADER_TYPE */);
+ type = GLctx.getShaderParameter(GL.shaders[shader], 0x8B4F /* GL_SHADER_TYPE */);
if (type == 0x8B30 /* GL_FRAGMENT_SHADER */) {
if (GL.findToken(source, "dFdx") ||
GL.findToken(source, "dFdy") ||
GL.findToken(source, "fwidth")) {
source = "#extension GL_OES_standard_derivatives : enable\n" + source;
- var extension = Module.ctx.getExtension("OES_standard_derivatives");
+ var extension = GLctx.getExtension("OES_standard_derivatives");
#if GL_DEBUG
if (!extension) {
Module.printErr("Shader attempts to use the standard derivatives extension which is not available.");
@@ -240,7 +314,7 @@ var LibraryGL = {
case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS
// WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be queried for length),
// so implement it ourselves to allow C++ GLES2 code get the length.
- var formats = Module.ctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/);
+ var formats = GLctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/);
ret = formats.length;
break;
case 0x8B9A: // GL_IMPLEMENTATION_COLOR_READ_TYPE
@@ -252,7 +326,7 @@ var LibraryGL = {
}
if (ret === undefined) {
- var result = Module.ctx.getParameter(name_);
+ var result = GLctx.getParameter(name_);
switch (typeof(result)) {
case "number":
ret = result;
@@ -391,7 +465,7 @@ var LibraryGL = {
default:
throw 'Invalid format (' + format + ')';
}
- internalFormat = Module.ctx.RGBA;
+ internalFormat = GLctx.RGBA;
break;
default:
throw 'Invalid type (' + type + ')';
@@ -417,13 +491,13 @@ var LibraryGL = {
enableVertexAttribArray: function enableVertexAttribArray(index) {
if (!GL.enabledClientAttribIndices[index]) {
GL.enabledClientAttribIndices[index] = true;
- Module.ctx.enableVertexAttribArray(index);
+ GLctx.enableVertexAttribArray(index);
}
},
disableVertexAttribArray: function disableVertexAttribArray(index) {
if (GL.enabledClientAttribIndices[index]) {
GL.enabledClientAttribIndices[index] = false;
- Module.ctx.disableVertexAttribArray(index);
+ GLctx.disableVertexAttribArray(index);
}
},
#endif
@@ -442,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];
@@ -453,29 +524,21 @@ 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);
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf);
- Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER,
+ var buf = GL.getTempVertexBuffer(size);
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, buf);
+ GLctx.bufferSubData(GLctx.ARRAY_BUFFER,
0,
HEAPU8.subarray(cb.ptr, cb.ptr + size));
#if GL_ASSERTIONS
GL.validateVertexAttribPointer(cb.size, cb.type, cb.stride, 0);
#endif
- Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0);
+ GLctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0);
}
},
postDrawHandleClientVertexAttribBindings: function postDrawHandleClientVertexAttribBindings() {
if (GL.resetBufferBinding) {
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]);
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]);
}
},
#endif
@@ -544,7 +607,7 @@ var LibraryGL = {
GL.miniTempBufferViews[i] = GL.miniTempBuffer.subarray(0, i+1);
}
- GL.maxVertexAttribs = Module.ctx.getParameter(Module.ctx.MAX_VERTEX_ATTRIBS);
+ GL.maxVertexAttribs = GLctx.getParameter(GLctx.MAX_VERTEX_ATTRIBS);
#if FULL_ES2
for (var i = 0; i < GL.maxVertexAttribs; i++) {
GL.clientBuffers[i] = { enabled: false, clientside: false, size: 0, type: 0, normalized: 0, stride: 0, ptr: 0 };
@@ -554,18 +617,18 @@ var LibraryGL = {
#endif
// Detect the presence of a few extensions manually, this GL interop layer itself will need to know if they exist.
- GL.compressionExt = Module.ctx.getExtension('WEBGL_compressed_texture_s3tc') ||
- Module.ctx.getExtension('MOZ_WEBGL_compressed_texture_s3tc') ||
- Module.ctx.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
+ GL.compressionExt = GLctx.getExtension('WEBGL_compressed_texture_s3tc') ||
+ GLctx.getExtension('MOZ_WEBGL_compressed_texture_s3tc') ||
+ GLctx.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
- GL.anisotropicExt = Module.ctx.getExtension('EXT_texture_filter_anisotropic') ||
- Module.ctx.getExtension('MOZ_EXT_texture_filter_anisotropic') ||
- Module.ctx.getExtension('WEBKIT_EXT_texture_filter_anisotropic');
+ GL.anisotropicExt = GLctx.getExtension('EXT_texture_filter_anisotropic') ||
+ GLctx.getExtension('MOZ_EXT_texture_filter_anisotropic') ||
+ GLctx.getExtension('WEBKIT_EXT_texture_filter_anisotropic');
- GL.floatExt = Module.ctx.getExtension('OES_texture_float');
+ GL.floatExt = GLctx.getExtension('OES_texture_float');
// Extension available from Firefox 26 and Google Chrome 30
- GL.instancedArraysExt = Module.ctx.getExtension('ANGLE_instanced_arrays');
+ GL.instancedArraysExt = GLctx.getExtension('ANGLE_instanced_arrays');
// These are the 'safe' feature-enabling extensions that don't add any performance impact related to e.g. debugging, and
// should be enabled by default so that client GLES2/GL code will not need to go through extra hoops to get its stuff working.
@@ -589,11 +652,11 @@ var LibraryGL = {
return false;
}
- var extensions = Module.ctx.getSupportedExtensions();
+ var extensions = GLctx.getSupportedExtensions();
for(var e in extensions) {
var ext = extensions[e].replace('MOZ_', '').replace('WEBKIT_', '');
if (automaticallyEnabledExtensions.indexOf(ext) != -1) {
- Module.ctx.getExtension(ext); // Calling .getExtension enables that extension permanently, no need to store the return value to be enabled.
+ GLctx.getExtension(ext); // Calling .getExtension enables that extension permanently, no need to store the return value to be enabled.
}
}
},
@@ -620,9 +683,9 @@ var LibraryGL = {
var utable = ptable.uniforms;
// A program's uniform table maps the string name of an uniform to an integer location of that uniform.
// The global GL.uniforms map maps integer locations to WebGLUniformLocations.
- var numUniforms = Module.ctx.getProgramParameter(p, Module.ctx.ACTIVE_UNIFORMS);
+ var numUniforms = GLctx.getProgramParameter(p, GLctx.ACTIVE_UNIFORMS);
for (var i = 0; i < numUniforms; ++i) {
- var u = Module.ctx.getActiveUniform(p, i);
+ var u = GLctx.getActiveUniform(p, i);
var name = u.name;
ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1);
@@ -636,14 +699,14 @@ var LibraryGL = {
// Optimize memory usage slightly: If we have an array of uniforms, e.g. 'vec3 colors[3];', then
// only store the string 'colors' in utable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i.
// Note that for the GL.uniforms table, we still need to fetch the all WebGLUniformLocations for all the indices.
- var loc = Module.ctx.getUniformLocation(p, name);
+ var loc = GLctx.getUniformLocation(p, name);
var id = GL.getNewId(GL.uniforms);
utable[name] = [u.size, id];
GL.uniforms[id] = loc;
for (var j = 1; j < u.size; ++j) {
var n = name + '['+j+']';
- loc = Module.ctx.getUniformLocation(p, n);
+ loc = GLctx.getUniformLocation(p, n);
id = GL.getNewId(GL.uniforms);
GL.uniforms[id] = loc;
@@ -659,7 +722,7 @@ var LibraryGL = {
} else if (pname == 0x0cf5 /* GL_UNPACK_ALIGNMENT */) {
GL.unpackAlignment = param;
}
- Module.ctx.pixelStorei(pname, param);
+ GLctx.pixelStorei(pname, param);
},
glGetString__sig: 'ii',
@@ -670,10 +733,10 @@ var LibraryGL = {
case 0x1F00 /* GL_VENDOR */:
case 0x1F01 /* GL_RENDERER */:
case 0x1F02 /* GL_VERSION */:
- ret = allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
+ ret = allocate(intArrayFromString(GLctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
break;
case 0x1F03 /* GL_EXTENSIONS */:
- var exts = Module.ctx.getSupportedExtensions();
+ var exts = GLctx.getSupportedExtensions();
var gl_exts = [];
for (i in exts) {
gl_exts.push(exts[i]);
@@ -714,7 +777,7 @@ var LibraryGL = {
glGenTextures: function(n, textures) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.textures);
- var texture = Module.ctx.createTexture();
+ var texture = GLctx.createTexture();
texture.name = id;
GL.textures[id] = texture;
{{{ makeSetValue('textures', 'i*4', 'id', 'i32') }}};
@@ -726,7 +789,7 @@ var LibraryGL = {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}};
var texture = GL.textures[id];
- Module.ctx.deleteTexture(texture);
+ GLctx.deleteTexture(texture);
texture.name = 0;
GL.textures[id] = null;
}
@@ -742,7 +805,8 @@ var LibraryGL = {
} else {
data = null;
}
- Module.ctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, data);
+ // N.b. using array notation explicitly to not confuse Closure minification.
+ GLctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, data);
},
glCompressedTexSubImage2D__sig: 'viiiiiiiii',
@@ -755,7 +819,7 @@ var LibraryGL = {
} else {
data = null;
}
- Module.ctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, data);
+ CLctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, data);
},
glTexImage2D__sig: 'viiiiiiiii',
@@ -767,7 +831,7 @@ var LibraryGL = {
} else {
pixels = null;
}
- Module.ctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels);
+ GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels);
},
glTexSubImage2D__sig: 'viiiiiiiii',
@@ -778,7 +842,7 @@ var LibraryGL = {
} else {
pixels = null;
}
- Module.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+ GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
},
glReadPixels__sig: 'viiiiiii',
@@ -802,7 +866,7 @@ var LibraryGL = {
return;
}
var totalSize = width*height*sizePerPixel;
- Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize));
+ GLctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels, pixels + totalSize));
},
glBindTexture__sig: 'vii',
@@ -810,7 +874,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.textures, texture, 'glBindTexture', 'texture');
#endif
- Module.ctx.bindTexture(target, texture ? GL.textures[texture] : null);
+ GLctx.bindTexture(target, texture ? GL.textures[texture] : null);
},
glGetTexParameterfv__sig: 'viii',
@@ -826,27 +890,27 @@ var LibraryGL = {
glTexParameterfv__sig: 'viii',
glTexParameterfv: function(target, pname, params) {
var param = {{{ makeGetValue('params', '0', 'float') }}};
- Module.ctx.texParameterf(target, pname, param);
+ GLctx.texParameterf(target, pname, param);
},
glTexParameteriv__sig: 'viii',
glTexParameteriv: function(target, pname, params) {
var param = {{{ makeGetValue('params', '0', 'i32') }}};
- Module.ctx.texParameteri(target, pname, param);
+ GLctx.texParameteri(target, pname, param);
},
glIsTexture__sig: 'ii',
glIsTexture: function(texture) {
var texture = GL.textures[texture];
if (!texture) return 0;
- return Module.ctx.isTexture(texture);
+ return GLctx.isTexture(texture);
},
glGenBuffers__sig: 'vii',
glGenBuffers: function(n, buffers) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.buffers);
- var buffer = Module.ctx.createBuffer();
+ var buffer = GLctx.createBuffer();
buffer.name = id;
GL.buffers[id] = buffer;
{{{ makeSetValue('buffers', 'i*4', 'id', 'i32') }}};
@@ -863,7 +927,7 @@ var LibraryGL = {
// correspond to existing buffer objects."
if (!buffer) continue;
- Module.ctx.deleteBuffer(buffer);
+ GLctx.deleteBuffer(buffer);
buffer.name = 0;
GL.buffers[id] = null;
@@ -874,7 +938,7 @@ var LibraryGL = {
glGetBufferParameteriv__sig: 'viii',
glGetBufferParameteriv: function(target, value, data) {
- {{{ makeSetValue('data', '0', 'Module.ctx.getBufferParameter(target, value)', 'i32') }}};
+ {{{ makeSetValue('data', '0', 'GLctx.getBufferParameter(target, value)', 'i32') }}};
},
glBufferData__sig: 'viiii',
@@ -893,26 +957,26 @@ var LibraryGL = {
usage = 0x88E8; // GL_DYNAMIC_DRAW
break;
}
- Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage);
+ GLctx.bufferData(target, HEAPU8.subarray(data, data+size), usage);
},
glBufferSubData__sig: 'viiii',
glBufferSubData: function(target, offset, size, data) {
- Module.ctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size));
+ GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size));
},
glIsBuffer__sig: 'ii',
glIsBuffer: function(buffer) {
var b = GL.buffers[buffer];
if (!b) return 0;
- return Module.ctx.isBuffer(b);
+ return GLctx.isBuffer(b);
},
glGenRenderbuffers__sig: 'vii',
glGenRenderbuffers: function(n, renderbuffers) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.renderbuffers);
- var renderbuffer = Module.ctx.createRenderbuffer();
+ var renderbuffer = GLctx.createRenderbuffer();
renderbuffer.name = id;
GL.renderbuffers[id] = renderbuffer;
{{{ makeSetValue('renderbuffers', 'i*4', 'id', 'i32') }}};
@@ -924,7 +988,7 @@ var LibraryGL = {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}};
var renderbuffer = GL.renderbuffers[id];
- Module.ctx.deleteRenderbuffer(renderbuffer);
+ GLctx.deleteRenderbuffer(renderbuffer);
renderbuffer.name = 0;
GL.renderbuffers[id] = null;
}
@@ -935,19 +999,19 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer');
#endif
- Module.ctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null);
+ GLctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null);
},
glGetRenderbufferParameteriv__sig: 'viii',
glGetRenderbufferParameteriv: function(target, pname, params) {
- {{{ makeSetValue('params', '0', 'Module.ctx.getRenderbufferParameter(target, pname)', 'i32') }}};
+ {{{ makeSetValue('params', '0', 'GLctx.getRenderbufferParameter(target, pname)', 'i32') }}};
},
glIsRenderbuffer__sig: 'ii',
glIsRenderbuffer: function(renderbuffer) {
var rb = GL.renderbuffers[renderbuffer];
if (!rb) return 0;
- return Module.ctx.isRenderbuffer(rb);
+ return GLctx.isRenderbuffer(rb);
},
glGetUniformfv__sig: 'viii',
@@ -956,7 +1020,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glGetUniformfv', 'program');
GL.validateGLObjectID(GL.uniforms, location, 'glGetUniformfv', 'location');
#endif
- var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]);
+ var data = GLctx.getUniform(GL.programs[program], GL.uniforms[location]);
if (typeof data == 'number') {
{{{ makeSetValue('params', '0', 'data', 'float') }}};
} else {
@@ -972,7 +1036,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glGetUniformiv', 'program');
GL.validateGLObjectID(GL.uniforms, location, 'glGetUniformiv', 'location');
#endif
- var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]);
+ var data = GLctx.getUniform(GL.programs[program], GL.uniforms[location]);
if (typeof data == 'number' || typeof data == 'boolean') {
{{{ makeSetValue('params', '0', 'data', 'i32') }}};
} else {
@@ -1023,7 +1087,7 @@ var LibraryGL = {
Module.printErr("glGetVertexAttribfv on client-side array: not supported, bad data returned");
}
#endif
- var data = Module.ctx.getVertexAttrib(index, pname);
+ var data = GLctx.getVertexAttrib(index, pname);
if (typeof data == 'number') {
{{{ makeSetValue('params', '0', 'data', 'float') }}};
} else {
@@ -1040,7 +1104,7 @@ var LibraryGL = {
Module.printErr("glGetVertexAttribiv on client-side array: not supported, bad data returned");
}
#endif
- var data = Module.ctx.getVertexAttrib(index, pname);
+ var data = GLctx.getVertexAttrib(index, pname);
if (typeof data == 'number' || typeof data == 'boolean') {
{{{ makeSetValue('params', '0', 'data', 'i32') }}};
} else {
@@ -1057,7 +1121,7 @@ var LibraryGL = {
Module.printErr("glGetVertexAttribPointer on client-side array: not supported, bad data returned");
}
#endif
- {{{ makeSetValue('pointer', '0', 'Module.ctx.getVertexAttribOffset(index, pname)', 'i32') }}};
+ {{{ makeSetValue('pointer', '0', 'GLctx.getVertexAttribOffset(index, pname)', 'i32') }}};
},
glGetActiveUniform__sig: 'viiiiiii',
@@ -1066,7 +1130,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniform', 'program');
#endif
program = GL.programs[program];
- var info = Module.ctx.getActiveUniform(program, index);
+ var info = GLctx.getActiveUniform(program, index);
var infoname = info.name.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(infoname, name);
@@ -1088,7 +1152,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform1f', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform1f(location, v0);
+ GLctx.uniform1f(location, v0);
},
glUniform2f__sig: 'viff',
@@ -1097,7 +1161,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform2f', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform2f(location, v0, v1);
+ GLctx.uniform2f(location, v0, v1);
},
glUniform3f__sig: 'vifff',
@@ -1106,7 +1170,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform3f', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform3f(location, v0, v1, v2);
+ GLctx.uniform3f(location, v0, v1, v2);
},
glUniform4f__sig: 'viffff',
@@ -1115,7 +1179,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform4f', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform4f(location, v0, v1, v2, v3);
+ GLctx.uniform4f(location, v0, v1, v2, v3);
},
glUniform1i__sig: 'vii',
@@ -1124,7 +1188,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform1i', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform1i(location, v0);
+ GLctx.uniform1i(location, v0);
},
glUniform2i__sig: 'viii',
@@ -1133,7 +1197,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform2i', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform2i(location, v0, v1);
+ GLctx.uniform2i(location, v0, v1);
},
glUniform3i__sig: 'viiii',
@@ -1142,7 +1206,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform3i', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform3i(location, v0, v1, v2);
+ GLctx.uniform3i(location, v0, v1, v2);
},
glUniform4i__sig: 'viiiii',
@@ -1151,7 +1215,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.uniforms, location, 'glUniform4i', 'location');
#endif
location = GL.uniforms[location];
- Module.ctx.uniform4i(location, v0, v1, v2, v3);
+ GLctx.uniform4i(location, v0, v1, v2, v3);
},
glUniform1iv__sig: 'viii',
@@ -1161,7 +1225,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
- Module.ctx.uniform1iv(location, value);
+ GLctx.uniform1iv(location, value);
},
glUniform2iv__sig: 'viii',
@@ -1172,7 +1236,7 @@ var LibraryGL = {
location = GL.uniforms[location];
count *= 2;
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
- Module.ctx.uniform2iv(location, value);
+ GLctx.uniform2iv(location, value);
},
glUniform3iv__sig: 'viii',
@@ -1183,7 +1247,7 @@ var LibraryGL = {
location = GL.uniforms[location];
count *= 3;
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
- Module.ctx.uniform3iv(location, value);
+ GLctx.uniform3iv(location, value);
},
glUniform4iv__sig: 'viii',
@@ -1194,7 +1258,7 @@ var LibraryGL = {
location = GL.uniforms[location];
count *= 4;
value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
- Module.ctx.uniform4iv(location, value);
+ GLctx.uniform4iv(location, value);
},
glUniform1fv__sig: 'viii',
@@ -1211,7 +1275,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
}
- Module.ctx.uniform1fv(location, view);
+ GLctx.uniform1fv(location, view);
},
glUniform2fv__sig: 'viii',
@@ -1229,7 +1293,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*8') }}};
}
- Module.ctx.uniform2fv(location, view);
+ GLctx.uniform2fv(location, view);
},
glUniform3fv__sig: 'viii',
@@ -1248,7 +1312,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*12') }}};
}
- Module.ctx.uniform3fv(location, view);
+ GLctx.uniform3fv(location, view);
},
glUniform4fv__sig: 'viii',
@@ -1268,7 +1332,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*16') }}};
}
- Module.ctx.uniform4fv(location, view);
+ GLctx.uniform4fv(location, view);
},
glUniformMatrix2fv__sig: 'viiii',
@@ -1287,7 +1351,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*16') }}};
}
- Module.ctx.uniformMatrix2fv(location, transpose, view);
+ GLctx.uniformMatrix2fv(location, transpose, view);
},
glUniformMatrix3fv__sig: 'viiii',
@@ -1306,7 +1370,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*36') }}};
}
- Module.ctx.uniformMatrix3fv(location, transpose, view);
+ GLctx.uniformMatrix3fv(location, transpose, view);
},
glUniformMatrix4fv__sig: 'viiii',
@@ -1325,7 +1389,7 @@ var LibraryGL = {
} else {
view = {{{ makeHEAPView('F32', 'value', 'value+count*64') }}};
}
- Module.ctx.uniformMatrix4fv(location, transpose, view);
+ GLctx.uniformMatrix4fv(location, transpose, view);
},
glBindBuffer__sig: 'vii',
@@ -1335,44 +1399,53 @@ var LibraryGL = {
#endif
var bufferObj = buffer ? GL.buffers[buffer] : null;
- if (target == Module.ctx.ARRAY_BUFFER) {
+#if FULL_ES2
+ if (target == GLctx.ARRAY_BUFFER) {
GL.currArrayBuffer = buffer;
- } else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
+ } else if (target == GLctx.ELEMENT_ARRAY_BUFFER) {
+ GL.currElementArrayBuffer = buffer;
+ }
+#endif
+#if LEGACY_GL_EMULATION
+ if (target == GLctx.ARRAY_BUFFER) {
+ GLImmediate.lastArrayBuffer = GL.currArrayBuffer = buffer;
+ } else if (target == GLctx.ELEMENT_ARRAY_BUFFER) {
GL.currElementArrayBuffer = buffer;
}
+#endif
- Module.ctx.bindBuffer(target, bufferObj);
+ GLctx.bindBuffer(target, bufferObj);
},
glVertexAttrib1fv__sig: 'vii',
glVertexAttrib1fv: function(index, v) {
v = {{{ makeHEAPView('F32', 'v', 'v+' + (1*4)) }}};
- Module.ctx.vertexAttrib1fv(index, v);
+ GLctx.vertexAttrib1fv(index, v);
},
glVertexAttrib2fv__sig: 'vii',
glVertexAttrib2fv: function(index, v) {
v = {{{ makeHEAPView('F32', 'v', 'v+' + (2*4)) }}};
- Module.ctx.vertexAttrib2fv(index, v);
+ GLctx.vertexAttrib2fv(index, v);
},
glVertexAttrib3fv__sig: 'vii',
glVertexAttrib3fv: function(index, v) {
v = {{{ makeHEAPView('F32', 'v', 'v+' + (3*4)) }}};
- Module.ctx.vertexAttrib3fv(index, v);
+ GLctx.vertexAttrib3fv(index, v);
},
glVertexAttrib4fv__sig: 'vii',
glVertexAttrib4fv: function(index, v) {
v = {{{ makeHEAPView('F32', 'v', 'v+' + (4*4)) }}};
- Module.ctx.vertexAttrib4fv(index, v);
+ GLctx.vertexAttrib4fv(index, v);
},
glGetAttribLocation__sig: 'vii',
glGetAttribLocation: function(program, name) {
program = GL.programs[program];
name = Pointer_stringify(name);
- return Module.ctx.getAttribLocation(program, name);
+ return GLctx.getAttribLocation(program, name);
},
glGetActiveAttrib__sig: 'viiiiiii',
@@ -1381,7 +1454,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glGetActiveAttrib', 'program');
#endif
program = GL.programs[program];
- var info = Module.ctx.getActiveAttrib(program, index);
+ var info = GLctx.getActiveAttrib(program, index);
var infoname = info.name.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(infoname, name);
@@ -1400,13 +1473,13 @@ var LibraryGL = {
glCreateShader__sig: 'ii',
glCreateShader: function(shaderType) {
var id = GL.getNewId(GL.shaders);
- GL.shaders[id] = Module.ctx.createShader(shaderType);
+ GL.shaders[id] = GLctx.createShader(shaderType);
return id;
},
glDeleteShader__sig: 'vi',
glDeleteShader: function(shader) {
- Module.ctx.deleteShader(GL.shaders[shader]);
+ GLctx.deleteShader(GL.shaders[shader]);
GL.shaders[shader] = null;
},
@@ -1415,7 +1488,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.programs, program, 'glGetAttachedShaders', 'program');
#endif
- var result = Module.ctx.getAttachedShaders(GL.programs[program]);
+ var result = GLctx.getAttachedShaders(GL.programs[program]);
var len = result.length;
if (len > maxCount) {
len = maxCount;
@@ -1436,7 +1509,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.shaders, shader, 'glShaderSource', 'shader');
#endif
var source = GL.getSource(shader, count, string, length);
- Module.ctx.shaderSource(GL.shaders[shader], source);
+ GLctx.shaderSource(GL.shaders[shader], source);
},
glGetShaderSource__sig: 'viiii',
@@ -1444,7 +1517,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderSource', 'shader');
#endif
- var result = Module.ctx.getShaderSource(GL.shaders[shader]);
+ var result = GLctx.getShaderSource(GL.shaders[shader]);
result = result.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(result, source);
if (length) {
@@ -1457,7 +1530,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.shaders, shader, 'glCompileShader', 'shader');
#endif
- Module.ctx.compileShader(GL.shaders[shader]);
+ GLctx.compileShader(GL.shaders[shader]);
},
glGetShaderInfoLog__sig: 'viiii',
@@ -1465,7 +1538,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader');
#endif
- var log = Module.ctx.getShaderInfoLog(GL.shaders[shader]);
+ var log = GLctx.getShaderInfoLog(GL.shaders[shader]);
// Work around a bug in Chromium which causes getShaderInfoLog to return null
if (!log) {
log = "";
@@ -1483,9 +1556,9 @@ var LibraryGL = {
GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderiv', 'shader');
#endif
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
- {{{ makeSetValue('p', '0', 'Module.ctx.getShaderInfoLog(GL.shaders[shader]).length + 1', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'GLctx.getShaderInfoLog(GL.shaders[shader]).length + 1', 'i32') }}};
} else {
- {{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.shaders[shader], pname)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'GLctx.getShaderParameter(GL.shaders[shader], pname)', 'i32') }}};
}
},
@@ -1495,7 +1568,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glGetProgramiv', 'program');
#endif
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
- {{{ makeSetValue('p', '0', 'Module.ctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'GLctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}};
} else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) {
var ptable = GL.programInfos[program];
if (ptable) {
@@ -1517,10 +1590,10 @@ var LibraryGL = {
if (ptable) {
if (ptable.maxAttributeLength == -1) {
var program = GL.programs[program];
- var numAttribs = Module.ctx.getProgramParameter(program, Module.ctx.ACTIVE_ATTRIBUTES);
+ var numAttribs = GLctx.getProgramParameter(program, GLctx.ACTIVE_ATTRIBUTES);
ptable.maxAttributeLength = 0; // Spec says if there are no active attribs, 0 must be returned.
for(var i = 0; i < numAttribs; ++i) {
- var activeAttrib = Module.ctx.getActiveAttrib(program, i);
+ var activeAttrib = GLctx.getActiveAttrib(program, i);
ptable.maxAttributeLength = Math.max(ptable.maxAttributeLength, activeAttrib.name.length+1);
}
}
@@ -1538,7 +1611,7 @@ var LibraryGL = {
GL.recordError(0x0501 /* GL_INVALID_VALUE */);
}
} else {
- {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'GLctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}};
}
},
@@ -1546,13 +1619,13 @@ var LibraryGL = {
glIsShader: function(shader) {
var s = GL.shaders[shader];
if (!s) return 0;
- return Module.ctx.isShader(s);
+ return GLctx.isShader(s);
},
glCreateProgram__sig: 'i',
glCreateProgram: function() {
var id = GL.getNewId(GL.programs);
- var program = Module.ctx.createProgram();
+ var program = GLctx.createProgram();
program.name = id;
GL.programs[id] = program;
return id;
@@ -1561,7 +1634,7 @@ var LibraryGL = {
glDeleteProgram__sig: 'vi',
glDeleteProgram: function(program) {
var program = GL.programs[program];
- Module.ctx.deleteProgram(program);
+ GLctx.deleteProgram(program);
program.name = 0;
GL.programs[program] = null;
GL.programInfos[program] = null;
@@ -1573,7 +1646,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glAttachShader', 'program');
GL.validateGLObjectID(GL.shaders, shader, 'glAttachShader', 'shader');
#endif
- Module.ctx.attachShader(GL.programs[program],
+ GLctx.attachShader(GL.programs[program],
GL.shaders[shader]);
},
@@ -1583,12 +1656,12 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glDetachShader', 'program');
GL.validateGLObjectID(GL.shaders, shader, 'glDetachShader', 'shader');
#endif
- Module.ctx.detachShader(GL.programs[program],
+ GLctx.detachShader(GL.programs[program],
GL.shaders[shader]);
},
glGetShaderPrecisionFormat: function(shaderType, precisionType, range, precision) {
- var result = Module.ctx.getShaderPrecisionFormat(shaderType, precisionType);
+ var result = GLctx.getShaderPrecisionFormat(shaderType, precisionType);
{{{ makeSetValue('range', '0', 'result.rangeMin', 'i32') }}};
{{{ makeSetValue('range', '4', 'result.rangeMax', 'i32') }}};
{{{ makeSetValue('precision', '0', 'result.precision', 'i32') }}};
@@ -1599,7 +1672,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.programs, program, 'glLinkProgram', 'program');
#endif
- Module.ctx.linkProgram(GL.programs[program]);
+ GLctx.linkProgram(GL.programs[program]);
GL.programInfos[program] = null; // uniforms no longer keep the same names after linking
GL.populateUniformTable(program);
},
@@ -1609,7 +1682,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.programs, program, 'glGetProgramInfoLog', 'program');
#endif
- var log = Module.ctx.getProgramInfoLog(GL.programs[program]);
+ var log = GLctx.getProgramInfoLog(GL.programs[program]);
// Work around a bug in Chromium which causes getProgramInfoLog to return null
if (!log) {
log = "";
@@ -1626,7 +1699,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.programs, program, 'glUseProgram', 'program');
#endif
- Module.ctx.useProgram(program ? GL.programs[program] : null);
+ GLctx.useProgram(program ? GL.programs[program] : null);
},
glValidateProgram__sig: 'vi',
@@ -1634,14 +1707,14 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.programs, program, 'glValidateProgram', 'program');
#endif
- Module.ctx.validateProgram(GL.programs[program]);
+ GLctx.validateProgram(GL.programs[program]);
},
glIsProgram__sig: 'ii',
glIsProgram: function(program) {
var program = GL.programs[program];
if (!program) return 0;
- return Module.ctx.isProgram(program);
+ return GLctx.isProgram(program);
},
glBindAttribLocation__sig: 'viii',
@@ -1650,7 +1723,7 @@ var LibraryGL = {
GL.validateGLObjectID(GL.programs, program, 'glBindAttribLocation', 'program');
#endif
name = Pointer_stringify(name);
- Module.ctx.bindAttribLocation(GL.programs[program], index, name);
+ GLctx.bindAttribLocation(GL.programs[program], index, name);
},
glBindFramebuffer__sig: 'vii',
@@ -1658,14 +1731,14 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.framebuffers, framebuffer, 'glBindFramebuffer', 'framebuffer');
#endif
- Module.ctx.bindFramebuffer(target, framebuffer ? GL.framebuffers[framebuffer] : null);
+ GLctx.bindFramebuffer(target, framebuffer ? GL.framebuffers[framebuffer] : null);
},
glGenFramebuffers__sig: 'vii',
glGenFramebuffers: function(n, ids) {
for (var i = 0; i < n; ++i) {
var id = GL.getNewId(GL.framebuffers);
- var framebuffer = Module.ctx.createFramebuffer();
+ var framebuffer = GLctx.createFramebuffer();
framebuffer.name = id;
GL.framebuffers[id] = framebuffer;
{{{ makeSetValue('ids', 'i*4', 'id', 'i32') }}};
@@ -1677,7 +1750,7 @@ var LibraryGL = {
for (var i = 0; i < n; ++i) {
var id = {{{ makeGetValue('framebuffers', 'i*4', 'i32') }}};
var framebuffer = GL.framebuffers[id];
- Module.ctx.deleteFramebuffer(framebuffer);
+ GLctx.deleteFramebuffer(framebuffer);
framebuffer.name = 0;
GL.framebuffers[id] = null;
}
@@ -1688,7 +1761,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glFramebufferRenderbuffer', 'renderbuffer');
#endif
- Module.ctx.framebufferRenderbuffer(target, attachment, renderbuffertarget,
+ GLctx.framebufferRenderbuffer(target, attachment, renderbuffertarget,
GL.renderbuffers[renderbuffer]);
},
@@ -1697,13 +1770,13 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTexture2D', 'texture');
#endif
- Module.ctx.framebufferTexture2D(target, attachment, textarget,
+ GLctx.framebufferTexture2D(target, attachment, textarget,
GL.textures[texture], level);
},
glGetFramebufferAttachmentParameteriv__sig: 'viiii',
glGetFramebufferAttachmentParameteriv: function(target, attachment, pname, params) {
- var result = Module.ctx.getFramebufferAttachmentParameter(target, attachment, pname);
+ var result = GLctx.getFramebufferAttachmentParameter(target, attachment, pname);
{{{ makeSetValue('params', '0', 'result', 'i32') }}};
},
@@ -1711,7 +1784,7 @@ var LibraryGL = {
glIsFramebuffer: function(framebuffer) {
var fb = GL.framebuffers[framebuffer];
if (!fb) return 0;
- return Module.ctx.isFramebuffer(fb);
+ return GLctx.isFramebuffer(fb);
},
#if LEGACY_GL_EMULATION
@@ -1775,9 +1848,12 @@ var LibraryGL = {
_glEnable = function _glEnable(cap) {
// Clean up the renderer on any change to the rendering state. The optimization of
// skipping renderer setup is aimed at the case of multiple glDraw* right after each other
- if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
+ if (GLImmediate.lastRenderer) GLImmediate.lastRenderer.cleanup();
if (cap == 0x0B60 /* GL_FOG */) {
- GLEmulation.fogEnabled = true;
+ if (GLEmulation.fogEnabled != true) {
+ GLImmediate.currentRenderer = null; // Fog parameter is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogEnabled = true;
+ }
return;
} else if (cap == 0x0de1 /* GL_TEXTURE_2D */) {
// XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
@@ -1795,9 +1871,12 @@ var LibraryGL = {
var glDisable = _glDisable;
_glDisable = function _glDisable(cap) {
- if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
+ if (GLImmediate.lastRenderer) GLImmediate.lastRenderer.cleanup();
if (cap == 0x0B60 /* GL_FOG */) {
- GLEmulation.fogEnabled = false;
+ if (GLEmulation.fogEnabled != false) {
+ GLImmediate.currentRenderer = null; // Fog parameter is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogEnabled = false;
+ }
return;
} else if (cap == 0x0de1 /* GL_TEXTURE_2D */) {
// XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
@@ -1818,14 +1897,14 @@ var LibraryGL = {
} else if (!(cap in validCapabilities)) {
return 0;
}
- return Module.ctx.isEnabled(cap);
+ return GLctx.isEnabled(cap);
};
var glGetBooleanv = _glGetBooleanv;
_glGetBooleanv = function _glGetBooleanv(pname, p) {
var attrib = GLEmulation.getAttributeFromCapability(pname);
if (attrib !== null) {
- var result = GL.immediate.enabledClientAttributes[attrib];
+ var result = GLImmediate.enabledClientAttributes[attrib];
{{{ makeSetValue('p', '0', 'result === true ? 1 : 0', 'i8') }}};
return;
}
@@ -1835,23 +1914,23 @@ var LibraryGL = {
var glGetIntegerv = _glGetIntegerv;
_glGetIntegerv = function _glGetIntegerv(pname, params) {
switch (pname) {
- case 0x84E2: pname = Module.ctx.MAX_TEXTURE_IMAGE_UNITS /* fake it */; break; // GL_MAX_TEXTURE_UNITS
+ case 0x84E2: pname = GLctx.MAX_TEXTURE_IMAGE_UNITS /* fake it */; break; // GL_MAX_TEXTURE_UNITS
case 0x8B4A: { // GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB
- var result = Module.ctx.getParameter(Module.ctx.MAX_VERTEX_UNIFORM_VECTORS);
+ var result = GLctx.getParameter(GLctx.MAX_VERTEX_UNIFORM_VECTORS);
{{{ makeSetValue('params', '0', 'result*4', 'i32') }}}; // GLES gives num of 4-element vectors, GL wants individual components, so multiply
return;
}
case 0x8B49: { // GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB
- var result = Module.ctx.getParameter(Module.ctx.MAX_FRAGMENT_UNIFORM_VECTORS);
+ var result = GLctx.getParameter(GLctx.MAX_FRAGMENT_UNIFORM_VECTORS);
{{{ makeSetValue('params', '0', 'result*4', 'i32') }}}; // GLES gives num of 4-element vectors, GL wants individual components, so multiply
return;
}
case 0x8B4B: { // GL_MAX_VARYING_FLOATS_ARB
- var result = Module.ctx.getParameter(Module.ctx.MAX_VARYING_VECTORS);
+ var result = GLctx.getParameter(GLctx.MAX_VARYING_VECTORS);
{{{ makeSetValue('params', '0', 'result*4', 'i32') }}}; // GLES gives num of 4-element vectors, GL wants individual components, so multiply
return;
}
- case 0x8871: pname = Module.ctx.MAX_COMBINED_TEXTURE_IMAGE_UNITS /* close enough */; break; // GL_MAX_TEXTURE_COORDS
+ case 0x8871: pname = GLctx.MAX_COMBINED_TEXTURE_IMAGE_UNITS /* close enough */; break; // GL_MAX_TEXTURE_COORDS
case 0x807A: { // GL_VERTEX_ARRAY_SIZE
var attribute = GLImmediate.clientAttributes[GLImmediate.VERTEX];
{{{ makeSetValue('params', '0', 'attribute ? attribute.size : 0', 'i32') }}};
@@ -1906,7 +1985,7 @@ var LibraryGL = {
if (GL.stringCache[name_]) return GL.stringCache[name_];
switch(name_) {
case 0x1F03 /* GL_EXTENSIONS */: // Add various extensions that we can support
- var ret = allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ') +
+ var ret = allocate(intArrayFromString(GLctx.getSupportedExtensions().join(' ') +
' GL_EXT_texture_env_combine GL_ARB_texture_env_crossbar GL_ATI_texture_env_combine3 GL_NV_texture_env_combine4 GL_EXT_texture_env_dot3 GL_ARB_multitexture GL_ARB_vertex_buffer_object GL_EXT_framebuffer_object GL_ARB_vertex_program GL_ARB_fragment_program GL_ARB_shading_language_100 GL_ARB_shader_objects GL_ARB_vertex_shader GL_ARB_fragment_shader GL_ARB_texture_cube_map GL_EXT_draw_range_elements' +
(GL.compressionExt ? ' GL_ARB_texture_compression GL_EXT_texture_compression_s3tc' : '') +
(GL.anisotropicExt ? ' GL_EXT_texture_filter_anisotropic' : '')
@@ -1951,7 +2030,7 @@ var LibraryGL = {
#endif
// XXX We add attributes and uniforms to shaders. The program can ask for the # of them, and see the
// ones we generated, potentially confusing it? Perhaps we should hide them.
- if (GL.shaderInfos[shader].type == Module.ctx.VERTEX_SHADER) {
+ if (GL.shaderInfos[shader].type == GLctx.VERTEX_SHADER) {
// Replace ftransform() with explicit project/modelview transforms, and add position and matrix info.
var has_pm = source.search(/u_projection/) >= 0;
var has_mm = source.search(/u_modelView/) >= 0;
@@ -1979,7 +2058,7 @@ var LibraryGL = {
if (need_mm && !has_mm) source = 'uniform mat4 u_modelView; \n' + source;
if (need_pm && !has_pm) source = 'uniform mat4 u_projection; \n' + source;
GL.shaderInfos[shader].ftransform = need_pm || need_mm || need_pv; // we will need to provide the fixed function stuff as attributes and uniforms
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
// XXX To handle both regular texture mapping and cube mapping, we use vec4 for tex coordinates.
var old = source;
var need_vtc = source.search('v_texCoord' + i) == -1;
@@ -2017,7 +2096,7 @@ var LibraryGL = {
}
source = ensurePrecision(source);
} else { // Fragment shader
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
var old = source;
source = source.replace(new RegExp('gl_TexCoord\\[' + i + '\\]', 'g'), 'v_texCoord' + i);
if (source != old) {
@@ -2053,15 +2132,15 @@ var LibraryGL = {
GL.shaderSources[shader] = source;
console.log("glShaderSource: Output: \n" + source);
#endif
- Module.ctx.shaderSource(GL.shaders[shader], source);
+ GLctx.shaderSource(GL.shaders[shader], source);
};
var glCompileShader = _glCompileShader;
_glCompileShader = function _glCompileShader(shader) {
- Module.ctx.compileShader(GL.shaders[shader]);
+ GLctx.compileShader(GL.shaders[shader]);
#if GL_DEBUG
- if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) {
- Module.printErr('Failed to compile shader: ' + Module.ctx.getShaderInfoLog(GL.shaders[shader]));
+ if (!GLctx.getShaderParameter(GL.shaders[shader], GLctx.COMPILE_STATUS)) {
+ Module.printErr('Failed to compile shader: ' + GLctx.getShaderInfoLog(GL.shaders[shader]));
Module.printErr('Info: ' + JSON.stringify(GL.shaderInfos[shader]));
Module.printErr('Original source: ' + GL.shaderOriginalSources[shader]);
Module.printErr('Source: ' + GL.shaderSources[shader]);
@@ -2104,16 +2183,20 @@ var LibraryGL = {
}
#endif
if (GL.currProgram != program) {
- GL.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
+ GLImmediate.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
GL.currProgram = program;
+ GLImmediate.fixedFunctionProgram = 0;
+ glUseProgram(program);
}
- glUseProgram(program);
}
var glDeleteProgram = _glDeleteProgram;
_glDeleteProgram = function _glDeleteProgram(program) {
glDeleteProgram(program);
- if (program == GL.currProgram) GL.currProgram = 0;
+ if (program == GL.currProgram) {
+ GLImmediate.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
+ GL.currProgram = 0;
+ }
};
// If attribute 0 was not bound, bind it to 0 for WebGL performance reasons. Track if 0 is free for that.
@@ -2126,7 +2209,7 @@ var LibraryGL = {
var glLinkProgram = _glLinkProgram;
_glLinkProgram = function _glLinkProgram(program) {
if (!(program in zeroUsedPrograms)) {
- Module.ctx.bindAttribLocation(GL.programs[program], 0, 'a_position');
+ GLctx.bindAttribLocation(GL.programs[program], 0, 'a_position');
}
glLinkProgram(program);
};
@@ -2134,14 +2217,14 @@ var LibraryGL = {
var glBindBuffer = _glBindBuffer;
_glBindBuffer = function _glBindBuffer(target, buffer) {
glBindBuffer(target, buffer);
- if (target == Module.ctx.ARRAY_BUFFER) {
+ if (target == GLctx.ARRAY_BUFFER) {
if (GLEmulation.currentVao) {
#if ASSERTIONS
assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
#endif
GLEmulation.currentVao.arrayBuffer = buffer;
}
- } else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
+ } else if (target == GLctx.ELEMENT_ARRAY_BUFFER) {
if (GLEmulation.currentVao) GLEmulation.currentVao.elementArrayBuffer = buffer;
}
};
@@ -2149,11 +2232,11 @@ var LibraryGL = {
var glGetFloatv = _glGetFloatv;
_glGetFloatv = function _glGetFloatv(pname, params) {
if (pname == 0x0BA6) { // GL_MODELVIEW_MATRIX
- HEAPF32.set(GL.immediate.matrix['m'], params >> 2);
+ HEAPF32.set(GLImmediate.matrix[0/*m*/], params >> 2);
} else if (pname == 0x0BA7) { // GL_PROJECTION_MATRIX
- HEAPF32.set(GL.immediate.matrix['p'], params >> 2);
+ HEAPF32.set(GLImmediate.matrix[1/*p*/], params >> 2);
} else if (pname == 0x0BA8) { // GL_TEXTURE_MATRIX
- HEAPF32.set(GL.immediate.matrix['t' + GL.immediate.clientActiveTexture], params >> 2);
+ HEAPF32.set(GLImmediate.matrix[2/*t*/ + GLImmediate.clientActiveTexture], params >> 2);
} else if (pname == 0x0B66) { // GL_FOG_COLOR
HEAPF32.set(GLEmulation.fogColor, params >> 2);
} else if (pname == 0x0B63) { // GL_FOG_START
@@ -2209,13 +2292,13 @@ var LibraryGL = {
#endif
// Fall through:
case 0x8078: // GL_TEXTURE_COORD_ARRAY
- attrib = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture; break;
+ attrib = GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture; break;
case 0x8074: // GL_VERTEX_ARRAY
- attrib = GL.immediate.VERTEX; break;
+ attrib = GLImmediate.VERTEX; break;
case 0x8075: // GL_NORMAL_ARRAY
- attrib = GL.immediate.NORMAL; break;
+ attrib = GLImmediate.NORMAL; break;
case 0x8076: // GL_COLOR_ARRAY
- attrib = GL.immediate.COLOR; break;
+ attrib = GLImmediate.COLOR; break;
}
return attrib;
},
@@ -2239,16 +2322,16 @@ var LibraryGL = {
glGetObjectParameteriv: function(id, type, result) {
if (GL.programs[id]) {
if (type == 0x8B84) { // GL_OBJECT_INFO_LOG_LENGTH_ARB
- {{{ makeSetValue('result', '0', 'Module.ctx.getProgramInfoLog(GL.programs[id]).length', 'i32') }}};
+ {{{ makeSetValue('result', '0', 'GLctx.getProgramInfoLog(GL.programs[id]).length', 'i32') }}};
return;
}
_glGetProgramiv(id, type, result);
} else if (GL.shaders[id]) {
if (type == 0x8B84) { // GL_OBJECT_INFO_LOG_LENGTH_ARB
- {{{ makeSetValue('result', '0', 'Module.ctx.getShaderInfoLog(GL.shaders[id]).length', 'i32') }}};
+ {{{ makeSetValue('result', '0', 'GLctx.getShaderInfoLog(GL.shaders[id]).length', 'i32') }}};
return;
} else if (type == 0x8B88) { // GL_OBJECT_SHADER_SOURCE_LENGTH_ARB
- {{{ makeSetValue('result', '0', 'Module.ctx.getShaderSource(GL.shaders[id]).length', 'i32') }}};
+ {{{ makeSetValue('result', '0', 'GLctx.getShaderSource(GL.shaders[id]).length', 'i32') }}};
return;
}
_glGetShaderiv(id, type, result);
@@ -2298,7 +2381,7 @@ var LibraryGL = {
// See comment in GLEmulation.init()
#if FULL_ES2 == 0
- $GLImmediate__postset: 'GL.immediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GL.immediate.init() });',
+ $GLImmediate__postset: 'GLImmediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GLImmediate.init() });',
#endif
$GLImmediate__deps: ['$Browser', '$GL', '$GLEmulation'],
$GLImmediate: {
@@ -2716,16 +2799,8 @@ var LibraryGL = {
}
this.invalidateKey = function() {
this.key0 = -1; // The key of this texture unit must be recomputed when rendering the next time.
- GL.immediate.currentRenderer = null; // The currently used renderer must be re-evaluated at next render.
+ 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() {
@@ -2734,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() {
@@ -2874,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("");
@@ -3060,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);
}
},
@@ -3087,26 +3191,30 @@ var LibraryGL = {
switch (cap) {
case GL_TEXTURE_1D:
if (!cur.enabled_tex1D) {
- GL.immediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
+ 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) {
- GL.immediate.currentRenderer = null;
+ GLImmediate.currentRenderer = null;
cur.enabled_tex2D = true;
+ cur.texTypesEnabled |= 2;
}
break;
case GL_TEXTURE_3D:
if (!cur.enabled_tex3D) {
- GL.immediate.currentRenderer = null;
+ GLImmediate.currentRenderer = null;
cur.enabled_tex3D = true;
+ cur.texTypesEnabled |= 4;
}
break;
case GL_TEXTURE_CUBE_MAP:
if (!cur.enabled_texCube) {
- GL.immediate.currentRenderer = null;
+ GLImmediate.currentRenderer = null;
cur.enabled_texCube = true;
+ cur.texTypesEnabled |= 8;
}
break;
}
@@ -3117,26 +3225,30 @@ var LibraryGL = {
switch (cap) {
case GL_TEXTURE_1D:
if (cur.enabled_tex1D) {
- GL.immediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
+ 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) {
- GL.immediate.currentRenderer = null;
+ GLImmediate.currentRenderer = null;
cur.enabled_tex2D = false;
+ cur.texTypesEnabled &= ~2;
}
break;
case GL_TEXTURE_3D:
if (cur.enabled_tex3D) {
- GL.immediate.currentRenderer = null;
+ GLImmediate.currentRenderer = null;
cur.enabled_tex3D = false;
+ cur.texTypesEnabled &= ~4;
}
break;
case GL_TEXTURE_CUBE_MAP:
if (cur.enabled_texCube) {
- GL.immediate.currentRenderer = null;
+ GLImmediate.currentRenderer = null;
cur.enabled_texCube = false;
+ cur.texTypesEnabled &= ~8;
}
break;
}
@@ -3325,9 +3437,9 @@ var LibraryGL = {
lastStride: -1, // ""
// The following data structures are used for OpenGL Immediate Mode matrix routines.
- matrix: {},
- matrixStack: {},
- currentMatrix: 'm', // default is modelview
+ matrix: [],
+ matrixStack: [],
+ currentMatrix: 0, // 0: modelview, 1: projection, 2+i, texture matrix i.
tempMatrix: null,
matricesModified: false,
useTextureMatrix: false,
@@ -3352,11 +3464,11 @@ var LibraryGL = {
fixedFunctionProgram: null,
setClientAttribute: function setClientAttribute(name, size, type, stride, pointer) {
- var attrib = this.clientAttributes[name];
+ var attrib = GLImmediate.clientAttributes[name];
if (!attrib) {
for (var i = 0; i <= name; i++) { // keep flat
- if (!this.clientAttributes[i]) {
- this.clientAttributes[i] = {
+ if (!GLImmediate.clientAttributes[i]) {
+ GLImmediate.clientAttributes[i] = {
name: name,
size: size,
type: type,
@@ -3374,43 +3486,42 @@ var LibraryGL = {
attrib.pointer = pointer;
attrib.offset = 0;
}
- this.modifiedClientAttributes = true;
+ GLImmediate.modifiedClientAttributes = true;
},
// Renderers
addRendererComponent: function addRendererComponent(name, size, type) {
- if (!this.rendererComponents[name]) {
- this.rendererComponents[name] = 1;
+ if (!GLImmediate.rendererComponents[name]) {
+ GLImmediate.rendererComponents[name] = 1;
#if ASSERTIONS
- if (this.enabledClientAttributes[name]) {
+ if (GLImmediate.enabledClientAttributes[name]) {
console.log("Warning: glTexCoord used after EnableClientState for TEXTURE_COORD_ARRAY for TEXTURE0. Disabling TEXTURE_COORD_ARRAY...");
}
#endif
- this.enabledClientAttributes[name] = true;
- this.setClientAttribute(name, size, type, 0, this.rendererComponentPointer);
- this.rendererComponentPointer += size * GL.byteSizeByType[type - GL.byteSizeByTypeRoot];
+ GLImmediate.enabledClientAttributes[name] = true;
+ GLImmediate.setClientAttribute(name, size, type, 0, GLImmediate.rendererComponentPointer);
+ GLImmediate.rendererComponentPointer += size * GL.byteSizeByType[type - GL.byteSizeByTypeRoot];
} else {
- this.rendererComponents[name]++;
+ GLImmediate.rendererComponents[name]++;
}
},
disableBeginEndClientAttributes: function disableBeginEndClientAttributes() {
- for (var i = 0; i < this.NUM_ATTRIBUTES; i++) {
- if (this.rendererComponents[i]) this.enabledClientAttributes[i] = false;
+ for (var i = 0; i < GLImmediate.NUM_ATTRIBUTES; i++) {
+ if (GLImmediate.rendererComponents[i]) GLImmediate.enabledClientAttributes[i] = false;
}
},
getRenderer: function getRenderer() {
// If no FFP state has changed that would have forced to re-evaluate which FFP emulation shader to use,
// we have the currently used renderer in cache, and can immediately return that.
- if (this.currentRenderer) {
- return this.currentRenderer;
+ if (GLImmediate.currentRenderer) {
+ return GLImmediate.currentRenderer;
}
// return a renderer object given the liveClientAttributes
// we maintain a cache of renderers, optimized to not generate garbage
- var attributes = GL.immediate.liveClientAttributes;
- var cacheMap = GL.immediate.rendererCache;
- var temp;
+ var attributes = GLImmediate.liveClientAttributes;
+ var cacheMap = GLImmediate.rendererCache;
var keyView = cacheMap.getStaticKeyView().reset();
// By attrib state:
@@ -3418,7 +3529,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;
@@ -3435,13 +3545,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) {
- GL.immediate.TexEnvJIT.traverseState(keyView);
+#endif
+ GLImmediate.TexEnvJIT.traverseState(keyView);
+#if !GL_FFP_ONLY
}
+#endif
// If we don't already have it, create it.
var renderer = keyView.get();
@@ -3449,26 +3563,26 @@ var LibraryGL = {
#if GL_DEBUG
Module.printErr('generating renderer for ' + JSON.stringify(attributes));
#endif
- renderer = this.createRenderer();
- this.currentRenderer = renderer;
+ renderer = GLImmediate.createRenderer();
+ GLImmediate.currentRenderer = renderer;
keyView.set(renderer);
return renderer;
}
- this.currentRenderer = renderer; // Cache the currently used renderer, so later lookups without state changes can get this fast.
+ GLImmediate.currentRenderer = renderer; // Cache the currently used renderer, so later lookups without state changes can get this fast.
return renderer;
},
createRenderer: function createRenderer(renderer) {
var useCurrProgram = !!GL.currProgram;
var hasTextures = false;
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- var texAttribName = GL.immediate.TEXTURE0 + i;
- if (!GL.immediate.enabledClientAttributes[texAttribName])
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
+ var texAttribName = GLImmediate.TEXTURE0 + i;
+ if (!GLImmediate.enabledClientAttributes[texAttribName])
continue;
#if ASSERTIONS
if (!useCurrProgram) {
- if (GL.immediate.TexEnvJIT.getTexUnitType(i) == 0) {
+ if (GLImmediate.TexEnvJIT.getTexUnitType(i) == 0) {
Runtime.warnOnce("GL_TEXTURE" + i + " coords are supplied, but that texture unit is disabled in the fixed-function pipeline.");
}
}
@@ -3484,10 +3598,10 @@ var LibraryGL = {
var aTexCoordPrefix = 'a_texCoord';
var vTexCoordPrefix = 'v_texCoord';
var vPrimColor = 'v_color';
- var uTexMatrixPrefix = GL.immediate.useTextureMatrix ? 'u_textureMatrix' : null;
+ var uTexMatrixPrefix = GLImmediate.useTextureMatrix ? 'u_textureMatrix' : null;
if (useCurrProgram) {
- if (GL.shaderInfos[GL.programShaders[GL.currProgram][0]].type == Module.ctx.VERTEX_SHADER) {
+ if (GL.shaderInfos[GL.programShaders[GL.currProgram][0]].type == GLctx.VERTEX_SHADER) {
this.vertexShader = GL.shaders[GL.programShaders[GL.currProgram][0]];
this.fragmentShader = GL.shaders[GL.programShaders[GL.currProgram][1]];
} else {
@@ -3518,14 +3632,14 @@ var LibraryGL = {
}
}
- GL.immediate.TexEnvJIT.setGLSLVars(uTexUnitPrefix, vTexCoordPrefix, vPrimColor, uTexMatrixPrefix);
- var fsTexEnvPass = GL.immediate.TexEnvJIT.genAllPassLines('gl_FragColor', 2);
+ GLImmediate.TexEnvJIT.setGLSLVars(uTexUnitPrefix, vTexCoordPrefix, vPrimColor, uTexMatrixPrefix);
+ var fsTexEnvPass = GLImmediate.TexEnvJIT.genAllPassLines('gl_FragColor', 2);
var texUnitAttribList = '';
var texUnitVaryingList = '';
var texUnitUniformList = '';
var vsTexCoordInits = '';
- this.usedTexUnitList = GL.immediate.TexEnvJIT.getUsedTexUnitList();
+ this.usedTexUnitList = GLImmediate.TexEnvJIT.getUsedTexUnitList();
for (var i = 0; i < this.usedTexUnitList.length; i++) {
var texUnit = this.usedTexUnitList[i];
texUnitAttribList += 'attribute vec4 ' + aTexCoordPrefix + texUnit + ';\n';
@@ -3533,7 +3647,7 @@ var LibraryGL = {
texUnitUniformList += 'uniform sampler2D ' + uTexUnitPrefix + texUnit + ';\n';
vsTexCoordInits += ' ' + vTexCoordPrefix + texUnit + ' = ' + aTexCoordPrefix + texUnit + ';\n';
- if (GL.immediate.useTextureMatrix) {
+ if (GLImmediate.useTextureMatrix) {
texUnitUniformList += 'uniform mat4 ' + uTexMatrixPrefix + texUnit + ';\n';
}
}
@@ -3563,9 +3677,9 @@ var LibraryGL = {
''
].join('\n').replace(/\n\n+/g, '\n');
- this.vertexShader = Module.ctx.createShader(Module.ctx.VERTEX_SHADER);
- Module.ctx.shaderSource(this.vertexShader, vsSource);
- Module.ctx.compileShader(this.vertexShader);
+ this.vertexShader = GLctx.createShader(GLctx.VERTEX_SHADER);
+ GLctx.shaderSource(this.vertexShader, vsSource);
+ GLctx.compileShader(this.vertexShader);
var fogHeaderIfNeeded = null;
if (GLEmulation.fogEnabled) {
@@ -3604,85 +3718,85 @@ var LibraryGL = {
''
].join("\n").replace(/\n\n+/g, '\n');
- this.fragmentShader = Module.ctx.createShader(Module.ctx.FRAGMENT_SHADER);
- Module.ctx.shaderSource(this.fragmentShader, fsSource);
- Module.ctx.compileShader(this.fragmentShader);
+ this.fragmentShader = GLctx.createShader(GLctx.FRAGMENT_SHADER);
+ GLctx.shaderSource(this.fragmentShader, fsSource);
+ GLctx.compileShader(this.fragmentShader);
- this.program = Module.ctx.createProgram();
- Module.ctx.attachShader(this.program, this.vertexShader);
- Module.ctx.attachShader(this.program, this.fragmentShader);
+ this.program = GLctx.createProgram();
+ GLctx.attachShader(this.program, this.vertexShader);
+ GLctx.attachShader(this.program, this.fragmentShader);
// As optimization, bind all attributes to prespecified locations, so that the FFP emulation
// code can submit attributes to any generated FFP shader without having to examine each shader in turn.
// These prespecified locations are only assumed if GL_FFP_ONLY is specified, since user could also create their
// own shaders that didn't have attributes in the same locations.
- Module.ctx.bindAttribLocation(this.program, GL.immediate.VERTEX, 'a_position');
- Module.ctx.bindAttribLocation(this.program, GL.immediate.COLOR, 'a_color');
- Module.ctx.bindAttribLocation(this.program, GL.immediate.NORMAL, 'a_normal');
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- Module.ctx.bindAttribLocation(this.program, GL.immediate.TEXTURE0 + i, 'a_texCoord'+i);
- Module.ctx.bindAttribLocation(this.program, GL.immediate.TEXTURE0 + i, aTexCoordPrefix+i);
+ GLctx.bindAttribLocation(this.program, GLImmediate.VERTEX, 'a_position');
+ GLctx.bindAttribLocation(this.program, GLImmediate.COLOR, 'a_color');
+ GLctx.bindAttribLocation(this.program, GLImmediate.NORMAL, 'a_normal');
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
+ GLctx.bindAttribLocation(this.program, GLImmediate.TEXTURE0 + i, 'a_texCoord'+i);
+ GLctx.bindAttribLocation(this.program, GLImmediate.TEXTURE0 + i, aTexCoordPrefix+i);
}
- Module.ctx.linkProgram(this.program);
+ GLctx.linkProgram(this.program);
}
- // Stores a map that remembers which matrix uniforms are up-to-date in this FFP renderer, so they don't need to be resubmitted
+ // Stores an array that remembers which matrix uniforms are up-to-date in this FFP renderer, so they don't need to be resubmitted
// each time we render with this program.
- this.textureMatrixVersion = {};
+ this.textureMatrixVersion = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
- this.positionLocation = Module.ctx.getAttribLocation(this.program, 'a_position');
+ this.positionLocation = GLctx.getAttribLocation(this.program, 'a_position');
this.texCoordLocations = [];
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- if (!GL.immediate.enabledClientAttributes[GL.immediate.TEXTURE0 + i]) {
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
+ if (!GLImmediate.enabledClientAttributes[GLImmediate.TEXTURE0 + i]) {
this.texCoordLocations[i] = -1;
continue;
}
if (useCurrProgram) {
- this.texCoordLocations[i] = Module.ctx.getAttribLocation(this.program, 'a_texCoord' + i);
+ this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, 'a_texCoord' + i);
} else {
- this.texCoordLocations[i] = Module.ctx.getAttribLocation(this.program, aTexCoordPrefix + i);
+ this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, aTexCoordPrefix + i);
}
}
if (!useCurrProgram) {
// Temporarily switch to the program so we can set our sampler uniforms early.
- var prevBoundProg = Module.ctx.getParameter(Module.ctx.CURRENT_PROGRAM);
- Module.ctx.useProgram(this.program);
+ var prevBoundProg = GLctx.getParameter(GLctx.CURRENT_PROGRAM);
+ GLctx.useProgram(this.program);
{
for (var i = 0; i < this.usedTexUnitList.length; i++) {
var texUnitID = this.usedTexUnitList[i];
- var texSamplerLoc = Module.ctx.getUniformLocation(this.program, uTexUnitPrefix + texUnitID);
- Module.ctx.uniform1i(texSamplerLoc, texUnitID);
+ var texSamplerLoc = GLctx.getUniformLocation(this.program, uTexUnitPrefix + texUnitID);
+ GLctx.uniform1i(texSamplerLoc, texUnitID);
}
}
- Module.ctx.useProgram(prevBoundProg);
+ GLctx.useProgram(prevBoundProg);
}
this.textureMatrixLocations = [];
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- this.textureMatrixLocations[i] = Module.ctx.getUniformLocation(this.program, 'u_textureMatrix' + i);
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
+ this.textureMatrixLocations[i] = GLctx.getUniformLocation(this.program, 'u_textureMatrix' + i);
}
- this.colorLocation = Module.ctx.getAttribLocation(this.program, 'a_color');
- this.normalLocation = Module.ctx.getAttribLocation(this.program, 'a_normal');
+ this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color');
+ this.normalLocation = GLctx.getAttribLocation(this.program, 'a_normal');
- this.modelViewLocation = Module.ctx.getUniformLocation(this.program, 'u_modelView');
- this.projectionLocation = Module.ctx.getUniformLocation(this.program, 'u_projection');
+ this.modelViewLocation = GLctx.getUniformLocation(this.program, 'u_modelView');
+ this.projectionLocation = GLctx.getUniformLocation(this.program, 'u_projection');
this.hasTextures = hasTextures;
- this.hasNormal = GL.immediate.enabledClientAttributes[GL.immediate.NORMAL] &&
- GL.immediate.clientAttributes[GL.immediate.NORMAL].size > 0 &&
+ this.hasNormal = GLImmediate.enabledClientAttributes[GLImmediate.NORMAL] &&
+ GLImmediate.clientAttributes[GLImmediate.NORMAL].size > 0 &&
this.normalLocation >= 0;
this.hasColor = (this.colorLocation === 0) || this.colorLocation > 0;
- this.floatType = Module.ctx.FLOAT; // minor optimization
+ this.floatType = GLctx.FLOAT; // minor optimization
- this.fogColorLocation = Module.ctx.getUniformLocation(this.program, 'u_fogColor');
- this.fogEndLocation = Module.ctx.getUniformLocation(this.program, 'u_fogEnd');
- this.fogScaleLocation = Module.ctx.getUniformLocation(this.program, 'u_fogScale');
- this.fogDensityLocation = Module.ctx.getUniformLocation(this.program, 'u_fogDensity');
+ this.fogColorLocation = GLctx.getUniformLocation(this.program, 'u_fogColor');
+ this.fogEndLocation = GLctx.getUniformLocation(this.program, 'u_fogEnd');
+ this.fogScaleLocation = GLctx.getUniformLocation(this.program, 'u_fogScale');
+ this.fogDensityLocation = GLctx.getUniformLocation(this.program, 'u_fogDensity');
this.hasFog = !!(this.fogColorLocation || this.fogEndLocation ||
this.fogScaleLocation || this.fogDensityLocation);
},
@@ -3691,12 +3805,12 @@ var LibraryGL = {
// Calculate the array buffer
var arrayBuffer;
if (!GL.currArrayBuffer) {
- var start = GL.immediate.firstVertex*GL.immediate.stride;
- var end = GL.immediate.lastVertex*GL.immediate.stride;
+ var start = GLImmediate.firstVertex*GLImmediate.stride;
+ var end = GLImmediate.lastVertex*GLImmediate.stride;
#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;
@@ -3706,177 +3820,176 @@ var LibraryGL = {
// If the array buffer is unchanged and the renderer as well, then we can avoid all the work here
// XXX We use some heuristics here, and this may not work in all cases. Try disabling GL_UNSAFE_OPTS if you
// have odd glitches
- var lastRenderer = GL.immediate.lastRenderer;
+ var lastRenderer = GLImmediate.lastRenderer;
var canSkip = this == lastRenderer &&
- arrayBuffer == GL.immediate.lastArrayBuffer &&
- (GL.currProgram || this.program) == GL.immediate.lastProgram &&
- GL.immediate.stride == GL.immediate.lastStride &&
- !GL.immediate.matricesModified;
+ arrayBuffer == GLImmediate.lastArrayBuffer &&
+ (GL.currProgram || this.program) == GLImmediate.lastProgram &&
+ GLImmediate.stride == GLImmediate.lastStride &&
+ !GLImmediate.matricesModified;
if (!canSkip && lastRenderer) lastRenderer.cleanup();
#endif
if (!GL.currArrayBuffer) {
// Bind the array buffer and upload data after cleaning up the previous renderer
-#if GL_UNSAFE_OPTS
- // Potentially unsafe, since lastArrayBuffer might not reflect the true array buffer in code that mixes immediate/non-immediate
- if (arrayBuffer != GL.immediate.lastArrayBuffer) {
-#endif
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, arrayBuffer);
-#if GL_UNSAFE_OPTS
+
+ if (arrayBuffer != GLImmediate.lastArrayBuffer) {
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, arrayBuffer);
+ GLImmediate.lastArrayBuffer = arrayBuffer;
}
-#endif
- Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER, start, GL.immediate.vertexData.subarray(start >> 2, end >> 2));
+
+ GLctx.bufferSubData(GLctx.ARRAY_BUFFER, start, GLImmediate.vertexData.subarray(start >> 2, end >> 2));
}
#if GL_UNSAFE_OPTS
if (canSkip) return;
- GL.immediate.lastRenderer = this;
- GL.immediate.lastArrayBuffer = arrayBuffer;
- GL.immediate.lastProgram = GL.currProgram || this.program;
- GL.immediate.lastStride == GL.immediate.stride;
- GL.immediate.matricesModified = false;
+ GLImmediate.lastRenderer = this;
+ GLImmediate.lastProgram = GL.currProgram || this.program;
+ GLImmediate.lastStride == GLImmediate.stride;
+ GLImmediate.matricesModified = false;
#endif
if (!GL.currProgram) {
- Module.ctx.useProgram(this.program);
- GL.immediate.fixedFunctionProgram = this.program;
+ if (GLImmediate.fixedFunctionProgram != this.program) {
+ GLctx.useProgram(this.program);
+ GLImmediate.fixedFunctionProgram = this.program;
+ }
}
- if (this.modelViewLocation && this.modelViewMatrixVersion != GL.immediate.matrixVersion['m']) {
- this.modelViewMatrixVersion = GL.immediate.matrixVersion['m'];
- Module.ctx.uniformMatrix4fv(this.modelViewLocation, false, GL.immediate.matrix['m']);
+ if (this.modelViewLocation && this.modelViewMatrixVersion != GLImmediate.matrixVersion[0/*m*/]) {
+ this.modelViewMatrixVersion = GLImmediate.matrixVersion[0/*m*/];
+ GLctx.uniformMatrix4fv(this.modelViewLocation, false, GLImmediate.matrix[0/*m*/]);
}
- if (this.projectionLocation && this.projectionMatrixVersion != GL.immediate.matrixVersion['p']) {
- this.projectionMatrixVersion = GL.immediate.matrixVersion['p'];
- Module.ctx.uniformMatrix4fv(this.projectionLocation, false, GL.immediate.matrix['p']);
+ if (this.projectionLocation && this.projectionMatrixVersion != GLImmediate.matrixVersion[1/*p*/]) {
+ this.projectionMatrixVersion = GLImmediate.matrixVersion[1/*p*/];
+ GLctx.uniformMatrix4fv(this.projectionLocation, false, GLImmediate.matrix[1/*p*/]);
}
- var clientAttributes = GL.immediate.clientAttributes;
- var posAttr = clientAttributes[GL.immediate.VERTEX];
+ var clientAttributes = GLImmediate.clientAttributes;
+ var posAttr = clientAttributes[GLImmediate.VERTEX];
#if GL_ASSERTIONS
- GL.validateVertexAttribPointer(posAttr.size, posAttr.type, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
+ GL.validateVertexAttribPointer(posAttr.size, posAttr.type, GLImmediate.stride, clientAttributes[GLImmediate.VERTEX].offset);
#endif
#if GL_FFP_ONLY
if (!GL.currArrayBuffer) {
- Module.ctx.vertexAttribPointer(GL.immediate.VERTEX, posAttr.size, posAttr.type, false, GL.immediate.stride, posAttr.offset);
- GL.enableVertexAttribArray(GL.immediate.VERTEX);
+ GLctx.vertexAttribPointer(GLImmediate.VERTEX, posAttr.size, posAttr.type, false, GLImmediate.stride, posAttr.offset);
+ GL.enableVertexAttribArray(GLImmediate.VERTEX);
if (this.hasNormal) {
- var normalAttr = clientAttributes[GL.immediate.NORMAL];
- Module.ctx.vertexAttribPointer(GL.immediate.NORMAL, normalAttr.size, normalAttr.type, true, GL.immediate.stride, normalAttr.offset);
- GL.enableVertexAttribArray(GL.immediate.NORMAL);
+ var normalAttr = clientAttributes[GLImmediate.NORMAL];
+ GLctx.vertexAttribPointer(GLImmediate.NORMAL, normalAttr.size, normalAttr.type, true, GLImmediate.stride, normalAttr.offset);
+ GL.enableVertexAttribArray(GLImmediate.NORMAL);
}
}
#else
- Module.ctx.vertexAttribPointer(this.positionLocation, posAttr.size, posAttr.type, false, GL.immediate.stride, posAttr.offset);
- Module.ctx.enableVertexAttribArray(this.positionLocation);
+ GLctx.vertexAttribPointer(this.positionLocation, posAttr.size, posAttr.type, false, GLImmediate.stride, posAttr.offset);
+ GLctx.enableVertexAttribArray(this.positionLocation);
if (this.hasNormal) {
- var normalAttr = clientAttributes[GL.immediate.NORMAL];
+ var normalAttr = clientAttributes[GLImmediate.NORMAL];
#if GL_ASSERTIONS
- GL.validateVertexAttribPointer(normalAttr.size, normalAttr.type, GL.immediate.stride, normalAttr.offset);
+ GL.validateVertexAttribPointer(normalAttr.size, normalAttr.type, GLImmediate.stride, normalAttr.offset);
#endif
- Module.ctx.vertexAttribPointer(this.normalLocation, normalAttr.size, normalAttr.type, true, GL.immediate.stride, normalAttr.offset);
- Module.ctx.enableVertexAttribArray(this.normalLocation);
+ GLctx.vertexAttribPointer(this.normalLocation, normalAttr.size, normalAttr.type, true, GLImmediate.stride, normalAttr.offset);
+ GLctx.enableVertexAttribArray(this.normalLocation);
}
#endif
if (this.hasTextures) {
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
#if GL_FFP_ONLY
if (!GL.currArrayBuffer) {
- var attribLoc = GL.immediate.TEXTURE0+i;
+ var attribLoc = GLImmediate.TEXTURE0+i;
var texAttr = clientAttributes[attribLoc];
if (texAttr.size) {
- Module.ctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GL.immediate.stride, texAttr.offset);
+ 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.
- Module.ctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
+ GLctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
GL.disableVertexAttribArray(attribLoc);
}
}
#else
var attribLoc = this.texCoordLocations[i];
if (attribLoc === undefined || attribLoc < 0) continue;
- var texAttr = clientAttributes[GL.immediate.TEXTURE0+i];
+ var texAttr = clientAttributes[GLImmediate.TEXTURE0+i];
if (texAttr.size) {
#if GL_ASSERTIONS
- GL.validateVertexAttribPointer(texAttr.size, texAttr.type, GL.immediate.stride, texAttr.offset);
+ GL.validateVertexAttribPointer(texAttr.size, texAttr.type, GLImmediate.stride, texAttr.offset);
#endif
- Module.ctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GL.immediate.stride, texAttr.offset);
- Module.ctx.enableVertexAttribArray(attribLoc);
+ GLctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GLImmediate.stride, texAttr.offset);
+ GLctx.enableVertexAttribArray(attribLoc);
} else {
// These two might be dangerous, but let's try them.
- Module.ctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
- Module.ctx.disableVertexAttribArray(attribLoc);
+ GLctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1);
+ GLctx.disableVertexAttribArray(attribLoc);
}
#endif
- var t = 't'+i;
- if (this.textureMatrixLocations[i] && this.textureMatrixVersion[t] != GL.immediate.matrixVersion[t]) { // XXX might we need this even without the condition we are currently in?
- this.textureMatrixVersion[t] = GL.immediate.matrixVersion[t];
- Module.ctx.uniformMatrix4fv(this.textureMatrixLocations[i], false, GL.immediate.matrix[t]);
+ var t = 2/*t*/+i;
+ if (this.textureMatrixLocations[i] && this.textureMatrixVersion[t] != GLImmediate.matrixVersion[t]) { // XXX might we need this even without the condition we are currently in?
+ this.textureMatrixVersion[t] = GLImmediate.matrixVersion[t];
+ GLctx.uniformMatrix4fv(this.textureMatrixLocations[i], false, GLImmediate.matrix[t]);
}
}
}
- if (GL.immediate.enabledClientAttributes[GL.immediate.COLOR]) {
- var colorAttr = clientAttributes[GL.immediate.COLOR];
+ if (GLImmediate.enabledClientAttributes[GLImmediate.COLOR]) {
+ var colorAttr = clientAttributes[GLImmediate.COLOR];
#if GL_ASSERTIONS
- GL.validateVertexAttribPointer(colorAttr.size, colorAttr.type, GL.immediate.stride, colorAttr.offset);
+ GL.validateVertexAttribPointer(colorAttr.size, colorAttr.type, GLImmediate.stride, colorAttr.offset);
#endif
#if GL_FFP_ONLY
if (!GL.currArrayBuffer) {
- Module.ctx.vertexAttribPointer(GL.immediate.COLOR, colorAttr.size, colorAttr.type, true, GL.immediate.stride, colorAttr.offset);
- GL.enableVertexAttribArray(GL.immediate.COLOR);
+ GLctx.vertexAttribPointer(GLImmediate.COLOR, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset);
+ GL.enableVertexAttribArray(GLImmediate.COLOR);
}
#else
- Module.ctx.vertexAttribPointer(this.colorLocation, colorAttr.size, colorAttr.type, true, GL.immediate.stride, colorAttr.offset);
- Module.ctx.enableVertexAttribArray(this.colorLocation);
+ 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(GL.immediate.COLOR);
- Module.ctx.vertexAttrib4fv(GL.immediate.COLOR, GL.immediate.clientColor);
+ GL.disableVertexAttribArray(GLImmediate.COLOR);
+ GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor);
#else
- Module.ctx.disableVertexAttribArray(this.colorLocation);
- Module.ctx.vertexAttrib4fv(this.colorLocation, GL.immediate.clientColor);
+ GLctx.disableVertexAttribArray(this.colorLocation);
+ GLctx.vertexAttrib4fv(this.colorLocation, GLImmediate.clientColor);
#endif
}
if (this.hasFog) {
- if (this.fogColorLocation) Module.ctx.uniform4fv(this.fogColorLocation, GLEmulation.fogColor);
- if (this.fogEndLocation) Module.ctx.uniform1f(this.fogEndLocation, GLEmulation.fogEnd);
- if (this.fogScaleLocation) Module.ctx.uniform1f(this.fogScaleLocation, 1/(GLEmulation.fogEnd - GLEmulation.fogStart));
- if (this.fogDensityLocation) Module.ctx.uniform1f(this.fogDensityLocation, GLEmulation.fogDensity);
+ if (this.fogColorLocation) GLctx.uniform4fv(this.fogColorLocation, GLEmulation.fogColor);
+ if (this.fogEndLocation) GLctx.uniform1f(this.fogEndLocation, GLEmulation.fogEnd);
+ if (this.fogScaleLocation) GLctx.uniform1f(this.fogScaleLocation, 1/(GLEmulation.fogEnd - GLEmulation.fogStart));
+ if (this.fogDensityLocation) GLctx.uniform1f(this.fogDensityLocation, GLEmulation.fogDensity);
}
},
cleanup: function cleanup() {
#if !GL_FFP_ONLY
- Module.ctx.disableVertexAttribArray(this.positionLocation);
+ GLctx.disableVertexAttribArray(this.positionLocation);
if (this.hasTextures) {
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- if (GL.immediate.enabledClientAttributes[GL.immediate.TEXTURE0+i] && this.texCoordLocations[i] >= 0) {
- Module.ctx.disableVertexAttribArray(this.texCoordLocations[i]);
+ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) {
+ if (GLImmediate.enabledClientAttributes[GLImmediate.TEXTURE0+i] && this.texCoordLocations[i] >= 0) {
+ GLctx.disableVertexAttribArray(this.texCoordLocations[i]);
}
}
}
if (this.hasColor) {
- Module.ctx.disableVertexAttribArray(this.colorLocation);
+ GLctx.disableVertexAttribArray(this.colorLocation);
}
if (this.hasNormal) {
- Module.ctx.disableVertexAttribArray(this.normalLocation);
+ GLctx.disableVertexAttribArray(this.normalLocation);
}
if (!GL.currProgram) {
- Module.ctx.useProgram(null);
+ GLctx.useProgram(null);
}
if (!GL.currArrayBuffer) {
- Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, null);
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null);
+ GLImmediate.lastArrayBuffer = null;
}
#if GL_UNSAFE_OPTS
- GL.immediate.lastRenderer = null;
- GL.immediate.lastArrayBuffer = null;
- GL.immediate.lastProgram = null;
+ GLImmediate.lastRenderer = null;
+ GLImmediate.lastProgram = null;
#endif
- GL.immediate.matricesModified = true;
+ GLImmediate.matricesModified = true;
#endif
}
};
@@ -3889,53 +4002,53 @@ var LibraryGL = {
// attributes enabled, and we use webgl-friendly modes (no GL_QUADS), then no need
// for emulation
_glDrawArrays = function _glDrawArrays(mode, first, count) {
- if (GL.immediate.totalEnabledClientAttributes == 0 && mode <= 6) {
- Module.ctx.drawArrays(mode, first, count);
+ if (GLImmediate.totalEnabledClientAttributes == 0 && mode <= 6) {
+ GLctx.drawArrays(mode, first, count);
return;
}
- GL.immediate.prepareClientAttributes(count, false);
- GL.immediate.mode = mode;
+ GLImmediate.prepareClientAttributes(count, false);
+ GLImmediate.mode = mode;
if (!GL.currArrayBuffer) {
- GL.immediate.vertexData = {{{ makeHEAPView('F32', 'GL.immediate.vertexPointer', 'GL.immediate.vertexPointer + (first+count)*GL.immediate.stride') }}}; // XXX assuming float
- GL.immediate.firstVertex = first;
- GL.immediate.lastVertex = first + count;
+ GLImmediate.vertexData = {{{ makeHEAPView('F32', 'GLImmediate.vertexPointer', 'GLImmediate.vertexPointer + (first+count)*GLImmediate.stride') }}}; // XXX assuming float
+ GLImmediate.firstVertex = first;
+ GLImmediate.lastVertex = first + count;
}
- GL.immediate.flush(null, first);
- GL.immediate.mode = -1;
+ GLImmediate.flush(null, first);
+ GLImmediate.mode = -1;
};
_glDrawElements = function _glDrawElements(mode, count, type, indices, start, end) { // start, end are given if we come from glDrawRangeElements
- if (GL.immediate.totalEnabledClientAttributes == 0 && mode <= 6 && GL.currElementArrayBuffer) {
- Module.ctx.drawElements(mode, count, type, indices);
+ if (GLImmediate.totalEnabledClientAttributes == 0 && mode <= 6 && GL.currElementArrayBuffer) {
+ GLctx.drawElements(mode, count, type, indices);
return;
}
#if ASSERTIONS
if (!GL.currElementArrayBuffer) {
- assert(type == Module.ctx.UNSIGNED_SHORT); // We can only emulate buffers of this kind, for now
+ assert(type == GLctx.UNSIGNED_SHORT); // We can only emulate buffers of this kind, for now
}
console.log("DrawElements doesn't actually prepareClientAttributes properly.");
#endif
- GL.immediate.prepareClientAttributes(count, false);
- GL.immediate.mode = mode;
+ GLImmediate.prepareClientAttributes(count, false);
+ GLImmediate.mode = mode;
if (!GL.currArrayBuffer) {
- GL.immediate.firstVertex = end ? start : TOTAL_MEMORY; // if we don't know the start, set an invalid value and we will calculate it later from the indices
- GL.immediate.lastVertex = end ? end+1 : 0;
- GL.immediate.vertexData = {{{ makeHEAPView('F32', 'GL.immediate.vertexPointer', '(end ? GL.immediate.vertexPointer + (end+1)*GL.immediate.stride : TOTAL_MEMORY)') }}}; // XXX assuming float
+ GLImmediate.firstVertex = end ? start : TOTAL_MEMORY; // if we don't know the start, set an invalid value and we will calculate it later from the indices
+ GLImmediate.lastVertex = end ? end+1 : 0;
+ GLImmediate.vertexData = {{{ makeHEAPView('F32', 'GLImmediate.vertexPointer', '(end ? GLImmediate.vertexPointer + (end+1)*GLImmediate.stride : TOTAL_MEMORY)') }}}; // XXX assuming float
}
- GL.immediate.flush(count, 0, indices);
- GL.immediate.mode = -1;
+ GLImmediate.flush(count, 0, indices);
+ GLImmediate.mode = -1;
};
// TexEnv stuff needs to be prepared early, so do it here.
// init() is too late for -O2, since it freezes the GL functions
// by that point.
- GL.immediate.MapTreeLib = GL.immediate.spawnMapTreeLib();
- GL.immediate.spawnMapTreeLib = null;
+ GLImmediate.MapTreeLib = GLImmediate.spawnMapTreeLib();
+ GLImmediate.spawnMapTreeLib = null;
- GL.immediate.TexEnvJIT = GL.immediate.spawnTexEnvJIT();
- GL.immediate.spawnTexEnvJIT = null;
+ GLImmediate.TexEnvJIT = GLImmediate.spawnTexEnvJIT();
+ GLImmediate.spawnTexEnvJIT = null;
- GL.immediate.setupHooks();
+ GLImmediate.setupHooks();
},
setupHooks: function() {
@@ -3945,36 +4058,36 @@ var LibraryGL = {
var glActiveTexture = _glActiveTexture;
_glActiveTexture = function _glActiveTexture(texture) {
- GL.immediate.TexEnvJIT.hook_activeTexture(texture);
+ GLImmediate.TexEnvJIT.hook_activeTexture(texture);
glActiveTexture(texture);
};
var glEnable = _glEnable;
_glEnable = function _glEnable(cap) {
- GL.immediate.TexEnvJIT.hook_enable(cap);
+ GLImmediate.TexEnvJIT.hook_enable(cap);
glEnable(cap);
};
var glDisable = _glDisable;
_glDisable = function _glDisable(cap) {
- GL.immediate.TexEnvJIT.hook_disable(cap);
+ GLImmediate.TexEnvJIT.hook_disable(cap);
glDisable(cap);
};
var glTexEnvf = (typeof(_glTexEnvf) != 'undefined') ? _glTexEnvf : function(){};
_glTexEnvf = function _glTexEnvf(target, pname, param) {
- GL.immediate.TexEnvJIT.hook_texEnvf(target, pname, param);
+ GLImmediate.TexEnvJIT.hook_texEnvf(target, pname, param);
// Don't call old func, since we are the implementor.
//glTexEnvf(target, pname, param);
};
var glTexEnvi = (typeof(_glTexEnvi) != 'undefined') ? _glTexEnvi : function(){};
_glTexEnvi = function _glTexEnvi(target, pname, param) {
- GL.immediate.TexEnvJIT.hook_texEnvi(target, pname, param);
+ GLImmediate.TexEnvJIT.hook_texEnvi(target, pname, param);
// Don't call old func, since we are the implementor.
//glTexEnvi(target, pname, param);
};
var glTexEnvfv = (typeof(_glTexEnvfv) != 'undefined') ? _glTexEnvfv : function(){};
_glTexEnvfv = function _glTexEnvfv(target, pname, param) {
- GL.immediate.TexEnvJIT.hook_texEnvfv(target, pname, param);
+ GLImmediate.TexEnvJIT.hook_texEnvfv(target, pname, param);
// Don't call old func, since we are the implementor.
//glTexEnvfv(target, pname, param);
};
@@ -3984,8 +4097,8 @@ var LibraryGL = {
switch (pname) {
case 0x8B8D: { // GL_CURRENT_PROGRAM
// Just query directly so we're working with WebGL objects.
- var cur = Module.ctx.getParameter(Module.ctx.CURRENT_PROGRAM);
- if (cur == GL.immediate.fixedFunctionProgram) {
+ var cur = GLctx.getParameter(GLctx.CURRENT_PROGRAM);
+ if (cur == GLImmediate.fixedFunctionProgram) {
// Pretend we're not using a program.
{{{ makeSetValue('params', '0', '0', 'i32') }}};
return;
@@ -4001,56 +4114,49 @@ var LibraryGL = {
initted: false,
init: function() {
Module.printErr('WARNING: using emscripten GL immediate mode emulation. This is very limited in what it supports');
- GL.immediate.initted = true;
+ GLImmediate.initted = true;
if (!Module.useWebGL) return; // a 2D canvas may be currently used TODO: make sure we are actually called in that case
- this.TexEnvJIT.init(Module.ctx);
-
// 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.
- GL.immediate.MAX_TEXTURES = Module['GL_MAX_TEXTURE_IMAGE_UNITS'] || Module.ctx.getParameter(Module.ctx.MAX_TEXTURE_IMAGE_UNITS);
- GL.immediate.NUM_ATTRIBUTES = 3 /*pos+normal+color attributes*/ + GL.immediate.MAX_TEXTURES;
- GL.immediate.clientAttributes = [];
+ 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 = [];
- for (var i = 0; i < GL.immediate.NUM_ATTRIBUTES; i++) {
- GL.immediate.clientAttributes.push({});
+ for (var i = 0; i < GLImmediate.NUM_ATTRIBUTES; i++) {
+ GLImmediate.clientAttributes.push({});
GLEmulation.enabledClientAttribIndices.push(false);
}
- this.matrixStack['m'] = [];
- this.matrixStack['p'] = [];
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- this.matrixStack['t' + i] = [];
- }
-
// Initialize matrix library
// When user sets a matrix, increment a 'version number' on the new data, and when rendering, submit
// the matrices to the shader program only if they have an old version of the data.
- GL.immediate.matrixVersion = {};
- GL.immediate.matrix['m'] = GL.immediate.matrix.lib.mat4.create();
- GL.immediate.matrixVersion['m'] = 0;
- GL.immediate.matrix.lib.mat4.identity(GL.immediate.matrix['m']);
- GL.immediate.matrix['p'] = GL.immediate.matrix.lib.mat4.create();
- GL.immediate.matrixVersion['p'] = 0;
- GL.immediate.matrix.lib.mat4.identity(GL.immediate.matrix['p']);
- for (var i = 0; i < GL.immediate.MAX_TEXTURES; i++) {
- GL.immediate.matrix['t' + i] = GL.immediate.matrix.lib.mat4.create();
- GL.immediate.matrixVersion['t' + i] = 0;
+ GLImmediate.matrix = [];
+ GLImmediate.matrixStack = [];
+ GLImmediate.matrixVersion = [];
+ for (var i = 0; i < 2 + GLImmediate.MAX_TEXTURES; i++) { // Modelview, Projection, plus one matrix for each texture coordinate.
+ GLImmediate.matrixStack.push([]);
+ GLImmediate.matrixVersion.push(0);
+ GLImmediate.matrix.push(GLImmediate.matrixLib.mat4.create());
+ GLImmediate.matrixLib.mat4.identity(GLImmediate.matrix[i]);
}
// Renderer cache
- this.rendererCache = this.MapTreeLib.create();
+ GLImmediate.rendererCache = GLImmediate.MapTreeLib.create();
// Buffers for data
- this.tempData = new Float32Array(GL.MAX_TEMP_BUFFER_SIZE >> 2);
- this.indexData = new Uint16Array(GL.MAX_TEMP_BUFFER_SIZE >> 1);
+ GLImmediate.tempData = new Float32Array(GL.MAX_TEMP_BUFFER_SIZE >> 2);
+ GLImmediate.indexData = new Uint16Array(GL.MAX_TEMP_BUFFER_SIZE >> 1);
- this.vertexDataU8 = new Uint8Array(this.tempData.buffer);
+ GLImmediate.vertexDataU8 = new Uint8Array(GLImmediate.tempData.buffer);
GL.generateTempBuffers(true);
- this.clientColor = new Float32Array([1, 1, 1, 1]);
+ GLImmediate.clientColor = new Float32Array([1, 1, 1, 1]);
},
// Prepares and analyzes client attributes.
@@ -4061,97 +4167,111 @@ var LibraryGL = {
// If no client attributes were modified since we were last called, do nothing. Note that this
// does not work for glBegin/End, where we generate renderer components dynamically and then
// disable them ourselves, but it does help with glDrawElements/Arrays.
- if (!this.modifiedClientAttributes) {
- GL.immediate.vertexCounter = (GL.immediate.stride * count) / 4; // XXX assuming float
+ if (!GLImmediate.modifiedClientAttributes) {
+#if GL_ASSERTIONS
+ if ((GLImmediate.stride & 3) != 0) {
+ Runtime.warnOnce('Warning: Rendering from client side vertex arrays where stride (' + GLImmediate.stride + ') is not a multiple of four! This is not currently supported!');
+ }
+#endif
+ GLImmediate.vertexCounter = (GLImmediate.stride * count) / 4; // XXX assuming float
return;
}
- this.modifiedClientAttributes = false;
-
- var stride = 0, start;
- var attributes = GL.immediate.liveClientAttributes;
+ GLImmediate.modifiedClientAttributes = false;
+
+ // The role of prepareClientAttributes is to examine the set of client-side vertex attribute buffers
+ // that user code has submitted, and to prepare them to be uploaded to a VBO in GPU memory
+ // (since WebGL does not support client-side rendering, i.e. rendering from vertex data in CPU memory)
+ // User can submit vertex data generally in three different configurations:
+ // 1. Fully planar: all attributes are in their own separate tightly-packed arrays in CPU memory.
+ // 2. Fully interleaved: all attributes share a single array where data is interleaved something like (pos,uv,normal), (pos,uv,normal), ...
+ // 3. Complex hybrid: Multiple separate arrays that either are sparsely strided, and/or partially interleave vertex attributes.
+
+ // For simplicity, we support the case (2) as the fast case. For (1) and (3), we do a memory copy of the
+ // vertex data here to prepare a relayouted buffer that is of the structure in case (2). The reason
+ // for this is that it allows the emulation code to get away with using just one VBO buffer for rendering,
+ // and not have to maintain multiple ones. Therefore cases (1) and (3) will be very slow, and case (2) is fast.
+
+ // Detect which case we are in by using a quick heuristic by examining the strides of the buffers. If all the buffers have identical
+ // stride, we assume we have case (2), otherwise we have something more complex.
+ var clientStartPointer = 0x7FFFFFFF;
+ var bytes = 0; // Total number of bytes taken up by a single vertex.
+ var minStride = 0x7FFFFFFF;
+ var maxStride = 0;
+ var attributes = GLImmediate.liveClientAttributes;
attributes.length = 0;
- for (var i = 0; i < GL.immediate.NUM_ATTRIBUTES; i++) {
- if (GL.immediate.enabledClientAttributes[i]) attributes.push(GL.immediate.clientAttributes[i]);
- }
- attributes.sort(function(x, y) { return !x ? (!y ? 0 : 1) : (!y ? -1 : (x.pointer - y.pointer)) });
- start = GL.currArrayBuffer ? 0 : attributes[0].pointer;
- var multiStrides = false;
- for (var i = 0; i < attributes.length; i++) {
- var attribute = attributes[i];
- if (!attribute) break;
- if (stride != 0 && stride != attribute.stride) multiStrides = true;
- if (attribute.stride) stride = attribute.stride;
+ for (var i = 0; i < 3+GLImmediate.MAX_TEXTURES; i++) {
+ if (GLImmediate.enabledClientAttributes[i]) {
+ var attr = GLImmediate.clientAttributes[i];
+ attributes.push(attr);
+ clientStartPointer = Math.min(clientStartPointer, attr.pointer);
+ attr.sizeBytes = attr.size * GL.byteSizeByType[attr.type - GL.byteSizeByTypeRoot];
+ bytes += attr.sizeBytes;
+ minStride = Math.min(minStride, attr.stride);
+ maxStride = Math.max(maxStride, attr.stride);
+ }
}
- if (multiStrides) stride = 0; // we will need to restride
- var bytes = 0; // total size in bytes
- if (!stride && !beginEnd) {
- // beginEnd can not have stride in the attributes, that is fine. otherwise,
- // no stride means that all attributes are in fact packed. to keep the rest of
- // our emulation code simple, we perform unpacking/restriding here. this adds overhead, so
- // it is a good idea to not hit this!
-#if ASSERTIONS
- Runtime.warnOnce('Unpacking/restriding attributes, this is slow and dangerous');
-#endif
- if (!GL.immediate.restrideBuffer) GL.immediate.restrideBuffer = _malloc(GL.MAX_TEMP_BUFFER_SIZE);
- start = GL.immediate.restrideBuffer;
-#if ASSERTIONS
- assert(start % 4 == 0);
+ if ((minStride != maxStride || maxStride < bytes) && !beginEnd) {
+ // We are in cases (1) or (3): slow path, shuffle the data around into a single interleaved vertex buffer.
+ // The immediate-mode glBegin()/glEnd() vertex submission gets automatically generated in appropriate layout,
+ // so never need to come down this path if that was used.
+#if GL_ASSERTIONS
+ Runtime.warnOnce('Rendering from planar client-side vertex arrays. This is a very slow emulation path! Use interleaved vertex arrays for best performance.');
#endif
+ if (!GLImmediate.restrideBuffer) GLImmediate.restrideBuffer = _malloc(GL.MAX_TEMP_BUFFER_SIZE);
+ var start = GLImmediate.restrideBuffer;
+ bytes = 0;
// calculate restrided offsets and total size
for (var i = 0; i < attributes.length; i++) {
- var attribute = attributes[i];
- if (!attribute) break;
- var size = attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
+ var attr = attributes[i];
+ var size = attr.sizeBytes;
if (size % 4 != 0) size += 4 - (size % 4); // align everything
- attribute.offset = bytes;
+ attr.offset = bytes;
bytes += size;
}
-#if ASSERTIONS
- assert(count*bytes <= GL.MAX_TEMP_BUFFER_SIZE);
-#endif
- // copy out the data (we need to know the stride for that, and define attribute.pointer
+ // copy out the data (we need to know the stride for that, and define attr.pointer)
for (var i = 0; i < attributes.length; i++) {
- var attribute = attributes[i];
- if (!attribute) break;
- var size4 = Math.floor((attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot])/4);
- for (var j = 0; j < count; j++) {
- for (var k = 0; k < size4; k++) { // copy in chunks of 4 bytes, our alignment makes this possible
- HEAP32[((start + attribute.offset + bytes*j)>>2) + k] = HEAP32[(attribute.pointer>>2) + j*size4 + k];
+ var attr = attributes[i];
+ var srcStride = Math.max(attr.sizeBytes, attr.stride);
+ if ((srcStride & 3) == 0 && (attr.sizeBytes & 3) == 0) {
+ var size4 = attr.sizeBytes>>2;
+ var srcStride4 = Math.max(attr.sizeBytes, attr.stride)>>2;
+ for (var j = 0; j < count; j++) {
+ for (var k = 0; k < size4; k++) { // copy in chunks of 4 bytes, our alignment makes this possible
+ HEAP32[((start + attr.offset + bytes*j)>>2) + k] = HEAP32[(attr.pointer>>2) + j*srcStride4 + k];
+ }
+ }
+ } else {
+ for (var j = 0; j < count; j++) {
+ for (var k = 0; k < attr.sizeBytes; k++) { // source data was not aligned to multiples of 4, must copy byte by byte.
+ HEAP8[start + attr.offset + bytes*j + k] = HEAP8[attr.pointer + j*srcStride + k];
+ }
}
}
- attribute.pointer = start + attribute.offset;
+ attr.pointer = start + attr.offset;
}
+ GLImmediate.stride = bytes;
+ GLImmediate.vertexPointer = start;
} else {
- // normal situation, everything is strided and in the same buffer
- for (var i = 0; i < attributes.length; i++) {
- var attribute = attributes[i];
- if (!attribute) break;
- attribute.offset = attribute.pointer - start;
- if (attribute.offset > bytes) { // ensure we start where we should
-#if ASSERTIONS
- assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
-#endif
- bytes += attribute.offset - bytes;
- }
- bytes += attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
- if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
+ // case (2): fast path, all data is interleaved to a single vertex array so we can get away with a single VBO upload.
+ if (GL.currArrayBuffer) {
+ GLImmediate.vertexPointer = 0;
+ } else {
+ GLImmediate.vertexPointer = clientStartPointer;
}
-#if ASSERTIONS
- assert(beginEnd || bytes <= stride); // if not begin-end, explicit stride should make sense with total byte size
-#endif
- if (bytes < stride) { // ensure the size is that of the stride
- bytes = stride;
+ for (var i = 0; i < attributes.length; i++) {
+ var attr = attributes[i];
+ attr.offset = attr.pointer - GLImmediate.vertexPointer; // Compute what will be the offset of this attribute in the VBO after we upload.
}
+ GLImmediate.stride = Math.max(maxStride, bytes);
}
- GL.immediate.stride = bytes;
-
if (!beginEnd) {
- bytes *= count;
- if (!GL.currArrayBuffer) {
- GL.immediate.vertexPointer = start;
+#if GL_ASSERTIONS
+ if ((GLImmediate.stride & 3) != 0) {
+ Runtime.warnOnce('Warning: Rendering from client side vertex arrays where stride (' + GLImmediate.stride + ') is not a multiple of four! This is not currently supported!');
}
- GL.immediate.vertexCounter = bytes / 4; // XXX assuming float
+#endif
+ GLImmediate.vertexCounter = (GLImmediate.stride * count) / 4; // XXX assuming float
}
},
@@ -4162,10 +4282,10 @@ var LibraryGL = {
startIndex = startIndex || 0;
ptr = ptr || 0;
- var renderer = this.getRenderer();
+ var renderer = GLImmediate.getRenderer();
// Generate index data in a format suitable for GLES 2.0/WebGL
- var numVertexes = 4 * this.vertexCounter / GL.immediate.stride;
+ var numVertexes = 4 * GLImmediate.vertexCounter / GLImmediate.stride;
#if ASSERTIONS
assert(numVertexes % 1 == 0, "`numVertexes` must be an integer.");
#endif
@@ -4173,7 +4293,7 @@ var LibraryGL = {
var numIndexes = 0;
if (numProvidedIndexes) {
numIndexes = numProvidedIndexes;
- if (!GL.currArrayBuffer && GL.immediate.firstVertex > GL.immediate.lastVertex) {
+ if (!GL.currArrayBuffer && GLImmediate.firstVertex > GLImmediate.lastVertex) {
// Figure out the first and last vertex from the index data
#if ASSERTIONS
assert(!GL.currElementArrayBuffer); // If we are going to upload array buffer data, we need to find which range to
@@ -4183,8 +4303,8 @@ var LibraryGL = {
#endif
for (var i = 0; i < numProvidedIndexes; i++) {
var currIndex = {{{ makeGetValue('ptr', 'i*2', 'i16', null, 1) }}};
- GL.immediate.firstVertex = Math.min(GL.immediate.firstVertex, currIndex);
- GL.immediate.lastVertex = Math.max(GL.immediate.lastVertex, currIndex+1);
+ GLImmediate.firstVertex = Math.min(GLImmediate.firstVertex, currIndex);
+ GLImmediate.lastVertex = Math.max(GLImmediate.lastVertex, currIndex+1);
}
}
if (!GL.currElementArrayBuffer) {
@@ -4192,99 +4312,102 @@ 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]];
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, indexBuffer);
- Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (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;
emulatedElementArrayBuffer = true;
}
- } else if (GL.immediate.mode > 6) { // above GL_TRIANGLE_FAN are the non-GL ES modes
- if (GL.immediate.mode != 7) throw 'unsupported immediate mode ' + GL.immediate.mode; // GL_QUADS
- // GL.immediate.firstVertex is the first vertex we want. Quad indexes are in the pattern
+ } else if (GLImmediate.mode > 6) { // above GL_TRIANGLE_FAN are the non-GL ES modes
+ if (GLImmediate.mode != 7) throw 'unsupported immediate mode ' + GLImmediate.mode; // GL_QUADS
+ // GLImmediate.firstVertex is the first vertex we want. Quad indexes are in the pattern
// 0 1 2, 0 2 3, 4 5 6, 4 6 7, so we need to look at index firstVertex * 1.5 to see it.
// Then since indexes are 2 bytes each, that means 3
#if ASSERTIONS
- assert(GL.immediate.firstVertex % 4 == 0);
+ assert(GLImmediate.firstVertex % 4 == 0);
#endif
- ptr = GL.immediate.firstVertex*3;
+ ptr = GLImmediate.firstVertex*3;
var numQuads = numVertexes / 4;
numIndexes = numQuads * 6; // 0 1 2, 0 2 3 pattern
#if ASSERTIONS
assert(ptr + (numIndexes << 1) <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (b)');
#endif
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempQuadIndexBuffer);
emulatedElementArrayBuffer = true;
}
renderer.prepare();
if (numIndexes) {
- Module.ctx.drawElements(Module.ctx.TRIANGLES, numIndexes, Module.ctx.UNSIGNED_SHORT, ptr);
+ GLctx.drawElements(GLctx.TRIANGLES, numIndexes, GLctx.UNSIGNED_SHORT, ptr);
} else {
- Module.ctx.drawArrays(GL.immediate.mode, startIndex, numVertexes);
+ GLctx.drawArrays(GLImmediate.mode, startIndex, numVertexes);
}
if (emulatedElementArrayBuffer) {
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null);
}
-#if GL_UNSAFE_OPTS == 0 && !GL_FFP_ONLY
+#if GL_UNSAFE_OPTS == 0
+#if !GL_FFP_ONLY
renderer.cleanup();
#endif
+#endif
}
},
- $GLImmediateSetup__deps: ['$GLImmediate', function() { return 'GL.immediate = GLImmediate; GL.immediate.matrix.lib = ' + read('gl-matrix.js') + ';\n' }],
+ $GLImmediateSetup: {},
+ $GLImmediateSetup__deps: ['$GLImmediate', function() { return 'GLImmediate.matrixLib = ' + read('gl-matrix.js') + ';\n' }],
$GLImmediateSetup: {},
glBegin__deps: ['$GLImmediateSetup'],
glBegin: function(mode) {
// Push the old state:
- GL.immediate.enabledClientAttributes_preBegin = GL.immediate.enabledClientAttributes;
- GL.immediate.enabledClientAttributes = [];
+ GLImmediate.enabledClientAttributes_preBegin = GLImmediate.enabledClientAttributes;
+ GLImmediate.enabledClientAttributes = [];
- GL.immediate.clientAttributes_preBegin = GL.immediate.clientAttributes;
- GL.immediate.clientAttributes = []
- for (var i = 0; i < GL.immediate.clientAttributes_preBegin.length; i++) {
- GL.immediate.clientAttributes.push({});
+ GLImmediate.clientAttributes_preBegin = GLImmediate.clientAttributes;
+ GLImmediate.clientAttributes = []
+ for (var i = 0; i < GLImmediate.clientAttributes_preBegin.length; i++) {
+ GLImmediate.clientAttributes.push({});
}
- GL.immediate.mode = mode;
- GL.immediate.vertexCounter = 0;
- var components = GL.immediate.rendererComponents = [];
- for (var i = 0; i < GL.immediate.NUM_ATTRIBUTES; i++) {
+ GLImmediate.mode = mode;
+ GLImmediate.vertexCounter = 0;
+ var components = GLImmediate.rendererComponents = [];
+ for (var i = 0; i < GLImmediate.NUM_ATTRIBUTES; i++) {
components[i] = 0;
}
- GL.immediate.rendererComponentPointer = 0;
- GL.immediate.vertexData = GL.immediate.tempData;
+ GLImmediate.rendererComponentPointer = 0;
+ GLImmediate.vertexData = GLImmediate.tempData;
},
glEnd: function() {
- GL.immediate.prepareClientAttributes(GL.immediate.rendererComponents[GL.immediate.VERTEX], true);
- GL.immediate.firstVertex = 0;
- GL.immediate.lastVertex = GL.immediate.vertexCounter / (GL.immediate.stride >> 2);
- GL.immediate.flush();
- GL.immediate.disableBeginEndClientAttributes();
- GL.immediate.mode = -1;
+ GLImmediate.prepareClientAttributes(GLImmediate.rendererComponents[GLImmediate.VERTEX], true);
+ GLImmediate.firstVertex = 0;
+ GLImmediate.lastVertex = GLImmediate.vertexCounter / (GLImmediate.stride >> 2);
+ GLImmediate.flush();
+ GLImmediate.disableBeginEndClientAttributes();
+ GLImmediate.mode = -1;
// Pop the old state:
- GL.immediate.enabledClientAttributes = GL.immediate.enabledClientAttributes_preBegin;
- GL.immediate.clientAttributes = GL.immediate.clientAttributes_preBegin;
-
- GL.immediate.modifiedClientAttributes = true;
+ GLImmediate.enabledClientAttributes = GLImmediate.enabledClientAttributes_preBegin;
+ GLImmediate.clientAttributes = GLImmediate.clientAttributes_preBegin;
+ GLImmediate.currentRenderer = null; // The set of active client attributes changed, we must re-lookup the renderer to use.
+ GLImmediate.modifiedClientAttributes = true;
},
glVertex3f: function(x, y, z) {
#if ASSERTIONS
- assert(GL.immediate.mode >= 0); // must be in begin/end
+ assert(GLImmediate.mode >= 0); // must be in begin/end
#endif
- GL.immediate.vertexData[GL.immediate.vertexCounter++] = x;
- GL.immediate.vertexData[GL.immediate.vertexCounter++] = y;
- GL.immediate.vertexData[GL.immediate.vertexCounter++] = z || 0;
+ GLImmediate.vertexData[GLImmediate.vertexCounter++] = x;
+ GLImmediate.vertexData[GLImmediate.vertexCounter++] = y;
+ GLImmediate.vertexData[GLImmediate.vertexCounter++] = z || 0;
#if ASSERTIONS
- assert(GL.immediate.vertexCounter << 2 < GL.MAX_TEMP_BUFFER_SIZE);
+ assert(GLImmediate.vertexCounter << 2 < GL.MAX_TEMP_BUFFER_SIZE);
#endif
- GL.immediate.addRendererComponent(GL.immediate.VERTEX, 3, Module.ctx.FLOAT);
+ GLImmediate.addRendererComponent(GLImmediate.VERTEX, 3, GLctx.FLOAT);
},
glVertex2f: 'glVertex3f',
@@ -4303,11 +4426,11 @@ var LibraryGL = {
glTexCoord2i: function(u, v) {
#if ASSERTIONS
- assert(GL.immediate.mode >= 0); // must be in begin/end
+ assert(GLImmediate.mode >= 0); // must be in begin/end
#endif
- GL.immediate.vertexData[GL.immediate.vertexCounter++] = u;
- GL.immediate.vertexData[GL.immediate.vertexCounter++] = v;
- GL.immediate.addRendererComponent(GL.immediate.TEXTURE0, 2, Module.ctx.FLOAT);
+ GLImmediate.vertexData[GLImmediate.vertexCounter++] = u;
+ GLImmediate.vertexData[GLImmediate.vertexCounter++] = v;
+ GLImmediate.addRendererComponent(GLImmediate.TEXTURE0, 2, GLctx.FLOAT);
},
glTexCoord2f: 'glTexCoord2i',
@@ -4325,19 +4448,19 @@ var LibraryGL = {
a = Math.max(Math.min(a, 1), 0);
// TODO: make ub the default, not f, save a few mathops
- if (GL.immediate.mode >= 0) {
- var start = GL.immediate.vertexCounter << 2;
- GL.immediate.vertexDataU8[start + 0] = r * 255;
- GL.immediate.vertexDataU8[start + 1] = g * 255;
- GL.immediate.vertexDataU8[start + 2] = b * 255;
- GL.immediate.vertexDataU8[start + 3] = a * 255;
- GL.immediate.vertexCounter++;
- GL.immediate.addRendererComponent(GL.immediate.COLOR, 4, Module.ctx.UNSIGNED_BYTE);
+ if (GLImmediate.mode >= 0) {
+ var start = GLImmediate.vertexCounter << 2;
+ GLImmediate.vertexDataU8[start + 0] = r * 255;
+ GLImmediate.vertexDataU8[start + 1] = g * 255;
+ GLImmediate.vertexDataU8[start + 2] = b * 255;
+ GLImmediate.vertexDataU8[start + 3] = a * 255;
+ GLImmediate.vertexCounter++;
+ GLImmediate.addRendererComponent(GLImmediate.COLOR, 4, GLctx.UNSIGNED_BYTE);
} else {
- GL.immediate.clientColor[0] = r;
- GL.immediate.clientColor[1] = g;
- GL.immediate.clientColor[2] = b;
- GL.immediate.clientColor[3] = a;
+ GLImmediate.clientColor[0] = r;
+ GLImmediate.clientColor[1] = g;
+ GLImmediate.clientColor[2] = b;
+ GLImmediate.clientColor[3] = a;
}
},
glColor4d: 'glColor4f',
@@ -4409,9 +4532,17 @@ var LibraryGL = {
switch (param) {
case 0x0801: // GL_EXP2
case 0x2601: // GL_LINEAR
- GLEmulation.fogMode = param; break;
+ if (GLEmulation.fogMode != param) {
+ GLImmediate.currentRenderer = null; // Fog mode is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogMode = param;
+ }
+ break;
default: // default to GL_EXP
- GLEmulation.fogMode = 0x0800 /* GL_EXP */; break;
+ if (GLEmulation.fogMode != 0x0800 /* GL_EXP */) {
+ GLImmediate.currentRenderer = null; // Fog mode is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogMode = 0x0800 /* GL_EXP */;
+ }
+ break;
}
break;
}
@@ -4465,7 +4596,7 @@ var LibraryGL = {
// ClientState/gl*Pointer
- glEnableClientState: function(cap, disable) {
+ glEnableClientState: function(cap) {
var attrib = GLEmulation.getAttributeFromCapability(cap);
if (attrib === null) {
#if ASSERTIONS
@@ -4473,65 +4604,73 @@ var LibraryGL = {
#endif
return;
}
- if (disable && GL.immediate.enabledClientAttributes[attrib]) {
- GL.immediate.enabledClientAttributes[attrib] = false;
- GL.immediate.totalEnabledClientAttributes--;
- this.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
- if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap];
- } else if (!disable && !GL.immediate.enabledClientAttributes[attrib]) {
- GL.immediate.enabledClientAttributes[attrib] = true;
- GL.immediate.totalEnabledClientAttributes++;
- this.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
+ if (!GLImmediate.enabledClientAttributes[attrib]) {
+ GLImmediate.enabledClientAttributes[attrib] = true;
+ GLImmediate.totalEnabledClientAttributes++;
+ GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1;
+ GLImmediate.modifiedClientAttributes = true;
}
- GL.immediate.modifiedClientAttributes = true;
},
glDisableClientState: function(cap) {
- _glEnableClientState(cap, 1);
+ var attrib = GLEmulation.getAttributeFromCapability(cap);
+ if (attrib === null) {
+#if ASSERTIONS
+ Module.printErr('WARNING: unhandled clientstate: ' + cap);
+#endif
+ return;
+ }
+ if (GLImmediate.enabledClientAttributes[attrib]) {
+ GLImmediate.enabledClientAttributes[attrib] = false;
+ GLImmediate.totalEnabledClientAttributes--;
+ GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed.
+ if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap];
+ GLImmediate.modifiedClientAttributes = true;
+ }
},
glVertexPointer__deps: ['$GLEmulation'], // if any pointers are used, glVertexPointer must be, and if it is, then we need emulation
glVertexPointer: function(size, type, stride, pointer) {
- GL.immediate.setClientAttribute(GL.immediate.VERTEX, size, type, stride, pointer);
+ GLImmediate.setClientAttribute(GLImmediate.VERTEX, size, type, stride, pointer);
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
- Module.ctx.vertexAttribPointer(GL.immediate.VERTEX, size, type, false, stride, pointer);
- GL.enableVertexAttribArray(GL.immediate.VERTEX);
+ GLctx.vertexAttribPointer(GLImmediate.VERTEX, size, type, false, stride, pointer);
+ GL.enableVertexAttribArray(GLImmediate.VERTEX);
}
#endif
},
glTexCoordPointer: function(size, type, stride, pointer) {
- GL.immediate.setClientAttribute(GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture, size, type, stride, pointer);
+ GLImmediate.setClientAttribute(GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture, size, type, stride, pointer);
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
- var loc = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture;
- Module.ctx.vertexAttribPointer(loc, size, type, false, stride, pointer);
+ var loc = GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture;
+ GLctx.vertexAttribPointer(loc, size, type, false, stride, pointer);
GL.enableVertexAttribArray(loc);
}
#endif
},
glNormalPointer: function(type, stride, pointer) {
- GL.immediate.setClientAttribute(GL.immediate.NORMAL, 3, type, stride, pointer);
+ GLImmediate.setClientAttribute(GLImmediate.NORMAL, 3, type, stride, pointer);
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
- Module.ctx.vertexAttribPointer(GL.immediate.NORMAL, size, type, true, stride, pointer);
- GL.enableVertexAttribArray(GL.immediate.NORMAL);
+ GLctx.vertexAttribPointer(GLImmediate.NORMAL, size, type, true, stride, pointer);
+ GL.enableVertexAttribArray(GLImmediate.NORMAL);
}
#endif
},
glColorPointer: function(size, type, stride, pointer) {
- GL.immediate.setClientAttribute(GL.immediate.COLOR, size, type, stride, pointer);
+ GLImmediate.setClientAttribute(GLImmediate.COLOR, size, type, stride, pointer);
#if GL_FFP_ONLY
if (GL.currArrayBuffer) {
- Module.ctx.vertexAttribPointer(GL.immediate.COLOR, size, type, true, stride, pointer);
- GL.enableVertexAttribArray(GL.immediate.COLOR);
+ GLctx.vertexAttribPointer(GLImmediate.COLOR, size, type, true, stride, pointer);
+ GL.enableVertexAttribArray(GLImmediate.COLOR);
}
#endif
},
glClientActiveTexture__sig: 'vi',
glClientActiveTexture: function(texture) {
- GL.immediate.clientActiveTexture = texture - 0x84C0; // GL_TEXTURE0
+ GLImmediate.clientActiveTexture = texture - 0x84C0; // GL_TEXTURE0
},
// Vertex array object (VAO) support. TODO: when the WebGL extension is popular, use that and remove this code and GL.vaos
@@ -4563,21 +4702,21 @@ var LibraryGL = {
glBindVertexArray: function(vao) {
// undo vao-related things, wipe the slate clean, both for vao of 0 or an actual vao
GLEmulation.currentVao = null; // make sure the commands we run here are not recorded
- if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
- _glBindBuffer(Module.ctx.ARRAY_BUFFER, 0); // XXX if one was there before we were bound?
- _glBindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, 0);
+ if (GLImmediate.lastRenderer) GLImmediate.lastRenderer.cleanup();
+ _glBindBuffer(GLctx.ARRAY_BUFFER, 0); // XXX if one was there before we were bound?
+ _glBindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, 0);
for (var vaa in GLEmulation.enabledVertexAttribArrays) {
- Module.ctx.disableVertexAttribArray(vaa);
+ GLctx.disableVertexAttribArray(vaa);
}
GLEmulation.enabledVertexAttribArrays = {};
- GL.immediate.enabledClientAttributes = [0, 0];
- GL.immediate.totalEnabledClientAttributes = 0;
- GL.immediate.modifiedClientAttributes = true;
+ GLImmediate.enabledClientAttributes = [0, 0];
+ GLImmediate.totalEnabledClientAttributes = 0;
+ GLImmediate.modifiedClientAttributes = true;
if (vao) {
// replay vao
var info = GLEmulation.vaos[vao];
- _glBindBuffer(Module.ctx.ARRAY_BUFFER, info.arrayBuffer); // XXX overwrite current binding?
- _glBindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, info.elementArrayBuffer);
+ _glBindBuffer(GLctx.ARRAY_BUFFER, info.arrayBuffer); // XXX overwrite current binding?
+ _glBindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, info.elementArrayBuffer);
for (var vaa in info.enabledVertexAttribArrays) {
_glEnableVertexAttribArray(vaa);
}
@@ -4596,132 +4735,132 @@ var LibraryGL = {
glMatrixMode__deps: ['$GL', '$GLImmediateSetup', '$GLEmulation'], // emulation is not strictly needed, this is a workaround
glMatrixMode: function(mode) {
if (mode == 0x1700 /* GL_MODELVIEW */) {
- GL.immediate.currentMatrix = 'm';
+ GLImmediate.currentMatrix = 0/*m*/;
} else if (mode == 0x1701 /* GL_PROJECTION */) {
- GL.immediate.currentMatrix = 'p';
+ GLImmediate.currentMatrix = 1/*p*/;
} else if (mode == 0x1702) { // GL_TEXTURE
- GL.immediate.useTextureMatrix = true;
- GL.immediate.currentMatrix = 't' + GL.immediate.clientActiveTexture;
+ GLImmediate.useTextureMatrix = true;
+ GLImmediate.currentMatrix = 2/*t*/ + GLImmediate.clientActiveTexture;
} else {
throw "Wrong mode " + mode + " passed to glMatrixMode";
}
},
glPushMatrix: function() {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrixStack[GL.immediate.currentMatrix].push(
- Array.prototype.slice.call(GL.immediate.matrix[GL.immediate.currentMatrix]));
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixStack[GLImmediate.currentMatrix].push(
+ Array.prototype.slice.call(GLImmediate.matrix[GLImmediate.currentMatrix]));
},
glPopMatrix: function() {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix[GL.immediate.currentMatrix] = GL.immediate.matrixStack[GL.immediate.currentMatrix].pop();
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrix[GLImmediate.currentMatrix] = GLImmediate.matrixStack[GLImmediate.currentMatrix].pop();
},
glLoadIdentity__deps: ['$GL', '$GLImmediateSetup'],
glLoadIdentity: function() {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.identity(GL.immediate.matrix[GL.immediate.currentMatrix]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.identity(GLImmediate.matrix[GLImmediate.currentMatrix]);
},
glLoadMatrixd: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GLImmediate.matrix[GLImmediate.currentMatrix]);
},
glLoadMatrixf: function(matrix) {
#if GL_DEBUG
if (GL.debug) Module.printErr('glLoadMatrixf receiving: ' + Array.prototype.slice.call(HEAPF32.subarray(matrix >> 2, (matrix >> 2) + 16)));
#endif
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GLImmediate.matrix[GLImmediate.currentMatrix]);
},
glLoadTransposeMatrixd: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
- GL.immediate.matrix.lib.mat4.transpose(GL.immediate.matrix[GL.immediate.currentMatrix]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GLImmediate.matrix[GLImmediate.currentMatrix]);
+ GLImmediate.matrixLib.mat4.transpose(GLImmediate.matrix[GLImmediate.currentMatrix]);
},
glLoadTransposeMatrixf: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GL.immediate.matrix[GL.immediate.currentMatrix]);
- GL.immediate.matrix.lib.mat4.transpose(GL.immediate.matrix[GL.immediate.currentMatrix]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, GLImmediate.matrix[GLImmediate.currentMatrix]);
+ GLImmediate.matrixLib.mat4.transpose(GLImmediate.matrix[GLImmediate.currentMatrix]);
},
glMultMatrixd: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.multiply(GLImmediate.matrix[GLImmediate.currentMatrix],
{{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}});
},
glMultMatrixf: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.multiply(GLImmediate.matrix[GLImmediate.currentMatrix],
{{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}});
},
glMultTransposeMatrixd: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- var colMajor = GL.immediate.matrix.lib.mat4.create();
- GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, colMajor);
- GL.immediate.matrix.lib.mat4.transpose(colMajor);
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix], colMajor);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ var colMajor = GLImmediate.matrixLib.mat4.create();
+ GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, colMajor);
+ GLImmediate.matrixLib.mat4.transpose(colMajor);
+ GLImmediate.matrixLib.mat4.multiply(GLImmediate.matrix[GLImmediate.currentMatrix], colMajor);
},
glMultTransposeMatrixf: function(matrix) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- var colMajor = GL.immediate.matrix.lib.mat4.create();
- GL.immediate.matrix.lib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, colMajor);
- GL.immediate.matrix.lib.mat4.transpose(colMajor);
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix], colMajor);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ var colMajor = GLImmediate.matrixLib.mat4.create();
+ GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F32', 'matrix', 'matrix+' + (16*4)) }}}, colMajor);
+ GLImmediate.matrixLib.mat4.transpose(colMajor);
+ GLImmediate.matrixLib.mat4.multiply(GLImmediate.matrix[GLImmediate.currentMatrix], colMajor);
},
glFrustum: function(left, right, bottom, top_, nearVal, farVal) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
- GL.immediate.matrix.lib.mat4.frustum(left, right, bottom, top_, nearVal, farVal));
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.multiply(GLImmediate.matrix[GLImmediate.currentMatrix],
+ GLImmediate.matrixLib.mat4.frustum(left, right, bottom, top_, nearVal, farVal));
},
glFrustumf: 'glFrustum',
glOrtho: function(left, right, bottom, top_, nearVal, farVal) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.multiply(GL.immediate.matrix[GL.immediate.currentMatrix],
- GL.immediate.matrix.lib.mat4.ortho(left, right, bottom, top_, nearVal, farVal));
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.multiply(GLImmediate.matrix[GLImmediate.currentMatrix],
+ GLImmediate.matrixLib.mat4.ortho(left, right, bottom, top_, nearVal, farVal));
},
glOrthof: 'glOrtho',
glScaled: function(x, y, z) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.scale(GL.immediate.matrix[GL.immediate.currentMatrix], [x, y, z]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.scale(GLImmediate.matrix[GLImmediate.currentMatrix], [x, y, z]);
},
glScalef: 'glScaled',
glTranslated: function(x, y, z) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.translate(GL.immediate.matrix[GL.immediate.currentMatrix], [x, y, z]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.translate(GLImmediate.matrix[GLImmediate.currentMatrix], [x, y, z]);
},
glTranslatef: 'glTranslated',
glRotated: function(angle, x, y, z) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.rotate(GL.immediate.matrix[GL.immediate.currentMatrix], angle*Math.PI/180, [x, y, z]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.rotate(GLImmediate.matrix[GLImmediate.currentMatrix], angle*Math.PI/180, [x, y, z]);
},
glRotatef: 'glRotated',
@@ -4802,17 +4941,17 @@ var LibraryGL = {
// GLU
gluPerspective: function(fov, aspect, near, far) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix[GL.immediate.currentMatrix] =
- GL.immediate.matrix.lib.mat4.perspective(fov, aspect, near, far,
- GL.immediate.matrix[GL.immediate.currentMatrix]);
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrix[GLImmediate.currentMatrix] =
+ GLImmediate.matrixLib.mat4.perspective(fov, aspect, near, far,
+ GLImmediate.matrix[GLImmediate.currentMatrix]);
},
gluLookAt: function(ex, ey, ez, cx, cy, cz, ux, uy, uz) {
- GL.immediate.matricesModified = true;
- GL.immediate.matrixVersion[GL.immediate.currentMatrix] = (GL.immediate.matrixVersion[GL.immediate.currentMatrix] + 1)|0;
- GL.immediate.matrix.lib.mat4.lookAt(GL.immediate.matrix[GL.immediate.currentMatrix], [ex, ey, ez],
+ GLImmediate.matricesModified = true;
+ GLImmediate.matrixVersion[GLImmediate.currentMatrix] = (GLImmediate.matrixVersion[GLImmediate.currentMatrix] + 1)|0;
+ GLImmediate.matrixLib.mat4.lookAt(GLImmediate.matrix[GLImmediate.currentMatrix], [ex, ey, ez],
[cx, cy, cz], [ux, uy, uz]);
},
@@ -4821,9 +4960,9 @@ var LibraryGL = {
var inVec = new Float32Array(4);
var outVec = new Float32Array(4);
- GL.immediate.matrix.lib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'model', 'model+' + (16*8)) }}},
+ GLImmediate.matrixLib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'model', 'model+' + (16*8)) }}},
[objX, objY, objZ, 1.0], outVec);
- GL.immediate.matrix.lib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'proj', 'proj+' + (16*8)) }}},
+ GLImmediate.matrixLib.mat4.multiplyVec4({{{ makeHEAPView('F64', 'proj', 'proj+' + (16*8)) }}},
outVec, inVec);
if (inVec[3] == 0.0) {
return 0 /* GL_FALSE */;
@@ -4847,7 +4986,7 @@ var LibraryGL = {
},
gluUnProject: function(winX, winY, winZ, model, proj, view, objX, objY, objZ) {
- var result = GL.immediate.matrix.lib.mat4.unproject([winX, winY, winZ],
+ var result = GLImmediate.matrixLib.mat4.unproject([winX, winY, winZ],
{{{ makeHEAPView('F64', 'model', 'model+' + (16*8)) }}},
{{{ makeHEAPView('F64', 'proj', 'proj+' + (16*8)) }}},
{{{ makeHEAPView('32', 'view', 'view+' + (4*4)) }}});
@@ -4891,7 +5030,7 @@ var LibraryGL = {
#if GL_ASSERTIONS
GL.validateVertexAttribPointer(size, type, stride, ptr);
#endif
- Module.ctx.vertexAttribPointer(index, size, type, normalized, stride, ptr);
+ GLctx.vertexAttribPointer(index, size, type, normalized, stride, ptr);
},
glEnableVertexAttribArray__sig: 'vi',
@@ -4903,7 +5042,7 @@ var LibraryGL = {
#endif
cb.enabled = true;
#endif
- Module.ctx.enableVertexAttribArray(index);
+ GLctx.enableVertexAttribArray(index);
},
glDisableVertexAttribArray__sig: 'vi',
@@ -4915,7 +5054,7 @@ var LibraryGL = {
#endif
cb.enabled = false;
#endif
- Module.ctx.disableVertexAttribArray(index);
+ GLctx.disableVertexAttribArray(index);
},
glDrawArrays__sig: 'viii',
@@ -4925,7 +5064,7 @@ var LibraryGL = {
GL.preDrawHandleClientVertexAttribBindings(first + count);
#endif
- Module.ctx.drawArrays(mode, first, count);
+ GLctx.drawArrays(mode, first, count);
#if FULL_ES2
GL.postDrawHandleClientVertexAttribBindings();
@@ -4938,9 +5077,9 @@ var LibraryGL = {
var buf;
if (!GL.currElementArrayBuffer) {
var size = GL.calcBufLength(1, type, 0, count);
- buf = GL.tempIndexBuffers[GL.tempBufferIndexLookup[size]];
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, buf);
- Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER,
+ buf = GL.getTempIndexBuffer(size);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, buf);
+ GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER,
0,
HEAPU8.subarray(indices, indices + size));
// the index is now 0
@@ -4951,13 +5090,13 @@ var LibraryGL = {
GL.preDrawHandleClientVertexAttribBindings(count);
#endif
- Module.ctx.drawElements(mode, count, type, indices);
+ GLctx.drawElements(mode, count, type, indices);
#if FULL_ES2
GL.postDrawHandleClientVertexAttribBindings(count);
if (!GL.currElementArrayBuffer) {
- Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, null);
}
#endif
},
@@ -4983,7 +5122,7 @@ var LibraryGL = {
GL.lastError = 0/*GL_NO_ERROR*/;
return error;
} else { // If there were none, return the GL error from the browser GL context.
- return Module.ctx.getError();
+ return GLctx.getError();
}
},
@@ -5074,8 +5213,8 @@ var LibraryGL = {
var num = data[0];
var names = data[1];
var args = range(num).map(function(i) { return 'x' + i }).join(', ');
- var plainStub = '(function(' + args + ') { Module.ctx.NAME(' + args + ') })';
- var returnStub = '(function(' + args + ') { return Module.ctx.NAME(' + args + ') })';
+ var plainStub = '(function(' + args + ') { GLctx.NAME(' + args + ') })';
+ var returnStub = '(function(' + args + ') { return GLctx.NAME(' + args + ') })';
var sigEnd = range(num).map(function() { return 'i' }).join('');
names.split(' ').forEach(function(name) {
var stub = plainStub;
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_glut.js b/src/library_glut.js
index ba4d75ab..65ac10c4 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -122,10 +122,14 @@ var LibraryGLUT = {
return keycode; // numeric TODO handle shift?
if (65 <= keycode && keycode <= 90)
return event['shiftKey'] ? keycode : keycode + 32;
+ if (96 <= keycode && keycode <= 105)
+ return keycode - 48; // numpad numbers
if (106 <= keycode && keycode <= 111)
return keycode - 106 + 42; // *,+-./ TODO handle shift?
switch (keycode) {
+ case 9: // tab key
+ case 13: // return key
case 27: // escape
case 32: // space
case 61: // equal
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 1c1e8107..fc38dd1c 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -1059,11 +1059,35 @@ var LibrarySDL = {
var src = buffer >> 2;
var dst = 0;
var isScreen = surf == SDL.screen;
- var data32 = new Uint32Array(data.buffer);
- var num = data32.length;
- while (dst < num) {
- // HEAP32[src++] is an optimization. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
- data32[dst++] = HEAP32[src++] | (isScreen ? 0xff000000 : 0);
+ var num;
+ if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) {
+ // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray,
+ // not UInt8ClampedArray. These don't have buffers, so we need to revert
+ // to copying a byte at a time. We do the undefined check because modern
+ // browsers do not define CanvasPixelArray anymore.
+ num = data.length;
+ while (dst < num) {
+ var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
+ data[dst ] = val & 0xff;
+ data[dst+1] = (val >> 8) & 0xff;
+ data[dst+2] = (val >> 16) & 0xff;
+ data[dst+3] = isScreen ? 0xff : ((val >> 24) & 0xff);
+ src++;
+ dst += 4;
+ }
+ } else {
+ var data32 = new Uint32Array(data.buffer);
+ num = data32.length;
+ if (isScreen) {
+ while (dst < num) {
+ // HEAP32[src++] is an optimization. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
+ data32[dst++] = HEAP32[src++] | 0xff000000;
+ }
+ } else {
+ while (dst < num) {
+ data32[dst++] = HEAP32[src++];
+ }
+ }
}
#else
var num = surfData.image.data.length;
diff --git a/src/library_uuid.js b/src/library_uuid.js
new file mode 100644
index 00000000..adfd1882
--- /dev/null
+++ b/src/library_uuid.js
@@ -0,0 +1,140 @@
+// Implementation of libuuid creating RFC4122 version 4 random UUIDs.
+
+mergeInto(LibraryManager.library, {
+ // Clear a 'compact' UUID.
+ uuid_clear: function(uu) {
+ // void uuid_clear(uuid_t uu);
+ _memset(uu, 0, 16);
+ },
+
+ // Compare whether or not two 'compact' UUIDs are the same.
+ // Returns an integer less than, equal to, or greater than zero if uu1 is found, respectively, to be
+ // lexigraphically less than, equal, or greater than uu2.
+ uuid_compare__deps: ['memcmp'],
+ uuid_compare: function(uu1, uu2) {
+ // int uuid_compare(const uuid_t uu1, const uuid_t uu2);
+ return _memcmp(uu1, uu2, 16);
+ },
+
+ // Copies the 'compact' UUID variable from src to dst.
+ uuid_copy: function(dst, src) {
+ // void uuid_copy(uuid_t dst, const uuid_t src);
+ _memcpy(dst, src, 16);
+ },
+
+ // Write a RFC4122 version 4 compliant UUID largely based on the method found in
+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
+ // tweaked slightly in order to use the 'compact' UUID form used by libuuid.
+ uuid_generate: function(out) {
+ // void uuid_generate(uuid_t out);
+ var uuid = null;
+
+ if (ENVIRONMENT_IS_NODE) {
+ // If Node.js try to use crypto.randomBytes
+ try {
+ var rb = require('crypto').randomBytes;
+ uuid = rb(16);
+ } catch(e) {}
+ } else if (ENVIRONMENT_IS_WEB &&
+ typeof(window.crypto) !== 'undefined' &&
+ typeof(window.crypto.getRandomValues) !== 'undefined') {
+ // If crypto.getRandomValues is available try to use it.
+ uuid = new Uint8Array(16);
+ window.crypto.getRandomValues(uuid);
+ }
+
+ // Fall back to Math.random if a higher quality random number generator is not available.
+ if (!uuid) {
+ uuid = new Array(16);
+ var d = new Date().getTime();
+ for (var i = 0; i < 16; i++) {
+ var r = (d + Math.random()*256)%256 | 0;
+ d = Math.floor(d/256);
+ uuid[i] = r;
+ }
+ }
+
+ uuid[6] = (uuid[6] & 0x0F) | 0x40;
+ uuid[8] = (uuid[8] & 0x7F) | 0x80;
+ writeArrayToMemory(uuid, out);
+ },
+
+ // Compares the value of the supplied 'compact' UUID variable uu to the NULL value.
+ // If the value is equal to the NULL UUID, 1 is returned, otherwise 0 is returned.
+ uuid_is_null: function(uu) {
+ // int uuid_is_null(const uuid_t uu);
+ for (var i = 0; i < 4; i++, uu = (uu+4)|0) {
+ var val = {{{ makeGetValue('uu', 0, 'i32') }}};
+ if (val) {
+ return 0;
+ }
+ }
+ return 1;
+ },
+
+ // converts the UUID string given by inp into the binary representation. The input UUID is a string of
+ // the form "%08x-%04x-%04x-%04x-%012x" 36 bytes plus the trailing '\0'.
+ // Upon successfully parsing the input string, 0 is returned, and the UUID is stored in the location
+ // pointed to by uu, otherwise -1 is returned.
+ uuid_parse: function(inp, uu) {
+ // int uuid_parse(const char *in, uuid_t uu);
+ var inp = Pointer_stringify(inp);
+ if (inp.length === 36) {
+ var i = 0;
+ var uuid = new Array(16);
+ inp.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) {
+ if (i < 16) {
+ uuid[i++] = parseInt(byte, 16);
+ }
+ });
+
+ if (i < 16) {
+ return -1;
+ } else {
+ writeArrayToMemory(uuid, uu);
+ return 0;
+ }
+ } else {
+ return -1;
+ }
+ },
+
+ // Convert a 'compact' form UUID to a string, if the upper parameter is supplied make the string upper case.
+ uuid_unparse: function(uu, out, upper) {
+ // void uuid_unparse(const uuid_t uu, char *out);
+ var i = 0;
+ var uuid = 'xxxx-xx-xx-xx-xxxxxx'.replace(/[x]/g, function(c) {
+ var r = upper ? ({{{ makeGetValue('uu', 'i', 'i8', 0, 1) }}}).toString(16).toUpperCase() :
+ ({{{ makeGetValue('uu', 'i', 'i8', 0, 1) }}}).toString(16);
+ r = (r.length === 1) ? '0' + r : r; // Zero pad single digit hex values
+ i++;
+ return r;
+ });
+ writeStringToMemory(uuid, out);
+ },
+
+ // Convert a 'compact' form UUID to a lower case string.
+ uuid_unparse_lower__deps: ['uuid_unparse'],
+ uuid_unparse_lower: function(uu, out) {
+ // void uuid_unparse_lower(const uuid_t uu, char *out);
+ _uuid_unparse(uu, out);
+ },
+
+ // Convert a 'compact' form UUID to an upper case string.
+ uuid_unparse_upper__deps: ['uuid_unparse'],
+ uuid_unparse_upper: function(uu, out) {
+ // void uuid_unparse_upper(const uuid_t uu, char *out);
+ _uuid_unparse(uu, out, true);
+ },
+
+ uuid_type: function(uu) {
+ // int uuid_type(const uuid_t uu);
+ return {{{ cDefine('UUID_TYPE_DCE_RANDOM') }}};
+ },
+
+ uuid_variant: function(uu) {
+ // int uuid_variant(const uuid_t uu);
+ return {{{ cDefine('UUID_VARIANT_DCE') }}};
+ }
+});
+
diff --git a/src/modules.js b/src/modules.js
index e2d3433f..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'].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 874514b1..be0cbcab 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -49,7 +49,8 @@ function preprocess(text) {
showStack.push(ident in this && this[ident] > 0);
}
} else if (line[2] == 'n') { // include
- ret += '\n' + read(line.substr(line.indexOf(' ')+1)) + '\n'
+ var included = read(line.substr(line.indexOf(' ')+1));
+ ret += '\n' + preprocess(included) + '\n'
}
} else if (line[2] == 'l') { // else
showStack.push(!showStack.pop());
@@ -462,7 +463,7 @@ function parseParamTokens(params) {
// handle 'byval' and 'byval align X'. We store the alignment in 'byVal'
byVal = QUANTUM_SIZE;
segment.splice(1, 1);
- if (segment[1] && segment[1].text === 'nocapture') {
+ if (segment[1] && (segment[1].text === 'nocapture' || segment[1].text === 'readonly')) {
segment.splice(1, 1);
}
if (segment[1] && segment[1].text === 'align') {
@@ -471,7 +472,7 @@ function parseParamTokens(params) {
segment.splice(1, 2);
}
}
- if (segment[1] && segment[1].text === 'nocapture') {
+ if (segment[1] && (segment[1].text === 'nocapture' || segment[1].text === 'readonly')) {
segment.splice(1, 1);
}
if (segment.length == 1) {
@@ -627,7 +628,7 @@ function parseLLVMSegment(segment) {
}
function cleanSegment(segment) {
- while (segment.length >= 2 && ['noalias', 'sret', 'nocapture', 'nest', 'zeroext', 'signext'].indexOf(segment[1].text) != -1) {
+ while (segment.length >= 2 && ['noalias', 'sret', 'nocapture', 'nest', 'zeroext', 'signext', 'readnone'].indexOf(segment[1].text) != -1) {
segment.splice(1, 1);
}
return segment;
@@ -961,8 +962,13 @@ function parseNumerical(value, type) {
}
if (isNumber(value)) {
var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50
+ // type may be undefined here, like when this is called from makeConst with a single argument.
+ // but if it is a number, then we can safely assume that this should handle negative zeros
+ // correctly.
+ if (type === undefined || type === 'double' || type === 'float') {
+ if (value[0] === '-' && ret === 0) { return '-.0'; } // fix negative 0, toString makes it 0
+ }
if (type === 'double' || type === 'float') {
- if (value[0] === '-' && ret === 0) return '-.0'; // fix negative 0, toString makes it 0
if (!RUNNING_JS_OPTS) ret = asmEnsureFloat(ret, type);
}
return ret.toString();
@@ -1639,7 +1645,10 @@ function getFastValue(a, op, b, type) {
}
function getFastValues(list, op, type) {
- assert(op == '+');
+ assert(op === '+' && type === 'i32');
+ for (var i = 0; i < list.length; i++) {
+ if (isNumber(list[i])) list[i] = (list[i]|0) + '';
+ }
var changed = true;
while (changed) {
changed = false;
@@ -1647,6 +1656,7 @@ function getFastValues(list, op, type) {
var fast = getFastValue(list[i], op, list[i+1], type);
var raw = list[i] + op + list[i+1];
if (fast.length < raw.length || fast.indexOf(op) < 0) {
+ if (isNumber(fast)) fast = (fast|0) + '';
list[i] = fast;
list.splice(i+1, 1);
i--;
@@ -2140,9 +2150,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 63495914..90a86474 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -117,17 +117,17 @@ function run(args) {
preRun();
- if (runDependencies > 0) {
- // a preRun added a dependency, run will be called later
- return;
- }
+ if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+ 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();
- Module['calledRun'] = true;
if (Module['_main'] && shouldRunNow) {
Module['callMain'](args);
}
diff --git a/src/preamble.js b/src/preamble.js
index f9fccdf6..ac6ee7b3 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -1090,7 +1090,8 @@ Module['writeAsciiToMemory'] = writeAsciiToMemory;
{{{ reSign }}}
#if PRECISE_I32_MUL
-if (!Math['imul']) Math['imul'] = function imul(a, b) {
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
var ah = a >>> 16;
var al = a & 0xffff;
var bh = b >>> 16;
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp
index de69e0ef..d5772c62 100644
--- a/src/relooper/Relooper.cpp
+++ b/src/relooper/Relooper.cpp
@@ -40,27 +40,56 @@ static void PutIndented(const char *String);
static char *OutputBufferRoot = NULL;
static char *OutputBuffer = NULL;
static int OutputBufferSize = 0;
+static int OutputBufferOwned = false;
+
+static int LeftInOutputBuffer() {
+ return OutputBufferSize - (OutputBuffer - OutputBufferRoot);
+}
+
+static bool EnsureOutputBuffer(int Needed) { // ensures the output buffer is sufficient. returns true is no problem happened
+ Needed++; // ensure the trailing \0 is not forgotten
+ int Left = LeftInOutputBuffer();
+ if (!OutputBufferOwned) {
+ assert(Needed < Left);
+ } else {
+ // we own the buffer, and can resize if necessary
+ if (Needed >= Left) {
+ int Offset = OutputBuffer - OutputBufferRoot;
+ int TotalNeeded = OutputBufferSize + Needed - Left + 10240;
+ int NewSize = OutputBufferSize;
+ while (NewSize < TotalNeeded) NewSize = NewSize + (NewSize/2);
+ //printf("resize %d => %d\n", OutputBufferSize, NewSize);
+ OutputBufferRoot = (char*)realloc(OutputBufferRoot, NewSize);
+ OutputBuffer = OutputBufferRoot + Offset;
+ OutputBufferSize = NewSize;
+ return false;
+ }
+ }
+ return true;
+}
void PrintIndented(const char *Format, ...) {
assert(OutputBuffer);
- assert(OutputBuffer + Indenter::CurrIndent*INDENTATION - OutputBufferRoot < OutputBufferSize);
+ EnsureOutputBuffer(Indenter::CurrIndent*INDENTATION);
for (int i = 0; i < Indenter::CurrIndent*INDENTATION; i++, OutputBuffer++) *OutputBuffer = ' ';
- va_list Args;
- va_start(Args, Format);
- int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot);
- int written = vsnprintf(OutputBuffer, left, Format, Args);
- assert(written < left);
- OutputBuffer += written;
- va_end(Args);
+ int Written;
+ while (1) { // write and potentially resize buffer until we have enough room
+ int Left = LeftInOutputBuffer();
+ va_list Args;
+ va_start(Args, Format);
+ Written = vsnprintf(OutputBuffer, Left, Format, Args);
+ va_end(Args);
+ if (EnsureOutputBuffer(Written)) break;
+ }
+ OutputBuffer += Written;
}
void PutIndented(const char *String) {
assert(OutputBuffer);
- assert(OutputBuffer + Indenter::CurrIndent*INDENTATION - OutputBufferRoot < OutputBufferSize);
+ EnsureOutputBuffer(Indenter::CurrIndent*INDENTATION);
for (int i = 0; i < Indenter::CurrIndent*INDENTATION; i++, OutputBuffer++) *OutputBuffer = ' ';
- int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot);
- int needed = strlen(String)+1;
- assert(needed < left);
+ int Needed = strlen(String)+1;
+ EnsureOutputBuffer(Needed);
strcpy(OutputBuffer, String);
OutputBuffer += strlen(String);
*OutputBuffer++ = '\n';
@@ -308,7 +337,7 @@ void MultipleShape::Render(bool InLoop) {
}
RenderLoopPostfix();
if (Next) Next->Render(InLoop);
-};
+}
// LoopShape
@@ -323,7 +352,7 @@ void LoopShape::Render(bool InLoop) {
Indenter::Unindent();
PrintIndented("}\n");
if (Next) Next->Render(InLoop);
-};
+}
// EmulatedShape
@@ -350,7 +379,7 @@ void EmulatedShape::Render(bool InLoop) {
Indenter::Unindent();
PrintIndented("}\n");
if (Next) Next->Render(InLoop);
-};
+}
// Relooper
@@ -358,8 +387,8 @@ Relooper::Relooper() : Root(NULL), Emulate(false), BlockIdCounter(1), ShapeIdCou
}
Relooper::~Relooper() {
- for (int i = 0; i < Blocks.size(); i++) delete Blocks[i];
- for (int i = 0; i < Shapes.size(); i++) delete Shapes[i];
+ for (unsigned i = 0; i < Blocks.size(); i++) delete Blocks[i];
+ for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i];
}
void Relooper::AddBlock(Block *New) {
@@ -399,7 +428,7 @@ void Relooper::Calculate(Block *Entry) {
// RAII cleanup. Without splitting, we will be forced to introduce labelled loops to allow
// reaching the final block
void SplitDeadEnds() {
- int TotalCodeSize = 0;
+ unsigned TotalCodeSize = 0;
for (BlockSet::iterator iter = Live.begin(); iter != Live.end(); iter++) {
Block *Curr = *iter;
TotalCodeSize += strlen(Curr->Code);
@@ -451,7 +480,7 @@ void Relooper::Calculate(Block *Entry) {
Pre.FindLive(Entry);
// Add incoming branches from live blocks, ignoring dead code
- for (int i = 0; i < Blocks.size(); i++) {
+ for (unsigned i = 0; i < Blocks.size(); i++) {
Block *Curr = Blocks[i];
if (!contains(Pre.Live, Curr)) continue;
for (BlockBranchMap::iterator iter = Curr->BranchesOut.begin(); iter != Curr->BranchesOut.end(); iter++) {
@@ -1158,11 +1187,18 @@ void Relooper::Render() {
void Relooper::SetOutputBuffer(char *Buffer, int Size) {
OutputBufferRoot = OutputBuffer = Buffer;
OutputBufferSize = Size;
+ OutputBufferOwned = false;
}
void Relooper::MakeOutputBuffer(int Size) {
+ if (OutputBufferRoot && OutputBufferSize >= Size && OutputBufferOwned) return;
OutputBufferRoot = OutputBuffer = (char*)malloc(Size);
OutputBufferSize = Size;
+ OutputBufferOwned = true;
+}
+
+char *Relooper::GetOutputBuffer() {
+ return OutputBufferRoot;
}
void Relooper::SetAsmJSMode(int On) {
diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h
index 04f2ffc3..6b9394db 100644
--- a/src/relooper/Relooper.h
+++ b/src/relooper/Relooper.h
@@ -89,11 +89,11 @@ struct Block {
// setjmp returns, etc.)
//
-class SimpleShape;
-class LabeledShape;
-class MultipleShape;
-class LoopShape;
-class EmulatedShape;
+struct SimpleShape;
+struct LabeledShape;
+struct MultipleShape;
+struct LoopShape;
+struct EmulatedShape;
struct Shape {
int Id; // A unique identifier. Used to identify loops, labels are Lx where x is the Id. Defined when added to relooper
@@ -200,11 +200,16 @@ struct Relooper {
void Render();
// Sets the global buffer all printing goes to. Must call this or MakeOutputBuffer.
+ // XXX: this is deprecated, see MakeOutputBuffer
static void SetOutputBuffer(char *Buffer, int Size);
- // Creates an output buffer. Must call this or SetOutputBuffer.
+ // Creates an internal output buffer. Must call this or SetOutputBuffer. Size is
+ // a hint for the initial size of the buffer, it can be resized later one demand.
+ // For that reason this is more recommended than SetOutputBuffer.
static void MakeOutputBuffer(int Size);
+ static char *GetOutputBuffer();
+
// Sets asm.js mode on or off (default is off)
static void SetAsmJSMode(int On);
diff --git a/src/relooper/fuzzer.py b/src/relooper/fuzzer.py
index fa47583e..18db997e 100644
--- a/src/relooper/fuzzer.py
+++ b/src/relooper/fuzzer.py
@@ -47,8 +47,18 @@ while(1) switch(label) {
int main() {
char *buffer = (char*)malloc(10*1024*1024);
+'''
+
+ if random.randint(0, 1) == 0:
+ make = False
+ fast += '''
Relooper::SetOutputBuffer(buffer, 10*1024*1024);
'''
+ else:
+ make = True
+ fast += '''
+ Relooper::MakeOutputBuffer(%d);
+''' % random.randint(1, 1024*1024*10)
for i in range(1, num):
slow += ' case %d: print(%d); state = check(); modded = state %% %d\n' % (i, i, len(branches[i])+1)
@@ -102,11 +112,11 @@ int main() {
printf("\\n\\n");
r.Render();
- puts(buffer);
+ puts(%s);
return 1;
}
-'''
+''' % ('buffer' if not make else 'Relooper::GetOutputBuffer()')
slow += '}'
diff --git a/src/relooper/test.cpp b/src/relooper/test.cpp
index 773f6ee4..b4ce669c 100644
--- a/src/relooper/test.cpp
+++ b/src/relooper/test.cpp
@@ -286,5 +286,33 @@ int main() {
puts(buffer);
}
+
+ if (1) {
+ Relooper::MakeOutputBuffer(10);
+
+ printf("\n\n-- If pattern, emulated, using MakeOutputBuffer --\n\n");
+
+ Block *b_a = new Block("// block A\n", NULL);
+ Block *b_b = new Block("// block B\n", "b_check()");
+ Block *b_c = new Block("// block C\n", NULL);
+
+ b_a->AddBranchTo(b_b, "check == 10", "atob();");
+ b_a->AddBranchTo(b_c, NULL, "atoc();");
+
+ b_b->AddBranchTo(b_c, "case 17:", "btoc();");
+ b_b->AddBranchTo(b_a, NULL, NULL);
+
+ Relooper r;
+ r.SetEmulate(true);
+ r.AddBlock(b_a);
+ r.AddBlock(b_b);
+ r.AddBlock(b_c);
+
+ r.Calculate(b_a);
+ printf("\n\n", "the_var");
+ r.Render();
+
+ puts(buffer);
+ }
}
diff --git a/src/relooper/test.txt b/src/relooper/test.txt
index 540f7bdb..cb02b867 100644
--- a/src/relooper/test.txt
+++ b/src/relooper/test.txt
@@ -91,7 +91,7 @@
}
default: {
var $x_1 = $x_0;
- label = -1;
+ label = 8;
break L1;
}
}
@@ -106,7 +106,7 @@
}
}
}
- if (label == -1) {
+ if (label == 8) {
// code 7
}
// code 4
@@ -315,3 +315,48 @@
}
}
+
+
+-- If pattern, emulated, using MakeOutputBuffer --
+
+
+
+ label = 1;
+ L0: while(1) {
+ switch(label|0) {
+ case 3: {
+ // block C
+ break;
+ }
+ case 1: {
+ // block A
+ if (check == 10) {
+ atob();
+ label = 2;
+ continue L0;
+ } else {
+ atoc();
+ label = 3;
+ continue L0;
+ }
+ break;
+ }
+ case 2: {
+ // block B
+ switch (b_check()) {
+ case 17: {
+ btoc();
+ label = 3;
+ continue L0;
+ break;
+ }
+ default: {
+ label = 1;
+ continue L0;
+ }
+ }
+ break;
+ }
+ }
+ }
+
diff --git a/src/settings.js b/src/settings.js
index 753e2367..720fb53f 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -123,6 +123,7 @@ var PRECISE_F32 = 0; // 0: Use JS numbers for floating-point values. These are 6
// 2: Model C++ floats precisely using Math.fround if available in the JS engine, otherwise
// use an empty polyfill. This will have less of a speed penalty than using the full
// polyfill in cases where engine support is not present.
+var SIMD = 0; // Whether to emit SIMD code ( https://github.com/johnmccutchan/ecmascript_simd )
var CLOSURE_ANNOTATIONS = 0; // If set, the generated code will be annotated for the closure
// compiler. This potentially lets closure optimize the code better.
@@ -156,6 +157,8 @@ var OUTLINING_LIMIT = 0; // A function size above which we try to automatically
// with, but something around 20,000 to 100,000 might make sense.
// (The unit size is number of AST nodes.)
+var AGGRESSIVE_VARIABLE_ELIMINATION = 0; // Run aggressiveVariableElimination in js-optimizer.js
+
// Generated code debugging options
var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give a clear
// error on what would be segfaults in a native build (like deferencing
diff --git a/src/struct_info.json b/src/struct_info.json
index c136cc8b..a22851b6 100644
--- a/src/struct_info.json
+++ b/src/struct_info.json
@@ -1061,5 +1061,17 @@
"patch"
]
}
+ },
+ {
+ "file": "uuid/uuid.h",
+ "defines": [
+ "UUID_VARIANT_NCS",
+ "UUID_VARIANT_DCE",
+ "UUID_VARIANT_MICROSOFT",
+ "UUID_VARIANT_OTHER",
+ "UUID_TYPE_DCE_TIME",
+ "UUID_TYPE_DCE_RANDOM"
+ ],
+ "structs": {}
}
]
diff --git a/system/include/GL/glew.h b/system/include/GL/glew.h
index 324c6b29..efd90d6f 100644
--- a/system/include/GL/glew.h
+++ b/system/include/GL/glew.h
@@ -1,6 +1,839 @@
+/* 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;
+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/__config b/system/include/libcxx/__config
index a45b02de..45207392 100644
--- a/system/include/libcxx/__config
+++ b/system/include/libcxx/__config
@@ -174,7 +174,7 @@
#endif
#ifndef _LIBCPP_TYPE_VIS
-# if __has_attribute(type_visibility)
+# if __has_attribute(__type_visibility__)
# define _LIBCPP_TYPE_VIS __attribute__ ((__type_visibility__("default")))
# else
# define _LIBCPP_TYPE_VIS __attribute__ ((__visibility__("default")))
@@ -389,9 +389,7 @@ namespace std {
#endif
#if _GNUC_VER < 404
-#define _LIBCPP_HAS_NO_ADVANCED_SFINAE
#define _LIBCPP_HAS_NO_DECLTYPE
-#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
#define _LIBCPP_HAS_NO_DELETED_FUNCTIONS
#define _LIBCPP_HAS_NO_UNICODE_CHARS
#define _LIBCPP_HAS_NO_VARIADICS
@@ -402,6 +400,11 @@ namespace std {
#define _LIBCPP_HAS_NO_NULLPTR
#endif
+#if _GNUC_VER < 407
+#define _LIBCPP_HAS_NO_ADVANCED_SFINAE
+#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif
+
#endif // __GXX_EXPERIMENTAL_CXX0X__
#define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { namespace _LIBCPP_NAMESPACE {
@@ -454,7 +457,6 @@ namespace std {
#define _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
#define _LIBCPP_HAS_NO_NULLPTR
#define _LIBCPP_HAS_NO_UNICODE_CHARS
-#define _LIBCPP_HAS_NO_STRONG_ENUMS
#define _LIBCPP_HAS_IS_BASE_OF
#if defined(_AIX)
@@ -514,7 +516,7 @@ template <unsigned> struct __static_assert_check {};
#define __has_feature(__x) 0
#endif
-#if __has_feature(cxx_explicit_conversions)
+#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__)
# define _LIBCPP_EXPLICIT explicit
#else
# define _LIBCPP_EXPLICIT
@@ -567,6 +569,16 @@ template <unsigned> struct __static_assert_check {};
#define _LIBCPP_WCTYPE_IS_MASK
#endif
+#if defined(__APPLE__)
+#ifndef _LIBCPP_TRIVIAL_PAIR_COPY_CTOR
+# define _LIBCPP_TRIVIAL_PAIR_COPY_CTOR 0
+#endif
+#endif
+
+#ifndef _LIBCPP_TRIVIAL_PAIR_COPY_CTOR
+# define _LIBCPP_TRIVIAL_PAIR_COPY_CTOR 1
+#endif
+
#ifndef _LIBCPP_STD_VER
# if __cplusplus <= 201103L
# define _LIBCPP_STD_VER 11
diff --git a/system/include/libcxx/__undef_min_max b/system/include/libcxx/__undef_min_max
index 2b6bc90a..5df9412c 100644
--- a/system/include/libcxx/__undef_min_max
+++ b/system/include/libcxx/__undef_min_max
@@ -10,7 +10,8 @@
#ifdef min
#if defined(_MSC_VER) && ! defined(__clang__)
-_LIBCPP_WARNING("macro min is incompatible with C++. #undefing min")
+_LIBCPP_WARNING("macro min is incompatible with C++. Try #define NOMINMAX "
+ "before any Windows header. #undefing min")
#else
#warning: macro min is incompatible with C++. #undefing min
#endif
@@ -19,7 +20,8 @@ _LIBCPP_WARNING("macro min is incompatible with C++. #undefing min")
#ifdef max
#if defined(_MSC_VER) && ! defined(__clang__)
-_LIBCPP_WARNING("macro max is incompatible with C++. #undefing max")
+_LIBCPP_WARNING("macro max is incompatible with C++. Try #define NOMINMAX "
+ "before any Windows header. #undefing max")
#else
#warning: macro max is incompatible with C++. #undefing max
#endif
diff --git a/system/include/libcxx/dynarray b/system/include/libcxx/experimental/dynarray
index b0d04f91..7c5c9b3f 100644
--- a/system/include/libcxx/dynarray
+++ b/system/include/libcxx/experimental/dynarray
@@ -17,7 +17,7 @@
/*
dynarray synopsis
-namespace std {
+namespace std { namespace experimental {
template< typename T >
class dynarray
@@ -93,7 +93,7 @@ public:
void fill(const T& v);
};
-} // std
+}} // std::experimental
*/
@@ -112,7 +112,7 @@ public:
#pragma GCC system_header
#endif
-_LIBCPP_BEGIN_NAMESPACE_STD
+namespace std { namespace experimental { inline namespace __array_extensions_v1 {
template <class _Tp>
struct _LIBCPP_TYPE_VIS_ONLY dynarray
@@ -302,9 +302,12 @@ dynarray<_Tp>::at(size_type __n) const
return data()[__n];
}
-template <class _Tp, class _Alloc>
-struct _LIBCPP_TYPE_VIS_ONLY uses_allocator<dynarray<_Tp>, _Alloc> : true_type {};
+}}}
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+template <class _Tp, class _Alloc>
+struct _LIBCPP_TYPE_VIS_ONLY uses_allocator<std::experimental::dynarray<_Tp>, _Alloc> : true_type {};
_LIBCPP_END_NAMESPACE_STD
#endif // if _LIBCPP_STD_VER > 11
diff --git a/system/include/libcxx/optional b/system/include/libcxx/experimental/optional
index a8e6a991..3848da87 100644
--- a/system/include/libcxx/optional
+++ b/system/include/libcxx/experimental/optional
@@ -18,8 +18,7 @@
#include <initializer_list>
-namespace std
-{
+namespace std { namespace experimental {
// optional for object types
template <class T>
@@ -110,7 +109,7 @@ template <class T> constexpr optional<typename decay<T>::type> make_optional(T&&
template <class T> struct hash;
template <class T> struct hash<optional<T>>;
-} // std
+}} // std::experimental
*/
@@ -118,8 +117,7 @@ template <class T> struct hash<optional<T>>;
#include <functional>
#include <stdexcept>
-namespace std // purposefully not using versioning namespace
-{
+namespace std { namespace experimental {
class _LIBCPP_EXCEPTION_ABI bad_optional_access
: public logic_error
@@ -142,7 +140,7 @@ public:
virtual ~bad_optional_access() _NOEXCEPT;
};
-} // std
+}} // std::experimental
#if _LIBCPP_STD_VER > 11
@@ -163,7 +161,7 @@ public:
#pragma GCC system_header
#endif
-_LIBCPP_BEGIN_NAMESPACE_STD
+namespace std { namespace experimental { inline namespace __library_fundamentals_v1 {
struct in_place_t {};
constexpr in_place_t in_place{};
@@ -677,10 +675,14 @@ make_optional(_Tp&& __v)
return optional<typename decay<_Tp>::type>(_VSTD::forward<_Tp>(__v));
}
+}}} // namespace std::experimental::__library_fundamentals_v1
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
template <class _Tp>
-struct _LIBCPP_TYPE_VIS_ONLY hash<optional<_Tp> >
+struct _LIBCPP_TYPE_VIS_ONLY hash<std::experimental::optional<_Tp> >
{
- typedef optional<_Tp> argument_type;
+ typedef std::experimental::optional<_Tp> argument_type;
typedef size_t result_type;
_LIBCPP_INLINE_VISIBILITY
diff --git a/system/include/libcxx/ext/__hash b/system/include/libcxx/ext/__hash
index 04975bfd..c0523cce 100644
--- a/system/include/libcxx/ext/__hash
+++ b/system/include/libcxx/ext/__hash
@@ -19,7 +19,7 @@
namespace __gnu_cxx {
using namespace std;
-template <typename T> struct _LIBCPP_TYPE_VIS_ONLY hash : public std::hash<T>
+template <typename _Tp> struct _LIBCPP_TYPE_VIS_ONLY hash : public std::hash<_Tp>
{ };
template <> struct _LIBCPP_TYPE_VIS_ONLY hash<const char*>
diff --git a/system/include/libcxx/iomanip b/system/include/libcxx/iomanip
index cdb0d5f0..e334c7de 100644
--- a/system/include/libcxx/iomanip
+++ b/system/include/libcxx/iomanip
@@ -14,6 +14,8 @@
/*
iomanip synopsis
+namespace std {
+
// types T1, T2, ... are unspecified implementation types
T1 resetiosflags(ios_base::fmtflags mask);
T2 setiosflags (ios_base::fmtflags mask);
@@ -604,7 +606,7 @@ basic_ostream<_CharT, _Traits>& operator<<(
basic_ostream<_CharT, _Traits>& __os,
const __quoted_proxy<_CharT, _Traits, _Allocator> & __proxy)
{
- return __quoted_output (__os, __proxy.string.cbegin (), __proxy.string.cend (), __proxy.__delim, __proxy.__escape);
+ return __quoted_output (__os, __proxy.__string.cbegin (), __proxy.__string.cend (), __proxy.__delim, __proxy.__escape);
}
// extractor for non-const basic_string& proxies
diff --git a/system/include/libcxx/memory b/system/include/libcxx/memory
index bf44837f..b382f70b 100644
--- a/system/include/libcxx/memory
+++ b/system/include/libcxx/memory
@@ -1954,7 +1954,7 @@ public:
_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2)
: __first_(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {}
-#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p)
@@ -1973,8 +1973,6 @@ public:
return *this;
}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p)
_NOEXCEPT_(is_nothrow_move_constructible<_T1>::value &&
@@ -1992,9 +1990,7 @@ public:
return *this;
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
#ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -2051,7 +2047,7 @@ public:
_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2)
: _T1(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {}
-#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p)
@@ -2069,8 +2065,6 @@ public:
return *this;
}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p)
_NOEXCEPT_(is_nothrow_move_constructible<_T1>::value &&
@@ -2087,9 +2081,7 @@ public:
return *this;
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
#ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -2147,7 +2139,7 @@ public:
is_nothrow_move_constructible<_T2>::value)
: _T2(_VSTD::forward<_T2_param>(__t2)), __first_(_VSTD::forward<_T1_param>(__t1)) {}
-#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p)
@@ -2165,8 +2157,6 @@ public:
return *this;
}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p)
_NOEXCEPT_(is_nothrow_move_constructible<_T1>::value &&
@@ -2183,9 +2173,7 @@ public:
return *this;
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
#ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -2241,7 +2229,7 @@ public:
_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2)
: _T1(_VSTD::forward<_T1_param>(__t1)), _T2(_VSTD::forward<_T2_param>(__t2)) {}
-#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p)
@@ -2259,8 +2247,6 @@ public:
return *this;
}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
_LIBCPP_INLINE_VISIBILITY
__libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p)
_NOEXCEPT_(is_nothrow_move_constructible<_T1>::value &&
@@ -2277,9 +2263,7 @@ public:
return *this;
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
#ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -2332,7 +2316,7 @@ public:
_LIBCPP_INLINE_VISIBILITY __compressed_pair(_T1_param __t1, _T2_param __t2)
: base(_VSTD::forward<_T1_param>(__t1), _VSTD::forward<_T2_param>(__t2)) {}
-#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
_LIBCPP_INLINE_VISIBILITY
__compressed_pair(const __compressed_pair& __p)
@@ -2349,7 +2333,6 @@ public:
return *this;
}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
__compressed_pair(__compressed_pair&& __p)
_NOEXCEPT_(is_nothrow_move_constructible<_T1>::value &&
@@ -2365,9 +2348,7 @@ public:
return *this;
}
-#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
#ifndef _LIBCPP_HAS_NO_VARIADICS
diff --git a/system/include/libcxx/new b/system/include/libcxx/new
index 31bb5982..ea4a4a01 100644
--- a/system/include/libcxx/new
+++ b/system/include/libcxx/new
@@ -94,6 +94,7 @@ public:
};
#if defined(_LIBCPP_BUILDING_NEW) || (_LIBCPP_STD_VER > 11)
+
class _LIBCPP_EXCEPTION_ABI bad_array_length
: public bad_alloc
{
@@ -102,7 +103,10 @@ public:
virtual ~bad_array_length() _NOEXCEPT;
virtual const char* what() const _NOEXCEPT;
};
-#endif
+
+#define _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+#endif // defined(_LIBCPP_BUILDING_NEW) || (_LIBCPP_STD_VER > 11)
_LIBCPP_FUNC_VIS void __throw_bad_alloc(); // not in C++ spec
diff --git a/system/include/libcxx/readme.txt b/system/include/libcxx/readme.txt
index ae8090fd..ccac2fcd 100644
--- a/system/include/libcxx/readme.txt
+++ b/system/include/libcxx/readme.txt
@@ -1 +1 @@
-These files are from libc++, svn revision 194185, 2013-11-07.
+These files are from libc++, svn revision 195693, 2013-11-26.
diff --git a/system/include/libcxx/support/ibm/support.h b/system/include/libcxx/support/ibm/support.h
index 3effbaed..0abfa7f9 100644
--- a/system/include/libcxx/support/ibm/support.h
+++ b/system/include/libcxx/support/ibm/support.h
@@ -15,7 +15,7 @@ extern "builtin" int __popcnt4(unsigned int);
extern "builtin" int __popcnt8(unsigned long long);
extern "builtin" unsigned int __cnttz4(unsigned int);
extern "builtin" unsigned int __cnttz8(unsigned long long);
-extern "builtin" unsigned int __cntlz4(unsigned long long);
+extern "builtin" unsigned int __cntlz4(unsigned int);
extern "builtin" unsigned int __cntlz8(unsigned long long);
// Builtin functions for counting population
diff --git a/system/include/libcxx/support/win32/locale_win32.h b/system/include/libcxx/support/win32/locale_win32.h
index e768af50..f728d234 100644
--- a/system/include/libcxx/support/win32/locale_win32.h
+++ b/system/include/libcxx/support/win32/locale_win32.h
@@ -103,9 +103,9 @@ isupper_l(int c, _locale_t loc)
#define sscanf_l( __s, __l, __f, ...) _sscanf_l( __s, __f, __l, __VA_ARGS__ )
#define vsscanf_l( __s, __l, __f, ...) _sscanf_l( __s, __f, __l, __VA_ARGS__ )
#define sprintf_l( __s, __l, __f, ... ) _sprintf_l( __s, __f, __l, __VA_ARGS__ )
-#define snprintf_l( __s, __n, __l, __f, ... ) _snprintf_l( __s, __n, __f, __l, __VA_ARGS__ )
#define vsprintf_l( __s, __l, __f, ... ) _vsprintf_l( __s, __f, __l, __VA_ARGS__ )
#define vsnprintf_l( __s, __n, __l, __f, ... ) _vsnprintf_l( __s, __n, __f, __l, __VA_ARGS__ )
+int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...);
int asprintf_l( char **ret, locale_t loc, const char *format, ... );
int vasprintf_l( char **ret, locale_t loc, const char *format, va_list ap );
diff --git a/system/include/libcxx/support/win32/support.h b/system/include/libcxx/support/win32/support.h
index b953ab77..ed1986e6 100644
--- a/system/include/libcxx/support/win32/support.h
+++ b/system/include/libcxx/support/win32/support.h
@@ -23,7 +23,6 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
-#include <Windows.h>
extern "C" {
diff --git a/system/include/libcxx/type_traits b/system/include/libcxx/type_traits
index b6430fbb..0ad7b7f2 100644
--- a/system/include/libcxx/type_traits
+++ b/system/include/libcxx/type_traits
@@ -1409,7 +1409,7 @@ template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type
// is_assignable
-template<typename, typename T> struct __select_2nd { typedef T type; };
+template<typename, typename _Tp> struct __select_2nd { typedef _Tp type; };
template <class _Tp, class _Arg>
typename __select_2nd<decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>())), true_type>::type
@@ -2437,7 +2437,7 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY is_trivially_default_construct
// is_trivially_copy_constructible
template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY is_trivially_copy_constructible
- : public is_trivially_constructible<_Tp, const typename add_lvalue_reference<_Tp>::type>
+ : public is_trivially_constructible<_Tp, typename add_lvalue_reference<const _Tp>::type>
{};
// is_trivially_move_constructible
diff --git a/system/include/libcxx/utility b/system/include/libcxx/utility
index 5fc2cf20..2c1f62cc 100644
--- a/system/include/libcxx/utility
+++ b/system/include/libcxx/utility
@@ -272,10 +272,10 @@ struct _LIBCPP_TYPE_VIS_ONLY pair
)
: first(__p.first), second(__p.second) {}
-#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
+#if !defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && _LIBCPP_TRIVIAL_PAIR_COPY_CTOR
_LIBCPP_INLINE_VISIBILITY
pair(const pair& __p) = default;
-#else
+#elif !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) || !_LIBCPP_TRIVIAL_PAIR_COPY_CTOR
_LIBCPP_INLINE_VISIBILITY
pair(const pair& __p)
_NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value &&
diff --git a/system/include/uuid/uuid.h b/system/include/uuid/uuid.h
new file mode 100644
index 00000000..0a84e02c
--- /dev/null
+++ b/system/include/uuid/uuid.h
@@ -0,0 +1,35 @@
+
+#ifndef _UUID_H
+#define _UUID_H
+
+typedef unsigned char uuid_t[16];
+
+#define UUID_VARIANT_NCS 0
+#define UUID_VARIANT_DCE 1
+#define UUID_VARIANT_MICROSOFT 2
+#define UUID_VARIANT_OTHER 3
+
+#define UUID_TYPE_DCE_TIME 1
+#define UUID_TYPE_DCE_RANDOM 4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void uuid_clear(uuid_t uu);
+int uuid_compare(const uuid_t uu1, const uuid_t uu2);
+void uuid_copy(uuid_t dst, const uuid_t src);
+void uuid_generate(uuid_t out);
+int uuid_is_null(const uuid_t uu);
+int uuid_parse(const char *in, uuid_t uu);
+void uuid_unparse(const uuid_t uu, char *out);
+void uuid_unparse_lower(const uuid_t uu, char *out);
+void uuid_unparse_upper(const uuid_t uu, char *out);
+int uuid_type(const uuid_t uu);
+int uuid_variant(const uuid_t uu);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UUID_H */
diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols
index 561f01c1..6f80ef90 100644
--- a/system/lib/libc.symbols
+++ b/system/lib/libc.symbols
@@ -1,9 +1,15 @@
+ T _ZNKSt16bad_array_length4whatEv
T _ZNKSt20bad_array_new_length4whatEv
T _ZNKSt9bad_alloc4whatEv
+ T _ZNSt16bad_array_lengthC1Ev
+ T _ZNSt16bad_array_lengthC2Ev
+ T _ZNSt16bad_array_lengthD0Ev
+ T _ZNSt16bad_array_lengthD1Ev
+ T _ZNSt16bad_array_lengthD2Ev
T _ZNSt20bad_array_new_lengthC1Ev
T _ZNSt20bad_array_new_lengthC2Ev
T _ZNSt20bad_array_new_lengthD0Ev
- ? _ZNSt20bad_array_new_lengthD1Ev
+ T _ZNSt20bad_array_new_lengthD1Ev
T _ZNSt20bad_array_new_lengthD2Ev
T _ZNSt9bad_allocC1Ev
T _ZNSt9bad_allocC2Ev
@@ -14,10 +20,15 @@
T _ZSt15set_new_handlerPFvvE
T _ZSt17__throw_bad_allocv
D _ZSt7nothrow
+ D _ZTISt16bad_array_length
D _ZTISt20bad_array_new_length
D _ZTISt9bad_alloc
+ C _ZTISt9exception
+ D _ZTSSt16bad_array_length
D _ZTSSt20bad_array_new_length
D _ZTSSt9bad_alloc
+ C _ZTSSt9exception
+ D _ZTVSt16bad_array_length
D _ZTVSt20bad_array_new_length
D _ZTVSt9bad_alloc
W _ZdaPv
@@ -28,23 +39,20 @@
W _ZnajRKSt9nothrow_t
W _Znwj
W _ZnwjRKSt9nothrow_t
- T _err
- T _errx
- T _verr
- T _verrx
- T _vwarn
- T _vwarnx
- T _warn
- T _warnx
+ T __floatscan
+ T __overflow
+ T __shgetc
+ T __shlim
+ W __strtod_l
+ W __strtof_l
+ W __strtold_l
+ T __toread
+ T __towrite
+ T __uflow
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
@@ -58,24 +66,16 @@
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
W realloc_in_place
+ T scalbn
+ T scalbnl
T strtod
T strtod_l
T strtof
+ T strtof_l
T strtold
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 9ca04036..9b9b6ad2 100644
--- a/system/lib/libc/musl/readme.txt
+++ b/system/lib/libc/musl/readme.txt
@@ -7,3 +7,8 @@ Differences from upstream musl include:
ino_t, dev_t, blkcnt_t, fsblkcnt_t, fsfilcnt_t, rlim_t.
* We don't define _POSIX_SHARED_MEMORY_OBJECTS.
* 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/internal/floatscan.c b/system/lib/libc/musl/src/internal/floatscan.c
new file mode 100644
index 00000000..f6e331d4
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/floatscan.c
@@ -0,0 +1,496 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "shgetc.h"
+#include "floatscan.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+
+#define LD_B1B_DIG 2
+#define LD_B1B_MAX 9007199, 254740991
+#define KMAX 128
+
+#else /* LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 */
+
+#define LD_B1B_DIG 3
+#define LD_B1B_MAX 18, 446744073, 709551615
+#define KMAX 2048
+
+#endif
+
+#define MASK (KMAX-1)
+
+#define CONCAT2(x,y) x ## y
+#define CONCAT(x,y) CONCAT2(x,y)
+
+static long long scanexp(FILE *f, int pok)
+{
+ int c;
+ int x;
+ long long y;
+ int neg = 0;
+
+ c = shgetc(f);
+ if (c=='+' || c=='-') {
+ neg = (c=='-');
+ c = shgetc(f);
+ if (c-'0'>=10U && pok) shunget(f);
+ }
+ if (c-'0'>=10U) {
+ shunget(f);
+ return LLONG_MIN;
+ }
+ for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f))
+ x = 10*x + c-'0';
+ for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f))
+ y = 10*y + c-'0';
+ for (; c-'0'<10U; c = shgetc(f));
+ shunget(f);
+ return neg ? -y : y;
+}
+
+
+static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int pok)
+{
+ uint32_t x[KMAX];
+ static const uint32_t th[] = { LD_B1B_MAX };
+ int i, j, k, a, z;
+ long long lrp=0, dc=0;
+ long long e10=0;
+ int lnz = 0;
+ int gotdig = 0, gotrad = 0;
+ int rp;
+ int e2;
+ int emax = -emin-bits+3;
+ int denormal = 0;
+ long double y;
+ long double frac=0;
+ long double bias=0;
+ static const int p10s[] = { 10, 100, 1000, 10000,
+ 100000, 1000000, 10000000, 100000000 };
+
+ j=0;
+ k=0;
+
+ /* Don't let leading zeros consume buffer space */
+ for (; c=='0'; c = shgetc(f)) gotdig=1;
+ if (c=='.') {
+ gotrad = 1;
+ for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--;
+ }
+
+ x[0] = 0;
+ for (; c-'0'<10U || c=='.'; c = shgetc(f)) {
+ if (c == '.') {
+ if (gotrad) break;
+ gotrad = 1;
+ lrp = dc;
+ } else if (k < KMAX-3) {
+ dc++;
+ if (c!='0') lnz = dc;
+ if (j) x[k] = x[k]*10 + c-'0';
+ else x[k] = c-'0';
+ if (++j==9) {
+ k++;
+ j=0;
+ }
+ gotdig=1;
+ } else {
+ dc++;
+ if (c!='0') x[KMAX-4] |= 1;
+ }
+ }
+ if (!gotrad) lrp=dc;
+
+ if (gotdig && (c|32)=='e') {
+ e10 = scanexp(f, pok);
+ if (e10 == LLONG_MIN) {
+ if (pok) {
+ shunget(f);
+ } else {
+ shlim(f, 0);
+ return 0;
+ }
+ e10 = 0;
+ }
+ lrp += e10;
+ } else if (c>=0) {
+ shunget(f);
+ }
+ if (!gotdig) {
+ errno = EINVAL;
+ shlim(f, 0);
+ return 0;
+ }
+
+ /* Handle zero specially to avoid nasty special cases later */
+ if (!x[0]) return sign * 0.0;
+
+ /* Optimize small integers (w/no exponent) and over/under-flow */
+ if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0))
+ return sign * (long double)x[0];
+ if (lrp > -emin/2) {
+ errno = ERANGE;
+ return sign * LDBL_MAX * LDBL_MAX;
+ }
+ if (lrp < emin-2*LDBL_MANT_DIG) {
+ errno = ERANGE;
+ return sign * LDBL_MIN * LDBL_MIN;
+ }
+
+ /* Align incomplete final B1B digit */
+ if (j) {
+ for (; j<9; j++) x[k]*=10;
+ k++;
+ j=0;
+ }
+
+ a = 0;
+ z = k;
+ e2 = 0;
+ rp = lrp;
+
+ /* Optimize small to mid-size integers (even in exp. notation) */
+ if (lnz<9 && lnz<=rp && rp < 18) {
+ if (rp == 9) return sign * (long double)x[0];
+ if (rp < 9) return sign * (long double)x[0] / p10s[8-rp];
+ int bitlim = bits-3*(int)(rp-9);
+ if (bitlim>30 || x[0]>>bitlim==0)
+ return sign * (long double)x[0] * p10s[rp-10];
+ }
+
+ /* Align radix point to B1B digit boundary */
+ if (rp % 9) {
+ int rpm9 = rp>=0 ? rp%9 : rp%9+9;
+ int p10 = p10s[8-rpm9];
+ uint32_t carry = 0;
+ for (k=a; k!=z; k++) {
+ uint32_t tmp = x[k] % p10;
+ x[k] = x[k]/p10 + carry;
+ carry = 1000000000/p10 * tmp;
+ if (k==a && !x[k]) {
+ a = (a+1 & MASK);
+ rp -= 9;
+ }
+ }
+ if (carry) x[z++] = carry;
+ rp += 9-rpm9;
+ }
+
+ /* Upscale until desired number of bits are left of radix point */
+ while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) {
+ uint32_t carry = 0;
+ e2 -= 29;
+ for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
+ uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
+ if (tmp > 1000000000) {
+ carry = tmp / 1000000000;
+ x[k] = tmp % 1000000000;
+ } else {
+ carry = 0;
+ x[k] = tmp;
+ }
+ if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
+ if (k==a) break;
+ }
+ if (carry) {
+ rp += 9;
+ a = (a-1 & MASK);
+ if (a == z) {
+ z = (z-1 & MASK);
+ x[z-1 & MASK] |= x[z];
+ }
+ x[a] = carry;
+ }
+ }
+
+ /* Downscale until exactly number of bits are left of radix point */
+ for (;;) {
+ uint32_t carry = 0;
+ int sh = 1;
+ for (i=0; i<LD_B1B_DIG; i++) {
+ k = (a+i & MASK);
+ if (k == z || x[k] < th[i]) {
+ i=LD_B1B_DIG;
+ break;
+ }
+ if (x[a+i & MASK] > th[i]) break;
+ }
+ if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break;
+ /* FIXME: find a way to compute optimal sh */
+ if (rp > 9+9*LD_B1B_DIG) sh = 9;
+ e2 += sh;
+ for (k=a; k!=z; k=(k+1 & MASK)) {
+ uint32_t tmp = x[k] & (1<<sh)-1;
+ x[k] = (x[k]>>sh) + carry;
+ carry = (1000000000>>sh) * tmp;
+ if (k==a && !x[k]) {
+ a = (a+1 & MASK);
+ i--;
+ rp -= 9;
+ }
+ }
+ if (carry) {
+ if ((z+1 & MASK) != a) {
+ x[z] = carry;
+ z = (z+1 & MASK);
+ } else x[z-1 & MASK] |= 1;
+ }
+ }
+
+ /* Assemble desired bits into floating point variable */
+ for (y=i=0; i<LD_B1B_DIG; i++) {
+ if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0;
+ y = 1000000000.0L * y + x[a+i & MASK];
+ }
+
+ y *= sign;
+
+ /* Limit precision for denormal results */
+ if (bits > LDBL_MANT_DIG+e2-emin) {
+ bits = LDBL_MANT_DIG+e2-emin;
+ if (bits<0) bits=0;
+ denormal = 1;
+ }
+
+ /* Calculate bias term to force rounding, move out lower bits */
+ if (bits < LDBL_MANT_DIG) {
+ bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y);
+ frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits));
+ y -= frac;
+ y += bias;
+ }
+
+ /* Process tail of decimal input so it can affect rounding */
+ if ((a+i & MASK) != z) {
+ uint32_t t = x[a+i & MASK];
+ if (t < 500000000 && (t || (a+i+1 & MASK) != z))
+ frac += 0.25*sign;
+ else if (t > 500000000)
+ frac += 0.75*sign;
+ else if (t == 500000000) {
+ if ((a+i+1 & MASK) == z)
+ frac += 0.5*sign;
+ else
+ frac += 0.75*sign;
+ }
+ if (LDBL_MANT_DIG-bits >= 2 && !fmodl(frac, 1))
+ frac++;
+ }
+
+ y += frac;
+ y -= bias;
+
+ if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) {
+ if (fabs(y) >= CONCAT(0x1p, LDBL_MANT_DIG)) {
+ if (denormal && bits==LDBL_MANT_DIG+e2-emin)
+ denormal = 0;
+ y *= 0.5;
+ e2++;
+ }
+ if (e2+LDBL_MANT_DIG>emax || (denormal && frac))
+ errno = ERANGE;
+ }
+
+ return scalbnl(y, e2);
+}
+
+static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok)
+{
+ uint32_t x = 0;
+ long double y = 0;
+ long double scale = 1;
+ long double bias = 0;
+ int gottail = 0, gotrad = 0, gotdig = 0;
+ long long rp = 0;
+ long long dc = 0;
+ long long e2 = 0;
+ int d;
+ int c;
+
+ c = shgetc(f);
+
+ /* Skip leading zeros */
+ for (; c=='0'; c = shgetc(f)) gotdig = 1;
+
+ if (c=='.') {
+ gotrad = 1;
+ c = shgetc(f);
+ /* Count zeros after the radix point before significand */
+ for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1;
+ }
+
+ for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) {
+ if (c=='.') {
+ if (gotrad) break;
+ rp = dc;
+ gotrad = 1;
+ } else {
+ gotdig = 1;
+ if (c > '9') d = (c|32)+10-'a';
+ else d = c-'0';
+ if (dc<8) {
+ x = x*16 + d;
+ } else if (dc < LDBL_MANT_DIG/4+1) {
+ y += d*(scale/=16);
+ } else if (d && !gottail) {
+ y += 0.5*scale;
+ gottail = 1;
+ }
+ dc++;
+ }
+ }
+ if (!gotdig) {
+ shunget(f);
+ if (pok) {
+ shunget(f);
+ if (gotrad) shunget(f);
+ } else {
+ shlim(f, 0);
+ }
+ return sign * 0.0;
+ }
+ if (!gotrad) rp = dc;
+ while (dc<8) x *= 16, dc++;
+ if ((c|32)=='p') {
+ e2 = scanexp(f, pok);
+ if (e2 == LLONG_MIN) {
+ if (pok) {
+ shunget(f);
+ } else {
+ shlim(f, 0);
+ return 0;
+ }
+ e2 = 0;
+ }
+ } else {
+ shunget(f);
+ }
+ e2 += 4*rp - 32;
+
+ if (!x) return sign * 0.0;
+ if (e2 > -emin) {
+ errno = ERANGE;
+ return sign * LDBL_MAX * LDBL_MAX;
+ }
+ if (e2 < emin-2*LDBL_MANT_DIG) {
+ errno = ERANGE;
+ return sign * LDBL_MIN * LDBL_MIN;
+ }
+
+ while (x < 0x80000000) {
+ if (y>=0.5) {
+ x += x + 1;
+ y += y - 1;
+ } else {
+ x += x;
+ y += y;
+ }
+ e2--;
+ }
+
+ if (bits > 32+e2-emin) {
+ bits = 32+e2-emin;
+ if (bits<0) bits=0;
+ }
+
+ if (bits < LDBL_MANT_DIG)
+ bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign);
+
+ if (bits<32 && y && !(x&1)) x++, y=0;
+
+ y = bias + sign*(long double)x + sign*y;
+ y -= bias;
+
+ if (!y) errno = ERANGE;
+
+ return scalbnl(y, e2);
+}
+
+long double __floatscan(FILE *f, int prec, int pok)
+{
+ int sign = 1;
+ size_t i;
+ int bits;
+ int emin;
+ int c;
+
+ switch (prec) {
+ case 0:
+ bits = FLT_MANT_DIG;
+ emin = FLT_MIN_EXP-bits;
+ break;
+ case 1:
+ bits = DBL_MANT_DIG;
+ emin = DBL_MIN_EXP-bits;
+ break;
+ case 2:
+ bits = LDBL_MANT_DIG;
+ emin = LDBL_MIN_EXP-bits;
+ break;
+ default:
+ return 0;
+ }
+
+ while (isspace((c=shgetc(f))));
+
+ if (c=='+' || c=='-') {
+ sign -= 2*(c=='-');
+ c = shgetc(f);
+ }
+
+ for (i=0; i<8 && (c|32)=="infinity"[i]; i++)
+ if (i<7) c = shgetc(f);
+ if (i==3 || i==8 || (i>3 && pok)) {
+ if (i!=8) {
+ shunget(f);
+ if (pok) for (; i>3; i--) shunget(f);
+ }
+ return sign * INFINITY;
+ }
+ if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++)
+ if (i<2) c = shgetc(f);
+ if (i==3) {
+ if (shgetc(f) != '(') {
+ shunget(f);
+ return NAN;
+ }
+ for (i=1; ; i++) {
+ c = shgetc(f);
+ if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_')
+ continue;
+ if (c==')') return NAN;
+ shunget(f);
+ if (!pok) {
+ errno = EINVAL;
+ shlim(f, 0);
+ return 0;
+ }
+ while (i--) shunget(f);
+ return NAN;
+ }
+ return NAN;
+ }
+
+ if (i) {
+ shunget(f);
+ errno = EINVAL;
+ shlim(f, 0);
+ return 0;
+ }
+
+ if (c=='0') {
+ c = shgetc(f);
+ if ((c|32) == 'x')
+ return hexfloat(f, bits, emin, sign, pok);
+ shunget(f);
+ c = '0';
+ }
+
+ return decfloat(f, c, bits, emin, sign, pok);
+}
diff --git a/system/lib/libc/musl/src/internal/floatscan.h b/system/lib/libc/musl/src/internal/floatscan.h
new file mode 100644
index 00000000..e027fa08
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/floatscan.h
@@ -0,0 +1,8 @@
+#ifndef FLOATSCAN_H
+#define FLOATSCAN_H
+
+#include <stdio.h>
+
+long double __floatscan(FILE *, int, int);
+
+#endif
diff --git a/system/lib/libc/musl/src/internal/intscan.c b/system/lib/libc/musl/src/internal/intscan.c
new file mode 100644
index 00000000..69350efa
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/intscan.c
@@ -0,0 +1,99 @@
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include "shgetc.h"
+
+/* Lookup table for digit values. -1==255>=36 -> invalid */
+static const unsigned char table[] = { -1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
+-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
+-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+};
+
+unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
+{
+ const unsigned char *val = table+1;
+ int c, neg=0;
+ unsigned x;
+ unsigned long long y;
+ if (base > 36) {
+ errno = EINVAL;
+ return 0;
+ }
+ while (isspace((c=shgetc(f))));
+ if (c=='+' || c=='-') {
+ neg = -(c=='-');
+ c = shgetc(f);
+ }
+ if ((base == 0 || base == 16) && c=='0') {
+ c = shgetc(f);
+ if ((c|32)=='x') {
+ c = shgetc(f);
+ if (val[c]>=16) {
+ shunget(f);
+ if (pok) shunget(f);
+ else shlim(f, 0);
+ return 0;
+ }
+ base = 16;
+ } else if (base == 0) {
+ base = 8;
+ }
+ } else {
+ if (base == 0) base = 10;
+ if (val[c] >= base) {
+ shunget(f);
+ shlim(f, 0);
+ errno = EINVAL;
+ return 0;
+ }
+ }
+ if (base == 10) {
+ for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
+ x = x*10 + (c-'0');
+ for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
+ y = y*10 + (c-'0');
+ if (c-'0'>=10U) goto done;
+ } else if (!(base & base-1)) {
+ int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
+ for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
+ x = x<<bs | val[c];
+ for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
+ y = y<<bs | val[c];
+ } else {
+ for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
+ x = x*base + val[c];
+ for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
+ y = y*base + val[c];
+ }
+ if (val[c]<base) {
+ for (; val[c]<base; c=shgetc(f));
+ errno = ERANGE;
+ y = lim;
+ }
+done:
+ shunget(f);
+ if (y>=lim) {
+ if (!(lim&1) && !neg) {
+ errno = ERANGE;
+ return lim-1;
+ } else if (y>lim) {
+ errno = ERANGE;
+ return lim;
+ }
+ }
+ return (y^neg)-neg;
+}
diff --git a/system/lib/libc/musl/src/internal/intscan.h b/system/lib/libc/musl/src/internal/intscan.h
new file mode 100644
index 00000000..994c5e7d
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/intscan.h
@@ -0,0 +1,8 @@
+#ifndef INTSCAN_H
+#define INTSCAN_H
+
+#include <stdio.h>
+
+unsigned long long __intscan(FILE *, unsigned, int, unsigned long long);
+
+#endif
diff --git a/system/lib/libc/musl/src/internal/libm.h b/system/lib/libc/musl/src/internal/libm.h
new file mode 100644
index 00000000..9f0d3bc8
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/libm.h
@@ -0,0 +1,169 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#ifndef _LIBM_H
+#define _LIBM_H
+
+#include <stdint.h>
+#include <float.h>
+#include <math.h>
+#include <complex.h>
+#include <endian.h>
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
+union ldshape {
+ long double f;
+ struct {
+ uint64_t m;
+ uint16_t se;
+ } i;
+};
+#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
+union ldshape {
+ long double f;
+ struct {
+ uint64_t lo;
+ uint32_t mid;
+ uint16_t top;
+ uint16_t se;
+ } i;
+ struct {
+ uint64_t lo;
+ uint64_t hi;
+ } i2;
+};
+#else
+#error Unsupported long double representation
+#endif
+
+#define FORCE_EVAL(x) do { \
+ if (sizeof(x) == sizeof(float)) { \
+ volatile float __x; \
+ __x = (x); \
+ } else if (sizeof(x) == sizeof(double)) { \
+ volatile double __x; \
+ __x = (x); \
+ } else { \
+ volatile long double __x; \
+ __x = (x); \
+ } \
+} while(0)
+
+/* Get two 32 bit ints from a double. */
+#define EXTRACT_WORDS(hi,lo,d) \
+do { \
+ union {double f; uint64_t i;} __u; \
+ __u.f = (d); \
+ (hi) = __u.i >> 32; \
+ (lo) = (uint32_t)__u.i; \
+} while (0)
+
+/* Get the more significant 32 bit int from a double. */
+#define GET_HIGH_WORD(hi,d) \
+do { \
+ union {double f; uint64_t i;} __u; \
+ __u.f = (d); \
+ (hi) = __u.i >> 32; \
+} while (0)
+
+/* Get the less significant 32 bit int from a double. */
+#define GET_LOW_WORD(lo,d) \
+do { \
+ union {double f; uint64_t i;} __u; \
+ __u.f = (d); \
+ (lo) = (uint32_t)__u.i; \
+} while (0)
+
+/* Set a double from two 32 bit ints. */
+#define INSERT_WORDS(d,hi,lo) \
+do { \
+ union {double f; uint64_t i;} __u; \
+ __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \
+ (d) = __u.f; \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int. */
+#define SET_HIGH_WORD(d,hi) \
+do { \
+ union {double f; uint64_t i;} __u; \
+ __u.f = (d); \
+ __u.i &= 0xffffffff; \
+ __u.i |= (uint64_t)(hi) << 32; \
+ (d) = __u.f; \
+} while (0)
+
+/* Set the less significant 32 bits of a double from an int. */
+#define SET_LOW_WORD(d,lo) \
+do { \
+ union {double f; uint64_t i;} __u; \
+ __u.f = (d); \
+ __u.i &= 0xffffffff00000000ull; \
+ __u.i |= (uint32_t)(lo); \
+ (d) = __u.f; \
+} while (0)
+
+/* Get a 32 bit int from a float. */
+#define GET_FLOAT_WORD(w,d) \
+do { \
+ union {float f; uint32_t i;} __u; \
+ __u.f = (d); \
+ (w) = __u.i; \
+} while (0)
+
+/* Set a float from a 32 bit int. */
+#define SET_FLOAT_WORD(d,w) \
+do { \
+ union {float f; uint32_t i;} __u; \
+ __u.i = (w); \
+ (d) = __u.f; \
+} while (0)
+
+/* fdlibm kernel functions */
+
+int __rem_pio2_large(double*,double*,int,int,int);
+
+int __rem_pio2(double,double*);
+double __sin(double,double,int);
+double __cos(double,double);
+double __tan(double,double,int);
+double __expo2(double);
+double complex __ldexp_cexp(double complex,int);
+
+int __rem_pio2f(float,double*);
+float __sindf(double);
+float __cosdf(double);
+float __tandf(double,int);
+float __expo2f(float);
+float complex __ldexp_cexpf(float complex,int);
+
+int __rem_pio2l(long double, long double *);
+long double __sinl(long double, long double, int);
+long double __cosl(long double, long double);
+long double __tanl(long double, long double, int);
+
+/* polynomial evaluation */
+long double __polevll(long double, const long double *, int);
+long double __p1evll(long double, const long double *, int);
+
+#if 0
+/* Attempt to get strict C99 semantics for assignment with non-C99 compilers. */
+#define STRICT_ASSIGN(type, lval, rval) do { \
+ volatile type __v = (rval); \
+ (lval) = __v; \
+} while (0)
+#else
+/* Should work with -fexcess-precision=standard (>=gcc-4.5) or -ffloat-store */
+#define STRICT_ASSIGN(type, lval, rval) ((lval) = (type)(rval))
+#endif
+
+#endif
diff --git a/system/lib/libc/musl/src/internal/shgetc.c b/system/lib/libc/musl/src/internal/shgetc.c
new file mode 100644
index 00000000..e878b00a
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/shgetc.c
@@ -0,0 +1,27 @@
+#include "shgetc.h"
+
+void __shlim(FILE *f, off_t lim)
+{
+ f->shlim = lim;
+ f->shcnt = f->rend - f->rpos;
+ if (lim && f->shcnt > lim)
+ f->shend = f->rpos + lim;
+ else
+ f->shend = f->rend;
+}
+
+int __shgetc(FILE *f)
+{
+ int c;
+ if (f->shlim && f->shcnt >= f->shlim || (c=__uflow(f)) < 0) {
+ f->shend = 0;
+ return EOF;
+ }
+ if (f->shlim && f->rend - f->rpos > f->shlim - f->shcnt - 1)
+ f->shend = f->rpos + (f->shlim - f->shcnt - 1);
+ else
+ f->shend = f->rend;
+ if (f->rend) f->shcnt += f->rend - f->rpos + 1;
+ if (f->rpos[-1] != c) f->rpos[-1] = c;
+ return c;
+}
diff --git a/system/lib/libc/musl/src/internal/shgetc.h b/system/lib/libc/musl/src/internal/shgetc.h
new file mode 100644
index 00000000..7beb8ce6
--- /dev/null
+++ b/system/lib/libc/musl/src/internal/shgetc.h
@@ -0,0 +1,9 @@
+#include "stdio_impl.h"
+
+void __shlim(FILE *, off_t);
+int __shgetc(FILE *);
+
+#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->rend))
+#define shlim(f, lim) __shlim((f), (lim))
+#define shgetc(f) (((f)->rpos < (f)->shend) ? *(f)->rpos++ : __shgetc(f))
+#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0)
diff --git a/system/lib/libc/musl/src/internal/stdio_impl.h b/system/lib/libc/musl/src/internal/stdio_impl.h
index 2083b2fe..6bcd44dc 100644
--- a/system/lib/libc/musl/src/internal/stdio_impl.h
+++ b/system/lib/libc/musl/src/internal/stdio_impl.h
@@ -7,9 +7,15 @@
#define UNGET 8
+#if 1 // XXX EMSCRIPTEN
+#define FFINALLOCK(f) 0
+#define FLOCK(f) 0
+#define FUNLOCK(f) 0
+#else
#define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0)
#define FUNLOCK(f) if (__need_unlock) __unlockfile((f)); else
+#endif
#define F_PERM 1
#define F_NORD 4
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/locale/strcasecmp_l.c b/system/lib/libc/musl/src/locale/strcasecmp_l.c
new file mode 100644
index 00000000..eea2f80b
--- /dev/null
+++ b/system/lib/libc/musl/src/locale/strcasecmp_l.c
@@ -0,0 +1,7 @@
+#include <strings.h>
+#include <ctype.h>
+
+int strcasecmp_l(const char *l, const char *r, locale_t loc)
+{
+ return strcasecmp(l, r);
+}
diff --git a/system/lib/libc/musl/src/locale/strncasecmp_l.c b/system/lib/libc/musl/src/locale/strncasecmp_l.c
new file mode 100644
index 00000000..af33ada6
--- /dev/null
+++ b/system/lib/libc/musl/src/locale/strncasecmp_l.c
@@ -0,0 +1,7 @@
+#include <strings.h>
+#include <locale.h>
+
+int strncasecmp_l(const char *l, const char *r, size_t n, locale_t loc)
+{
+ return strncasecmp(l, r, n);
+}
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/__cosdf.c b/system/lib/libc/musl/src/math/__cosdf.c
new file mode 100644
index 00000000..2124989b
--- /dev/null
+++ b/system/lib/libc/musl/src/math/__cosdf.c
@@ -0,0 +1,35 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */
+/*
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Debugged and optimized by Bruce D. Evans.
+ */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "libm.h"
+
+/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */
+static const double
+C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */
+C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */
+C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */
+C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */
+
+float __cosdf(double x)
+{
+ double_t r, w, z;
+
+ /* Try to optimize for parallel evaluation as in __tandf.c. */
+ z = x*x;
+ w = z*z;
+ r = C2+z*C3;
+ return ((1.0+z*C0) + w*C1) + (w*z)*r;
+}
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/math/__sindf.c b/system/lib/libc/musl/src/math/__sindf.c
new file mode 100644
index 00000000..8fec2a3f
--- /dev/null
+++ b/system/lib/libc/musl/src/math/__sindf.c
@@ -0,0 +1,36 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */
+/*
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Optimized by Bruce D. Evans.
+ */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "libm.h"
+
+/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */
+static const double
+S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */
+S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */
+S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */
+S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */
+
+float __sindf(double x)
+{
+ double_t r, s, w, z;
+
+ /* Try to optimize for parallel evaluation as in __tandf.c. */
+ z = x*x;
+ w = z*z;
+ r = S3 + z*S4;
+ s = z*x;
+ return (x + s*(S1 + z*S2)) + s*w*r;
+}
diff --git a/system/lib/libc/musl/src/math/ilogb.c b/system/lib/libc/musl/src/math/ilogb.c
new file mode 100644
index 00000000..64d40154
--- /dev/null
+++ b/system/lib/libc/musl/src/math/ilogb.c
@@ -0,0 +1,26 @@
+#include <limits.h>
+#include "libm.h"
+
+int ilogb(double x)
+{
+ #pragma STDC FENV_ACCESS ON
+ union {double f; uint64_t i;} u = {x};
+ uint64_t i = u.i;
+ int e = i>>52 & 0x7ff;
+
+ if (!e) {
+ i <<= 12;
+ if (i == 0) {
+ FORCE_EVAL(0/0.0f);
+ return FP_ILOGB0;
+ }
+ /* subnormal x */
+ for (e = -0x3ff; i>>63 == 0; e--, i<<=1);
+ return e;
+ }
+ if (e == 0x7ff) {
+ FORCE_EVAL(0/0.0f);
+ return i<<12 ? FP_ILOGBNAN : INT_MAX;
+ }
+ return e - 0x3ff;
+}
diff --git a/system/lib/libc/musl/src/math/ilogbf.c b/system/lib/libc/musl/src/math/ilogbf.c
new file mode 100644
index 00000000..e23ba209
--- /dev/null
+++ b/system/lib/libc/musl/src/math/ilogbf.c
@@ -0,0 +1,26 @@
+#include <limits.h>
+#include "libm.h"
+
+int ilogbf(float x)
+{
+ #pragma STDC FENV_ACCESS ON
+ union {float f; uint32_t i;} u = {x};
+ uint32_t i = u.i;
+ int e = i>>23 & 0xff;
+
+ if (!e) {
+ i <<= 9;
+ if (i == 0) {
+ FORCE_EVAL(0/0.0f);
+ return FP_ILOGB0;
+ }
+ /* subnormal x */
+ for (e = -0x7f; i>>31 == 0; e--, i<<=1);
+ return e;
+ }
+ if (e == 0xff) {
+ FORCE_EVAL(0/0.0f);
+ return i<<9 ? FP_ILOGBNAN : INT_MAX;
+ }
+ return e - 0x7f;
+}
diff --git a/system/lib/libc/musl/src/math/ilogbl.c b/system/lib/libc/musl/src/math/ilogbl.c
new file mode 100644
index 00000000..7b1a9cf8
--- /dev/null
+++ b/system/lib/libc/musl/src/math/ilogbl.c
@@ -0,0 +1,55 @@
+#include <limits.h>
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+int ilogbl(long double x)
+{
+ return ilogb(x);
+}
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
+int ilogbl(long double x)
+{
+ #pragma STDC FENV_ACCESS ON
+ union ldshape u = {x};
+ uint64_t m = u.i.m;
+ int e = u.i.se & 0x7fff;
+
+ if (!e) {
+ if (m == 0) {
+ FORCE_EVAL(0/0.0f);
+ return FP_ILOGB0;
+ }
+ /* subnormal x */
+ for (e = -0x3fff+1; m>>63 == 0; e--, m<<=1);
+ return e;
+ }
+ if (e == 0x7fff) {
+ FORCE_EVAL(0/0.0f);
+ return m<<1 ? FP_ILOGBNAN : INT_MAX;
+ }
+ return e - 0x3fff;
+}
+#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
+int ilogbl(long double x)
+{
+ #pragma STDC FENV_ACCESS ON
+ union ldshape u = {x};
+ int e = u.i.se & 0x7fff;
+
+ if (!e) {
+ if (x == 0) {
+ FORCE_EVAL(0/0.0f);
+ return FP_ILOGB0;
+ }
+ /* subnormal x */
+ x *= 0x1p120;
+ return ilogbl(x) - 120;
+ }
+ if (e == 0x7fff) {
+ FORCE_EVAL(0/0.0f);
+ u.i.se = 0;
+ return u.f ? FP_ILOGBNAN : INT_MAX;
+ }
+ return e - 0x3fff;
+}
+#endif
diff --git a/system/lib/libc/musl/src/math/ldexp.c b/system/lib/libc/musl/src/math/ldexp.c
new file mode 100644
index 00000000..f4d1cd6a
--- /dev/null
+++ b/system/lib/libc/musl/src/math/ldexp.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+double ldexp(double x, int n)
+{
+ return scalbn(x, n);
+}
diff --git a/system/lib/libc/musl/src/math/ldexpf.c b/system/lib/libc/musl/src/math/ldexpf.c
new file mode 100644
index 00000000..3bad5f39
--- /dev/null
+++ b/system/lib/libc/musl/src/math/ldexpf.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+float ldexpf(float x, int n)
+{
+ return scalbnf(x, n);
+}
diff --git a/system/lib/libc/musl/src/math/ldexpl.c b/system/lib/libc/musl/src/math/ldexpl.c
new file mode 100644
index 00000000..fd145ccc
--- /dev/null
+++ b/system/lib/libc/musl/src/math/ldexpl.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+long double ldexpl(long double x, int n)
+{
+ return scalbnl(x, n);
+}
diff --git a/system/lib/libc/musl/src/math/lgamma.c b/system/lib/libc/musl/src/math/lgamma.c
new file mode 100644
index 00000000..36006682
--- /dev/null
+++ b/system/lib/libc/musl/src/math/lgamma.c
@@ -0,0 +1,9 @@
+#include <math.h>
+
+extern int signgam;
+double __lgamma_r(double, int *);
+
+double lgamma(double x)
+{
+ return __lgamma_r(x, &signgam);
+}
diff --git a/system/lib/libc/musl/src/math/lgamma_r.c b/system/lib/libc/musl/src/math/lgamma_r.c
new file mode 100644
index 00000000..82e296f5
--- /dev/null
+++ b/system/lib/libc/musl/src/math/lgamma_r.c
@@ -0,0 +1,314 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.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.
+ * ====================================================
+ *
+ */
+/* lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * where
+ * poly(z) is a 14 degree polynomial.
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * with accuracy
+ * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ * where
+ * |w - f(z)| < 2**-58.74
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1) = lgamma(2) = 0
+ * lgamma(x) ~ -log(|x|) for tiny x
+ * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero
+ * lgamma(inf) = inf
+ * lgamma(-inf) = inf (bug for bug compatible with C99!?)
+ *
+ */
+
+#include "libm.h"
+#include "libc.h"
+
+static const double
+two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static double sin_pi(double x)
+{
+ double y,z;
+ int n,ix;
+
+ GET_HIGH_WORD(ix, x);
+ ix &= 0x7fffffff;
+
+ if (ix < 0x3fd00000)
+ return __sin(pi*x, 0.0, 0);
+
+ y = -x; /* negative x is assumed */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floor(y);
+ if (z != y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */
+ n = (int)(y*4.0);
+ } else {
+ if (ix >= 0x43400000) {
+ y = 0.0; /* y must be even */
+ n = 0;
+ } else {
+ if (ix < 0x43300000)
+ z = y + two52; /* exact */
+ GET_LOW_WORD(n, z);
+ n &= 1;
+ y = n;
+ n <<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __sin(pi*y, 0.0, 0); break;
+ case 1:
+ case 2: y = __cos(pi*(0.5-y), 0.0); break;
+ case 3:
+ case 4: y = __sin(pi*(1.0-y), 0.0, 0); break;
+ case 5:
+ case 6: y = -__cos(pi*(y-1.5), 0.0); break;
+ default: y = __sin(pi*(y-2.0), 0.0, 0); break;
+ }
+ return -y;
+}
+
+
+double __lgamma_r(double x, int *signgamp)
+{
+ double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int32_t hx;
+ int i,lx,ix;
+
+ EXTRACT_WORDS(hx, lx, x);
+
+ /* purge off +-inf, NaN, +-0, tiny and negative arguments */
+ *signgamp = 1;
+ ix = hx & 0x7fffffff;
+ if (ix >= 0x7ff00000)
+ return x*x;
+ if ((ix|lx) == 0)
+ return 1.0/0.0;
+ if (ix < 0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ if(hx < 0) {
+ *signgamp = -1;
+ return -log(-x);
+ }
+ return -log(x);
+ }
+ if (hx < 0) {
+ if (ix >= 0x43300000) /* |x|>=2**52, must be -integer */
+ return 1.0/0.0;
+ t = sin_pi(x);
+ if (t == 0.0) /* -integer */
+ return 1.0/0.0;
+ nadj = log(pi/fabs(t*x));
+ if (t < 0.0)
+ *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if (((ix - 0x3ff00000)|lx) == 0 || ((ix - 0x40000000)|lx) == 0)
+ r = 0;
+ /* for x < 2.0 */
+ else if (ix < 0x40000000) {
+ if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -log(x);
+ if (ix >= 0x3FE76944) {
+ y = 1.0 - x;
+ i = 0;
+ } else if (ix >= 0x3FCDA661) {
+ y = x - (tc-1.0);
+ i = 1;
+ } else {
+ y = x;
+ i = 2;
+ }
+ } else {
+ r = 0.0;
+ if (ix >= 0x3FFBB4C3) { /* [1.7316,2] */
+ y = 2.0 - x;
+ i = 0;
+ } else if(ix >= 0x3FF3B4C4) { /* [1.23,1.73] */
+ y = x - tc;
+ i = 1;
+ } else {
+ y = x - 1.0;
+ i = 2;
+ }
+ }
+ switch (i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-0.5*y);
+ break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += tf + p;
+ break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = 1.0+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += -0.5*y + p1/p2;
+ }
+ } else if (ix < 0x40200000) { /* x < 8.0 */
+ i = (int)x;
+ y = x - (double)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = 1.0+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = 0.5*y+p/q;
+ z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch (i) {
+ case 7: z *= y + 6.0; /* FALLTHRU */
+ case 6: z *= y + 5.0; /* FALLTHRU */
+ case 5: z *= y + 4.0; /* FALLTHRU */
+ case 4: z *= y + 3.0; /* FALLTHRU */
+ case 3: z *= y + 2.0; /* FALLTHRU */
+ r += log(z);
+ break;
+ }
+ } else if (ix < 0x43900000) { /* 8.0 <= x < 2**58 */
+ t = log(x);
+ z = 1.0/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-0.5)*(t-1.0)+w;
+ } else /* 2**58 <= x <= inf */
+ r = x*(log(x)-1.0);
+ if (hx < 0)
+ r = nadj - r;
+ return r;
+}
+
+weak_alias(__lgamma_r, lgamma_r);
diff --git a/system/lib/libc/musl/src/math/lgammaf.c b/system/lib/libc/musl/src/math/lgammaf.c
new file mode 100644
index 00000000..628e6ade
--- /dev/null
+++ b/system/lib/libc/musl/src/math/lgammaf.c
@@ -0,0 +1,9 @@
+#include <math.h>
+
+extern int signgam;
+float __lgammaf_r(float, int *);
+
+float lgammaf(float x)
+{
+ return __lgammaf_r(x, &signgam);
+}
diff --git a/system/lib/libc/musl/src/math/lgammaf_r.c b/system/lib/libc/musl/src/math/lgammaf_r.c
new file mode 100644
index 00000000..dc65bace
--- /dev/null
+++ b/system/lib/libc/musl/src/math/lgammaf_r.c
@@ -0,0 +1,249 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */
+/*
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include "libm.h"
+#include "libc.h"
+
+static const float
+two23= 8.3886080000e+06, /* 0x4b000000 */
+pi = 3.1415927410e+00, /* 0x40490fdb */
+a0 = 7.7215664089e-02, /* 0x3d9e233f */
+a1 = 3.2246702909e-01, /* 0x3ea51a66 */
+a2 = 6.7352302372e-02, /* 0x3d89f001 */
+a3 = 2.0580807701e-02, /* 0x3ca89915 */
+a4 = 7.3855509982e-03, /* 0x3bf2027e */
+a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */
+a6 = 1.1927076848e-03, /* 0x3a9c54a1 */
+a7 = 5.1006977446e-04, /* 0x3a05b634 */
+a8 = 2.2086278477e-04, /* 0x39679767 */
+a9 = 1.0801156895e-04, /* 0x38e28445 */
+a10 = 2.5214456400e-05, /* 0x37d383a2 */
+a11 = 4.4864096708e-05, /* 0x383c2c75 */
+tc = 1.4616321325e+00, /* 0x3fbb16c3 */
+tf = -1.2148628384e-01, /* 0xbdf8cdcd */
+/* tt = -(tail of tf) */
+tt = 6.6971006518e-09, /* 0x31e61c52 */
+t0 = 4.8383611441e-01, /* 0x3ef7b95e */
+t1 = -1.4758771658e-01, /* 0xbe17213c */
+t2 = 6.4624942839e-02, /* 0x3d845a15 */
+t3 = -3.2788541168e-02, /* 0xbd064d47 */
+t4 = 1.7970675603e-02, /* 0x3c93373d */
+t5 = -1.0314224288e-02, /* 0xbc28fcfe */
+t6 = 6.1005386524e-03, /* 0x3bc7e707 */
+t7 = -3.6845202558e-03, /* 0xbb7177fe */
+t8 = 2.2596477065e-03, /* 0x3b141699 */
+t9 = -1.4034647029e-03, /* 0xbab7f476 */
+t10 = 8.8108185446e-04, /* 0x3a66f867 */
+t11 = -5.3859531181e-04, /* 0xba0d3085 */
+t12 = 3.1563205994e-04, /* 0x39a57b6b */
+t13 = -3.1275415677e-04, /* 0xb9a3f927 */
+t14 = 3.3552918467e-04, /* 0x39afe9f7 */
+u0 = -7.7215664089e-02, /* 0xbd9e233f */
+u1 = 6.3282704353e-01, /* 0x3f2200f4 */
+u2 = 1.4549225569e+00, /* 0x3fba3ae7 */
+u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */
+u4 = 2.2896373272e-01, /* 0x3e6a7578 */
+u5 = 1.3381091878e-02, /* 0x3c5b3c5e */
+v1 = 2.4559779167e+00, /* 0x401d2ebe */
+v2 = 2.1284897327e+00, /* 0x4008392d */
+v3 = 7.6928514242e-01, /* 0x3f44efdf */
+v4 = 1.0422264785e-01, /* 0x3dd572af */
+v5 = 3.2170924824e-03, /* 0x3b52d5db */
+s0 = -7.7215664089e-02, /* 0xbd9e233f */
+s1 = 2.1498242021e-01, /* 0x3e5c245a */
+s2 = 3.2577878237e-01, /* 0x3ea6cc7a */
+s3 = 1.4635047317e-01, /* 0x3e15dce6 */
+s4 = 2.6642270386e-02, /* 0x3cda40e4 */
+s5 = 1.8402845599e-03, /* 0x3af135b4 */
+s6 = 3.1947532989e-05, /* 0x3805ff67 */
+r1 = 1.3920053244e+00, /* 0x3fb22d3b */
+r2 = 7.2193557024e-01, /* 0x3f38d0c5 */
+r3 = 1.7193385959e-01, /* 0x3e300f6e */
+r4 = 1.8645919859e-02, /* 0x3c98bf54 */
+r5 = 7.7794247773e-04, /* 0x3a4beed6 */
+r6 = 7.3266842264e-06, /* 0x36f5d7bd */
+w0 = 4.1893854737e-01, /* 0x3ed67f1d */
+w1 = 8.3333335817e-02, /* 0x3daaaaab */
+w2 = -2.7777778450e-03, /* 0xbb360b61 */
+w3 = 7.9365057172e-04, /* 0x3a500cfd */
+w4 = -5.9518753551e-04, /* 0xba1c065c */
+w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
+w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
+
+static float sin_pif(float x)
+{
+ float y,z;
+ int n,ix;
+
+ GET_FLOAT_WORD(ix, x);
+ ix &= 0x7fffffff;
+
+ if(ix < 0x3e800000)
+ return __sindf(pi*x);
+
+ y = -x; /* negative x is assumed */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floorf(y);
+ if (z != y) { /* inexact anyway */
+ y *= 0.5f;
+ y = 2.0f*(y - floorf(y)); /* y = |x| mod 2.0 */
+ n = (int)(y*4.0f);
+ } else {
+ if (ix >= 0x4b800000) {
+ y = 0.0f; /* y must be even */
+ n = 0;
+ } else {
+ if (ix < 0x4b000000)
+ z = y + two23; /* exact */
+ GET_FLOAT_WORD(n, z);
+ n &= 1;
+ y = n;
+ n <<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __sindf(pi*y); break;
+ case 1:
+ case 2: y = __cosdf(pi*(0.5f - y)); break;
+ case 3:
+ case 4: y = __sindf(pi*(1.0f - y)); break;
+ case 5:
+ case 6: y = -__cosdf(pi*(y - 1.5f)); break;
+ default: y = __sindf(pi*(y - 2.0f)); break;
+ }
+ return -y;
+}
+
+
+float __lgammaf_r(float x, int *signgamp)
+{
+ float t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int32_t hx;
+ int i,ix;
+
+ GET_FLOAT_WORD(hx, x);
+
+ /* purge off +-inf, NaN, +-0, tiny and negative arguments */
+ *signgamp = 1;
+ ix = hx & 0x7fffffff;
+ if (ix >= 0x7f800000)
+ return x*x;
+ if (ix == 0)
+ return 1.0f/0.0f;
+ if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */
+ if (hx < 0) {
+ *signgamp = -1;
+ return -logf(-x);
+ }
+ return -logf(x);
+ }
+ if (hx < 0) {
+ if (ix >= 0x4b000000) /* |x| >= 2**23, must be -integer */
+ return 1.0f/0.0f;
+ t = sin_pif(x);
+ if (t == 0.0f) /* -integer */
+ return 1.0f/0.0f;
+ nadj = logf(pi/fabsf(t*x));
+ if (t < 0.0f)
+ *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if (ix == 0x3f800000 || ix == 0x40000000)
+ r = 0;
+ /* for x < 2.0 */
+ else if (ix < 0x40000000) {
+ if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -logf(x);
+ if (ix >= 0x3f3b4a20) {
+ y = 1.0f - x;
+ i = 0;
+ } else if (ix >= 0x3e6d3308) {
+ y = x - (tc-1.0f);
+ i = 1;
+ } else {
+ y = x;
+ i = 2;
+ }
+ } else {
+ r = 0.0f;
+ if (ix >= 0x3fdda618) { /* [1.7316,2] */
+ y = 2.0f - x;
+ i = 0;
+ } else if (ix >= 0x3F9da620) { /* [1.23,1.73] */
+ y = x - tc;
+ i = 1;
+ } else {
+ y = x - 1.0f;
+ i = 2;
+ }
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += p - 0.5f*y;
+ break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p);
+ break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = 1.0f+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += -0.5f*y + p1/p2;
+ }
+ } else if (ix < 0x41000000) { /* x < 8.0 */
+ i = (int)x;
+ y = x - (float)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = 1.0f+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = 0.5f*y+p/q;
+ z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch (i) {
+ case 7: z *= y + 6.0f; /* FALLTHRU */
+ case 6: z *= y + 5.0f; /* FALLTHRU */
+ case 5: z *= y + 4.0f; /* FALLTHRU */
+ case 4: z *= y + 3.0f; /* FALLTHRU */
+ case 3: z *= y + 2.0f; /* FALLTHRU */
+ r += logf(z);
+ break;
+ }
+ } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */
+ t = logf(x);
+ z = 1.0f/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-0.5f)*(t-1.0f)+w;
+ } else /* 2**58 <= x <= inf */
+ r = x*(logf(x)-1.0f);
+ if (hx < 0)
+ r = nadj - r;
+ return r;
+}
+
+weak_alias(__lgammaf_r, lgammaf_r);
diff --git a/system/lib/libc/musl/src/math/lgammal.c b/system/lib/libc/musl/src/math/lgammal.c
new file mode 100644
index 00000000..9686d9ee
--- /dev/null
+++ b/system/lib/libc/musl/src/math/lgammal.c
@@ -0,0 +1,386 @@
+/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_lgammal.c */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * 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.
+ */
+/* lgammal(x)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1)=lgamma(2)=0
+ * lgamma(x) ~ -log(x) for tiny x
+ * lgamma(0) = lgamma(inf) = inf
+ * lgamma(-integer) = +-inf
+ *
+ */
+
+#define _GNU_SOURCE
+#include "libm.h"
+#include "libc.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+double __lgamma_r(double x, int *sg);
+
+long double __lgammal_r(long double x, int *sg)
+{
+ return __lgamma_r(x, sg);
+}
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
+static const long double
+pi = 3.14159265358979323846264L,
+two63 = 9.223372036854775808e18L,
+
+/* lgam(1+x) = 0.5 x + x a(x)/b(x)
+ -0.268402099609375 <= x <= 0
+ peak relative error 6.6e-22 */
+a0 = -6.343246574721079391729402781192128239938E2L,
+a1 = 1.856560238672465796768677717168371401378E3L,
+a2 = 2.404733102163746263689288466865843408429E3L,
+a3 = 8.804188795790383497379532868917517596322E2L,
+a4 = 1.135361354097447729740103745999661157426E2L,
+a5 = 3.766956539107615557608581581190400021285E0L,
+
+b0 = 8.214973713960928795704317259806842490498E3L,
+b1 = 1.026343508841367384879065363925870888012E4L,
+b2 = 4.553337477045763320522762343132210919277E3L,
+b3 = 8.506975785032585797446253359230031874803E2L,
+b4 = 6.042447899703295436820744186992189445813E1L,
+/* b5 = 1.000000000000000000000000000000000000000E0 */
+
+
+tc = 1.4616321449683623412626595423257213284682E0L,
+tf = -1.2148629053584961146050602565082954242826E-1, /* double precision */
+/* tt = (tail of tf), i.e. tf + tt has extended precision. */
+tt = 3.3649914684731379602768989080467587736363E-18L,
+/* lgam ( 1.4616321449683623412626595423257213284682E0 ) =
+-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */
+
+/* lgam (x + tc) = tf + tt + x g(x)/h(x)
+ -0.230003726999612341262659542325721328468 <= x
+ <= 0.2699962730003876587373404576742786715318
+ peak relative error 2.1e-21 */
+g0 = 3.645529916721223331888305293534095553827E-18L,
+g1 = 5.126654642791082497002594216163574795690E3L,
+g2 = 8.828603575854624811911631336122070070327E3L,
+g3 = 5.464186426932117031234820886525701595203E3L,
+g4 = 1.455427403530884193180776558102868592293E3L,
+g5 = 1.541735456969245924860307497029155838446E2L,
+g6 = 4.335498275274822298341872707453445815118E0L,
+
+h0 = 1.059584930106085509696730443974495979641E4L,
+h1 = 2.147921653490043010629481226937850618860E4L,
+h2 = 1.643014770044524804175197151958100656728E4L,
+h3 = 5.869021995186925517228323497501767586078E3L,
+h4 = 9.764244777714344488787381271643502742293E2L,
+h5 = 6.442485441570592541741092969581997002349E1L,
+/* h6 = 1.000000000000000000000000000000000000000E0 */
+
+
+/* lgam (x+1) = -0.5 x + x u(x)/v(x)
+ -0.100006103515625 <= x <= 0.231639862060546875
+ peak relative error 1.3e-21 */
+u0 = -8.886217500092090678492242071879342025627E1L,
+u1 = 6.840109978129177639438792958320783599310E2L,
+u2 = 2.042626104514127267855588786511809932433E3L,
+u3 = 1.911723903442667422201651063009856064275E3L,
+u4 = 7.447065275665887457628865263491667767695E2L,
+u5 = 1.132256494121790736268471016493103952637E2L,
+u6 = 4.484398885516614191003094714505960972894E0L,
+
+v0 = 1.150830924194461522996462401210374632929E3L,
+v1 = 3.399692260848747447377972081399737098610E3L,
+v2 = 3.786631705644460255229513563657226008015E3L,
+v3 = 1.966450123004478374557778781564114347876E3L,
+v4 = 4.741359068914069299837355438370682773122E2L,
+v5 = 4.508989649747184050907206782117647852364E1L,
+/* v6 = 1.000000000000000000000000000000000000000E0 */
+
+
+/* lgam (x+2) = .5 x + x s(x)/r(x)
+ 0 <= x <= 1
+ peak relative error 7.2e-22 */
+s0 = 1.454726263410661942989109455292824853344E6L,
+s1 = -3.901428390086348447890408306153378922752E6L,
+s2 = -6.573568698209374121847873064292963089438E6L,
+s3 = -3.319055881485044417245964508099095984643E6L,
+s4 = -7.094891568758439227560184618114707107977E5L,
+s5 = -6.263426646464505837422314539808112478303E4L,
+s6 = -1.684926520999477529949915657519454051529E3L,
+
+r0 = -1.883978160734303518163008696712983134698E7L,
+r1 = -2.815206082812062064902202753264922306830E7L,
+r2 = -1.600245495251915899081846093343626358398E7L,
+r3 = -4.310526301881305003489257052083370058799E6L,
+r4 = -5.563807682263923279438235987186184968542E5L,
+r5 = -3.027734654434169996032905158145259713083E4L,
+r6 = -4.501995652861105629217250715790764371267E2L,
+/* r6 = 1.000000000000000000000000000000000000000E0 */
+
+
+/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2)
+ x >= 8
+ Peak relative error 1.51e-21
+w0 = LS2PI - 0.5 */
+w0 = 4.189385332046727417803e-1L,
+w1 = 8.333333333333331447505E-2L,
+w2 = -2.777777777750349603440E-3L,
+w3 = 7.936507795855070755671E-4L,
+w4 = -5.952345851765688514613E-4L,
+w5 = 8.412723297322498080632E-4L,
+w6 = -1.880801938119376907179E-3L,
+w7 = 4.885026142432270781165E-3L;
+
+static long double sin_pi(long double x)
+{
+ union ldshape u = {x};
+ uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48;
+ long double y, z;
+ int n;
+
+ if (ix < 0x3ffd8000) /* 0.25 */
+ return sinl(pi * x);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floorl(y);
+ if (z != y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - floorl(y));/* y = |x| mod 2.0 */
+ n = (int) (y*4.0);
+ } else {
+ if (ix >= 0x403f8000) { /* 2^64 */
+ y = 0.0; /* y must be even */
+ n = 0;
+ } else {
+ if (ix < 0x403e8000) /* 2^63 */
+ z = y + two63; /* exact */
+ u.f = z;
+ n = u.i.m & 1;
+ y = n;
+ n <<= 2;
+ }
+ }
+
+ switch (n) {
+ case 0:
+ y = sinl(pi * y);
+ break;
+ case 1:
+ case 2:
+ y = cosl(pi * (0.5 - y));
+ break;
+ case 3:
+ case 4:
+ y = sinl(pi * (1.0 - y));
+ break;
+ case 5:
+ case 6:
+ y = -cosl(pi * (y - 1.5));
+ break;
+ default:
+ y = sinl(pi * (y - 2.0));
+ break;
+ }
+ return -y;
+}
+
+long double __lgammal_r(long double x, int *sg) {
+ long double t, y, z, nadj, p, p1, p2, q, r, w;
+ union ldshape u = {x};
+ uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48;
+ int sign = u.i.se >> 15;
+ int i;
+
+ *sg = 1;
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ if (ix >= 0x7fff0000)
+ return x * x;
+ if (x == 0) {
+ *sg -= 2*sign;
+ return 1.0 / fabsl(x);
+ }
+ if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */
+ if (sign) {
+ *sg = -1;
+ return -logl(-x);
+ }
+ return -logl(x);
+ }
+ if (sign) {
+ t = sin_pi (x);
+ if (t == 0.0)
+ return 1.0 / fabsl(t); /* -integer */
+ nadj = logl(pi / fabsl(t * x));
+ if (t < 0.0)
+ *sg = -1;
+ x = -x;
+ }
+
+ if (ix < 0x40008000) { /* x < 2.0 */
+ if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */
+ /* lgamma(x) = lgamma(x+1) - log(x) */
+ r = -logl(x);
+ if (ix >= 0x3ffebb4a) { /* 7.31597900390625e-1 */
+ y = x - 1.0;
+ i = 0;
+ } else if (ix >= 0x3ffced33) { /* 2.31639862060546875e-1 */
+ y = x - (tc - 1.0);
+ i = 1;
+ } else { /* x < 0.23 */
+ y = x;
+ i = 2;
+ }
+ } else {
+ r = 0.0;
+ if (ix >= 0x3fffdda6) { /* 1.73162841796875 */
+ /* [1.7316,2] */
+ y = x - 2.0;
+ i = 0;
+ } else if (ix >= 0x3fff9da6) { /* 1.23162841796875 */
+ /* [1.23,1.73] */
+ y = x - tc;
+ i = 1;
+ } else {
+ /* [0.9, 1.23] */
+ y = x - 1.0;
+ i = 2;
+ }
+ }
+ switch (i) {
+ case 0:
+ p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5))));
+ p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y))));
+ r += 0.5 * y + y * p1/p2;
+ break;
+ case 1:
+ p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6)))));
+ p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y)))));
+ p = tt + y * p1/p2;
+ r += (tf + p);
+ break;
+ case 2:
+ p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6))))));
+ p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y)))));
+ r += (-0.5 * y + p1 / p2);
+ }
+ } else if (ix < 0x40028000) { /* 8.0 */
+ /* x < 8.0 */
+ i = (int)x;
+ t = 0.0;
+ y = x - (double)i;
+ p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))))));
+ q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y))))));
+ r = 0.5 * y + p / q;
+ z = 1.0;/* lgamma(1+s) = log(s) + lgamma(s) */
+ switch (i) {
+ case 7:
+ z *= (y + 6.0); /* FALLTHRU */
+ case 6:
+ z *= (y + 5.0); /* FALLTHRU */
+ case 5:
+ z *= (y + 4.0); /* FALLTHRU */
+ case 4:
+ z *= (y + 3.0); /* FALLTHRU */
+ case 3:
+ z *= (y + 2.0); /* FALLTHRU */
+ r += logl(z);
+ break;
+ }
+ } else if (ix < 0x40418000) { /* 2^66 */
+ /* 8.0 <= x < 2**66 */
+ t = logl(x);
+ z = 1.0 / x;
+ y = z * z;
+ w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7))))));
+ r = (x - 0.5) * (t - 1.0) + w;
+ } else /* 2**66 <= x <= inf */
+ r = x * (logl(x) - 1.0);
+ if (sign)
+ r = nadj - r;
+ return r;
+}
+#endif
+
+extern int signgam;
+
+long double lgammal(long double x)
+{
+ return __lgammal_r(x, &signgam);
+}
+
+weak_alias(__lgammal_r, lgammal_r);
diff --git a/system/lib/libc/musl/src/math/logb.c b/system/lib/libc/musl/src/math/logb.c
new file mode 100644
index 00000000..7f8bdfae
--- /dev/null
+++ b/system/lib/libc/musl/src/math/logb.c
@@ -0,0 +1,17 @@
+#include <math.h>
+
+/*
+special cases:
+ logb(+-0) = -inf, and raise divbyzero
+ logb(+-inf) = +inf
+ logb(nan) = nan
+*/
+
+double logb(double x)
+{
+ if (!isfinite(x))
+ return x * x;
+ if (x == 0)
+ return -1/(x*x);
+ return ilogb(x);
+}
diff --git a/system/lib/libc/musl/src/math/logbf.c b/system/lib/libc/musl/src/math/logbf.c
new file mode 100644
index 00000000..a0a0b5ed
--- /dev/null
+++ b/system/lib/libc/musl/src/math/logbf.c
@@ -0,0 +1,10 @@
+#include <math.h>
+
+float logbf(float x)
+{
+ if (!isfinite(x))
+ return x * x;
+ if (x == 0)
+ return -1/(x*x);
+ return ilogbf(x);
+}
diff --git a/system/lib/libc/musl/src/math/logbl.c b/system/lib/libc/musl/src/math/logbl.c
new file mode 100644
index 00000000..962973a7
--- /dev/null
+++ b/system/lib/libc/musl/src/math/logbl.c
@@ -0,0 +1,16 @@
+#include <math.h>
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double logbl(long double x)
+{
+ return logb(x);
+}
+#else
+long double logbl(long double x)
+{
+ if (!isfinite(x))
+ return x * x;
+ if (x == 0)
+ return -1/(x*x);
+ return ilogbl(x);
+}
+#endif
diff --git a/system/lib/libc/musl/src/math/scalbn.c b/system/lib/libc/musl/src/math/scalbn.c
new file mode 100644
index 00000000..530e07c7
--- /dev/null
+++ b/system/lib/libc/musl/src/math/scalbn.c
@@ -0,0 +1,31 @@
+#include <math.h>
+#include <stdint.h>
+
+double scalbn(double x, int n)
+{
+ union {double f; uint64_t i;} u;
+ double_t y = x;
+
+ if (n > 1023) {
+ y *= 0x1p1023;
+ n -= 1023;
+ if (n > 1023) {
+ y *= 0x1p1023;
+ n -= 1023;
+ if (n > 1023)
+ n = 1023;
+ }
+ } else if (n < -1022) {
+ y *= 0x1p-1022;
+ n += 1022;
+ if (n < -1022) {
+ y *= 0x1p-1022;
+ n += 1022;
+ if (n < -1022)
+ n = -1022;
+ }
+ }
+ u.i = (uint64_t)(0x3ff+n)<<52;
+ x = y * u.f;
+ return x;
+}
diff --git a/system/lib/libc/musl/src/math/scalbnf.c b/system/lib/libc/musl/src/math/scalbnf.c
new file mode 100644
index 00000000..0b62c3c7
--- /dev/null
+++ b/system/lib/libc/musl/src/math/scalbnf.c
@@ -0,0 +1,31 @@
+#include <math.h>
+#include <stdint.h>
+
+float scalbnf(float x, int n)
+{
+ union {float f; uint32_t i;} u;
+ float_t y = x;
+
+ if (n > 127) {
+ y *= 0x1p127f;
+ n -= 127;
+ if (n > 127) {
+ y *= 0x1p127f;
+ n -= 127;
+ if (n > 127)
+ n = 127;
+ }
+ } else if (n < -126) {
+ y *= 0x1p-126f;
+ n += 126;
+ if (n < -126) {
+ y *= 0x1p-126f;
+ n += 126;
+ if (n < -126)
+ n = -126;
+ }
+ }
+ u.i = (uint32_t)(0x7f+n)<<23;
+ x = y * u.f;
+ return x;
+}
diff --git a/system/lib/libc/musl/src/math/scalbnl.c b/system/lib/libc/musl/src/math/scalbnl.c
new file mode 100644
index 00000000..08a4c587
--- /dev/null
+++ b/system/lib/libc/musl/src/math/scalbnl.c
@@ -0,0 +1,36 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double scalbnl(long double x, int n)
+{
+ return scalbn(x, n);
+}
+#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
+long double scalbnl(long double x, int n)
+{
+ union ldshape u;
+
+ if (n > 16383) {
+ x *= 0x1p16383L;
+ n -= 16383;
+ if (n > 16383) {
+ x *= 0x1p16383L;
+ n -= 16383;
+ if (n > 16383)
+ n = 16383;
+ }
+ } else if (n < -16382) {
+ x *= 0x1p-16382L;
+ n += 16382;
+ if (n < -16382) {
+ x *= 0x1p-16382L;
+ n += 16382;
+ if (n < -16382)
+ n = -16382;
+ }
+ }
+ u.f = 1.0;
+ u.i.se = 0x3fff + n;
+ return x * u.f;
+}
+#endif
diff --git a/system/lib/libc/musl/src/math/signgam.c b/system/lib/libc/musl/src/math/signgam.c
new file mode 100644
index 00000000..ee5d70f1
--- /dev/null
+++ b/system/lib/libc/musl/src/math/signgam.c
@@ -0,0 +1,4 @@
+#include <math.h>
+#include "libc.h"
+
+int signgam = 0;
diff --git a/system/lib/libc/musl/src/math/tgamma.c b/system/lib/libc/musl/src/math/tgamma.c
new file mode 100644
index 00000000..f91af735
--- /dev/null
+++ b/system/lib/libc/musl/src/math/tgamma.c
@@ -0,0 +1,222 @@
+/*
+"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964)
+"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001)
+"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004)
+
+approximation method:
+
+ (x - 0.5) S(x)
+Gamma(x) = (x + g - 0.5) * ----------------
+ exp(x + g - 0.5)
+
+with
+ a1 a2 a3 aN
+S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ]
+ x + 1 x + 2 x + 3 x + N
+
+with a0, a1, a2, a3,.. aN constants which depend on g.
+
+for x < 0 the following reflection formula is used:
+
+Gamma(x)*Gamma(-x) = -pi/(x sin(pi x))
+
+most ideas and constants are from boost and python
+*/
+#include "libm.h"
+
+static const double pi = 3.141592653589793238462643383279502884;
+
+/* sin(pi x) with x > 0 && isnormal(x) assumption */
+static double sinpi(double x)
+{
+ int n;
+
+ /* argument reduction: x = |x| mod 2 */
+ /* spurious inexact when x is odd int */
+ x = x * 0.5;
+ x = 2 * (x - floor(x));
+
+ /* reduce x into [-.25,.25] */
+ n = 4 * x;
+ n = (n+1)/2;
+ x -= n * 0.5;
+
+ x *= pi;
+ switch (n) {
+ default: /* case 4 */
+ case 0:
+ return __sin(x, 0, 0);
+ case 1:
+ return __cos(x, 0);
+ case 2:
+ /* sin(0-x) and -sin(x) have different sign at 0 */
+ return __sin(0-x, 0, 0);
+ case 3:
+ return -__cos(x, 0);
+ }
+}
+
+#define N 12
+//static const double g = 6.024680040776729583740234375;
+static const double gmhalf = 5.524680040776729583740234375;
+static const double Snum[N+1] = {
+ 23531376880.410759688572007674451636754734846804940,
+ 42919803642.649098768957899047001988850926355848959,
+ 35711959237.355668049440185451547166705960488635843,
+ 17921034426.037209699919755754458931112671403265390,
+ 6039542586.3520280050642916443072979210699388420708,
+ 1439720407.3117216736632230727949123939715485786772,
+ 248874557.86205415651146038641322942321632125127801,
+ 31426415.585400194380614231628318205362874684987640,
+ 2876370.6289353724412254090516208496135991145378768,
+ 186056.26539522349504029498971604569928220784236328,
+ 8071.6720023658162106380029022722506138218516325024,
+ 210.82427775157934587250973392071336271166969580291,
+ 2.5066282746310002701649081771338373386264310793408,
+};
+static const double Sden[N+1] = {
+ 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535,
+ 2637558, 357423, 32670, 1925, 66, 1,
+};
+/* n! for small integer n */
+static const double fact[] = {
+ 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0,
+ 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0,
+ 355687428096000.0, 6402373705728000.0, 121645100408832000.0,
+ 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0,
+};
+
+/* S(x) rational function for positive x */
+static double S(double x)
+{
+ double_t num = 0, den = 0;
+ int i;
+
+ /* to avoid overflow handle large x differently */
+ if (x < 8)
+ for (i = N; i >= 0; i--) {
+ num = num * x + Snum[i];
+ den = den * x + Sden[i];
+ }
+ else
+ for (i = 0; i <= N; i++) {
+ num = num / x + Snum[i];
+ den = den / x + Sden[i];
+ }
+ return num/den;
+}
+
+double tgamma(double x)
+{
+ double absx, y, dy, z, r;
+
+ /* special cases */
+ if (!isfinite(x))
+ /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */
+ return x + INFINITY;
+
+ /* integer arguments */
+ /* raise inexact when non-integer */
+ if (x == floor(x)) {
+ if (x == 0)
+ /* tgamma(+-0)=+-inf with divide-by-zero */
+ return 1/x;
+ if (x < 0)
+ return 0/0.0;
+ if (x <= sizeof fact/sizeof *fact)
+ return fact[(int)x - 1];
+ }
+
+ absx = fabs(x);
+
+ /* x ~ 0: tgamma(x) ~ 1/x */
+ if (absx < 0x1p-54)
+ return 1/x;
+
+ /* x >= 172: tgamma(x)=inf with overflow */
+ /* x =< -184: tgamma(x)=+-0 with underflow */
+ if (absx >= 184) {
+ if (x < 0) {
+ FORCE_EVAL((float)(0x1p-126/x));
+ if (floor(x) * 0.5 == floor(x * 0.5))
+ return 0;
+ return -0.0;
+ }
+ x *= 0x1p1023;
+ return x;
+ }
+
+ /* handle the error of x + g - 0.5 */
+ y = absx + gmhalf;
+ if (absx > gmhalf) {
+ dy = y - absx;
+ dy -= gmhalf;
+ } else {
+ dy = y - gmhalf;
+ dy -= absx;
+ }
+
+ z = absx - 0.5;
+ r = S(absx) * exp(-y);
+ if (x < 0) {
+ /* reflection formula for negative x */
+ r = -pi / (sinpi(absx) * absx * r);
+ dy = -dy;
+ z = -z;
+ }
+ r += dy * (gmhalf+0.5) * r / y;
+ z = pow(y, 0.5*z);
+ r = r * z * z;
+ return r;
+}
+
+#if 0
+double __lgamma_r(double x, int *sign)
+{
+ double r, absx, z, zz, w;
+
+ *sign = 1;
+
+ /* special cases */
+ if (!isfinite(x))
+ /* lgamma(nan)=nan, lgamma(+-inf)=inf */
+ return x*x;
+
+ /* integer arguments */
+ if (x == floor(x) && x <= 2) {
+ /* n <= 0: lgamma(n)=inf with divbyzero */
+ /* n == 1,2: lgamma(n)=0 */
+ if (x <= 0)
+ return 1/0.0;
+ return 0;
+ }
+
+ absx = fabs(x);
+
+ /* lgamma(x) ~ -log(|x|) for tiny |x| */
+ if (absx < 0x1p-54) {
+ *sign = 1 - 2*!!signbit(x);
+ return -log(absx);
+ }
+
+ /* use tgamma for smaller |x| */
+ if (absx < 128) {
+ x = tgamma(x);
+ *sign = 1 - 2*!!signbit(x);
+ return log(fabs(x));
+ }
+
+ /* second term (log(S)-g) could be more precise here.. */
+ /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */
+ r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5));
+ if (x < 0) {
+ /* reflection formula for negative x */
+ x = sinpi(absx);
+ *sign = 2*!!signbit(x) - 1;
+ r = log(pi/(fabs(x)*absx)) - r;
+ }
+ return r;
+}
+
+weak_alias(__lgamma_r, lgamma_r);
+#endif
diff --git a/system/lib/libc/musl/src/math/tgammaf.c b/system/lib/libc/musl/src/math/tgammaf.c
new file mode 100644
index 00000000..b4ca51c9
--- /dev/null
+++ b/system/lib/libc/musl/src/math/tgammaf.c
@@ -0,0 +1,6 @@
+#include <math.h>
+
+float tgammaf(float x)
+{
+ return tgamma(x);
+}
diff --git a/system/lib/libc/musl/src/math/tgammal.c b/system/lib/libc/musl/src/math/tgammal.c
new file mode 100644
index 00000000..5c1a02a6
--- /dev/null
+++ b/system/lib/libc/musl/src/math/tgammal.c
@@ -0,0 +1,275 @@
+/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_tgammal.c */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * 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.
+ */
+/*
+ * Gamma function
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double x, y, tgammal();
+ *
+ * y = tgammal( x );
+ *
+ *
+ * DESCRIPTION:
+ *
+ * Returns gamma function of the argument. The result is
+ * correctly signed.
+ *
+ * Arguments |x| <= 13 are reduced by recurrence and the function
+ * approximated by a rational function of degree 7/8 in the
+ * interval (2,3). Large arguments are handled by Stirling's
+ * formula. Large negative arguments are made positive using
+ * a reflection formula.
+ *
+ *
+ * ACCURACY:
+ *
+ * Relative error:
+ * arithmetic domain # trials peak rms
+ * IEEE -40,+40 10000 3.6e-19 7.9e-20
+ * IEEE -1755,+1755 10000 4.8e-18 6.5e-19
+ *
+ * Accuracy for large arguments is dominated by error in powl().
+ *
+ */
+
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double tgammal(long double x)
+{
+ return tgamma(x);
+}
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
+/*
+tgamma(x+2) = tgamma(x+2) P(x)/Q(x)
+0 <= x <= 1
+Relative error
+n=7, d=8
+Peak error = 1.83e-20
+Relative error spread = 8.4e-23
+*/
+static const long double P[8] = {
+ 4.212760487471622013093E-5L,
+ 4.542931960608009155600E-4L,
+ 4.092666828394035500949E-3L,
+ 2.385363243461108252554E-2L,
+ 1.113062816019361559013E-1L,
+ 3.629515436640239168939E-1L,
+ 8.378004301573126728826E-1L,
+ 1.000000000000000000009E0L,
+};
+static const long double Q[9] = {
+-1.397148517476170440917E-5L,
+ 2.346584059160635244282E-4L,
+-1.237799246653152231188E-3L,
+-7.955933682494738320586E-4L,
+ 2.773706565840072979165E-2L,
+-4.633887671244534213831E-2L,
+-2.243510905670329164562E-1L,
+ 4.150160950588455434583E-1L,
+ 9.999999999999999999908E-1L,
+};
+
+/*
+static const long double P[] = {
+-3.01525602666895735709e0L,
+-3.25157411956062339893e1L,
+-2.92929976820724030353e2L,
+-1.70730828800510297666e3L,
+-7.96667499622741999770e3L,
+-2.59780216007146401957e4L,
+-5.99650230220855581642e4L,
+-7.15743521530849602425e4L
+};
+static const long double Q[] = {
+ 1.00000000000000000000e0L,
+-1.67955233807178858919e1L,
+ 8.85946791747759881659e1L,
+ 5.69440799097468430177e1L,
+-1.98526250512761318471e3L,
+ 3.31667508019495079814e3L,
+ 1.60577839621734713377e4L,
+-2.97045081369399940529e4L,
+-7.15743521530849602412e4L
+};
+*/
+#define MAXGAML 1755.455L
+/*static const long double LOGPI = 1.14472988584940017414L;*/
+
+/* Stirling's formula for the gamma function
+tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x))
+z(x) = x
+13 <= x <= 1024
+Relative error
+n=8, d=0
+Peak error = 9.44e-21
+Relative error spread = 8.8e-4
+*/
+static const long double STIR[9] = {
+ 7.147391378143610789273E-4L,
+-2.363848809501759061727E-5L,
+-5.950237554056330156018E-4L,
+ 6.989332260623193171870E-5L,
+ 7.840334842744753003862E-4L,
+-2.294719747873185405699E-4L,
+-2.681327161876304418288E-3L,
+ 3.472222222230075327854E-3L,
+ 8.333333333333331800504E-2L,
+};
+
+#define MAXSTIR 1024.0L
+static const long double SQTPI = 2.50662827463100050242E0L;
+
+/* 1/tgamma(x) = z P(z)
+ * z(x) = 1/x
+ * 0 < x < 0.03125
+ * Peak relative error 4.2e-23
+ */
+static const long double S[9] = {
+-1.193945051381510095614E-3L,
+ 7.220599478036909672331E-3L,
+-9.622023360406271645744E-3L,
+-4.219773360705915470089E-2L,
+ 1.665386113720805206758E-1L,
+-4.200263503403344054473E-2L,
+-6.558780715202540684668E-1L,
+ 5.772156649015328608253E-1L,
+ 1.000000000000000000000E0L,
+};
+
+/* 1/tgamma(-x) = z P(z)
+ * z(x) = 1/x
+ * 0 < x < 0.03125
+ * Peak relative error 5.16e-23
+ * Relative error spread = 2.5e-24
+ */
+static const long double SN[9] = {
+ 1.133374167243894382010E-3L,
+ 7.220837261893170325704E-3L,
+ 9.621911155035976733706E-3L,
+-4.219773343731191721664E-2L,
+-1.665386113944413519335E-1L,
+-4.200263503402112910504E-2L,
+ 6.558780715202536547116E-1L,
+ 5.772156649015328608727E-1L,
+-1.000000000000000000000E0L,
+};
+
+static const long double PIL = 3.1415926535897932384626L;
+
+/* Gamma function computed by Stirling's formula.
+ */
+static long double stirf(long double x)
+{
+ long double y, w, v;
+
+ w = 1.0/x;
+ /* For large x, use rational coefficients from the analytical expansion. */
+ if (x > 1024.0)
+ w = (((((6.97281375836585777429E-5L * w
+ + 7.84039221720066627474E-4L) * w
+ - 2.29472093621399176955E-4L) * w
+ - 2.68132716049382716049E-3L) * w
+ + 3.47222222222222222222E-3L) * w
+ + 8.33333333333333333333E-2L) * w
+ + 1.0;
+ else
+ w = 1.0 + w * __polevll(w, STIR, 8);
+ y = expl(x);
+ if (x > MAXSTIR) { /* Avoid overflow in pow() */
+ v = powl(x, 0.5L * x - 0.25L);
+ y = v * (v / y);
+ } else {
+ y = powl(x, x - 0.5L) / y;
+ }
+ y = SQTPI * y * w;
+ return y;
+}
+
+long double tgammal(long double x)
+{
+ long double p, q, z;
+
+ if (!isfinite(x))
+ return x + INFINITY;
+
+ q = fabsl(x);
+ if (q > 13.0) {
+ if (x < 0.0) {
+ p = floorl(q);
+ z = q - p;
+ if (z == 0)
+ return 0 / z;
+ if (q > MAXGAML) {
+ z = 0;
+ } else {
+ if (z > 0.5) {
+ p += 1.0;
+ z = q - p;
+ }
+ z = q * sinl(PIL * z);
+ z = fabsl(z) * stirf(q);
+ z = PIL/z;
+ }
+ if (0.5 * p == floorl(q * 0.5))
+ z = -z;
+ } else if (x > MAXGAML) {
+ z = x * 0x1p16383L;
+ } else {
+ z = stirf(x);
+ }
+ return z;
+ }
+
+ z = 1.0;
+ while (x >= 3.0) {
+ x -= 1.0;
+ z *= x;
+ }
+ while (x < -0.03125L) {
+ z /= x;
+ x += 1.0;
+ }
+ if (x <= 0.03125L)
+ goto small;
+ while (x < 2.0) {
+ z /= x;
+ x += 1.0;
+ }
+ if (x == 2.0)
+ return z;
+
+ x -= 2.0;
+ p = __polevll(x, P, 7);
+ q = __polevll(x, Q, 8);
+ z = z * p / q;
+ return z;
+
+small:
+ /* z==1 if x was originally +-0 */
+ if (x == 0 && z != 1)
+ return x / x;
+ if (x < 0.0) {
+ x = -x;
+ q = z / (x * __polevll(x, SN, 8));
+ } else
+ q = z / (x * __polevll(x, S, 8));
+ return q;
+}
+#endif
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/stdio/__overflow.c b/system/lib/libc/musl/src/stdio/__overflow.c
new file mode 100644
index 00000000..3bb37923
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/__overflow.c
@@ -0,0 +1,10 @@
+#include "stdio_impl.h"
+
+int __overflow(FILE *f, int _c)
+{
+ unsigned char c = _c;
+ if (!f->wend && __towrite(f)) return EOF;
+ if (f->wpos < f->wend && c != f->lbf) return *f->wpos++ = c;
+ if (f->write(f, &c, 1)!=1) return EOF;
+ return c;
+}
diff --git a/system/lib/libc/musl/src/stdio/__toread.c b/system/lib/libc/musl/src/stdio/__toread.c
new file mode 100644
index 00000000..f00cc467
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/__toread.c
@@ -0,0 +1,14 @@
+#include <stdio_impl.h>
+
+int __toread(FILE *f)
+{
+ f->mode |= f->mode-1;
+ if (f->wpos > f->buf) f->write(f, 0, 0);
+ f->wpos = f->wbase = f->wend = 0;
+ if (f->flags & (F_EOF|F_NORD)) {
+ if (f->flags & F_NORD) f->flags |= F_ERR;
+ return EOF;
+ }
+ f->rpos = f->rend = f->buf;
+ return 0;
+}
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/__uflow.c b/system/lib/libc/musl/src/stdio/__uflow.c
new file mode 100644
index 00000000..e28922c2
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/__uflow.c
@@ -0,0 +1,11 @@
+#include "stdio_impl.h"
+
+/* This function will never be called if there is already data
+ * buffered for reading. Thus we can get by with very few branches. */
+
+int __uflow(FILE *f)
+{
+ unsigned char c;
+ if ((f->rend || !__toread(f)) && f->read(f, &c, 1)==1) return c;
+ return EOF;
+}
diff --git a/system/lib/libc/musl/src/stdio/fputwc.c b/system/lib/libc/musl/src/stdio/fputwc.c
new file mode 100644
index 00000000..603fa615
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/fputwc.c
@@ -0,0 +1,53 @@
+#include "stdio_impl.h"
+#include <wchar.h>
+#include <limits.h>
+#include <ctype.h>
+
+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)) {
+ 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 {
+ 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)
+{
+ FLOCK(f);
+ c = __fputwc_unlocked(c, f);
+ FUNLOCK(f);
+ return c;
+}
+
+weak_alias(__fputwc_unlocked, fputwc_unlocked);
+weak_alias(__fputwc_unlocked, putwc_unlocked);
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/atof.c b/system/lib/libc/musl/src/stdlib/atof.c
new file mode 100644
index 00000000..f7fcd826
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/atof.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+double atof(const char *s)
+{
+ return strtod(s, 0);
+}
diff --git a/system/lib/libc/musl/src/stdlib/strtod.c b/system/lib/libc/musl/src/stdlib/strtod.c
new file mode 100644
index 00000000..35f640da
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/strtod.c
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+#include "shgetc.h"
+#include "floatscan.h"
+#include "stdio_impl.h"
+#include "libc.h"
+
+static long double strtox(const char *s, char **p, int prec)
+{
+ FILE f = {
+ .buf = (void *)s, .rpos = (void *)s,
+ .rend = (void *)-1, .lock = -1
+ };
+ shlim(&f, 0);
+ long double y = __floatscan(&f, prec, 1);
+ off_t cnt = shcnt(&f);
+ if (p) *p = cnt ? (char *)s + cnt : (char *)s;
+ return y;
+}
+
+float strtof(const char *restrict s, char **restrict p)
+{
+ return strtox(s, p, 0);
+}
+
+double strtod(const char *restrict s, char **restrict p)
+{
+ return strtox(s, p, 1);
+}
+
+long double strtold(const char *restrict s, char **restrict p)
+{
+ return strtox(s, p, 2);
+}
+
+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/musl/src/stdlib/wcstod.c b/system/lib/libc/musl/src/stdlib/wcstod.c
new file mode 100644
index 00000000..83f308d3
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/wcstod.c
@@ -0,0 +1,64 @@
+#include "shgetc.h"
+#include "floatscan.h"
+#include "stdio_impl.h"
+#include <wctype.h>
+
+/* This read function heavily cheats. It knows:
+ * (1) len will always be 1
+ * (2) non-ascii characters don't matter */
+
+static size_t do_read(FILE *f, unsigned char *buf, size_t len)
+{
+ size_t i;
+ const wchar_t *wcs = f->cookie;
+
+ if (!wcs[0]) wcs=L"@";
+ for (i=0; i<f->buf_size && wcs[i]; i++)
+ f->buf[i] = wcs[i] < 128 ? wcs[i] : '@';
+ f->rpos = f->buf;
+ f->rend = f->buf + i;
+ f->cookie = (void *)(wcs+i);
+
+ if (i && len) {
+ *buf = *f->rpos++;
+ return 1;
+ }
+ return 0;
+}
+
+static long double wcstox(const wchar_t *s, wchar_t **p, int prec)
+{
+ wchar_t *t = (wchar_t *)s;
+ unsigned char buf[64];
+ FILE f = {0};
+ f.flags = 0;
+ f.rpos = f.rend = 0;
+ f.buf = buf + 4;
+ f.buf_size = sizeof buf - 4;
+ f.lock = -1;
+ f.read = do_read;
+ while (iswspace(*t)) t++;
+ f.cookie = (void *)t;
+ shlim(&f, 0);
+ long double y = __floatscan(&f, prec, 1);
+ if (p) {
+ size_t cnt = shcnt(&f);
+ *p = cnt ? t + cnt : (wchar_t *)s;
+ }
+ return y;
+}
+
+float wcstof(const wchar_t *restrict s, wchar_t **restrict p)
+{
+ return wcstox(s, p, 0);
+}
+
+double wcstod(const wchar_t *restrict s, wchar_t **restrict p)
+{
+ return wcstox(s, p, 1);
+}
+
+long double wcstold(const wchar_t *restrict s, wchar_t **restrict p)
+{
+ return wcstox(s, p, 2);
+}
diff --git a/system/lib/libc/musl/src/stdlib/wcstol.c b/system/lib/libc/musl/src/stdlib/wcstol.c
new file mode 100644
index 00000000..4443f577
--- /dev/null
+++ b/system/lib/libc/musl/src/stdlib/wcstol.c
@@ -0,0 +1,82 @@
+#include "stdio_impl.h"
+#include "intscan.h"
+#include "shgetc.h"
+#include <inttypes.h>
+#include <limits.h>
+#include <wctype.h>
+#include <wchar.h>
+
+/* This read function heavily cheats. It knows:
+ * (1) len will always be 1
+ * (2) non-ascii characters don't matter */
+
+static size_t do_read(FILE *f, unsigned char *buf, size_t len)
+{
+ size_t i;
+ const wchar_t *wcs = f->cookie;
+
+ if (!wcs[0]) wcs=L"@";
+ for (i=0; i<f->buf_size && wcs[i]; i++)
+ f->buf[i] = wcs[i] < 128 ? wcs[i] : '@';
+ f->rpos = f->buf;
+ f->rend = f->buf + i;
+ f->cookie = (void *)(wcs+i);
+
+ if (i && len) {
+ *buf = *f->rpos++;
+ return 1;
+ }
+ return 0;
+}
+
+static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsigned long long lim)
+{
+ wchar_t *t = (wchar_t *)s;
+ unsigned char buf[64];
+ FILE f = {0};
+ f.flags = 0;
+ f.rpos = f.rend = 0;
+ f.buf = buf + 4;
+ f.buf_size = sizeof buf - 4;
+ f.lock = -1;
+ f.read = do_read;
+ while (iswspace(*t)) t++;
+ f.cookie = (void *)t;
+ shlim(&f, 0);
+ unsigned long long y = __intscan(&f, base, 1, lim);
+ if (p) {
+ size_t cnt = shcnt(&f);
+ *p = cnt ? t + cnt : (wchar_t *)s;
+ }
+ return y;
+}
+
+unsigned long long wcstoull(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, ULLONG_MAX);
+}
+
+long long wcstoll(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, LLONG_MIN);
+}
+
+unsigned long wcstoul(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, ULONG_MAX);
+}
+
+long wcstol(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstox(s, p, base, 0UL+LONG_MIN);
+}
+
+intmax_t wcstoimax(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstoll(s, p, base);
+}
+
+uintmax_t wcstoumax(const wchar_t *restrict s, wchar_t **restrict p, int base)
+{
+ return wcstoull(s, p, base);
+}
diff --git a/system/lib/libc/musl/src/string/memccpy.c b/system/lib/libc/musl/src/string/memccpy.c
new file mode 100644
index 00000000..b85009c8
--- /dev/null
+++ b/system/lib/libc/musl/src/string/memccpy.c
@@ -0,0 +1,32 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
+{
+ unsigned char *d = dest;
+ const unsigned char *s = src;
+ size_t *wd, k;
+ const size_t *ws;
+
+ c = (unsigned char)c;
+ if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
+ for (; ((uintptr_t)s & ALIGN) && n && (*d=*s)!=c; n--, s++, d++);
+ if ((uintptr_t)s & ALIGN) goto tail;
+ k = ONES * c;
+ wd=(void *)d; ws=(const void *)s;
+ for (; n>=sizeof(size_t) && !HASZERO(*ws^k);
+ n-=sizeof(size_t), ws++, wd++) *wd = *ws;
+ d=(void *)wd; s=(const void *)ws;
+ }
+ for (; n && (*d=*s)!=c; n--, s++, d++);
+tail:
+ if (*s==c) return d+1;
+ return 0;
+}
diff --git a/system/lib/libc/musl/src/string/memmem.c b/system/lib/libc/musl/src/string/memmem.c
new file mode 100644
index 00000000..861fef2f
--- /dev/null
+++ b/system/lib/libc/musl/src/string/memmem.c
@@ -0,0 +1,148 @@
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
+{
+ uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
+ for (h++, k--; k; k--, hw = hw<<8 | *++h)
+ if (hw == nw) return (char *)h-1;
+ return 0;
+}
+
+static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
+{
+ uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8;
+ uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8;
+ for (h+=2, k-=2; k; k--, hw = (hw|*++h)<<8)
+ if (hw == nw) return (char *)h-2;
+ return 0;
+}
+
+static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
+{
+ uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
+ uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
+ for (h+=3, k-=3; k; k--, hw = hw<<8 | *++h)
+ if (hw == nw) return (char *)h-3;
+ return 0;
+}
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+static char *twoway_memmem(const unsigned char *h, const unsigned char *z, const unsigned char *n, size_t l)
+{
+ size_t i, ip, jp, k, p, ms, p0, mem, mem0;
+ size_t byteset[32 / sizeof(size_t)] = { 0 };
+ size_t shift[256];
+
+ /* Computing length of needle and fill shift table */
+ for (i=0; i<l; i++)
+ BITOP(byteset, n[i], |=), shift[n[i]] = i+1;
+
+ /* Compute maximal suffix */
+ ip = -1; jp = 0; k = p = 1;
+ while (jp+k<l) {
+ if (n[ip+k] == n[jp+k]) {
+ if (k == p) {
+ jp += p;
+ k = 1;
+ } else k++;
+ } else if (n[ip+k] > n[jp+k]) {
+ jp += k;
+ k = 1;
+ p = jp - ip;
+ } else {
+ ip = jp++;
+ k = p = 1;
+ }
+ }
+ ms = ip;
+ p0 = p;
+
+ /* And with the opposite comparison */
+ ip = -1; jp = 0; k = p = 1;
+ while (jp+k<l) {
+ if (n[ip+k] == n[jp+k]) {
+ if (k == p) {
+ jp += p;
+ k = 1;
+ } else k++;
+ } else if (n[ip+k] < n[jp+k]) {
+ jp += k;
+ k = 1;
+ p = jp - ip;
+ } else {
+ ip = jp++;
+ k = p = 1;
+ }
+ }
+ if (ip+1 > ms+1) ms = ip;
+ else p = p0;
+
+ /* Periodic needle? */
+ if (memcmp(n, n+p, ms+1)) {
+ mem0 = 0;
+ p = MAX(ms, l-ms-1) + 1;
+ } else mem0 = l-p;
+ mem = 0;
+
+ /* Search loop */
+ for (;;) {
+ /* If remainder of haystack is shorter than needle, done */
+ if (z-h < l) return 0;
+
+ /* Check last byte first; advance by shift on mismatch */
+ if (BITOP(byteset, h[l-1], &)) {
+ k = l-shift[h[l-1]];
+ if (k) {
+ if (mem0 && mem && k < p) k = l-p;
+ h += k;
+ mem = 0;
+ continue;
+ }
+ } else {
+ h += l;
+ mem = 0;
+ continue;
+ }
+
+ /* Compare right half */
+ for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
+ if (n[k]) {
+ h += k-ms;
+ mem = 0;
+ continue;
+ }
+ /* Compare left half */
+ for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
+ if (k == mem) return (char *)h;
+ h += p;
+ mem = mem0;
+ }
+}
+
+void *memmem(const void *h0, size_t k, const void *n0, size_t l)
+{
+ const unsigned char *h = h0, *n = n0;
+
+ /* Return immediately on empty needle */
+ if (!l) return (void *)h;
+
+ /* Return immediately when needle is longer than haystack */
+ if (k<l) return 0;
+
+ /* Use faster algorithms for short needles */
+ h = memchr(h0, *n, k);
+ if (!h || l==1) return (void *)h;
+ if (l==2) return twobyte_memmem(h, k, n);
+ if (l==3) return threebyte_memmem(h, k, n);
+ if (l==4) return fourbyte_memmem(h, k, n);
+
+ return twoway_memmem(h, h+k, n, l);
+}
diff --git a/system/lib/libc/musl/src/string/mempcpy.c b/system/lib/libc/musl/src/string/mempcpy.c
new file mode 100644
index 00000000..c23ca69e
--- /dev/null
+++ b/system/lib/libc/musl/src/string/mempcpy.c
@@ -0,0 +1,6 @@
+#include <string.h>
+
+void *mempcpy(void *dest, const void *src, size_t n)
+{
+ return (char *)memcpy(dest, src, n) + n;
+}
diff --git a/system/lib/libc/musl/src/string/memrchr.c b/system/lib/libc/musl/src/string/memrchr.c
new file mode 100644
index 00000000..a78e9d6c
--- /dev/null
+++ b/system/lib/libc/musl/src/string/memrchr.c
@@ -0,0 +1,12 @@
+#include <string.h>
+#include "libc.h"
+
+void *__memrchr(const void *m, int c, size_t n)
+{
+ const unsigned char *s = m;
+ c = (unsigned char)c;
+ while (n--) if (s[n]==c) return (void *)(s+n);
+ return 0;
+}
+
+weak_alias(__memrchr, memrchr);
diff --git a/system/lib/libc/musl/src/string/strcasestr.c b/system/lib/libc/musl/src/string/strcasestr.c
new file mode 100644
index 00000000..af109f36
--- /dev/null
+++ b/system/lib/libc/musl/src/string/strcasestr.c
@@ -0,0 +1,9 @@
+#define _GNU_SOURCE
+#include <string.h>
+
+char *strcasestr(const char *h, const char *n)
+{
+ size_t l = strlen(n);
+ for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h;
+ return 0;
+}
diff --git a/system/lib/libc/musl/src/string/strchrnul.c b/system/lib/libc/musl/src/string/strchrnul.c
new file mode 100644
index 00000000..ceae4d45
--- /dev/null
+++ b/system/lib/libc/musl/src/string/strchrnul.c
@@ -0,0 +1,27 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "libc.h"
+
+#define ALIGN (sizeof(size_t))
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+char *__strchrnul(const char *s, int c)
+{
+ size_t *w, k;
+
+ c = (unsigned char)c;
+ if (!c) return (char *)s + strlen(s);
+
+ for (; (uintptr_t)s % ALIGN; s++)
+ if (!*s || *(unsigned char *)s == c) return (char *)s;
+ k = ONES * c;
+ for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
+ for (s = (void *)w; *s && *(unsigned char *)s != c; s++);
+ return (char *)s;
+}
+
+weak_alias(__strchrnul, strchrnul);
diff --git a/system/lib/libc/musl/src/string/strlcat.c b/system/lib/libc/musl/src/string/strlcat.c
new file mode 100644
index 00000000..ef81209e
--- /dev/null
+++ b/system/lib/libc/musl/src/string/strlcat.c
@@ -0,0 +1,9 @@
+#define _BSD_SOURCE
+#include <string.h>
+
+size_t strlcat(char *d, const char *s, size_t n)
+{
+ size_t l = strnlen(d, n);
+ if (l == n) return l + strlen(s);
+ return l + strlcpy(d+l, s, n-l);
+}
diff --git a/system/lib/libc/musl/src/string/strlcpy.c b/system/lib/libc/musl/src/string/strlcpy.c
new file mode 100644
index 00000000..4d3ff92a
--- /dev/null
+++ b/system/lib/libc/musl/src/string/strlcpy.c
@@ -0,0 +1,32 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "libc.h"
+
+#define ALIGN (sizeof(size_t)-1)
+#define ONES ((size_t)-1/UCHAR_MAX)
+#define HIGHS (ONES * (UCHAR_MAX/2+1))
+#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
+
+size_t strlcpy(char *d, const char *s, size_t n)
+{
+ char *d0 = d;
+ size_t *wd;
+ const size_t *ws;
+
+ if (!n--) goto finish;
+ if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
+ for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++);
+ if (n && *s) {
+ wd=(void *)d; ws=(const void *)s;
+ for (; n>=sizeof(size_t) && !HASZERO(*ws);
+ n-=sizeof(size_t), ws++, wd++) *wd = *ws;
+ d=(void *)wd; s=(const void *)ws;
+ }
+ }
+ for (; n && (*d=*s); n--, s++, d++);
+ *d = 0;
+finish:
+ return d-d0 + strlen(s);
+}
diff --git a/system/lib/libc/musl/src/string/strsep.c b/system/lib/libc/musl/src/string/strsep.c
new file mode 100644
index 00000000..cb37c32e
--- /dev/null
+++ b/system/lib/libc/musl/src/string/strsep.c
@@ -0,0 +1,13 @@
+#define _GNU_SOURCE
+#include <string.h>
+
+char *strsep(char **str, const char *sep)
+{
+ char *s = *str, *end;
+ if (!s) return NULL;
+ end = s + strcspn(s, sep);
+ if (*end) *end++ = 0;
+ else end = 0;
+ *str = end;
+ return s;
+}
diff --git a/system/lib/libc/musl/src/string/strverscmp.c b/system/lib/libc/musl/src/string/strverscmp.c
new file mode 100644
index 00000000..94d2e15c
--- /dev/null
+++ b/system/lib/libc/musl/src/string/strverscmp.c
@@ -0,0 +1,42 @@
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+
+int strverscmp(const char *l, const char *r)
+{
+ int haszero=1;
+ while (*l==*r) {
+ if (!*l) return 0;
+
+ if (*l=='0') {
+ if (haszero==1) {
+ haszero=0;
+ }
+ } else if (isdigit(*l)) {
+ if (haszero==1) {
+ haszero=2;
+ }
+ } else {
+ haszero=1;
+ }
+ l++; r++;
+ }
+ if (haszero==1 && (*l=='0' || *r=='0')) {
+ haszero=0;
+ }
+ if ((isdigit(*l) && isdigit(*r) ) && haszero) {
+ size_t lenl=0, lenr=0;
+ while (isdigit(l[lenl]) ) lenl++;
+ while (isdigit(r[lenr]) ) lenr++;
+ if (lenl==lenr) {
+ return (*l - *r);
+ } else if (lenl>lenr) {
+ return 1;
+ } else {
+ return -1;
+ }
+ } else {
+ return (*l - *r);
+ }
+}
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 d169ead6..6f1039f1 100644
--- a/system/lib/libcextra.symbols
+++ b/system/lib/libcextra.symbols
@@ -1,4 +1,18 @@
+ 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
W __towlower_l
W __towupper_l
@@ -10,12 +24,22 @@
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
+ T ilogb
+ T ilogbf
+ T ilogbl
T iswalnum
T iswalnum_l
T iswalpha
@@ -42,6 +66,18 @@
T iswupper_l
T iswxdigit
T iswxdigit_l
+ T ldexp
+ T ldexpf
+ T ldexpl
+ T lgamma
+ W lgamma_r
+ T lgammaf
+ W lgammaf_r
+ T lgammal
+ W lgammal_r
+ T logb
+ T logbf
+ T logbl
T mblen
T mbrlen
T mbrtowc
@@ -50,24 +86,53 @@
T mbsrtowcs
T mbstowcs
T mbtowc
+ T memccpy
+ 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
T regfree
+ T scalbnf
+ D signgam
+ T strcasecmp_l
+ T strcasestr
+ W strchrnul
T strfmon
T strfmon_l
+ T strlcat
+ T strlcpy
+ T strncasecmp_l
+ T strsep
+ T strverscmp
T strxfrm
W strxfrm_l
T swprintf
+ T tgamma
+ T tgammaf
+ T tgammal
T towctrans
T towctrans_l
T towlower
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
@@ -94,8 +159,17 @@
T wcsrtombs
T wcsspn
T wcsstr
+ T wcstod
+ T wcstof
+ T wcstoimax
T wcstok
+ T wcstol
+ T wcstold
+ T wcstoll
T wcstombs
+ T wcstoul
+ T wcstoull
+ T wcstoumax
T wcswcs
T wcswidth
T wcsxfrm
diff --git a/system/lib/libcxx/exception.cpp b/system/lib/libcxx/exception.cpp
index 83f6fd19..3ce6f2e1 100644
--- a/system/lib/libcxx/exception.cpp
+++ b/system/lib/libcxx/exception.cpp
@@ -24,7 +24,7 @@
#ifndef _LIBCPPABI_VERSION
using namespace __cxxabiapple;
// On Darwin, there are two STL shared libraries and a lower level ABI
- // shared libray. The globals holding the current terminate handler and
+ // shared library. The globals holding the current terminate handler and
// current unexpected handler are in the ABI library.
#define __terminate_handler __cxxabiapple::__cxa_terminate_handler
#define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
diff --git a/system/lib/libcxx/locale.cpp b/system/lib/libcxx/locale.cpp
index a326323a..8e7fdb43 100644
--- a/system/lib/libcxx/locale.cpp
+++ b/system/lib/libcxx/locale.cpp
@@ -1036,7 +1036,7 @@ ctype<char>::classic_table() _NOEXCEPT
#elif defined(__EMSCRIPTEN__)
return *__ctype_b_loc();
#elif defined(_AIX)
- return (const unsigned long *)__lc_ctype_ptr->obj->mask;
+ return (const unsigned int *)__lc_ctype_ptr->obj->mask;
#else
// Platform not supported: abort so the person doing the port knows what to
// fix
diff --git a/system/lib/libcxx/new.cpp b/system/lib/libcxx/new.cpp
index fa0331a8..f4998cfb 100644
--- a/system/lib/libcxx/new.cpp
+++ b/system/lib/libcxx/new.cpp
@@ -22,7 +22,7 @@
#ifndef _LIBCPPABI_VERSION
// On Darwin, there are two STL shared libraries and a lower level ABI
- // shared libray. The global holding the current new handler is
+ // shared library. The global holding the current new handler is
// in the ABI library and named __cxa_new_handler.
#define __new_handler __cxxabiapple::__cxa_new_handler
#endif
diff --git a/system/lib/libcxx/optional.cpp b/system/lib/libcxx/optional.cpp
index fde071c9..b614d811 100644
--- a/system/lib/libcxx/optional.cpp
+++ b/system/lib/libcxx/optional.cpp
@@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "optional"
+#include "experimental/optional"
namespace std // purposefully not using versioning namespace
-{
+{ namespace experimental {
#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
@@ -22,4 +22,4 @@ bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
#endif
-} // std
+}} // std::experimental
diff --git a/system/lib/libcxx/random.cpp b/system/lib/libcxx/random.cpp
index 47cdee40..bd24f2e5 100644
--- a/system/lib/libcxx/random.cpp
+++ b/system/lib/libcxx/random.cpp
@@ -19,8 +19,10 @@
#ifdef __sun__
#define rename solaris_headers_are_broken
#endif
+#if !defined(_WIN32)
#include <fcntl.h>
#include <unistd.h>
+#endif // defined(_WIN32)
#include <errno.h>
_LIBCPP_BEGIN_NAMESPACE_STD
diff --git a/system/lib/libcxx/readme.txt b/system/lib/libcxx/readme.txt
index ae8090fd..ccac2fcd 100644
--- a/system/lib/libcxx/readme.txt
+++ b/system/lib/libcxx/readme.txt
@@ -1 +1 @@
-These files are from libc++, svn revision 194185, 2013-11-07.
+These files are from libc++, svn revision 195693, 2013-11-26.
diff --git a/system/lib/libcxx/support/win32/locale_win32.cpp b/system/lib/libcxx/support/win32/locale_win32.cpp
index 1729d84a..5a437434 100644
--- a/system/lib/libcxx/support/win32/locale_win32.cpp
+++ b/system/lib/libcxx/support/win32/locale_win32.cpp
@@ -80,6 +80,16 @@ int wctob_l( wint_t c, locale_t loc )
return wctob( c );
}
+int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...)
+{
+ __locale_raii __current( uselocale(loc), uselocale );
+ va_list ap;
+ va_start( ap, format );
+ int result = vsnprintf( ret, n, format, ap );
+ va_end(ap);
+ return result;
+}
+
int asprintf_l( char **ret, locale_t loc, const char *format, ... )
{
va_list ap;
diff --git a/system/lib/libcxx/symbols b/system/lib/libcxx/symbols
index 51368bce..2c026b0f 100644
--- a/system/lib/libcxx/symbols
+++ b/system/lib/libcxx/symbols
@@ -2408,7 +2408,6 @@
D _ZTISt15underflow_error
D _ZTISt16invalid_argument
D _ZTISt16nested_exception
- C _ZTISt9exception
C _ZTSNSt3__110__stdinbufIcEE
C _ZTSNSt3__110__stdinbufIwEE
C _ZTSNSt3__110__time_getE
@@ -2542,7 +2541,6 @@
D _ZTSSt15underflow_error
D _ZTSSt16invalid_argument
D _ZTSSt16nested_exception
- C _ZTSSt9exception
D _ZTTNSt3__110istrstreamE
D _ZTTNSt3__110ostrstreamE
W _ZTTNSt3__113basic_istreamIcNS_11char_traitsIcEEEE
diff --git a/system/lib/libcxxabi/CREDITS.TXT b/system/lib/libcxxabi/CREDITS.TXT
index 5446562a..bd54ba90 100644
--- a/system/lib/libcxxabi/CREDITS.TXT
+++ b/system/lib/libcxxabi/CREDITS.TXT
@@ -8,18 +8,30 @@ beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
-N: Howard Hinnant
-E: hhinnant@apple.com
-D: Architect and primary coauthor of libc++abi
-
N: Marshall Clow
E: mclow.lists@gmail.com
E: marshall@idio.com
D: Architect and primary coauthor of libc++abi
+N: Matthew Dempsky
+E: matthew@dempsky.org
+D: Minor patches and bug fixes.
+
+N: Nowar Gu
+E: wenhan.gu@gmail.com
+D: Minor patches and fixes
+
+N: Howard Hinnant
+E: hhinnant@apple.com
+D: Architect and primary coauthor of libc++abi
+
N: Nick Kledzik
E: kledzik@apple.com
+N: Bruce Mitchener, Jr.
+E: bruce.mitchener@gmail.com
+D: Minor typo fixes
+
N: Andrew Morrow
E: andrew.c.morrow@gmail.com
D: Minor patches and fixes
@@ -28,11 +40,3 @@ N: Erik Olofsson
E: erik.olofsson@hansoft.se
E: erik@olofsson.info
D: Minor patches and fixes
-
-N: Nowar Gu
-E: wenhan.gu@gmail.com
-D: Minor patches and fixes
-
-N: Bruce Mitchener, Jr.
-E: bruce.mitchener@gmail.com
-D: Minor typo fixes
diff --git a/system/lib/libcxxabi/LICENSE.TXT b/system/lib/libcxxabi/LICENSE.TXT
index b04ba2c9..17969ae2 100644
--- a/system/lib/libcxxabi/LICENSE.TXT
+++ b/system/lib/libcxxabi/LICENSE.TXT
@@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
University of Illinois/NCSA
Open Source License
-Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
All rights reserved.
@@ -55,7 +55,7 @@ SOFTWARE.
==============================================================================
-Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/system/lib/libcxxabi/include/cxa_demangle.h b/system/lib/libcxxabi/include/cxa_demangle.h
deleted file mode 100644
index 46dc9821..00000000
--- a/system/lib/libcxxabi/include/cxa_demangle.h
+++ /dev/null
@@ -1,167 +0,0 @@
-//===-------------------------- cxa_demangle.h ----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _CXA_DEMANGLE_H
-#define _CXA_DEMANGLE_H
-
-#include <cxxabi.h>
-
-#pragma GCC visibility push(hidden)
-
-namespace __cxxabiv1
-{
-
-namespace __libcxxabi
-{
-
-class __demangle_tree;
-class __node;
-
-char*
-__demangle(__demangle_tree, char*, size_t*, int*);
-
-struct __demangle_tree_rv
-{
- __demangle_tree* ptr_;
-
- explicit __demangle_tree_rv(__demangle_tree* ptr)
- : ptr_(ptr) {}
-};
-
-class __demangle_tree
-{
- const char* __mangled_name_begin_;
- const char* __mangled_name_end_;
- int __status_;
- __node* __root_;
- __node* __node_begin_;
- __node* __node_end_;
- __node* __node_cap_;
- __node** __sub_begin_;
- __node** __sub_end_;
- __node** __sub_cap_;
- __node** __t_begin_;
- __node** __t_end_;
- __node** __t_cap_;
- bool __tag_templates_;
- bool __fix_forward_references_;
- bool __owns_buf_;
-
- __demangle_tree& operator=(const __demangle_tree&);
-public:
- __demangle_tree(const char*, char*, size_t);
- ~__demangle_tree();
-
- __demangle_tree(__demangle_tree&);
- __demangle_tree(__demangle_tree_rv);
- operator __demangle_tree_rv() {return __demangle_tree_rv(this);}
-
- int __status() const;
- size_t size() const;
- char* __get_demangled_name(char*) const;
-
- void __parse();
-
-private:
- const char* __parse_encoding(const char*, const char*);
- const char* __parse_type(const char*, const char*,
- bool = true, bool = false);
- const char* __parse_special_name(const char*, const char*);
- const char* __parse_name(const char*, const char*);
- const char* __parse_bare_function_type(const char*, const char*);
- const char* __parse_call_offset(const char*, const char*);
- const char* __parse_number(const char*, const char*);
- const char* __parse_cv_qualifiers(const char* first, const char* last,
- unsigned& cv, bool = false);
- const char* __parse_nested_name(const char*, const char*);
- const char* __parse_discriminator(const char*, const char*);
- const char* __parse_local_name(const char*, const char*);
- const char* __parse_unscoped_template_name(const char*, const char*);
- const char* __parse_unscoped_name(const char*, const char*);
- const char* __parse_operator_name(const char*, const char*, int* = 0);
- const char* __parse_unqualified_name(const char*, const char*);
- const char* __parse_source_name(const char*, const char*);
- const char* __parse_ctor_dtor_name(const char*, const char*);
- const char* __parse_unnamed_type_name(const char*, const char*);
- const char* __parse_template_args(const char*, const char*);
- const char* __parse_template_arg(const char*, const char*);
- const char* __parse_expression(const char*, const char*);
- const char* __parse_expr_primary(const char*, const char*);
- const char* __parse_substitution(const char*, const char*);
- const char* __parse_builtin_type(const char*, const char*);
- const char* __parse_function_type(const char*, const char*);
- const char* __parse_class_enum_type(const char*, const char*);
- const char* __parse_array_type(const char*, const char*);
- const char* __parse_pointer_to_member_type(const char*, const char*);
- const char* __parse_decltype(const char*, const char*);
- const char* __parse_template_param(const char*, const char*);
- const char* __parse_unresolved_name(const char*, const char*);
- const char* __parse_unresolved_type(const char*, const char*);
- const char* __parse_base_unresolved_name(const char*, const char*);
- const char* __parse_simple_id(const char*, const char*);
- const char* __parse_destructor_name(const char*, const char*);
- const char* __parse_function_param(const char*, const char*);
- const char* __parse_const_cast_expr(const char*, const char*);
- const char* __parse_alignof_expr(const char*, const char*);
- const char* __parse_call_expr(const char*, const char*);
- const char* __parse_conversion_expr(const char*, const char*);
- const char* __parse_delete_array_expr(const char*, const char*);
- const char* __parse_delete_expr(const char*, const char*);
- const char* __parse_dynamic_cast_expr(const char*, const char*);
- const char* __parse_dot_star_expr(const char*, const char*);
- const char* __parse_dot_expr(const char*, const char*);
- const char* __parse_decrement_expr(const char*, const char*);
- const char* __parse_new_expr(const char*, const char*);
- const char* __parse_increment_expr(const char*, const char*);
- const char* __parse_arrow_expr(const char*, const char*);
- const char* __parse_reinterpret_cast_expr(const char*, const char*);
- const char* __parse_static_cast_expr(const char*, const char*);
- const char* __parse_sizeof_type_expr(const char*, const char*);
- const char* __parse_sizeof_param_pack_expr(const char*, const char*);
- const char* __parse_typeid_expr(const char*, const char*);
- const char* __parse_throw_expr(const char*, const char*);
- const char* __parse_pack_expansion(const char*, const char*);
- const char* __parse_sizeof_function_param_pack_expr(const char*, const char*);
- const char* __parse_dot_suffix(const char*, const char*);
- const char* __parse_unresolved_qualifier_level(const char*, const char*);
- const char* __parse_vector_type(const char*, const char*);
- const char* __parse_hex_number(const char*, const char*, unsigned long long&);
-
- template <class _Tp> bool __make();
- template <class _Tp, class _A0> bool __make(_A0 __a0);
- template <class _Tp, class _A0, class _A1> bool __make(_A0 __a0, _A1 __a1);
- template <class _Tp, class _A0, class _A1, class _A2>
- bool __make(_A0 __a0, _A1 __a1, _A2 __a2);
- template <class _Tp, class _A0, class _A1, class _A2, class _A3>
- bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3);
- template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4>
- bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4);
- template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4,
- class _A5>
- bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4, _A5 __a5);
-
- friend
- char*
- __demangle(__demangle_tree, char*, size_t*, int*);
-
-};
-
-__demangle_tree
-__demangle(const char*);
-
-__demangle_tree
-__demangle(const char*, char*, size_t);
-
-} // __libcxxabi
-} // __cxxabiv1
-
-#pragma GCC visibility pop
-
-
-#endif // _CXA_DEMANGLE_H
diff --git a/system/lib/libcxxabi/include/libunwind.h b/system/lib/libcxxabi/include/libunwind.h
new file mode 100644
index 00000000..eaeab39f
--- /dev/null
+++ b/system/lib/libcxxabi/include/libunwind.h
@@ -0,0 +1,486 @@
+//===---------------------------- libunwind.h -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Compatible with libuwind API documented at:
+// http://www.nongnu.org/libunwind/man/libunwind(3).html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND__
+#define __LIBUNWIND__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#if __APPLE__
+ #include <Availability.h>
+ #if __arm__
+ #define LIBUNWIND_AVAIL __attribute__((unavailable))
+ #else
+ #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+ #endif
+#else
+ #define LIBUNWIND_AVAIL
+#endif
+
+/* error codes */
+enum {
+ UNW_ESUCCESS = 0, /* no error */
+ UNW_EUNSPEC = -6540, /* unspecified (general) error */
+ UNW_ENOMEM = -6541, /* out of memory */
+ UNW_EBADREG = -6542, /* bad register number */
+ UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
+ UNW_ESTOPUNWIND = -6544, /* stop unwinding */
+ UNW_EINVALIDIP = -6545, /* invalid IP */
+ UNW_EBADFRAME = -6546, /* bad frame */
+ UNW_EINVAL = -6547, /* unsupported operation or bad value */
+ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
+ UNW_ENOINFO = -6549 /* no unwind info found */
+};
+
+struct unw_context_t {
+ uint64_t data[128];
+};
+typedef struct unw_context_t unw_context_t;
+
+struct unw_cursor_t {
+ uint64_t data[140];
+};
+typedef struct unw_cursor_t unw_cursor_t;
+
+typedef struct unw_addr_space *unw_addr_space_t;
+
+typedef int unw_regnum_t;
+typedef uint64_t unw_word_t;
+typedef double unw_fpreg_t;
+
+struct unw_proc_info_t {
+ unw_word_t start_ip; /* start address of function */
+ unw_word_t end_ip; /* address after end of function */
+ unw_word_t lsda; /* address of language specific data area, */
+ /* or zero if not used */
+ unw_word_t handler; /* personality routine, or zero if not used */
+ unw_word_t gp; /* not used */
+ unw_word_t flags; /* not used */
+ uint32_t format; /* compact unwind encoding, or zero if none */
+ uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */
+ unw_word_t unwind_info; /* address of dwarf unwind info, or zero */
+ unw_word_t extra; /* mach_header of mach-o image containing func */
+};
+typedef struct unw_proc_info_t unw_proc_info_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
+extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
+extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
+extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL;
+extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL;
+extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;
+
+extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
+extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL;
+extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
+extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL;
+extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL;
+//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
+
+#if UNW_REMOTE
+/*
+ * Mac OS X "remote" API for unwinding other processes on same machine
+ *
+ */
+extern unw_addr_space_t unw_local_addr_space;
+extern unw_addr_space_t unw_create_addr_space_for_task(task_t);
+extern void unw_destroy_addr_space(unw_addr_space_t);
+extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *);
+#endif
+
+/*
+ * traditional libuwind "remote" API
+ * NOT IMPLEMENTED on Mac OS X
+ *
+ * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t,
+ * thread_t*);
+ * extern unw_accessors_t unw_get_accessors(unw_addr_space_t);
+ * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int);
+ * extern void unw_flush_cache(unw_addr_space_t, unw_word_t,
+ * unw_word_t);
+ * extern int unw_set_caching_policy(unw_addr_space_t,
+ * unw_caching_policy_t);
+ * extern void _U_dyn_register(unw_dyn_info_t*);
+ * extern void _U_dyn_cancel(unw_dyn_info_t*);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+// architecture independent register numbers
+enum {
+ UNW_REG_IP = -1, // instruction pointer
+ UNW_REG_SP = -2, // stack pointer
+};
+
+// 32-bit x86 registers
+enum {
+ UNW_X86_EAX = 0,
+ UNW_X86_ECX = 1,
+ UNW_X86_EDX = 2,
+ UNW_X86_EBX = 3,
+ UNW_X86_EBP = 4,
+ UNW_X86_ESP = 5,
+ UNW_X86_ESI = 6,
+ UNW_X86_EDI = 7
+};
+
+// 64-bit x86_64 registers
+enum {
+ UNW_X86_64_RAX = 0,
+ UNW_X86_64_RDX = 1,
+ UNW_X86_64_RCX = 2,
+ UNW_X86_64_RBX = 3,
+ UNW_X86_64_RSI = 4,
+ UNW_X86_64_RDI = 5,
+ UNW_X86_64_RBP = 6,
+ UNW_X86_64_RSP = 7,
+ UNW_X86_64_R8 = 8,
+ UNW_X86_64_R9 = 9,
+ UNW_X86_64_R10 = 10,
+ UNW_X86_64_R11 = 11,
+ UNW_X86_64_R12 = 12,
+ UNW_X86_64_R13 = 13,
+ UNW_X86_64_R14 = 14,
+ UNW_X86_64_R15 = 15
+};
+
+
+// 32-bit ppc register numbers
+enum {
+ UNW_PPC_R0 = 0,
+ UNW_PPC_R1 = 1,
+ UNW_PPC_R2 = 2,
+ UNW_PPC_R3 = 3,
+ UNW_PPC_R4 = 4,
+ UNW_PPC_R5 = 5,
+ UNW_PPC_R6 = 6,
+ UNW_PPC_R7 = 7,
+ UNW_PPC_R8 = 8,
+ UNW_PPC_R9 = 9,
+ UNW_PPC_R10 = 10,
+ UNW_PPC_R11 = 11,
+ UNW_PPC_R12 = 12,
+ UNW_PPC_R13 = 13,
+ UNW_PPC_R14 = 14,
+ UNW_PPC_R15 = 15,
+ UNW_PPC_R16 = 16,
+ UNW_PPC_R17 = 17,
+ UNW_PPC_R18 = 18,
+ UNW_PPC_R19 = 19,
+ UNW_PPC_R20 = 20,
+ UNW_PPC_R21 = 21,
+ UNW_PPC_R22 = 22,
+ UNW_PPC_R23 = 23,
+ UNW_PPC_R24 = 24,
+ UNW_PPC_R25 = 25,
+ UNW_PPC_R26 = 26,
+ UNW_PPC_R27 = 27,
+ UNW_PPC_R28 = 28,
+ UNW_PPC_R29 = 29,
+ UNW_PPC_R30 = 30,
+ UNW_PPC_R31 = 31,
+ UNW_PPC_F0 = 32,
+ UNW_PPC_F1 = 33,
+ UNW_PPC_F2 = 34,
+ UNW_PPC_F3 = 35,
+ UNW_PPC_F4 = 36,
+ UNW_PPC_F5 = 37,
+ UNW_PPC_F6 = 38,
+ UNW_PPC_F7 = 39,
+ UNW_PPC_F8 = 40,
+ UNW_PPC_F9 = 41,
+ UNW_PPC_F10 = 42,
+ UNW_PPC_F11 = 43,
+ UNW_PPC_F12 = 44,
+ UNW_PPC_F13 = 45,
+ UNW_PPC_F14 = 46,
+ UNW_PPC_F15 = 47,
+ UNW_PPC_F16 = 48,
+ UNW_PPC_F17 = 49,
+ UNW_PPC_F18 = 50,
+ UNW_PPC_F19 = 51,
+ UNW_PPC_F20 = 52,
+ UNW_PPC_F21 = 53,
+ UNW_PPC_F22 = 54,
+ UNW_PPC_F23 = 55,
+ UNW_PPC_F24 = 56,
+ UNW_PPC_F25 = 57,
+ UNW_PPC_F26 = 58,
+ UNW_PPC_F27 = 59,
+ UNW_PPC_F28 = 60,
+ UNW_PPC_F29 = 61,
+ UNW_PPC_F30 = 62,
+ UNW_PPC_F31 = 63,
+ UNW_PPC_MQ = 64,
+ UNW_PPC_LR = 65,
+ UNW_PPC_CTR = 66,
+ UNW_PPC_AP = 67,
+ UNW_PPC_CR0 = 68,
+ UNW_PPC_CR1 = 69,
+ UNW_PPC_CR2 = 70,
+ UNW_PPC_CR3 = 71,
+ UNW_PPC_CR4 = 72,
+ UNW_PPC_CR5 = 73,
+ UNW_PPC_CR6 = 74,
+ UNW_PPC_CR7 = 75,
+ UNW_PPC_XER = 76,
+ UNW_PPC_V0 = 77,
+ UNW_PPC_V1 = 78,
+ UNW_PPC_V2 = 79,
+ UNW_PPC_V3 = 80,
+ UNW_PPC_V4 = 81,
+ UNW_PPC_V5 = 82,
+ UNW_PPC_V6 = 83,
+ UNW_PPC_V7 = 84,
+ UNW_PPC_V8 = 85,
+ UNW_PPC_V9 = 86,
+ UNW_PPC_V10 = 87,
+ UNW_PPC_V11 = 88,
+ UNW_PPC_V12 = 89,
+ UNW_PPC_V13 = 90,
+ UNW_PPC_V14 = 91,
+ UNW_PPC_V15 = 92,
+ UNW_PPC_V16 = 93,
+ UNW_PPC_V17 = 94,
+ UNW_PPC_V18 = 95,
+ UNW_PPC_V19 = 96,
+ UNW_PPC_V20 = 97,
+ UNW_PPC_V21 = 98,
+ UNW_PPC_V22 = 99,
+ UNW_PPC_V23 = 100,
+ UNW_PPC_V24 = 101,
+ UNW_PPC_V25 = 102,
+ UNW_PPC_V26 = 103,
+ UNW_PPC_V27 = 104,
+ UNW_PPC_V28 = 105,
+ UNW_PPC_V29 = 106,
+ UNW_PPC_V30 = 107,
+ UNW_PPC_V31 = 108,
+ UNW_PPC_VRSAVE = 109,
+ UNW_PPC_VSCR = 110,
+ UNW_PPC_SPE_ACC = 111,
+ UNW_PPC_SPEFSCR = 112
+};
+
+// 64-bit ARM64 registers
+enum {
+ UNW_ARM64_X0 = 0,
+ UNW_ARM64_X1 = 1,
+ UNW_ARM64_X2 = 2,
+ UNW_ARM64_X3 = 3,
+ UNW_ARM64_X4 = 4,
+ UNW_ARM64_X5 = 5,
+ UNW_ARM64_X6 = 6,
+ UNW_ARM64_X7 = 7,
+ UNW_ARM64_X8 = 8,
+ UNW_ARM64_X9 = 9,
+ UNW_ARM64_X10 = 10,
+ UNW_ARM64_X11 = 11,
+ UNW_ARM64_X12 = 12,
+ UNW_ARM64_X13 = 13,
+ UNW_ARM64_X14 = 14,
+ UNW_ARM64_X15 = 15,
+ UNW_ARM64_X16 = 16,
+ UNW_ARM64_X17 = 17,
+ UNW_ARM64_X18 = 18,
+ UNW_ARM64_X19 = 19,
+ UNW_ARM64_X20 = 20,
+ UNW_ARM64_X21 = 21,
+ UNW_ARM64_X22 = 22,
+ UNW_ARM64_X23 = 23,
+ UNW_ARM64_X24 = 24,
+ UNW_ARM64_X25 = 25,
+ UNW_ARM64_X26 = 26,
+ UNW_ARM64_X27 = 27,
+ UNW_ARM64_X28 = 28,
+ UNW_ARM64_X29 = 29,
+ UNW_ARM64_FP = 29,
+ UNW_ARM64_X30 = 30,
+ UNW_ARM64_LR = 30,
+ UNW_ARM64_X31 = 31,
+ UNW_ARM64_SP = 31,
+ // reserved block
+ UNW_ARM64_D0 = 64,
+ UNW_ARM64_D1 = 65,
+ UNW_ARM64_D2 = 66,
+ UNW_ARM64_D3 = 67,
+ UNW_ARM64_D4 = 68,
+ UNW_ARM64_D5 = 69,
+ UNW_ARM64_D6 = 70,
+ UNW_ARM64_D7 = 71,
+ UNW_ARM64_D8 = 72,
+ UNW_ARM64_D9 = 73,
+ UNW_ARM64_D10 = 74,
+ UNW_ARM64_D11 = 75,
+ UNW_ARM64_D12 = 76,
+ UNW_ARM64_D13 = 77,
+ UNW_ARM64_D14 = 78,
+ UNW_ARM64_D15 = 79,
+ UNW_ARM64_D16 = 80,
+ UNW_ARM64_D17 = 81,
+ UNW_ARM64_D18 = 82,
+ UNW_ARM64_D19 = 83,
+ UNW_ARM64_D20 = 84,
+ UNW_ARM64_D21 = 85,
+ UNW_ARM64_D22 = 86,
+ UNW_ARM64_D23 = 87,
+ UNW_ARM64_D24 = 88,
+ UNW_ARM64_D25 = 89,
+ UNW_ARM64_D26 = 90,
+ UNW_ARM64_D27 = 91,
+ UNW_ARM64_D28 = 92,
+ UNW_ARM64_D29 = 93,
+ UNW_ARM64_D30 = 94,
+ UNW_ARM64_D31 = 95,
+};
+
+// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1.
+// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3.
+// In this scheme, even though the 64-bit floating point registers D0-D31
+// overlap physically with the 32-bit floating pointer registers S0-S31,
+// they are given a non-overlapping range of register numbers.
+//
+// Commented out ranges are not preserved during unwinding.
+enum {
+ UNW_ARM_R0 = 0,
+ UNW_ARM_R1 = 1,
+ UNW_ARM_R2 = 2,
+ UNW_ARM_R3 = 3,
+ UNW_ARM_R4 = 4,
+ UNW_ARM_R5 = 5,
+ UNW_ARM_R6 = 6,
+ UNW_ARM_R7 = 7,
+ UNW_ARM_R8 = 8,
+ UNW_ARM_R9 = 9,
+ UNW_ARM_R10 = 10,
+ UNW_ARM_R11 = 11,
+ UNW_ARM_R12 = 12,
+ UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP
+ UNW_ARM_R13 = 13,
+ UNW_ARM_LR = 14,
+ UNW_ARM_R14 = 14,
+ UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP
+ UNW_ARM_R15 = 15,
+ // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31.
+ UNW_ARM_S0 = 64,
+ UNW_ARM_S1 = 65,
+ UNW_ARM_S2 = 66,
+ UNW_ARM_S3 = 67,
+ UNW_ARM_S4 = 68,
+ UNW_ARM_S5 = 69,
+ UNW_ARM_S6 = 70,
+ UNW_ARM_S7 = 71,
+ UNW_ARM_S8 = 72,
+ UNW_ARM_S9 = 73,
+ UNW_ARM_S10 = 74,
+ UNW_ARM_S11 = 75,
+ UNW_ARM_S12 = 76,
+ UNW_ARM_S13 = 77,
+ UNW_ARM_S14 = 78,
+ UNW_ARM_S15 = 79,
+ UNW_ARM_S16 = 80,
+ UNW_ARM_S17 = 81,
+ UNW_ARM_S18 = 82,
+ UNW_ARM_S19 = 83,
+ UNW_ARM_S20 = 84,
+ UNW_ARM_S21 = 85,
+ UNW_ARM_S22 = 86,
+ UNW_ARM_S23 = 87,
+ UNW_ARM_S24 = 88,
+ UNW_ARM_S25 = 89,
+ UNW_ARM_S26 = 90,
+ UNW_ARM_S27 = 91,
+ UNW_ARM_S28 = 92,
+ UNW_ARM_S29 = 93,
+ UNW_ARM_S30 = 94,
+ UNW_ARM_S31 = 95,
+ // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP.
+ // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX)
+ UNW_ARM_WR0 = 112,
+ UNW_ARM_WR1 = 113,
+ UNW_ARM_WR2 = 114,
+ UNW_ARM_WR3 = 115,
+ UNW_ARM_WR4 = 116,
+ UNW_ARM_WR5 = 117,
+ UNW_ARM_WR6 = 118,
+ UNW_ARM_WR7 = 119,
+ UNW_ARM_WR8 = 120,
+ UNW_ARM_WR9 = 121,
+ UNW_ARM_WR10 = 122,
+ UNW_ARM_WR11 = 123,
+ UNW_ARM_WR12 = 124,
+ UNW_ARM_WR13 = 125,
+ UNW_ARM_WR14 = 126,
+ UNW_ARM_WR15 = 127,
+ // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC}
+ // 134-143 -- Reserved
+ // 144-150 -- R8_USR–R14_USR
+ // 151-157 -- R8_FIQ–R14_FIQ
+ // 158-159 -- R13_IRQ–R14_IRQ
+ // 160-161 -- R13_ABT–R14_ABT
+ // 162-163 -- R13_UND–R14_UND
+ // 164-165 -- R13_SVC–R14_SVC
+ // 166-191 -- Reserved
+ UNW_ARM_WC0 = 192,
+ UNW_ARM_WC1 = 193,
+ UNW_ARM_WC2 = 194,
+ UNW_ARM_WC3 = 195,
+ // 196-199 -- wC4-wC7 (Intel wireless MMX control)
+ // 200-255 -- Reserved
+ UNW_ARM_D0 = 256,
+ UNW_ARM_D1 = 257,
+ UNW_ARM_D2 = 258,
+ UNW_ARM_D3 = 259,
+ UNW_ARM_D4 = 260,
+ UNW_ARM_D5 = 261,
+ UNW_ARM_D6 = 262,
+ UNW_ARM_D7 = 263,
+ UNW_ARM_D8 = 264,
+ UNW_ARM_D9 = 265,
+ UNW_ARM_D10 = 266,
+ UNW_ARM_D11 = 267,
+ UNW_ARM_D12 = 268,
+ UNW_ARM_D13 = 269,
+ UNW_ARM_D14 = 270,
+ UNW_ARM_D15 = 271,
+ UNW_ARM_D16 = 272,
+ UNW_ARM_D17 = 273,
+ UNW_ARM_D18 = 274,
+ UNW_ARM_D19 = 275,
+ UNW_ARM_D20 = 276,
+ UNW_ARM_D21 = 277,
+ UNW_ARM_D22 = 278,
+ UNW_ARM_D23 = 279,
+ UNW_ARM_D24 = 280,
+ UNW_ARM_D25 = 281,
+ UNW_ARM_D26 = 282,
+ UNW_ARM_D27 = 283,
+ UNW_ARM_D28 = 284,
+ UNW_ARM_D29 = 285,
+ UNW_ARM_D30 = 286,
+ UNW_ARM_D31 = 287,
+ // 288-319 -- Reserved for VFP/Neon
+ // 320-8191 -- Reserved
+ // 8192-16383 -- Unspecified vendor co-processor register.
+};
+
+#endif
diff --git a/system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h b/system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h
new file mode 100644
index 00000000..61106880
--- /dev/null
+++ b/system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h
@@ -0,0 +1,487 @@
+//===------------------ mach-o/compact_unwind_encoding.h ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Darwin's alternative to dwarf based unwind encodings.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __COMPACT_UNWIND_ENCODING__
+#define __COMPACT_UNWIND_ENCODING__
+
+#include <stdint.h>
+
+//
+// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section
+// of object files. Or compilers can emit compact unwind information in
+// the __LD,__compact_unwind section.
+//
+// When the linker creates a final linked image, it will create a
+// __TEXT,__unwind_info section. This section is a small and fast way for the
+// runtime to access unwind info for any given function. If the compiler
+// emitted compact unwind info for the function, that compact unwind info will
+// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
+// dwarf unwind info, the __TEXT,__unwind_info section will contain the offset
+// of the FDE in the __TEXT,__eh_frame section in the final linked image.
+//
+// Note: Previously, the linker would transform some dwarf unwind infos into
+// compact unwind info. But that is fragile and no longer done.
+
+
+//
+// The compact unwind endoding is a 32-bit value which encoded in an
+// architecture specific way, which registers to restore from where, and how
+// to unwind out of the function.
+//
+typedef uint32_t compact_unwind_encoding_t;
+
+
+// architecture independent bits
+enum {
+ UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
+ UNWIND_HAS_LSDA = 0x40000000,
+ UNWIND_PERSONALITY_MASK = 0x30000000,
+};
+
+
+
+
+//
+// x86
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// ebp based:
+// 15-bits (5*3-bits per reg) register permutation
+// 8-bits for stack offset
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_MODE_MASK = 0x0F000000,
+ UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
+ UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_REG_NONE = 0,
+ UNWIND_X86_REG_EBX = 1,
+ UNWIND_X86_REG_ECX = 2,
+ UNWIND_X86_REG_EDX = 3,
+ UNWIND_X86_REG_EDI = 4,
+ UNWIND_X86_REG_ESI = 5,
+ UNWIND_X86_REG_EBP = 6,
+};
+
+//
+// For x86 there are four modes for the compact unwind encoding:
+// UNWIND_X86_MODE_EBP_FRAME:
+// EBP based frame where EBP is push on stack immediately after return address,
+// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
+// EPB value, then EBP is restored by popping off the stack, and the return
+// is done by popping the stack once more into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
+// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved
+// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
+// Each entry contains which register to restore.
+// UNWIND_X86_MODE_STACK_IMMD:
+// A "frameless" (EBP not used as frame pointer) function with a small
+// constant stack size. To return, a constant (encoded in the compact
+// unwind encoding) is added to the ESP. Then the return is done by
+// popping the stack into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// on the stack immediately after the return address. The stack_size/4 is
+// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
+// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
+// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+// saved and their order.
+// UNWIND_X86_MODE_STACK_IND:
+// A "frameless" (EBP not used as frame pointer) function large constant
+// stack size. This case is like the previous, except the stack size is too
+// large to encode in the compact unwind encoding. Instead it requires that
+// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
+// encoding contains the offset to the nnnnnnnn value in the function in
+// UNWIND_X86_FRAMELESS_STACK_SIZE.
+// UNWIND_X86_MODE_DWARF:
+// No compact unwind encoding is available. Instead the low 24-bits of the
+// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
+// This mode is never used in object files. It is only generated by the
+// linker in final linked images which have only dwarf unwind info for a
+// function.
+//
+// The following is the algorithm used to create the permutation encoding used
+// with frameless stacks. It is passed the number of registers to be saved and
+// an array of the register numbers saved.
+//
+//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6])
+//{
+// uint32_t renumregs[6];
+// for (int i=6-registerCount; i < 6; ++i) {
+// int countless = 0;
+// for (int j=6-registerCount; j < i; ++j) {
+// if ( registers[j] < registers[i] )
+// ++countless;
+// }
+// renumregs[i] = registers[i] - countless -1;
+// }
+// uint32_t permutationEncoding = 0;
+// switch ( registerCount ) {
+// case 6:
+// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
+// + 6*renumregs[2] + 2*renumregs[3]
+// + renumregs[4]);
+// break;
+// case 5:
+// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
+// + 6*renumregs[3] + 2*renumregs[4]
+// + renumregs[5]);
+// break;
+// case 4:
+// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
+// + 3*renumregs[4] + renumregs[5]);
+// break;
+// case 3:
+// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
+// + renumregs[5]);
+// break;
+// case 2:
+// permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+// break;
+// case 1:
+// permutationEncoding |= (renumregs[5]);
+// break;
+// }
+// return permutationEncoding;
+//}
+//
+
+
+
+
+//
+// x86_64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// rbp based:
+// 15-bits (5*3-bits per reg) register permutation
+// 8-bits for stack offset
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_64_MODE_MASK = 0x0F000000,
+ UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
+ UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_64_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_64_REG_NONE = 0,
+ UNWIND_X86_64_REG_RBX = 1,
+ UNWIND_X86_64_REG_R12 = 2,
+ UNWIND_X86_64_REG_R13 = 3,
+ UNWIND_X86_64_REG_R14 = 4,
+ UNWIND_X86_64_REG_R15 = 5,
+ UNWIND_X86_64_REG_RBP = 6,
+};
+//
+// For x86_64 there are four modes for the compact unwind encoding:
+// UNWIND_X86_64_MODE_RBP_FRAME:
+// RBP based frame where RBP is push on stack immediately after return address,
+// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
+// EPB value, then RBP is restored by popping off the stack, and the return
+// is done by popping the stack once more into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// in a small range in the stack that starts RBP-8 to RBP-1020. The offset/4
+// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
+// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
+// Each entry contains which register to restore.
+// UNWIND_X86_64_MODE_STACK_IMMD:
+// A "frameless" (RBP not used as frame pointer) function with a small
+// constant stack size. To return, a constant (encoded in the compact
+// unwind encoding) is added to the RSP. Then the return is done by
+// popping the stack into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// on the stack immediately after the return address. The stack_size/4 is
+// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 1024).
+// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
+// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+// saved and their order.
+// UNWIND_X86_64_MODE_STACK_IND:
+// A "frameless" (RBP not used as frame pointer) function large constant
+// stack size. This case is like the previous, except the stack size is too
+// large to encode in the compact unwind encoding. Instead it requires that
+// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
+// encoding contains the offset to the nnnnnnnn value in the function in
+// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
+// UNWIND_X86_64_MODE_DWARF:
+// No compact unwind encoding is available. Instead the low 24-bits of the
+// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
+// This mode is never used in object files. It is only generated by the
+// linker in final linked images which have only dwarf unwind info for a
+// function.
+//
+
+
+#ifndef __OPEN_SOURCE__
+
+// ARM64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 4=frame-based, 2=frameless, 3=dwarf
+// frameless:
+// 12-bits of stack size
+// frame-based:
+// 4-bits D reg pairs saved
+// 5-bits X reg pairs saved
+// dwarf:
+// 24-bits offset of dwarf FDE in __eh_frame section
+//
+enum {
+ UNWIND_ARM64_MODE_MASK = 0x0F000000,
+ UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
+ UNWIND_ARM64_MODE_DWARF = 0x03000000,
+ UNWIND_ARM64_MODE_FRAME = 0x04000000,
+
+ UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
+ UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
+ UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
+ UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
+ UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
+ UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
+ UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
+ UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
+ UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
+
+ UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD = 0x00000001,
+ UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD = 0x00000002,
+ UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD = 0x00000004,
+ UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD = 0x00000008,
+ UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD = 0x00000010,
+ UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD = 0x00000020,
+ UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD = 0x00000040,
+ UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD = 0x00000080,
+
+ UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
+ UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+// For arm64 there are three modes for the compact unwind encoding:
+// UNWIND_ARM64_MODE_FRAME:
+// This is a standard arm64 prolog where FP/LR are immediately pushed on the
+// stack, then SP is copied to FP. If there are any non-volatile registers
+// saved, then are copied into the stack frame in pairs in a contiguous
+// range right below the saved FP/LR pair. Any subset of the five X pairs
+// and four D pairs can be saved, but the memory layout must be in register
+// number order.
+// UNWIND_ARM64_MODE_FRAMELESS:
+// A "frameless" leaf function, where FP/LR are not saved. The return address
+// remains in LR throughout the function. If any non-volatile registers
+// are saved, they must be pushed onto the stack before any stack space is
+// allocated for local variables. The stack sized (including any saved
+// non-volatile registers) divided by 16 is encoded in the bits
+// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
+// UNWIND_ARM64_MODE_DWARF:
+// No compact unwind encoding is available. Instead the low 24-bits of the
+// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
+// This mode is never used in object files. It is only generated by the
+// linker in final linked images which have only dwarf unwind info for a
+// function.
+//
+
+#endif // __OPEN_SOURCE__
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Relocatable Object Files: __LD,__compact_unwind
+//
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// A compiler can generated compact unwind information for a function by adding
+// a "row" to the __LD,__compact_unwind section. This section has the
+// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
+// It is removed by the new linker, so never ends up in final executables.
+// This section is a table, initially with one row per function (that needs
+// unwind info). The table columns and some conceptual entries are:
+//
+// range-start pointer to start of function/range
+// range-length
+// compact-unwind-encoding 32-bit encoding
+// personality-function or zero if no personality function
+// lsda or zero if no LSDA data
+//
+// The length and encoding fields are 32-bits. The other are all pointer sized.
+//
+// In x86_64 assembly, these entry would look like:
+//
+// .section __LD,__compact_unwind,regular,debug
+//
+// #compact unwind for _foo
+// .quad _foo
+// .set L1,LfooEnd-_foo
+// .long L1
+// .long 0x01010001
+// .quad 0
+// .quad 0
+//
+// #compact unwind for _bar
+// .quad _bar
+// .set L2,LbarEnd-_bar
+// .long L2
+// .long 0x01020011
+// .quad __gxx_personality
+// .quad except_tab1
+//
+//
+// Notes: There is no need for any labels in the the __compact_unwind section.
+// The use of the .set directive is to force the evaluation of the
+// range-length at assembly time, instead of generating relocations.
+//
+// To support future compiler optimizations where which non-volatile registers
+// are saved changes within a function (e.g. delay saving non-volatiles until
+// necessary), there can by multiple lines in the __compact_unwind table for one
+// function, each with a different (non-overlapping) range and each with
+// different compact unwind encodings that correspond to the non-volatiles
+// saved at that range of the function.
+//
+// If a particular function is so wacky that there is no compact unwind way
+// to encode it, then the compiler can emit traditional dwarf unwind info.
+// The runtime will use which ever is available.
+//
+// Runtime support for compact unwind encodings are only available on 10.6
+// and later. So, the compiler should not generate it when targeting pre-10.6.
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Final Linked Images: __TEXT,__unwind_info
+//
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
+// The header of the section contains a coarse index that maps function address
+// to the page (4096 byte block) containing the unwind info for that function.
+//
+
+#define UNWIND_SECTION_VERSION 1
+struct unwind_info_section_header
+{
+ uint32_t version; // UNWIND_SECTION_VERSION
+ uint32_t commonEncodingsArraySectionOffset;
+ uint32_t commonEncodingsArrayCount;
+ uint32_t personalityArraySectionOffset;
+ uint32_t personalityArrayCount;
+ uint32_t indexSectionOffset;
+ uint32_t indexCount;
+ // compact_unwind_encoding_t[]
+ // uintptr_t personalities[]
+ // unwind_info_section_header_index_entry[]
+ // unwind_info_section_header_lsda_index_entry[]
+};
+
+struct unwind_info_section_header_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
+ uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
+};
+
+struct unwind_info_section_header_lsda_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t lsdaOffset;
+};
+
+//
+// There are two kinds of second level index pages: regular and compressed.
+// A compressed page can hold up to 1021 entries, but it cannot be used
+// if too many different encoding types are used. The regular page holds
+// 511 entries.
+//
+
+struct unwind_info_regular_second_level_entry
+{
+ uint32_t functionOffset;
+ compact_unwind_encoding_t encoding;
+};
+
+#define UNWIND_SECOND_LEVEL_REGULAR 2
+struct unwind_info_regular_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ // entry array
+};
+
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
+struct unwind_info_compressed_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ uint16_t encodingsPageOffset;
+ uint16_t encodingsCount;
+ // 32-bit entry array
+ // encodings array
+};
+
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
+
+
+
+#endif
+
diff --git a/system/lib/libcxxabi/include/unwind.h b/system/lib/libcxxabi/include/unwind.h
new file mode 100644
index 00000000..c5acd934
--- /dev/null
+++ b/system/lib/libcxxabi/include/unwind.h
@@ -0,0 +1,217 @@
+//===------------------------------- unwind.h -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// C++ ABI Level 1 ABI documented at:
+// http://mentorembedded.github.io/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_H__
+#define __UNWIND_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#if defined(__APPLE__)
+#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
+#else
+#define LIBUNWIND_UNAVAIL
+#endif
+
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+typedef enum {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16 // gcc extension to C++ ABI
+} _Unwind_Action;
+
+struct _Unwind_Context; // opaque
+struct _Unwind_Exception; // forward declaration
+
+struct _Unwind_Exception {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code reason,
+ struct _Unwind_Exception *exc);
+ uintptr_t private_1; // non-zero means forced unwind
+ uintptr_t private_2; // holds sp that phase1 found for phase2 to use
+#if !__LP64__
+ // The gcc implementation of _Unwind_Exception used attribute mode on the
+ // above fields which had the side effect of causing this whole struct to
+ // round up to 32 bytes in size. To be more explicit, we add pad fields
+ // added for binary compatibility.
+ uint32_t reserved[3];
+#endif
+};
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context,
+ void* stop_parameter );
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ struct _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// The following are the base functions documented by the C++ ABI
+//
+#if __arm__
+extern _Unwind_Reason_Code
+ _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object);
+extern void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+ _Unwind_RaiseException(struct _Unwind_Exception *exception_object);
+extern void _Unwind_Resume(struct _Unwind_Exception *exception_object);
+#endif
+extern void _Unwind_DeleteException(struct _Unwind_Exception *exception_object);
+extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
+extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+ uintptr_t new_value);
+extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
+extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
+extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
+extern uintptr_t
+ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context);
+#if __arm__
+extern _Unwind_Reason_Code
+ _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter);
+#else
+extern _Unwind_Reason_Code
+ _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter);
+#endif
+
+#if __arm__
+typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t;
+extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
+extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
+#endif
+
+//
+// The following are semi-suppoted extensions to the C++ ABI
+//
+
+//
+// called by __cxa_rethrow().
+//
+#if __arm__
+extern _Unwind_Reason_Code
+ _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+ _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object);
+#endif
+
+// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
+// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
+// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
+ void *);
+extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
+
+// _Unwind_GetCFA is a gcc extension that can be called from within a
+// personality handler to get the CFA (stack pointer before call) of
+// current frame.
+extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
+
+
+// _Unwind_GetIPInfo is a gcc extension that can be called from within a
+// personality handler. Similar to _Unwind_GetIP() but also returns in
+// *ipBefore a non-zero value if the instruction pointer is at or before the
+// instruction causing the unwind. Normally, in a function call, the IP returned
+// is the return address which is after the call instruction and may be past the
+// end of the function containing the call instruction.
+extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+ int *ipBefore);
+
+
+// __register_frame() is used with dynamically generated code to register the
+// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point
+// to its function and optional LSDA.
+// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and
+// 10.5 it was buggy and did not actually register the FDE with the unwinder.
+// In 10.6 and later it does register properly.
+extern void __register_frame(const void *fde);
+extern void __deregister_frame(const void *fde);
+
+// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
+// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind
+// info" which the runtime uses in preference to dwarf unwind info. This
+// function will only work if the target function has an FDE but no compact
+// unwind info.
+struct dwarf_eh_bases {
+ uintptr_t tbase;
+ uintptr_t dbase;
+ uintptr_t func;
+};
+extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
+
+
+// This function attempts to find the start (address of first instruction) of
+// a function given an address inside the function. It only works if the
+// function has an FDE (dwarf unwind info).
+// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
+// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
+extern void *_Unwind_FindEnclosingFunction(void *pc);
+
+// Mac OS X does not support text-rel and data-rel addressing so these functions
+// are unimplemented
+extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
+ LIBUNWIND_UNAVAIL;
+extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
+ LIBUNWIND_UNAVAIL;
+
+// Mac OS X 10.4 and 10.5 had implementations of these functions in
+// libgcc_s.dylib, but they never worked.
+/// These functions are no longer available on Mac OS X.
+extern void __register_frame_info_bases(const void *fde, void *ob, void *tb,
+ void *db) LIBUNWIND_UNAVAIL;
+extern void __register_frame_info(const void *fde, void *ob)
+ LIBUNWIND_UNAVAIL;
+extern void __register_frame_info_table_bases(const void *fde, void *ob,
+ void *tb, void *db)
+ LIBUNWIND_UNAVAIL;
+extern void __register_frame_info_table(const void *fde, void *ob)
+ LIBUNWIND_UNAVAIL;
+extern void __register_frame_table(const void *fde)
+ LIBUNWIND_UNAVAIL;
+extern void *__deregister_frame_info(const void *fde)
+ LIBUNWIND_UNAVAIL;
+extern void *__deregister_frame_info_bases(const void *fde)
+ LIBUNWIND_UNAVAIL;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UNWIND_H__
diff --git a/system/lib/libcxxabi/lib/buildit b/system/lib/libcxxabi/lib/buildit
index 75a7028a..5a4a7109 100755
--- a/system/lib/libcxxabi/lib/buildit
+++ b/system/lib/libcxxabi/lib/buildit
@@ -27,7 +27,7 @@ then
RC_ProjectSourceVersion=1
fi
-EXTRA_FLAGS="-std=c++0x -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 \
+EXTRA_FLAGS="-std=c++11 -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 \
-Wsign-conversion -Wshadow -Wconversion -Wunused-variable \
-Wmissing-field-initializers -Wchar-subscripts -Wmismatched-tags \
-Wmissing-braces -Wshorten-64-to-32 -Wsign-compare \
@@ -82,12 +82,12 @@ fi
set -x
for FILE in ../src/*.cpp; do
- $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE
+ $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE
done
case $TRIPLE in
*-*-mingw*)
for FILE in ../src/support/win32/*.cpp; do
- $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE
+ $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE
done
;;
esac
diff --git a/system/lib/libcxxabi/readme.txt b/system/lib/libcxxabi/readme.txt
index f55da87c..700a2183 100644
--- a/system/lib/libcxxabi/readme.txt
+++ b/system/lib/libcxxabi/readme.txt
@@ -1 +1 @@
-These files are from libcxxabi, svn revision 175275, Feb 15, 2013.
+These files are from libcxxabi, svn revision 198643, Jan 7, 2014.
diff --git a/system/lib/libcxxabi/src/Unwind/AddressSpace.hpp b/system/lib/libcxxabi/src/Unwind/AddressSpace.hpp
new file mode 100644
index 00000000..67b0973d
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/AddressSpace.hpp
@@ -0,0 +1,430 @@
+//===------------------------- AddressSpace.hpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Abstracts accessing local vs remote address spaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#if __APPLE__
+#include <mach-o/getsect.h>
+namespace libunwind {
+ bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
+}
+#endif
+
+#include "libunwind.h"
+#include "config.h"
+#include "dwarf2.h"
+#include "Registers.hpp"
+
+namespace libunwind {
+
+/// Used by findUnwindSections() to return info about needed sections.
+struct UnwindInfoSections {
+ uintptr_t dso_base;
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ uintptr_t dwarf_section;
+ uintptr_t dwarf_section_length;
+#endif
+#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ uintptr_t dwarf_index_section;
+ uintptr_t dwarf_index_section_length;
+#endif
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ uintptr_t compact_unwind_section;
+ uintptr_t compact_unwind_section_length;
+#endif
+};
+
+
+/// LocalAddressSpace is used as a template parameter to UnwindCursor when
+/// unwinding a thread in the same process. The wrappers compile away,
+/// making local unwinds fast.
+class __attribute__((visibility("hidden"))) LocalAddressSpace {
+public:
+#if __LP64__
+ typedef uint64_t pint_t;
+ typedef int64_t sint_t;
+#else
+ typedef uint32_t pint_t;
+ typedef int32_t sint_t;
+#endif
+ uint8_t get8(pint_t addr) { return *((uint8_t *)addr); }
+ uint16_t get16(pint_t addr) { return *((uint16_t *)addr); }
+ uint32_t get32(pint_t addr) { return *((uint32_t *)addr); }
+ uint64_t get64(pint_t addr) { return *((uint64_t *)addr); }
+ double getDouble(pint_t addr) { return *((double *)addr); }
+ v128 getVector(pint_t addr) { return *((v128 *)addr); }
+ uintptr_t getP(pint_t addr);
+ static uint64_t getULEB128(pint_t &addr, pint_t end);
+ static int64_t getSLEB128(pint_t &addr, pint_t end);
+
+ pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
+ bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
+ unw_word_t *offset);
+ bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
+ bool findOtherFDE(pint_t targetAddr, pint_t &fde);
+
+ static LocalAddressSpace sThisAddressSpace;
+};
+
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
+#if __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+}
+
+/// Read a ULEB128 into a 64-bit word.
+inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
+ const uint8_t *p = (uint8_t *)addr;
+ const uint8_t *pend = (uint8_t *)end;
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ uint64_t b;
+
+ if (p == pend)
+ _LIBUNWIND_ABORT("truncated uleb128 expression");
+
+ b = *p & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b) {
+ _LIBUNWIND_ABORT("malformed uleb128 expression");
+ } else {
+ result |= b << bit;
+ bit += 7;
+ }
+ } while (*p++ >= 0x80);
+ addr = (pint_t) p;
+ return result;
+}
+
+/// Read a SLEB128 into a 64-bit word.
+inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
+ const uint8_t *p = (uint8_t *)addr;
+ const uint8_t *pend = (uint8_t *)end;
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ if (p == pend)
+ _LIBUNWIND_ABORT("truncated sleb128 expression");
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ((byte & 0x40) != 0)
+ result |= (-1LL) << bit;
+ addr = (pint_t) p;
+ return result;
+}
+
+inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
+ pint_t end,
+ uint8_t encoding) {
+ pint_t startAddr = addr;
+ const uint8_t *p = (uint8_t *)addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = getP(addr);
+ p += sizeof(pint_t);
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = (pint_t)getULEB128(addr, end);
+ break;
+ case DW_EH_PE_udata2:
+ result = get16(addr);
+ p += 2;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_udata4:
+ result = get32(addr);
+ p += 4;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_udata8:
+ result = (pint_t)get64(addr);
+ p += 8;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = (pint_t)getSLEB128(addr, end);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (uint16_t)get16(addr);
+ p += 2;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (uint32_t)get32(addr);
+ p += 4;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = (pint_t)get64(addr);
+ p += 8;
+ addr = (pint_t) p;
+ break;
+ default:
+ _LIBUNWIND_ABORT("unknown pointer encoding");
+ }
+
+ // then add relative offset
+ switch (encoding & 0x70) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ case DW_EH_PE_textrel:
+ _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
+ break;
+ case DW_EH_PE_funcrel:
+ _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ _LIBUNWIND_ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if (encoding & DW_EH_PE_indirect)
+ result = getP(result);
+
+ return result;
+}
+
+#if __APPLE__
+ struct dyld_unwind_sections
+ {
+ const struct mach_header* mh;
+ const void* dwarf_section;
+ uintptr_t dwarf_section_length;
+ const void* compact_unwind_section;
+ uintptr_t compact_unwind_section_length;
+ };
+ #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
+ && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
+ // In 10.7.0 or later, libSystem.dylib implements this function.
+ extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
+ #else
+ // In 10.6.x and earlier, we need to implement this functionality.
+ static inline bool _dyld_find_unwind_sections(void* addr,
+ dyld_unwind_sections* info) {
+ // Find mach-o image containing address.
+ Dl_info dlinfo;
+ if (!dladdr(addr, &dlinfo))
+ return false;
+ const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
+
+ // Find dwarf unwind section in that image.
+ unsigned long size;
+ const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
+ if (!p)
+ return false;
+
+ // Fill in return struct.
+ info->mh = mh;
+ info->dwarf_section = p;
+ info->dwarf_section_length = size;
+ info->compact_unwind_section = 0;
+ info->compact_unwind_section_length = 0;
+
+ return true;
+ }
+ #endif
+#endif
+
+inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
+ UnwindInfoSections &info) {
+#if __APPLE__
+ dyld_unwind_sections dyldInfo;
+ if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
+ info.dso_base = (uintptr_t)dyldInfo.mh;
+ #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
+ info.dwarf_section_length = dyldInfo.dwarf_section_length;
+ #endif
+ info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
+ info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
+ return true;
+ }
+#else
+ // TO DO
+
+#endif
+
+ return false;
+}
+
+
+inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
+#if __APPLE__
+ return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
+#else
+ // TO DO: if OS has way to dynamically register FDEs, check that.
+ return false;
+#endif
+}
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
+ size_t bufLen,
+ unw_word_t *offset) {
+ dl_info dyldInfo;
+ if (dladdr((void *)addr, &dyldInfo)) {
+ if (dyldInfo.dli_sname != NULL) {
+ strlcpy(buf, dyldInfo.dli_sname, bufLen);
+ *offset = (addr - (pint_t) dyldInfo.dli_saddr);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+#if UNW_REMOTE
+
+/// OtherAddressSpace is used as a template parameter to UnwindCursor when
+/// unwinding a thread in the another process. The other process can be a
+/// different endianness and a different pointer size which is handled by
+/// the P template parameter.
+template <typename P>
+class OtherAddressSpace {
+public:
+ OtherAddressSpace(task_t task) : fTask(task) {}
+
+ typedef typename P::uint_t pint_t;
+
+ uint8_t get8(pint_t addr);
+ uint16_t get16(pint_t addr);
+ uint32_t get32(pint_t addr);
+ uint64_t get64(pint_t addr);
+ pint_t getP(pint_t addr);
+ uint64_t getULEB128(pint_t &addr, pint_t end);
+ int64_t getSLEB128(pint_t &addr, pint_t end);
+ pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
+ bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
+ unw_word_t *offset);
+ bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
+ bool findOtherFDE(pint_t targetAddr, pint_t &fde);
+private:
+ void *localCopy(pint_t addr);
+
+ task_t fTask;
+};
+
+template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
+ return *((uint8_t *)localCopy(addr));
+}
+
+template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
+ return P::E::get16(*(uint16_t *)localCopy(addr));
+}
+
+template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
+ return P::E::get32(*(uint32_t *)localCopy(addr));
+}
+
+template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
+ return P::E::get64(*(uint64_t *)localCopy(addr));
+}
+
+template <typename P>
+typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
+ return P::getP(*(uint64_t *)localCopy(addr));
+}
+
+template <typename P>
+uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
+ uintptr_t size = (end - addr);
+ LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
+ LocalAddressSpace::pint_t sladdr = laddr;
+ uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
+ addr += (laddr - sladdr);
+ return result;
+}
+
+template <typename P>
+int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
+ uintptr_t size = (end - addr);
+ LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
+ LocalAddressSpace::pint_t sladdr = laddr;
+ uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
+ addr += (laddr - sladdr);
+ return result;
+}
+
+template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
+ // FIX ME
+}
+
+template <typename P>
+bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
+ size_t bufLen, unw_word_t *offset) {
+ // FIX ME
+}
+
+/// unw_addr_space is the base class that abstract unw_addr_space_t type in
+/// libunwind.h points to.
+struct unw_addr_space {
+ cpu_type_t cpuType;
+ task_t taskPort;
+};
+
+/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
+/// to when examining
+/// a 32-bit intel process.
+struct unw_addr_space_i386 : public unw_addr_space {
+ unw_addr_space_i386(task_t task) : oas(task) {}
+ OtherAddressSpace<Pointer32<LittleEndian> > oas;
+};
+
+/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
+/// points to when examining
+/// a 64-bit intel process.
+struct unw_addr_space_x86_64 : public unw_addr_space {
+ unw_addr_space_x86_64(task_t task) : oas(task) {}
+ OtherAddressSpace<Pointer64<LittleEndian> > oas;
+};
+
+/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
+/// to when examining
+/// a 32-bit PowerPC process.
+struct unw_addr_space_ppc : public unw_addr_space {
+ unw_addr_space_ppc(task_t task) : oas(task) {}
+ OtherAddressSpace<Pointer32<BigEndian> > oas;
+};
+
+#endif // UNW_REMOTE
+
+} // namespace libunwind
+
+#endif // __ADDRESSSPACE_HPP__
diff --git a/system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp b/system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp
new file mode 100644
index 00000000..0dc187f1
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp
@@ -0,0 +1,693 @@
+//===-------------------------- CompactUnwinder.hpp -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Does runtime stack unwinding using compact unwind encodings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __COMPACT_UNWINDER_HPP__
+#define __COMPACT_UNWINDER_HPP__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+
+#define EXTRACT_BITS(value, mask) \
+ ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
+
+namespace libunwind {
+
+/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_x86 register set
+template <typename A>
+class CompactUnwinder_x86 {
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t info,
+ uint32_t functionStart, A &addressSpace,
+ Registers_x86 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A &addressSpace, Registers_x86 &registers);
+ static void framelessUnwind(A &addressSpace,
+ typename A::pint_t returnAddressLocation,
+ Registers_x86 &registers);
+ static int
+ stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
+ uint32_t functionStart, A &addressSpace,
+ Registers_x86 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers) {
+ switch (compactEncoding & UNWIND_X86_MODE_MASK) {
+ case UNWIND_X86_MODE_EBP_FRAME:
+ return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
+ addressSpace, registers);
+ case UNWIND_X86_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, false);
+ case UNWIND_X86_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, true);
+ }
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers) {
+ uint32_t savedRegistersOffset =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+ uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
+ for (int i = 0; i < 5; ++i) {
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ (void)functionStart;
+ _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
+ "function starting at 0x%X\n",
+ compactEncoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t encoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers, bool indirectStackSize) {
+ uint32_t stackSizeEncoded =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded * 4;
+ if (indirectStackSize) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
+ stackSize = subl + 4 * stackAdjust;
+ }
+ // decompress permutation
+ uint32_t permunreg[6];
+ switch (regCount) {
+ case 6:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation / 60;
+ permutation -= (permunreg[0] * 60);
+ permunreg[1] = permutation / 12;
+ permutation -= (permunreg[1] * 12);
+ permunreg[2] = permutation / 3;
+ permutation -= (permunreg[2] * 3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation / 20;
+ permutation -= (permunreg[0] * 20);
+ permunreg[1] = permutation / 4;
+ permutation -= (permunreg[1] * 4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation / 5;
+ permutation -= (permunreg[0] * 5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i = 0; i < regCount; ++i) {
+ uint32_t renum = 0;
+ for (int u = 1; u < 7; ++u) {
+ if (!used[u]) {
+ if (renum == permunreg[i]) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
+ for (uint32_t i = 0; i < regCount; ++i) {
+ switch (registersSaved[i]) {
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EBP:
+ registers.setEBP(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+ "function starting at 0x%X\n",
+ encoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
+ Registers_x86 &registers) {
+ typename A::pint_t bp = registers.getEBP();
+ // ebp points to old ebp
+ registers.setEBP(addressSpace.get32(bp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP((uint32_t)bp + 8);
+ // pop return address into eip
+ registers.setIP(addressSpace.get32(bp + 4));
+}
+
+template <typename A>
+void CompactUnwinder_x86<A>::framelessUnwind(
+ A &addressSpace, typename A::pint_t returnAddressLocation,
+ Registers_x86 &registers) {
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get32(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP((uint32_t)returnAddressLocation + 4);
+}
+
+
+/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_x86_64 register set
+template <typename A>
+class CompactUnwinder_x86_64 {
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
+ static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
+ Registers_x86_64 &registers);
+ static int
+ stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers) {
+ switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
+ case UNWIND_X86_64_MODE_RBP_FRAME:
+ return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
+ addressSpace, registers);
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, false);
+ case UNWIND_X86_64_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, true);
+ }
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers) {
+ uint32_t savedRegistersOffset =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+
+ uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
+ for (int i = 0; i < 5; ++i) {
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters));
+ break;
+ default:
+ (void)functionStart;
+ _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
+ "function starting at 0x%llX\n",
+ compactEncoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers, bool indirectStackSize) {
+ uint32_t stackSizeEncoded =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded * 8;
+ if (indirectStackSize) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
+ stackSize = subl + 8 * stackAdjust;
+ }
+ // decompress permutation
+ uint32_t permunreg[6];
+ switch (regCount) {
+ case 6:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation / 60;
+ permutation -= (permunreg[0] * 60);
+ permunreg[1] = permutation / 12;
+ permutation -= (permunreg[1] * 12);
+ permunreg[2] = permutation / 3;
+ permutation -= (permunreg[2] * 3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation / 20;
+ permutation -= (permunreg[0] * 20);
+ permunreg[1] = permutation / 4;
+ permutation -= (permunreg[1] * 4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation / 5;
+ permutation -= (permunreg[0] * 5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i = 0; i < regCount; ++i) {
+ uint32_t renum = 0;
+ for (int u = 1; u < 7; ++u) {
+ if (!used[u]) {
+ if (renum == permunreg[i]) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
+ for (uint32_t i = 0; i < regCount; ++i) {
+ switch (registersSaved[i]) {
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ registers.setRBP(addressSpace.get64(savedRegisters));
+ break;
+ default:
+ _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+ "function starting at 0x%llX\n",
+ encoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
+ Registers_x86_64 &registers) {
+ uint64_t rbp = registers.getRBP();
+ // ebp points to old ebp
+ registers.setRBP(addressSpace.get64(rbp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP(rbp + 16);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rbp + 8));
+}
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
+ uint64_t returnAddressLocation,
+ Registers_x86_64 &registers) {
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get64(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation + 8);
+}
+
+
+
+/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_arm64 register set
+template <typename A>
+class CompactUnwinder_arm64 {
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_arm64 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static int
+ stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_arm64 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_arm64 &registers);
+};
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_arm64 &registers) {
+ switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
+ case UNWIND_ARM64_MODE_FRAME:
+ return stepWithCompactEncodingFrame(compactEncoding, functionStart,
+ addressSpace, registers);
+ case UNWIND_ARM64_MODE_FRAMELESS:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers);
+ }
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
+ Registers_arm64 &registers) {
+ uint32_t stackSize =
+ 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+
+ uint64_t savedRegisterLoc = registers.getSP() + stackSize;
+
+ if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
+ registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
+ registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
+ registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
+ registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
+ registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D8,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D9,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D10,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D11,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D12,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D13,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D14,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D15,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ // subtract stack size off of sp
+ registers.setSP(savedRegisterLoc);
+
+ // set pc to be value in lr
+ registers.setIP(registers.getRegister(UNW_ARM64_LR));
+
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
+ compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
+ Registers_arm64 &registers) {
+ uint64_t savedRegisterLoc = registers.getFP() - 8;
+
+ if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
+ registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
+ registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
+ registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
+ registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
+ registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D8,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D9,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D10,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D11,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D12,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D13,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D14,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D15,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ uint64_t fp = registers.getFP();
+ // fp points to old fp
+ registers.setFP(addressSpace.get64(fp));
+ // old sp is fp less saved fp and lr
+ registers.setSP(fp + 16);
+ // pop return address into pc
+ registers.setIP(addressSpace.get64(fp + 8));
+
+ return UNW_STEP_SUCCESS;
+}
+
+
+}; // namespace libunwind
+
+#endif // __COMPACT_UNWINDER_HPP__
diff --git a/system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp b/system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp
new file mode 100644
index 00000000..158bad87
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp
@@ -0,0 +1,888 @@
+//===-------------------------- DwarfInstructions.hpp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Processor specific interpretation of dwarf unwind info.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dwarf2.h"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "config.h"
+
+
+namespace libunwind {
+
+
+/// DwarfInstructions maps abtract dwarf unwind instructions to a particular
+/// architecture
+template <typename A, typename R>
+class DwarfInstructions {
+public:
+ typedef typename A::pint_t pint_t;
+ typedef typename A::sint_t sint_t;
+
+ static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
+ R &registers);
+
+private:
+
+ enum {
+ DW_X86_64_RET_ADDR = 16
+ };
+
+ enum {
+ DW_X86_RET_ADDR = 8
+ };
+
+ typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation;
+ typedef typename CFI_Parser<A>::PrologInfo PrologInfo;
+ typedef typename CFI_Parser<A>::FDE_Info FDE_Info;
+ typedef typename CFI_Parser<A>::CIE_Info CIE_Info;
+
+ static pint_t evaluateExpression(pint_t expression, A &addressSpace,
+ const R &registers,
+ pint_t initialStackValue);
+ static pint_t getSavedRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+ static double getSavedFloatRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+ static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+
+ // x86 specific variants
+ static int lastRestoreReg(const Registers_x86 &);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86 &);
+ static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
+ const Registers_x86 &);
+
+ // x86_64 specific variants
+ static int lastRestoreReg(const Registers_x86_64 &);
+ static bool isReturnAddressRegister(int regNum, const Registers_x86_64 &);
+ static pint_t getCFA(A &addressSpace,
+ const PrologInfo &prolog,
+ const Registers_x86_64 &);
+
+ // ppc specific variants
+ static int lastRestoreReg(const Registers_ppc &);
+ static bool isReturnAddressRegister(int regNum, const Registers_ppc &);
+ static pint_t getCFA(A &addressSpace,
+ const PrologInfo &prolog,
+ const Registers_ppc &);
+
+ // arm64 specific variants
+ static bool isReturnAddressRegister(int regNum, const Registers_arm64 &);
+ static int lastRestoreReg(const Registers_arm64 &);
+ static pint_t getCFA(A &addressSpace,
+ const PrologInfo &prolog,
+ const Registers_arm64 &);
+
+};
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
+ A &addressSpace, const R &registers, pint_t cfa,
+ const RegisterLocation &savedReg) {
+ switch (savedReg.location) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getP(cfa + (pint_t)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getP(
+ evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ return evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa);
+
+ case CFI_Parser<A>::kRegisterInRegister:
+ return registers.getRegister((int)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ // FIX ME
+ break;
+ }
+ _LIBUNWIND_ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A, R>::getSavedFloatRegister(
+ A &addressSpace, const R &registers, pint_t cfa,
+ const RegisterLocation &savedReg) {
+ switch (savedReg.location) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getDouble(
+ evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ _LIBUNWIND_ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A, R>::getSavedVectorRegister(
+ A &addressSpace, const R &registers, pint_t cfa,
+ const RegisterLocation &savedReg) {
+ switch (savedReg.location) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getVector(cfa + (pint_t)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getVector(
+ evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ _LIBUNWIND_ABORT("unsupported restore location for vector register");
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
+ pint_t fdeStart, R &registers) {
+ FDE_Info fdeInfo;
+ CIE_Info cieInfo;
+ if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart,
+ &fdeInfo, &cieInfo) == NULL) {
+ PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
+ &prolog)) {
+ R newRegisters = registers;
+
+ // get pointer to cfa (architecture specific)
+ pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+ // restore registers that dwarf says were saved
+ pint_t returnAddress = 0;
+ for (int i = 0; i <= lastRestoreReg(newRegisters); ++i) {
+ if (prolog.savedRegisters[i].location !=
+ CFI_Parser<A>::kRegisterUnused) {
+ if (registers.validFloatRegister(i))
+ newRegisters.setFloatRegister(
+ i, getSavedFloatRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]));
+ else if (registers.validVectorRegister(i))
+ newRegisters.setVectorRegister(
+ i, getSavedVectorRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]));
+ else if (isReturnAddressRegister(i, registers))
+ returnAddress = getSavedRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]);
+ else if (registers.validRegister(i))
+ newRegisters.setRegister(
+ i, getSavedRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]));
+ else
+ return UNW_EBADREG;
+ }
+ }
+
+ // By definition, the CFA is the stack pointer at the call site, so
+ // restoring SP means setting it to CFA.
+ newRegisters.setSP(cfa);
+
+ // Return address is address after call site instruction, so setting IP to
+ // that does simualates a return.
+ newRegisters.setIP(returnAddress);
+
+ // Simulate the step by replacing the register set with the new ones.
+ registers = newRegisters;
+
+ return UNW_STEP_SUCCESS;
+ }
+ }
+ return UNW_EBADFRAME;
+}
+
+template <typename A, typename R>
+typename A::pint_t
+DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
+ const R &registers,
+ pint_t initialStackValue) {
+ const bool log = false;
+ pint_t p = expression;
+ pint_t expressionEnd = expression + 20; // temp, until len read
+ pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
+ expressionEnd = p + length;
+ if (log)
+ fprintf(stderr, "evaluateExpression(): length=%llu\n", (uint64_t)length);
+ pint_t stack[100];
+ pint_t *sp = stack;
+ *(++sp) = initialStackValue;
+
+ while (p < expressionEnd) {
+ if (log) {
+ for (pint_t *t = sp; t > stack; --t) {
+ fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t));
+ }
+ }
+ uint8_t opcode = addressSpace.get8(p++);
+ sint_t svalue, svalue2;
+ pint_t value;
+ uint32_t reg;
+ switch (opcode) {
+ case DW_OP_addr:
+ // push immediate address sized value
+ value = addressSpace.getP(p);
+ p += sizeof(pint_t);
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_deref:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *(++sp) = addressSpace.getP(value);
+ if (log)
+ fprintf(stderr, "dereference 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_const1u:
+ // push immediate 1 byte value
+ value = addressSpace.get8(p);
+ p += 1;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_const1s:
+ // push immediate 1 byte signed value
+ svalue = (int8_t) addressSpace.get8(p);
+ p += 1;
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue);
+ break;
+
+ case DW_OP_const2u:
+ // push immediate 2 byte value
+ value = addressSpace.get16(p);
+ p += 2;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_const2s:
+ // push immediate 2 byte signed value
+ svalue = (int16_t) addressSpace.get16(p);
+ p += 2;
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue);
+ break;
+
+ case DW_OP_const4u:
+ // push immediate 4 byte value
+ value = addressSpace.get32(p);
+ p += 4;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_const4s:
+ // push immediate 4 byte signed value
+ svalue = (int32_t)addressSpace.get32(p);
+ p += 4;
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue);
+ break;
+
+ case DW_OP_const8u:
+ // push immediate 8 byte value
+ value = (pint_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_const8s:
+ // push immediate 8 byte signed value
+ value = (pint_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_constu:
+ // push immediate ULEB128 value
+ value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_consts:
+ // push immediate SLEB128 value
+ svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue);
+ break;
+
+ case DW_OP_dup:
+ // push top of stack
+ value = *sp;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "duplicate top of stack\n");
+ break;
+
+ case DW_OP_drop:
+ // pop
+ --sp;
+ if (log)
+ fprintf(stderr, "pop top of stack\n");
+ break;
+
+ case DW_OP_over:
+ // dup second
+ value = sp[-1];
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "duplicate second in stack\n");
+ break;
+
+ case DW_OP_pick:
+ // pick from
+ reg = addressSpace.get8(p);
+ p += 1;
+ value = sp[-reg];
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "duplicate %d in stack\n", reg);
+ break;
+
+ case DW_OP_swap:
+ // swap top two
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = value;
+ if (log)
+ fprintf(stderr, "swap top of stack\n");
+ break;
+
+ case DW_OP_rot:
+ // rotate top three
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = value;
+ if (log)
+ fprintf(stderr, "rotate top three of stack\n");
+ break;
+
+ case DW_OP_xderef:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *sp = *((pint_t*)value);
+ if (log)
+ fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_abs:
+ svalue = (sint_t)*sp;
+ if (svalue < 0)
+ *sp = (pint_t)(-svalue);
+ if (log)
+ fprintf(stderr, "abs\n");
+ break;
+
+ case DW_OP_and:
+ value = *sp--;
+ *sp &= value;
+ if (log)
+ fprintf(stderr, "and\n");
+ break;
+
+ case DW_OP_div:
+ svalue = (sint_t)(*sp--);
+ svalue2 = (sint_t)*sp;
+ *sp = (pint_t)(svalue2 / svalue);
+ if (log)
+ fprintf(stderr, "div\n");
+ break;
+
+ case DW_OP_minus:
+ value = *sp--;
+ *sp = *sp - value;
+ if (log)
+ fprintf(stderr, "minus\n");
+ break;
+
+ case DW_OP_mod:
+ svalue = (sint_t)(*sp--);
+ svalue2 = (sint_t)*sp;
+ *sp = (pint_t)(svalue2 % svalue);
+ if (log)
+ fprintf(stderr, "module\n");
+ break;
+
+ case DW_OP_mul:
+ svalue = (sint_t)(*sp--);
+ svalue2 = (sint_t)*sp;
+ *sp = (pint_t)(svalue2 * svalue);
+ if (log)
+ fprintf(stderr, "mul\n");
+ break;
+
+ case DW_OP_neg:
+ *sp = 0 - *sp;
+ if (log)
+ fprintf(stderr, "neg\n");
+ break;
+
+ case DW_OP_not:
+ svalue = (sint_t)(*sp);
+ *sp = (pint_t)(~svalue);
+ if (log)
+ fprintf(stderr, "not\n");
+ break;
+
+ case DW_OP_or:
+ value = *sp--;
+ *sp |= value;
+ if (log)
+ fprintf(stderr, "or\n");
+ break;
+
+ case DW_OP_plus:
+ value = *sp--;
+ *sp += value;
+ if (log)
+ fprintf(stderr, "plus\n");
+ break;
+
+ case DW_OP_plus_uconst:
+ // pop stack, add uelb128 constant, push result
+ *sp += addressSpace.getULEB128(p, expressionEnd);
+ if (log)
+ fprintf(stderr, "add constant\n");
+ break;
+
+ case DW_OP_shl:
+ value = *sp--;
+ *sp = *sp << value;
+ if (log)
+ fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shr:
+ value = *sp--;
+ *sp = *sp >> value;
+ if (log)
+ fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shra:
+ value = *sp--;
+ svalue = (sint_t)*sp;
+ *sp = (pint_t)(svalue >> value);
+ if (log)
+ fprintf(stderr, "shift left arithmetric\n");
+ break;
+
+ case DW_OP_xor:
+ value = *sp--;
+ *sp ^= value;
+ if (log)
+ fprintf(stderr, "xor\n");
+ break;
+
+ case DW_OP_skip:
+ svalue = (int16_t) addressSpace.get16(p);
+ p += 2;
+ p = (pint_t)((sint_t)p + svalue);
+ if (log)
+ fprintf(stderr, "skip %lld\n", (uint64_t) svalue);
+ break;
+
+ case DW_OP_bra:
+ svalue = (int16_t) addressSpace.get16(p);
+ p += 2;
+ if (*sp--)
+ p = (pint_t)((sint_t)p + svalue);
+ if (log)
+ fprintf(stderr, "bra %lld\n", (uint64_t) svalue);
+ break;
+
+ case DW_OP_eq:
+ value = *sp--;
+ *sp = (*sp == value);
+ if (log)
+ fprintf(stderr, "eq\n");
+ break;
+
+ case DW_OP_ge:
+ value = *sp--;
+ *sp = (*sp >= value);
+ if (log)
+ fprintf(stderr, "ge\n");
+ break;
+
+ case DW_OP_gt:
+ value = *sp--;
+ *sp = (*sp > value);
+ if (log)
+ fprintf(stderr, "gt\n");
+ break;
+
+ case DW_OP_le:
+ value = *sp--;
+ *sp = (*sp <= value);
+ if (log)
+ fprintf(stderr, "le\n");
+ break;
+
+ case DW_OP_lt:
+ value = *sp--;
+ *sp = (*sp < value);
+ if (log)
+ fprintf(stderr, "lt\n");
+ break;
+
+ case DW_OP_ne:
+ value = *sp--;
+ *sp = (*sp != value);
+ if (log)
+ fprintf(stderr, "ne\n");
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ value = opcode - DW_OP_lit0;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push literal 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ reg = opcode - DW_OP_reg0;
+ *(++sp) = registers.getRegister((int)reg);
+ if (log)
+ fprintf(stderr, "push reg %d\n", reg);
+ break;
+
+ case DW_OP_regx:
+ reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = registers.getRegister((int)reg);
+ if (log)
+ fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue);
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ reg = opcode - DW_OP_breg0;
+ svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+ svalue += registers.getRegister((int)reg);
+ *(++sp) = (pint_t)(svalue);
+ if (log)
+ fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue);
+ break;
+
+ case DW_OP_bregx:
+ reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd);
+ svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+ svalue += registers.getRegister((int)reg);
+ *(++sp) = (pint_t)(svalue);
+ if (log)
+ fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue);
+ break;
+
+ case DW_OP_fbreg:
+ _LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
+ break;
+
+ case DW_OP_piece:
+ _LIBUNWIND_ABORT("DW_OP_piece not implemented");
+ break;
+
+ case DW_OP_deref_size:
+ // pop stack, dereference, push result
+ value = *sp--;
+ switch (addressSpace.get8(p++)) {
+ case 1:
+ value = addressSpace.get8(value);
+ break;
+ case 2:
+ value = addressSpace.get16(value);
+ break;
+ case 4:
+ value = addressSpace.get32(value);
+ break;
+ case 8:
+ value = (pint_t)addressSpace.get64(value);
+ break;
+ default:
+ _LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
+ }
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t) value);
+ break;
+
+ case DW_OP_xderef_size:
+ case DW_OP_nop:
+ case DW_OP_push_object_addres:
+ case DW_OP_call2:
+ case DW_OP_call4:
+ case DW_OP_call_ref:
+ default:
+ _LIBUNWIND_ABORT("dwarf opcode not implemented");
+ }
+
+ }
+ if (log)
+ fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t) * sp);
+ return *sp;
+}
+
+//
+// x86_64 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_x86_64 &) {
+ static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+ > (int)DW_X86_64_RET_ADDR, "register number out of range");
+ return DW_X86_64_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool
+DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+ const Registers_x86_64 &) {
+ return (regNum == DW_X86_64_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(
+ A &addressSpace, const PrologInfo &prolog,
+ const Registers_x86_64 &registers) {
+ if (prolog.cfaRegister != 0)
+ return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister)
+ + prolog.cfaRegisterOffset);
+ else if (prolog.cfaExpression != 0)
+ return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, registers, 0);
+ else
+ _LIBUNWIND_ABORT("getCFA(): unknown location for x86_64 cfa");
+}
+
+
+//
+// x86 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_x86 &) {
+ static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+ > (int)DW_X86_RET_ADDR, "register number out of range");
+ return DW_X86_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+ const Registers_x86 &) {
+ return (regNum == DW_X86_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(
+ A &addressSpace, const PrologInfo &prolog,
+ const Registers_x86 &registers) {
+ if (prolog.cfaRegister != 0)
+ return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister)
+ + prolog.cfaRegisterOffset);
+ else if (prolog.cfaExpression != 0)
+ return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
+ registers, 0);
+ else
+ _LIBUNWIND_ABORT("getCFA(): unknown location for x86 cfa");
+}
+
+
+//
+// ppc specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_ppc &) {
+ static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+ > (int)UNW_PPC_SPEFSCR, "register number out of range");
+ return UNW_PPC_SPEFSCR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+ const Registers_ppc &) {
+ return (regNum == UNW_PPC_LR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(
+ A &addressSpace, const PrologInfo &prolog,
+ const Registers_ppc &registers) {
+ if (prolog.cfaRegister != 0)
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else if (prolog.cfaExpression != 0)
+ return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
+ registers, 0);
+ else
+ _LIBUNWIND_ABORT("getCFA(): unknown location for ppc cfa");
+}
+
+
+
+//
+// arm64 specific functions
+//
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+ const Registers_arm64 &) {
+ return (regNum == UNW_ARM64_LR);
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_arm64 &) {
+ static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+ > (int)UNW_ARM64_D31, "register number out of range");
+ return UNW_ARM64_D31;
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(A&, const PrologInfo &prolog,
+ const Registers_arm64 &registers) {
+ if (prolog.cfaRegister != 0)
+ return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+ else
+ _LIBUNWIND_ABORT("getCFA(): unsupported location for arm64 cfa");
+}
+
+
+} // namespace libunwind
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
diff --git a/system/lib/libcxxabi/src/Unwind/DwarfParser.hpp b/system/lib/libcxxabi/src/Unwind/DwarfParser.hpp
new file mode 100644
index 00000000..152baab9
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/DwarfParser.hpp
@@ -0,0 +1,713 @@
+//===--------------------------- DwarfParser.hpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Parses DWARF CFIs (FDEs and CIEs).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+
+#include "AddressSpace.hpp"
+
+namespace libunwind {
+
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See Dwarf Spec for details:
+/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser {
+public:
+ typedef typename A::pint_t pint_t;
+
+ /// Information encoded in a CIE (Common Information Entry)
+ struct CIE_Info {
+ pint_t cieStart;
+ pint_t cieLength;
+ pint_t cieInstructions;
+ uint8_t pointerEncoding;
+ uint8_t lsdaEncoding;
+ uint8_t personalityEncoding;
+ uint8_t personalityOffsetInCIE;
+ pint_t personality;
+ uint32_t codeAlignFactor;
+ int dataAlignFactor;
+ bool isSignalFrame;
+ bool fdesHaveAugmentationData;
+ };
+
+ /// Information about an FDE (Frame Description Entry)
+ struct FDE_Info {
+ pint_t fdeStart;
+ pint_t fdeLength;
+ pint_t fdeInstructions;
+ pint_t pcStart;
+ pint_t pcEnd;
+ pint_t lsda;
+ };
+
+ enum {
+ kMaxRegisterNumber = 120
+ };
+ enum RegisterSavedWhere {
+ kRegisterUnused,
+ kRegisterInCFA,
+ kRegisterOffsetFromCFA,
+ kRegisterInRegister,
+ kRegisterAtExpression,
+ kRegisterIsExpression
+ };
+ struct RegisterLocation {
+ RegisterSavedWhere location;
+ int64_t value;
+ };
+ /// Information about a frame layout and registers saved determined
+ /// by "running" the dwarf FDE "instructions"
+ struct PrologInfo {
+ uint32_t cfaRegister;
+ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
+ int64_t cfaExpression; // CFA = expression
+ uint32_t spExtraArgSize;
+ uint32_t codeOffsetAtStackDecrement;
+ bool registersInOtherRegisters;
+ bool sameValueUsed;
+ RegisterLocation savedRegisters[kMaxRegisterNumber];
+ };
+
+ struct PrologInfoStackEntry {
+ PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
+ : next(n), info(i) {}
+ PrologInfoStackEntry *next;
+ PrologInfo info;
+ };
+
+ static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
+ uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+ CIE_Info *cieInfo);
+ static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
+ FDE_Info *fdeInfo, CIE_Info *cieInfo);
+ static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
+ const CIE_Info &cieInfo, pint_t upToPC,
+ PrologInfo *results);
+
+ static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
+
+private:
+ static bool parseInstructions(A &addressSpace, pint_t instructions,
+ pint_t instructionsEnd, const CIE_Info &cieInfo,
+ pint_t pcoffset,
+ PrologInfoStackEntry *&rememberStack,
+ PrologInfo *results);
+};
+
+/// Parse a FDE into a CIE_Info and an FDE_Info
+template <typename A>
+const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
+ FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+ pint_t p = fdeStart;
+ pint_t cfiLength = (pint_t)addressSpace.get32(p);
+ p += 4;
+ if (cfiLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = (pint_t)addressSpace.get64(p);
+ p += 8;
+ }
+ if (cfiLength == 0)
+ return "FDE has zero length"; // end marker
+ uint32_t ciePointer = addressSpace.get32(p);
+ if (ciePointer == 0)
+ return "FDE is really a CIE"; // this is a CIE not an FDE
+ pint_t nextCFI = p + cfiLength;
+ pint_t cieStart = p - ciePointer;
+ const char *err = parseCIE(addressSpace, cieStart, cieInfo);
+ if (err != NULL)
+ return err;
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart =
+ addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange =
+ addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if (cieInfo->fdesHaveAugmentationData) {
+ pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if (cieInfo->lsdaEncoding != 0) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
+ 0) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda =
+ addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = fdeStart;
+ fdeInfo->fdeLength = nextCFI - fdeStart;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart + pcRange;
+ return NULL; // success
+}
+
+/// Scan an eh_frame section to find an FDE for a pc
+template <typename A>
+bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
+ uint32_t sectionLength, pint_t fdeHint,
+ FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+ //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+ pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ while (p < ehSectionEnd) {
+ pint_t currentCFI = p;
+ //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+ pint_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if (cfiLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = (pint_t)addressSpace.get64(p);
+ p += 8;
+ }
+ if (cfiLength == 0)
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if (id == 0) {
+ // skip over CIEs
+ p += cfiLength;
+ } else {
+ // process FDE to see if it covers pc
+ pint_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = addressSpace.get32(p);
+ pint_t cieStart = p - ciePointer;
+ // validate pointer to CIE is within section
+ if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
+ if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
+ p += 4;
+ // parse pc begin and range
+ pint_t pcStart =
+ addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ pint_t pcRange = addressSpace.getEncodedP(
+ p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+ // test if pc is within the function this FDE covers
+ if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if (cieInfo->fdesHaveAugmentationData) {
+ pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
+ pint_t endOfAug = p + augLen;
+ if (cieInfo->lsdaEncoding != 0) {
+ // peek at value (without indirection). Zero means no lsda
+ pint_t lsdaStart = p;
+ if (addressSpace.getEncodedP(
+ p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace
+ .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = currentCFI;
+ fdeInfo->fdeLength = nextCFI - currentCFI;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart + pcRange;
+ return true;
+ } else {
+ // pc is not in begin/range, skip this FDE
+ }
+ } else {
+ // malformed CIE, now augmentation describing pc range encoding
+ }
+ } else {
+ // malformed FDE. CIE is bad
+ }
+ p = nextCFI;
+ }
+ }
+ return false;
+}
+
+/// Extract info from a CIE
+template <typename A>
+const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
+ CIE_Info *cieInfo) {
+ cieInfo->pointerEncoding = 0;
+ cieInfo->lsdaEncoding = 0;
+ cieInfo->personalityEncoding = 0;
+ cieInfo->personalityOffsetInCIE = 0;
+ cieInfo->personality = 0;
+ cieInfo->codeAlignFactor = 0;
+ cieInfo->dataAlignFactor = 0;
+ cieInfo->isSignalFrame = false;
+ cieInfo->fdesHaveAugmentationData = false;
+ cieInfo->cieStart = cie;
+ pint_t p = cie;
+ pint_t cieLength = (pint_t)addressSpace.get32(p);
+ p += 4;
+ pint_t cieContentEnd = p + cieLength;
+ if (cieLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cieLength = (pint_t)addressSpace.get64(p);
+ p += 8;
+ cieContentEnd = p + cieLength;
+ }
+ if (cieLength == 0)
+ return NULL;
+ // CIE ID is always 0
+ if (addressSpace.get32(p) != 0)
+ return "CIE ID is not zero";
+ p += 4;
+ // Version is always 1 or 3
+ uint8_t version = addressSpace.get8(p);
+ if ((version != 1) && (version != 3))
+ return "CIE version is not 1 or 3";
+ ++p;
+ // save start of augmentation string and find end
+ pint_t strStart = p;
+ while (addressSpace.get8(p) != 0)
+ ++p;
+ ++p;
+ // parse code aligment factor
+ cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
+ // parse data alignment factor
+ cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
+ // parse return address register
+ addressSpace.getULEB128(p, cieContentEnd);
+ // parse augmentation data based on augmentation string
+ const char *result = NULL;
+ if (addressSpace.get8(strStart) == 'z') {
+ // parse augmentation data length
+ addressSpace.getULEB128(p, cieContentEnd);
+ for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
+ switch (addressSpace.get8(s)) {
+ case 'z':
+ cieInfo->fdesHaveAugmentationData = true;
+ break;
+ case 'P':
+ cieInfo->personalityEncoding = addressSpace.get8(p);
+ ++p;
+ cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
+ cieInfo->personality = addressSpace
+ .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+ break;
+ case 'L':
+ cieInfo->lsdaEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'R':
+ cieInfo->pointerEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'S':
+ cieInfo->isSignalFrame = true;
+ break;
+ default:
+ // ignore unknown letters
+ break;
+ }
+ }
+ }
+ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+ cieInfo->cieInstructions = p;
+ return result;
+}
+
+
+/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
+template <typename A>
+bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
+ const FDE_Info &fdeInfo,
+ const CIE_Info &cieInfo, pint_t upToPC,
+ PrologInfo *results) {
+ // clear results
+ bzero(results, sizeof(PrologInfo));
+ PrologInfoStackEntry *rememberStack = NULL;
+
+ // parse CIE then FDE instructions
+ return parseInstructions(addressSpace, cieInfo.cieInstructions,
+ cieInfo.cieStart + cieInfo.cieLength, cieInfo,
+ (pint_t)(-1), rememberStack, results) &&
+ parseInstructions(addressSpace, fdeInfo.fdeInstructions,
+ fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
+ upToPC - fdeInfo.pcStart, rememberStack, results);
+}
+
+/// "run" the dwarf instructions
+template <typename A>
+bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
+ pint_t instructionsEnd,
+ const CIE_Info &cieInfo, pint_t pcoffset,
+ PrologInfoStackEntry *&rememberStack,
+ PrologInfo *results) {
+ const bool logDwarf = false;
+ pint_t p = instructions;
+ pint_t codeOffset = 0;
+ PrologInfo initialState = *results;
+ if (logDwarf)
+ fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n",
+ (uint64_t) instructionsEnd);
+
+ // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+ while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
+ uint64_t reg;
+ uint64_t reg2;
+ int64_t offset;
+ uint64_t length;
+ uint8_t opcode = addressSpace.get8(p);
+ uint8_t operand;
+ PrologInfoStackEntry *entry;
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_nop\n");
+ break;
+ case DW_CFA_set_loc:
+ codeOffset =
+ addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_set_loc\n");
+ break;
+ case DW_CFA_advance_loc1:
+ codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+ p += 1;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_advance_loc1: new offset=%llu\n",
+ (uint64_t)codeOffset);
+ break;
+ case DW_CFA_advance_loc2:
+ codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+ p += 2;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_advance_loc2: new offset=%llu\n",
+ (uint64_t)codeOffset);
+ break;
+ case DW_CFA_advance_loc4:
+ codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+ p += 4;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_advance_loc4: new offset=%llu\n",
+ (uint64_t)codeOffset);
+ break;
+ case DW_CFA_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
+ * cieInfo.dataAlignFactor;
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg,
+ offset);
+ break;
+ case DW_CFA_restore_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ ;
+ if (reg > kMaxRegisterNumber) {
+ fprintf(
+ stderr,
+ "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_undefined:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterUnused;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_same_value:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
+ return false;
+ }
+ // <rdar://problem/8456377> DW_CFA_same_value unsupported
+ // "same value" means register was stored in frame, but its current
+ // value has not changed, so no need to restore from frame.
+ // We model this as if the register was never saved.
+ results->savedRegisters[reg].location = kRegisterUnused;
+ // set flag to disable conversion to compact unwind
+ results->sameValueUsed = true;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg);
+ break;
+ case DW_CFA_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ reg2 = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ if (reg2 > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterInRegister;
+ results->savedRegisters[reg].value = (int64_t)reg2;
+ // set flag to disable conversion to compact unwind
+ results->registersInOtherRegisters = true;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2);
+ break;
+ case DW_CFA_remember_state:
+ // avoid operator new, because that would be an upward dependency
+ entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
+ if (entry != NULL) {
+ entry->next = rememberStack;
+ entry->info = *results;
+ rememberStack = entry;
+ } else {
+ return false;
+ }
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_remember_state\n");
+ break;
+ case DW_CFA_restore_state:
+ if (rememberStack != NULL) {
+ PrologInfoStackEntry *top = rememberStack;
+ *results = top->info;
+ rememberStack = top->next;
+ free((char *)top);
+ } else {
+ return false;
+ }
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_restore_state\n");
+ break;
+ case DW_CFA_def_cfa:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ results->cfaRegisterOffset = (int32_t)offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset);
+ break;
+ case DW_CFA_def_cfa_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(
+ stderr,
+ "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg);
+ break;
+ case DW_CFA_def_cfa_offset:
+ results->cfaRegisterOffset = (int32_t)
+ addressSpace.getULEB128(p, instructionsEnd);
+ results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n",
+ results->cfaRegisterOffset);
+ break;
+ case DW_CFA_def_cfa_expression:
+ results->cfaRegister = 0;
+ results->cfaExpression = (int64_t)p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if (logDwarf)
+ fprintf(stderr,
+ "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n",
+ results->cfaExpression, length);
+ break;
+ case DW_CFA_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterAtExpression;
+ results->savedRegisters[reg].value = (int64_t)p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if (logDwarf)
+ fprintf(stderr,
+ "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_offset_extended_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(
+ stderr,
+ "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset =
+ addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n",
+ reg, offset);
+ break;
+ case DW_CFA_def_cfa_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset =
+ addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ results->cfaRegisterOffset = (int32_t)offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg,
+ offset);
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ results->cfaRegisterOffset = (int32_t)
+ (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
+ results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n",
+ results->cfaRegisterOffset);
+ break;
+ case DW_CFA_val_offset:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
+ * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg,
+ offset);
+ break;
+ case DW_CFA_val_offset_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
+ return false;
+ }
+ offset =
+ addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
+ results->savedRegisters[reg].value = offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg,
+ offset);
+ break;
+ case DW_CFA_val_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterIsExpression;
+ results->savedRegisters[reg].value = (int64_t)p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ p += length;
+ if (logDwarf)
+ fprintf(
+ stderr,
+ "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_GNU_args_size:
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ results->spExtraArgSize = (uint32_t)length;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", length);
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf "
+ "unwind, reg too big\n");
+ return false;
+ }
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
+ * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = -offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset);
+ break;
+ default:
+ operand = opcode & 0x3F;
+ switch (opcode & 0xC0) {
+ case DW_CFA_offset:
+ reg = operand;
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
+ * cieInfo.dataAlignFactor;
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value = offset;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand,
+ offset);
+ break;
+ case DW_CFA_advance_loc:
+ codeOffset += operand * cieInfo.codeAlignFactor;
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_advance_loc: new offset=%llu\n",
+ (uint64_t)codeOffset);
+ break;
+ case DW_CFA_restore:
+ reg = operand;
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg);
+ break;
+ default:
+ if (logDwarf)
+ fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace libunwind
+
+#endif // __DWARF_PARSER_HPP__
diff --git a/system/lib/libcxxabi/src/Unwind/Registers.hpp b/system/lib/libcxxabi/src/Unwind/Registers.hpp
new file mode 100644
index 00000000..584e4492
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/Registers.hpp
@@ -0,0 +1,1568 @@
+//===----------------------------- Registers.hpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Models register sets for supported processors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <strings.h>
+
+#include "libunwind.h"
+#include "config.h"
+
+namespace libunwind {
+
+// For emulating 128-bit registers
+struct v128 { uint32_t vec[4]; };
+
+
+/// Registers_x86 holds the register state of a thread in a 32-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86 {
+public:
+ Registers_x86();
+ Registers_x86(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+
+ uint32_t getSP() const { return _registers.__esp; }
+ void setSP(uint32_t value) { _registers.__esp = value; }
+ uint32_t getIP() const { return _registers.__eip; }
+ void setIP(uint32_t value) { _registers.__eip = value; }
+ uint32_t getEBP() const { return _registers.__ebp; }
+ void setEBP(uint32_t value) { _registers.__ebp = value; }
+ uint32_t getEBX() const { return _registers.__ebx; }
+ void setEBX(uint32_t value) { _registers.__ebx = value; }
+ uint32_t getECX() const { return _registers.__ecx; }
+ void setECX(uint32_t value) { _registers.__ecx = value; }
+ uint32_t getEDX() const { return _registers.__edx; }
+ void setEDX(uint32_t value) { _registers.__edx = value; }
+ uint32_t getESI() const { return _registers.__esi; }
+ void setESI(uint32_t value) { _registers.__esi = value; }
+ uint32_t getEDI() const { return _registers.__edi; }
+ void setEDI(uint32_t value) { _registers.__edi = value; }
+
+private:
+ struct GPRs {
+ unsigned int __eax;
+ unsigned int __ebx;
+ unsigned int __ecx;
+ unsigned int __edx;
+ unsigned int __edi;
+ unsigned int __esi;
+ unsigned int __ebp;
+ unsigned int __esp;
+ unsigned int __ss;
+ unsigned int __eflags;
+ unsigned int __eip;
+ unsigned int __cs;
+ unsigned int __ds;
+ unsigned int __es;
+ unsigned int __fs;
+ unsigned int __gs;
+ };
+
+ GPRs _registers;
+};
+
+inline Registers_x86::Registers_x86(const void *registers) {
+ static_assert(sizeof(Registers_x86) < sizeof(unw_context_t),
+ "x86 registers do not fit into unw_context_t");
+ _registers = *((GPRs *)registers);
+}
+
+inline Registers_x86::Registers_x86() {
+ bzero(&_registers, sizeof(_registers));
+}
+
+inline bool Registers_x86::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum > 7)
+ return false;
+ return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__eip;
+ case UNW_REG_SP:
+ return _registers.__esp;
+ case UNW_X86_EAX:
+ return _registers.__eax;
+ case UNW_X86_ECX:
+ return _registers.__ecx;
+ case UNW_X86_EDX:
+ return _registers.__edx;
+ case UNW_X86_EBX:
+ return _registers.__ebx;
+ case UNW_X86_EBP:
+ return _registers.__ebp;
+ case UNW_X86_ESP:
+ return _registers.__esp;
+ case UNW_X86_ESI:
+ return _registers.__esi;
+ case UNW_X86_EDI:
+ return _registers.__edi;
+ }
+ _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__eip = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__esp = value;
+ return;
+ case UNW_X86_EAX:
+ _registers.__eax = value;
+ return;
+ case UNW_X86_ECX:
+ _registers.__ecx = value;
+ return;
+ case UNW_X86_EDX:
+ _registers.__edx = value;
+ return;
+ case UNW_X86_EBX:
+ _registers.__ebx = value;
+ return;
+ case UNW_X86_EBP:
+ _registers.__ebp = value;
+ return;
+ case UNW_X86_ESP:
+ _registers.__esp = value;
+ return;
+ case UNW_X86_ESI:
+ _registers.__esi = value;
+ return;
+ case UNW_X86_EDI:
+ _registers.__edi = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline const char *Registers_x86::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "esp";
+ case UNW_X86_EAX:
+ return "eax";
+ case UNW_X86_ECX:
+ return "ecx";
+ case UNW_X86_EDX:
+ return "edx";
+ case UNW_X86_EBX:
+ return "ebx";
+ case UNW_X86_EBP:
+ return "ebp";
+ case UNW_X86_ESP:
+ return "esp";
+ case UNW_X86_ESI:
+ return "esi";
+ case UNW_X86_EDI:
+ return "edi";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+
+/// Registers_x86_64 holds the register state of a thread in a 64-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86_64 {
+public:
+ Registers_x86_64();
+ Registers_x86_64(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+
+ uint64_t getSP() const { return _registers.__rsp; }
+ void setSP(uint64_t value) { _registers.__rsp = value; }
+ uint64_t getIP() const { return _registers.__rip; }
+ void setIP(uint64_t value) { _registers.__rip = value; }
+ uint64_t getRBP() const { return _registers.__rbp; }
+ void setRBP(uint64_t value) { _registers.__rbp = value; }
+ uint64_t getRBX() const { return _registers.__rbx; }
+ void setRBX(uint64_t value) { _registers.__rbx = value; }
+ uint64_t getR12() const { return _registers.__r12; }
+ void setR12(uint64_t value) { _registers.__r12 = value; }
+ uint64_t getR13() const { return _registers.__r13; }
+ void setR13(uint64_t value) { _registers.__r13 = value; }
+ uint64_t getR14() const { return _registers.__r14; }
+ void setR14(uint64_t value) { _registers.__r14 = value; }
+ uint64_t getR15() const { return _registers.__r15; }
+ void setR15(uint64_t value) { _registers.__r15 = value; }
+
+private:
+ struct GPRs {
+ uint64_t __rax;
+ uint64_t __rbx;
+ uint64_t __rcx;
+ uint64_t __rdx;
+ uint64_t __rdi;
+ uint64_t __rsi;
+ uint64_t __rbp;
+ uint64_t __rsp;
+ uint64_t __r8;
+ uint64_t __r9;
+ uint64_t __r10;
+ uint64_t __r11;
+ uint64_t __r12;
+ uint64_t __r13;
+ uint64_t __r14;
+ uint64_t __r15;
+ uint64_t __rip;
+ uint64_t __rflags;
+ uint64_t __cs;
+ uint64_t __fs;
+ uint64_t __gs;
+ };
+ GPRs _registers;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void *registers) {
+ static_assert(sizeof(Registers_x86_64) < sizeof(unw_context_t),
+ "x86_64 registers do not fit into unw_context_t");
+ _registers = *((GPRs *)registers);
+}
+
+inline Registers_x86_64::Registers_x86_64() {
+ bzero(&_registers, sizeof(_registers));
+}
+
+inline bool Registers_x86_64::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum > 15)
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__rip;
+ case UNW_REG_SP:
+ return _registers.__rsp;
+ case UNW_X86_64_RAX:
+ return _registers.__rax;
+ case UNW_X86_64_RDX:
+ return _registers.__rdx;
+ case UNW_X86_64_RCX:
+ return _registers.__rcx;
+ case UNW_X86_64_RBX:
+ return _registers.__rbx;
+ case UNW_X86_64_RSI:
+ return _registers.__rsi;
+ case UNW_X86_64_RDI:
+ return _registers.__rdi;
+ case UNW_X86_64_RBP:
+ return _registers.__rbp;
+ case UNW_X86_64_RSP:
+ return _registers.__rsp;
+ case UNW_X86_64_R8:
+ return _registers.__r8;
+ case UNW_X86_64_R9:
+ return _registers.__r9;
+ case UNW_X86_64_R10:
+ return _registers.__r10;
+ case UNW_X86_64_R11:
+ return _registers.__r11;
+ case UNW_X86_64_R12:
+ return _registers.__r12;
+ case UNW_X86_64_R13:
+ return _registers.__r13;
+ case UNW_X86_64_R14:
+ return _registers.__r14;
+ case UNW_X86_64_R15:
+ return _registers.__r15;
+ }
+ _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__rip = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__rsp = value;
+ return;
+ case UNW_X86_64_RAX:
+ _registers.__rax = value;
+ return;
+ case UNW_X86_64_RDX:
+ _registers.__rdx = value;
+ return;
+ case UNW_X86_64_RCX:
+ _registers.__rcx = value;
+ return;
+ case UNW_X86_64_RBX:
+ _registers.__rbx = value;
+ return;
+ case UNW_X86_64_RSI:
+ _registers.__rsi = value;
+ return;
+ case UNW_X86_64_RDI:
+ _registers.__rdi = value;
+ return;
+ case UNW_X86_64_RBP:
+ _registers.__rbp = value;
+ return;
+ case UNW_X86_64_RSP:
+ _registers.__rsp = value;
+ return;
+ case UNW_X86_64_R8:
+ _registers.__r8 = value;
+ return;
+ case UNW_X86_64_R9:
+ _registers.__r9 = value;
+ return;
+ case UNW_X86_64_R10:
+ _registers.__r10 = value;
+ return;
+ case UNW_X86_64_R11:
+ _registers.__r11 = value;
+ return;
+ case UNW_X86_64_R12:
+ _registers.__r12 = value;
+ return;
+ case UNW_X86_64_R13:
+ _registers.__r13 = value;
+ return;
+ case UNW_X86_64_R14:
+ _registers.__r14 = value;
+ return;
+ case UNW_X86_64_R15:
+ _registers.__r15 = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline const char *Registers_x86_64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "rip";
+ case UNW_REG_SP:
+ return "rsp";
+ case UNW_X86_64_RAX:
+ return "rax";
+ case UNW_X86_64_RDX:
+ return "rdx";
+ case UNW_X86_64_RCX:
+ return "rcx";
+ case UNW_X86_64_RBX:
+ return "rbx";
+ case UNW_X86_64_RSI:
+ return "rsi";
+ case UNW_X86_64_RDI:
+ return "rdi";
+ case UNW_X86_64_RBP:
+ return "rbp";
+ case UNW_X86_64_RSP:
+ return "rsp";
+ case UNW_X86_64_R8:
+ return "r8";
+ case UNW_X86_64_R9:
+ return "r9";
+ case UNW_X86_64_R10:
+ return "r10";
+ case UNW_X86_64_R11:
+ return "r11";
+ case UNW_X86_64_R12:
+ return "r12";
+ case UNW_X86_64_R13:
+ return "r13";
+ case UNW_X86_64_R14:
+ return "r14";
+ case UNW_X86_64_R15:
+ return "r15";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86_64::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline void Registers_x86_64::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no x86_64 vector registers");
+}
+
+
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC
+/// process.
+class _LIBUNWIND_HIDDEN Registers_ppc {
+public:
+ Registers_ppc();
+ Registers_ppc(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+
+ uint64_t getSP() const { return _registers.__r1; }
+ void setSP(uint32_t value) { _registers.__r1 = value; }
+ uint64_t getIP() const { return _registers.__srr0; }
+ void setIP(uint32_t value) { _registers.__srr0 = value; }
+
+private:
+ struct ppc_thread_state_t {
+ unsigned int __srr0; /* Instruction address register (PC) */
+ unsigned int __srr1; /* Machine state register (supervisor) */
+ unsigned int __r0;
+ unsigned int __r1;
+ unsigned int __r2;
+ unsigned int __r3;
+ unsigned int __r4;
+ unsigned int __r5;
+ unsigned int __r6;
+ unsigned int __r7;
+ unsigned int __r8;
+ unsigned int __r9;
+ unsigned int __r10;
+ unsigned int __r11;
+ unsigned int __r12;
+ unsigned int __r13;
+ unsigned int __r14;
+ unsigned int __r15;
+ unsigned int __r16;
+ unsigned int __r17;
+ unsigned int __r18;
+ unsigned int __r19;
+ unsigned int __r20;
+ unsigned int __r21;
+ unsigned int __r22;
+ unsigned int __r23;
+ unsigned int __r24;
+ unsigned int __r25;
+ unsigned int __r26;
+ unsigned int __r27;
+ unsigned int __r28;
+ unsigned int __r29;
+ unsigned int __r30;
+ unsigned int __r31;
+ unsigned int __cr; /* Condition register */
+ unsigned int __xer; /* User's integer exception register */
+ unsigned int __lr; /* Link register */
+ unsigned int __ctr; /* Count register */
+ unsigned int __mq; /* MQ register (601 only) */
+ unsigned int __vrsave; /* Vector Save Register */
+ };
+
+ struct ppc_float_state_t {
+ double __fpregs[32];
+
+ unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
+ unsigned int __fpscr; /* floating point status register */
+ };
+
+ ppc_thread_state_t _registers;
+ ppc_float_state_t _floatRegisters;
+ v128 _vectorRegisters[32]; // offset 424
+};
+
+inline Registers_ppc::Registers_ppc(const void *registers) {
+ static_assert(sizeof(Registers_ppc) < sizeof(unw_context_t),
+ "ppc registers do not fit into unw_context_t");
+ _registers = *((ppc_thread_state_t *)registers);
+ _floatRegisters = *((ppc_float_state_t *)((char *)registers + 160));
+ memcpy(_vectorRegisters, ((char *)registers + 424), sizeof(_vectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc() {
+ bzero(&_registers, sizeof(_registers));
+ bzero(&_floatRegisters, sizeof(_floatRegisters));
+ bzero(&_vectorRegisters, sizeof(_vectorRegisters));
+}
+
+inline bool Registers_ppc::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum == UNW_PPC_VRSAVE)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum <= UNW_PPC_R31)
+ return true;
+ if (regNum == UNW_PPC_MQ)
+ return true;
+ if (regNum == UNW_PPC_LR)
+ return true;
+ if (regNum == UNW_PPC_CTR)
+ return true;
+ if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7))
+ return true;
+ return false;
+}
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__srr0;
+ case UNW_REG_SP:
+ return _registers.__r1;
+ case UNW_PPC_R0:
+ return _registers.__r0;
+ case UNW_PPC_R1:
+ return _registers.__r1;
+ case UNW_PPC_R2:
+ return _registers.__r2;
+ case UNW_PPC_R3:
+ return _registers.__r3;
+ case UNW_PPC_R4:
+ return _registers.__r4;
+ case UNW_PPC_R5:
+ return _registers.__r5;
+ case UNW_PPC_R6:
+ return _registers.__r6;
+ case UNW_PPC_R7:
+ return _registers.__r7;
+ case UNW_PPC_R8:
+ return _registers.__r8;
+ case UNW_PPC_R9:
+ return _registers.__r9;
+ case UNW_PPC_R10:
+ return _registers.__r10;
+ case UNW_PPC_R11:
+ return _registers.__r11;
+ case UNW_PPC_R12:
+ return _registers.__r12;
+ case UNW_PPC_R13:
+ return _registers.__r13;
+ case UNW_PPC_R14:
+ return _registers.__r14;
+ case UNW_PPC_R15:
+ return _registers.__r15;
+ case UNW_PPC_R16:
+ return _registers.__r16;
+ case UNW_PPC_R17:
+ return _registers.__r17;
+ case UNW_PPC_R18:
+ return _registers.__r18;
+ case UNW_PPC_R19:
+ return _registers.__r19;
+ case UNW_PPC_R20:
+ return _registers.__r20;
+ case UNW_PPC_R21:
+ return _registers.__r21;
+ case UNW_PPC_R22:
+ return _registers.__r22;
+ case UNW_PPC_R23:
+ return _registers.__r23;
+ case UNW_PPC_R24:
+ return _registers.__r24;
+ case UNW_PPC_R25:
+ return _registers.__r25;
+ case UNW_PPC_R26:
+ return _registers.__r26;
+ case UNW_PPC_R27:
+ return _registers.__r27;
+ case UNW_PPC_R28:
+ return _registers.__r28;
+ case UNW_PPC_R29:
+ return _registers.__r29;
+ case UNW_PPC_R30:
+ return _registers.__r30;
+ case UNW_PPC_R31:
+ return _registers.__r31;
+ case UNW_PPC_LR:
+ return _registers.__lr;
+ case UNW_PPC_CR0:
+ return (_registers.__cr & 0xF0000000);
+ case UNW_PPC_CR1:
+ return (_registers.__cr & 0x0F000000);
+ case UNW_PPC_CR2:
+ return (_registers.__cr & 0x00F00000);
+ case UNW_PPC_CR3:
+ return (_registers.__cr & 0x000F0000);
+ case UNW_PPC_CR4:
+ return (_registers.__cr & 0x0000F000);
+ case UNW_PPC_CR5:
+ return (_registers.__cr & 0x00000F00);
+ case UNW_PPC_CR6:
+ return (_registers.__cr & 0x000000F0);
+ case UNW_PPC_CR7:
+ return (_registers.__cr & 0x0000000F);
+ case UNW_PPC_VRSAVE:
+ return _registers.__vrsave;
+ }
+ _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value) {
+ //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__srr0 = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__r1 = value;
+ return;
+ case UNW_PPC_R0:
+ _registers.__r0 = value;
+ return;
+ case UNW_PPC_R1:
+ _registers.__r1 = value;
+ return;
+ case UNW_PPC_R2:
+ _registers.__r2 = value;
+ return;
+ case UNW_PPC_R3:
+ _registers.__r3 = value;
+ return;
+ case UNW_PPC_R4:
+ _registers.__r4 = value;
+ return;
+ case UNW_PPC_R5:
+ _registers.__r5 = value;
+ return;
+ case UNW_PPC_R6:
+ _registers.__r6 = value;
+ return;
+ case UNW_PPC_R7:
+ _registers.__r7 = value;
+ return;
+ case UNW_PPC_R8:
+ _registers.__r8 = value;
+ return;
+ case UNW_PPC_R9:
+ _registers.__r9 = value;
+ return;
+ case UNW_PPC_R10:
+ _registers.__r10 = value;
+ return;
+ case UNW_PPC_R11:
+ _registers.__r11 = value;
+ return;
+ case UNW_PPC_R12:
+ _registers.__r12 = value;
+ return;
+ case UNW_PPC_R13:
+ _registers.__r13 = value;
+ return;
+ case UNW_PPC_R14:
+ _registers.__r14 = value;
+ return;
+ case UNW_PPC_R15:
+ _registers.__r15 = value;
+ return;
+ case UNW_PPC_R16:
+ _registers.__r16 = value;
+ return;
+ case UNW_PPC_R17:
+ _registers.__r17 = value;
+ return;
+ case UNW_PPC_R18:
+ _registers.__r18 = value;
+ return;
+ case UNW_PPC_R19:
+ _registers.__r19 = value;
+ return;
+ case UNW_PPC_R20:
+ _registers.__r20 = value;
+ return;
+ case UNW_PPC_R21:
+ _registers.__r21 = value;
+ return;
+ case UNW_PPC_R22:
+ _registers.__r22 = value;
+ return;
+ case UNW_PPC_R23:
+ _registers.__r23 = value;
+ return;
+ case UNW_PPC_R24:
+ _registers.__r24 = value;
+ return;
+ case UNW_PPC_R25:
+ _registers.__r25 = value;
+ return;
+ case UNW_PPC_R26:
+ _registers.__r26 = value;
+ return;
+ case UNW_PPC_R27:
+ _registers.__r27 = value;
+ return;
+ case UNW_PPC_R28:
+ _registers.__r28 = value;
+ return;
+ case UNW_PPC_R29:
+ _registers.__r29 = value;
+ return;
+ case UNW_PPC_R30:
+ _registers.__r30 = value;
+ return;
+ case UNW_PPC_R31:
+ _registers.__r31 = value;
+ return;
+ case UNW_PPC_MQ:
+ _registers.__mq = value;
+ return;
+ case UNW_PPC_LR:
+ _registers.__lr = value;
+ return;
+ case UNW_PPC_CTR:
+ _registers.__ctr = value;
+ return;
+ case UNW_PPC_CR0:
+ _registers.__cr &= 0x0FFFFFFF;
+ _registers.__cr |= (value & 0xF0000000);
+ return;
+ case UNW_PPC_CR1:
+ _registers.__cr &= 0xF0FFFFFF;
+ _registers.__cr |= (value & 0x0F000000);
+ return;
+ case UNW_PPC_CR2:
+ _registers.__cr &= 0xFF0FFFFF;
+ _registers.__cr |= (value & 0x00F00000);
+ return;
+ case UNW_PPC_CR3:
+ _registers.__cr &= 0xFFF0FFFF;
+ _registers.__cr |= (value & 0x000F0000);
+ return;
+ case UNW_PPC_CR4:
+ _registers.__cr &= 0xFFFF0FFF;
+ _registers.__cr |= (value & 0x0000F000);
+ return;
+ case UNW_PPC_CR5:
+ _registers.__cr &= 0xFFFFF0FF;
+ _registers.__cr |= (value & 0x00000F00);
+ return;
+ case UNW_PPC_CR6:
+ _registers.__cr &= 0xFFFFFF0F;
+ _registers.__cr |= (value & 0x000000F0);
+ return;
+ case UNW_PPC_CR7:
+ _registers.__cr &= 0xFFFFFFF0;
+ _registers.__cr |= (value & 0x0000000F);
+ return;
+ case UNW_PPC_VRSAVE:
+ _registers.__vrsave = value;
+ return;
+ // not saved
+ return;
+ case UNW_PPC_XER:
+ _registers.__xer = value;
+ return;
+ case UNW_PPC_AP:
+ case UNW_PPC_VSCR:
+ case UNW_PPC_SPEFSCR:
+ // not saved
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const {
+ if (regNum < UNW_PPC_F0)
+ return false;
+ if (regNum > UNW_PPC_F31)
+ return false;
+ return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const {
+ assert(validFloatRegister(regNum));
+ return _floatRegisters.__fpregs[regNum - UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value) {
+ assert(validFloatRegister(regNum));
+ _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value;
+}
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const {
+ if (regNum < UNW_PPC_V0)
+ return false;
+ if (regNum > UNW_PPC_V31)
+ return false;
+ return true;
+}
+
+inline v128 Registers_ppc::getVectorRegister(int regNum) const {
+ assert(validVectorRegister(regNum));
+ v128 result = _vectorRegisters[regNum - UNW_PPC_V0];
+ return result;
+}
+
+inline void Registers_ppc::setVectorRegister(int regNum, v128 value) {
+ assert(validVectorRegister(regNum));
+ _vectorRegisters[regNum - UNW_PPC_V0] = value;
+}
+
+inline const char *Registers_ppc::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_PPC_R0:
+ return "r0";
+ case UNW_PPC_R1:
+ return "r1";
+ case UNW_PPC_R2:
+ return "r2";
+ case UNW_PPC_R3:
+ return "r3";
+ case UNW_PPC_R4:
+ return "r4";
+ case UNW_PPC_R5:
+ return "r5";
+ case UNW_PPC_R6:
+ return "r6";
+ case UNW_PPC_R7:
+ return "r7";
+ case UNW_PPC_R8:
+ return "r8";
+ case UNW_PPC_R9:
+ return "r9";
+ case UNW_PPC_R10:
+ return "r10";
+ case UNW_PPC_R11:
+ return "r11";
+ case UNW_PPC_R12:
+ return "r12";
+ case UNW_PPC_R13:
+ return "r13";
+ case UNW_PPC_R14:
+ return "r14";
+ case UNW_PPC_R15:
+ return "r15";
+ case UNW_PPC_R16:
+ return "r16";
+ case UNW_PPC_R17:
+ return "r17";
+ case UNW_PPC_R18:
+ return "r18";
+ case UNW_PPC_R19:
+ return "r19";
+ case UNW_PPC_R20:
+ return "r20";
+ case UNW_PPC_R21:
+ return "r21";
+ case UNW_PPC_R22:
+ return "r22";
+ case UNW_PPC_R23:
+ return "r23";
+ case UNW_PPC_R24:
+ return "r24";
+ case UNW_PPC_R25:
+ return "r25";
+ case UNW_PPC_R26:
+ return "r26";
+ case UNW_PPC_R27:
+ return "r27";
+ case UNW_PPC_R28:
+ return "r28";
+ case UNW_PPC_R29:
+ return "r29";
+ case UNW_PPC_R30:
+ return "r30";
+ case UNW_PPC_R31:
+ return "r31";
+ case UNW_PPC_F0:
+ return "fp0";
+ case UNW_PPC_F1:
+ return "fp1";
+ case UNW_PPC_F2:
+ return "fp2";
+ case UNW_PPC_F3:
+ return "fp3";
+ case UNW_PPC_F4:
+ return "fp4";
+ case UNW_PPC_F5:
+ return "fp5";
+ case UNW_PPC_F6:
+ return "fp6";
+ case UNW_PPC_F7:
+ return "fp7";
+ case UNW_PPC_F8:
+ return "fp8";
+ case UNW_PPC_F9:
+ return "fp9";
+ case UNW_PPC_F10:
+ return "fp10";
+ case UNW_PPC_F11:
+ return "fp11";
+ case UNW_PPC_F12:
+ return "fp12";
+ case UNW_PPC_F13:
+ return "fp13";
+ case UNW_PPC_F14:
+ return "fp14";
+ case UNW_PPC_F15:
+ return "fp15";
+ case UNW_PPC_F16:
+ return "fp16";
+ case UNW_PPC_F17:
+ return "fp17";
+ case UNW_PPC_F18:
+ return "fp18";
+ case UNW_PPC_F19:
+ return "fp19";
+ case UNW_PPC_F20:
+ return "fp20";
+ case UNW_PPC_F21:
+ return "fp21";
+ case UNW_PPC_F22:
+ return "fp22";
+ case UNW_PPC_F23:
+ return "fp23";
+ case UNW_PPC_F24:
+ return "fp24";
+ case UNW_PPC_F25:
+ return "fp25";
+ case UNW_PPC_F26:
+ return "fp26";
+ case UNW_PPC_F27:
+ return "fp27";
+ case UNW_PPC_F28:
+ return "fp28";
+ case UNW_PPC_F29:
+ return "fp29";
+ case UNW_PPC_F30:
+ return "fp30";
+ case UNW_PPC_F31:
+ return "fp31";
+ case UNW_PPC_LR:
+ return "lr";
+ default:
+ return "unknown register";
+ }
+
+}
+
+
+/// Registers_arm64 holds the register state of a thread in a 64-bit arm
+/// process.
+class _LIBUNWIND_HIDDEN Registers_arm64 {
+public:
+ Registers_arm64();
+ Registers_arm64(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+
+ uint64_t getSP() const { return _registers.__sp; }
+ void setSP(uint64_t value) { _registers.__sp = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint64_t value) { _registers.__pc = value; }
+ uint64_t getFP() const { return _registers.__fp; }
+ void setFP(uint64_t value) { _registers.__fp = value; }
+
+private:
+ struct GPRs {
+ uint64_t __x[29]; // x0-x28
+ uint64_t __fp; // Frame pointer x29
+ uint64_t __lr; // Link register x30
+ uint64_t __sp; // Stack pointer x31
+ uint64_t __pc; // Program counter
+ uint64_t padding; // 16-byte align
+ };
+
+ GPRs _registers;
+ double _vectorHalfRegisters[32];
+ // Currently only the lower double in 128-bit vectore registers
+ // is perserved during unwinding. We could define new register
+ // numbers (> 96) which mean whole vector registers, then this
+ // struct would need to change to contain whole vector registers.
+};
+
+inline Registers_arm64::Registers_arm64(const void *registers) {
+ static_assert(sizeof(Registers_arm64) < sizeof(unw_context_t),
+ "arm64 registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+ memcpy(_vectorHalfRegisters, (((char *)registers) + 0x110),
+ sizeof(_vectorHalfRegisters));
+}
+
+inline Registers_arm64::Registers_arm64() {
+ bzero(&_registers, sizeof(_registers));
+ bzero(&_vectorHalfRegisters, sizeof(_vectorHalfRegisters));
+}
+
+inline bool Registers_arm64::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum > 95)
+ return false;
+ if ((regNum > 31) && (regNum < 64))
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_arm64::getRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return _registers.__pc;
+ if (regNum == UNW_REG_SP)
+ return _registers.__sp;
+ if ((regNum >= 0) && (regNum < 32))
+ return _registers.__x[regNum];
+ _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
+ if (regNum == UNW_REG_IP)
+ _registers.__pc = value;
+ else if (regNum == UNW_REG_SP)
+ _registers.__sp = value;
+ else if ((regNum >= 0) && (regNum < 32))
+ _registers.__x[regNum] = value;
+ else
+ _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline const char *Registers_arm64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "pc";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_ARM64_X0:
+ return "x0";
+ case UNW_ARM64_X1:
+ return "x1";
+ case UNW_ARM64_X2:
+ return "x2";
+ case UNW_ARM64_X3:
+ return "x3";
+ case UNW_ARM64_X4:
+ return "x4";
+ case UNW_ARM64_X5:
+ return "x5";
+ case UNW_ARM64_X6:
+ return "x6";
+ case UNW_ARM64_X7:
+ return "x7";
+ case UNW_ARM64_X8:
+ return "x8";
+ case UNW_ARM64_X9:
+ return "x9";
+ case UNW_ARM64_X10:
+ return "x10";
+ case UNW_ARM64_X11:
+ return "x11";
+ case UNW_ARM64_X12:
+ return "x12";
+ case UNW_ARM64_X13:
+ return "x13";
+ case UNW_ARM64_X14:
+ return "x14";
+ case UNW_ARM64_X15:
+ return "x15";
+ case UNW_ARM64_X16:
+ return "x16";
+ case UNW_ARM64_X17:
+ return "x17";
+ case UNW_ARM64_X18:
+ return "x18";
+ case UNW_ARM64_X19:
+ return "x19";
+ case UNW_ARM64_X20:
+ return "x20";
+ case UNW_ARM64_X21:
+ return "x21";
+ case UNW_ARM64_X22:
+ return "x22";
+ case UNW_ARM64_X23:
+ return "x23";
+ case UNW_ARM64_X24:
+ return "x24";
+ case UNW_ARM64_X25:
+ return "x25";
+ case UNW_ARM64_X26:
+ return "x26";
+ case UNW_ARM64_X27:
+ return "x27";
+ case UNW_ARM64_X28:
+ return "x28";
+ case UNW_ARM64_X29:
+ return "fp";
+ case UNW_ARM64_X30:
+ return "lr";
+ case UNW_ARM64_X31:
+ return "sp";
+ case UNW_ARM64_D0:
+ return "d0";
+ case UNW_ARM64_D1:
+ return "d1";
+ case UNW_ARM64_D2:
+ return "d2";
+ case UNW_ARM64_D3:
+ return "d3";
+ case UNW_ARM64_D4:
+ return "d4";
+ case UNW_ARM64_D5:
+ return "d5";
+ case UNW_ARM64_D6:
+ return "d6";
+ case UNW_ARM64_D7:
+ return "d7";
+ case UNW_ARM64_D8:
+ return "d8";
+ case UNW_ARM64_D9:
+ return "d9";
+ case UNW_ARM64_D10:
+ return "d10";
+ case UNW_ARM64_D11:
+ return "d11";
+ case UNW_ARM64_D12:
+ return "d12";
+ case UNW_ARM64_D13:
+ return "d13";
+ case UNW_ARM64_D14:
+ return "d14";
+ case UNW_ARM64_D15:
+ return "d15";
+ case UNW_ARM64_D16:
+ return "d16";
+ case UNW_ARM64_D17:
+ return "d17";
+ case UNW_ARM64_D18:
+ return "d18";
+ case UNW_ARM64_D19:
+ return "d19";
+ case UNW_ARM64_D20:
+ return "d20";
+ case UNW_ARM64_D21:
+ return "d21";
+ case UNW_ARM64_D22:
+ return "d22";
+ case UNW_ARM64_D23:
+ return "d23";
+ case UNW_ARM64_D24:
+ return "d24";
+ case UNW_ARM64_D25:
+ return "d25";
+ case UNW_ARM64_D26:
+ return "d26";
+ case UNW_ARM64_D27:
+ return "d27";
+ case UNW_ARM64_D28:
+ return "d28";
+ case UNW_ARM64_D29:
+ return "d29";
+ case UNW_ARM64_D30:
+ return "d30";
+ case UNW_ARM64_D31:
+ return "d31";
+ default:
+ return "unknown register";
+ }
+}
+
+inline bool Registers_arm64::validFloatRegister(int regNum) const {
+ if (regNum < UNW_ARM64_D0)
+ return false;
+ if (regNum > UNW_ARM64_D31)
+ return false;
+ return true;
+}
+
+inline double Registers_arm64::getFloatRegister(int regNum) const {
+ assert(validFloatRegister(regNum));
+ return _vectorHalfRegisters[regNum - UNW_ARM64_D0];
+}
+
+inline void Registers_arm64::setFloatRegister(int regNum, double value) {
+ assert(validFloatRegister(regNum));
+ _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value;
+}
+
+inline bool Registers_arm64::validVectorRegister(int) const {
+ return false;
+}
+
+inline v128 Registers_arm64::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+inline void Registers_arm64::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+/// Registers_arm holds the register state of a thread in a 32-bit arm
+/// process.
+///
+/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit,
+/// this uses more memory than required.
+///
+/// FIXME: Support MMX Data Registers, Control registers, and load/stores
+/// for different representations in the VFP registers as listed in
+/// Table 1 of EHABI #7.5.2
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+ Registers_arm();
+ Registers_arm(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ // FIXME: Due to ARM VRS's support for reading/writing different
+ // representations into the VFP registers this set of accessors seem wrong.
+ // If {get,set}FloatRegister() is the backing store for
+ // _Unwind_VRS_{Get,Set} then it might be best to return a tagged union
+ // with types for each representation in _Unwind_VRS_DataRepresentation.
+ // Similarly, unw_{get,set}_fpreg in the public libunwind API may want to
+ // use a similar tagged union to back the unw_fpreg_t output parameter type.
+ bool validFloatRegister(int num) const;
+ unw_fpreg_t getFloatRegister(int num) const;
+ void setFloatRegister(int num, unw_fpreg_t value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+
+ uint32_t getSP() const { return _registers.__sp; }
+ void setSP(uint32_t value) { _registers.__sp = value; }
+ uint32_t getIP() const { return _registers.__pc; }
+ void setIP(uint32_t value) { _registers.__pc = value; }
+
+private:
+ struct GPRs {
+ uint32_t __r[13]; // r0-r12
+ uint32_t __sp; // Stack pointer r13
+ uint32_t __lr; // Link register r14
+ uint32_t __pc; // Program counter r15
+ };
+
+ GPRs _registers;
+};
+
+inline Registers_arm::Registers_arm(const void *registers) {
+ static_assert(sizeof(Registers_arm) < sizeof(unw_context_t),
+ "arm registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_arm::Registers_arm() {
+ bzero(&_registers, sizeof(_registers));
+}
+
+inline bool Registers_arm::validRegister(int regNum) const {
+ // Returns true for all non-VFP registers supported by the EHABI
+ // virtual register set (VRS).
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R15))
+ return true;
+ return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) const {
+ if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+ return _registers.__sp;
+ if (regNum == UNW_ARM_LR)
+ return _registers.__lr;
+ if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+ return _registers.__pc;
+ if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+ return _registers.__r[regNum];
+ _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline void Registers_arm::setRegister(int regNum, uint32_t value) {
+ if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+ _registers.__sp = value;
+ else if (regNum == UNW_ARM_LR)
+ _registers.__lr = value;
+ else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+ _registers.__pc = value;
+ else if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+ _registers.__r[regNum] = value;
+ else
+ _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline const char *Registers_arm::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ case UNW_ARM_IP: // UNW_ARM_R15 is alias
+ return "pc";
+ case UNW_ARM_LR: // UNW_ARM_R14 is alias
+ return "lr";
+ case UNW_REG_SP:
+ case UNW_ARM_SP: // UNW_ARM_R13 is alias
+ return "sp";
+ case UNW_ARM_R0:
+ return "r0";
+ case UNW_ARM_R1:
+ return "r1";
+ case UNW_ARM_R2:
+ return "r2";
+ case UNW_ARM_R3:
+ return "r3";
+ case UNW_ARM_R4:
+ return "r4";
+ case UNW_ARM_R5:
+ return "r5";
+ case UNW_ARM_R6:
+ return "r6";
+ case UNW_ARM_R7:
+ return "r7";
+ case UNW_ARM_R8:
+ return "r8";
+ case UNW_ARM_R9:
+ return "r9";
+ case UNW_ARM_R10:
+ return "r10";
+ case UNW_ARM_R11:
+ return "r11";
+ case UNW_ARM_R12:
+ return "r12";
+ case UNW_ARM_S0:
+ return "s0";
+ case UNW_ARM_S1:
+ return "s1";
+ case UNW_ARM_S2:
+ return "s2";
+ case UNW_ARM_S3:
+ return "s3";
+ case UNW_ARM_S4:
+ return "s4";
+ case UNW_ARM_S5:
+ return "s5";
+ case UNW_ARM_S6:
+ return "s6";
+ case UNW_ARM_S7:
+ return "s7";
+ case UNW_ARM_S8:
+ return "s8";
+ case UNW_ARM_S9:
+ return "s9";
+ case UNW_ARM_S10:
+ return "s10";
+ case UNW_ARM_S11:
+ return "s11";
+ case UNW_ARM_S12:
+ return "s12";
+ case UNW_ARM_S13:
+ return "s13";
+ case UNW_ARM_S14:
+ return "s14";
+ case UNW_ARM_S15:
+ return "s15";
+ case UNW_ARM_S16:
+ return "s16";
+ case UNW_ARM_S17:
+ return "s17";
+ case UNW_ARM_S18:
+ return "s18";
+ case UNW_ARM_S19:
+ return "s19";
+ case UNW_ARM_S20:
+ return "s20";
+ case UNW_ARM_S21:
+ return "s21";
+ case UNW_ARM_S22:
+ return "s22";
+ case UNW_ARM_S23:
+ return "s23";
+ case UNW_ARM_S24:
+ return "s24";
+ case UNW_ARM_S25:
+ return "s25";
+ case UNW_ARM_S26:
+ return "s26";
+ case UNW_ARM_S27:
+ return "s27";
+ case UNW_ARM_S28:
+ return "s28";
+ case UNW_ARM_S29:
+ return "s29";
+ case UNW_ARM_S30:
+ return "s30";
+ case UNW_ARM_S31:
+ return "s31";
+ case UNW_ARM_D0:
+ return "d0";
+ case UNW_ARM_D1:
+ return "d1";
+ case UNW_ARM_D2:
+ return "d2";
+ case UNW_ARM_D3:
+ return "d3";
+ case UNW_ARM_D4:
+ return "d4";
+ case UNW_ARM_D5:
+ return "d5";
+ case UNW_ARM_D6:
+ return "d6";
+ case UNW_ARM_D7:
+ return "d7";
+ case UNW_ARM_D8:
+ return "d8";
+ case UNW_ARM_D9:
+ return "d9";
+ case UNW_ARM_D10:
+ return "d10";
+ case UNW_ARM_D11:
+ return "d11";
+ case UNW_ARM_D12:
+ return "d12";
+ case UNW_ARM_D13:
+ return "d13";
+ case UNW_ARM_D14:
+ return "d14";
+ case UNW_ARM_D15:
+ return "d15";
+ case UNW_ARM_D16:
+ return "d16";
+ case UNW_ARM_D17:
+ return "d17";
+ case UNW_ARM_D18:
+ return "d18";
+ case UNW_ARM_D19:
+ return "d19";
+ case UNW_ARM_D20:
+ return "d20";
+ case UNW_ARM_D21:
+ return "d21";
+ case UNW_ARM_D22:
+ return "d22";
+ case UNW_ARM_D23:
+ return "d23";
+ case UNW_ARM_D24:
+ return "d24";
+ case UNW_ARM_D25:
+ return "d25";
+ case UNW_ARM_D26:
+ return "d26";
+ case UNW_ARM_D27:
+ return "d27";
+ case UNW_ARM_D28:
+ return "d28";
+ case UNW_ARM_D29:
+ return "d29";
+ case UNW_ARM_D30:
+ return "d30";
+ case UNW_ARM_D31:
+ return "d31";
+ default:
+ return "unknown register";
+ }
+}
+
+inline bool Registers_arm::validFloatRegister(int) const {
+ // FIXME: Implement float register support.
+ return false;
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("ARM float register support not yet implemented");
+}
+
+inline void Registers_arm::setFloatRegister(int, unw_fpreg_t) {
+ _LIBUNWIND_ABORT("ARM float register support not yet implemented");
+}
+
+inline bool Registers_arm::validVectorRegister(int) const {
+ return false;
+}
+
+inline v128 Registers_arm::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+inline void Registers_arm::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+} // namespace libunwind
+
+#endif // __REGISTERS_HPP__
diff --git a/system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c b/system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c
new file mode 100644
index 00000000..f9256b5a
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c
@@ -0,0 +1,468 @@
+//===--------------------------- Unwind-sjlj.c ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Implements setjump-longjump based C++ exceptions
+//
+//===----------------------------------------------------------------------===//
+
+#include <unwind.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "unwind_ext.h"
+
+//
+// 32-bit iOS uses setjump/longjump based C++ exceptions.
+// Other architectures use "zero cost" exceptions.
+//
+// With SJLJ based exceptions, any function that has a catch clause or needs to
+// do any clean up when an exception propagates through it, needs to call
+// _Unwind_SjLj_Register() at the start of the function and
+// _Unwind_SjLj_Unregister() at the end. The register function is called with
+// the address of a block of memory in the function's stack frame. The runtime
+// keeps a linked list (stack) of these blocks - one per thread. The calling
+// function also sets the personality and lsda fields of the block.
+//
+
+#if _LIBUNWIND_BUILD_SJLJ_APIS
+
+struct _Unwind_FunctionContext {
+ // next function in stack of handlers
+ struct _Unwind_FunctionContext *prev;
+
+ // set by calling function before registering to be the landing pad
+ uintptr_t resumeLocation;
+
+ // set by personality handler to be parameters passed to landing pad function
+ uintptr_t resumeParameters[4];
+
+ // set by calling function before registering
+ __personality_routine personality; // arm offset=24
+ uintptr_t lsda; // arm offset=28
+
+ // variable length array, contains registers to restore
+ // 0 = r7, 1 = pc, 2 = sp
+ void *jbuf[];
+};
+
+
+/// Called at start of each function that catches exceptions
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {
+ fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
+ __Unwind_SjLj_SetTopOfFunctionStack(fc);
+}
+
+
+/// Called at end of each function that catches exceptions
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
+ __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase1(struct _Unwind_Exception *exception_object) {
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p\n", c);
+
+ // walk each frame looking for a place to stop
+ for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
+
+ // check for no more frames
+ if (c == NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
+ "bottom => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p\n", c);
+ // if there is a personality routine, ask it if it will want to stop at this
+ // frame
+ if (c->personality != NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
+ "personality function %p\n",
+ exception_object, c->personality);
+ _Unwind_Reason_Code personalityResult = (*c->personality)(
+ 1, _UA_SEARCH_PHASE, exception_object->exception_class,
+ exception_object, (struct _Unwind_Context *)c);
+ switch (personalityResult) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember function context
+ handlerNotFound = false;
+ exception_object->private_2 = (uintptr_t) c;
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+ "_URC_HANDLER_FOUND\n", exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+ "_URC_CONTINUE_UNWIND\n", exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while (true) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p\n",
+ exception_object, c);
+
+ // check for no more frames
+ if (c == NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if (c->personality != NULL) {
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if ((uintptr_t) c == exception_object->private_2)
+ action = (_Unwind_Action)(
+ _UA_CLEANUP_PHASE |
+ _UA_HANDLER_FRAME); // tell personality this was the frame it marked
+ // in phase 1
+ _Unwind_Reason_Code personalityResult =
+ (*c->personality)(1, action, exception_object->exception_class,
+ exception_object, (struct _Unwind_Context *)c);
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ // continue unwinding
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ exception_object);
+ if ((uintptr_t) c == exception_object->private_2) {
+ // phase 1 said we would stop at this frame, but we did not...
+ _LIBUNWIND_ABORT("during phase1 personality function said it would "
+ "stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
+ "_URC_INSTALL_CONTEXT, will resume at "
+ "landing pad %p\n",
+ exception_object, c->jbuf[1]);
+ // personality routine says to transfer control to landing pad
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ // unw_resume() only returns if there was an error
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // something went wrong
+ _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+ personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // clean up phase did not resume at the frame that the search phase said it
+ // would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(struct _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter) {
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while (true) {
+
+ // get next frame (skip over first which is _Unwind_RaiseException)
+ if (c == NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // call stop function at each frame
+ _Unwind_Action action =
+ (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult =
+ (*stop)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)c, stop_parameter);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "stop function returned %d\n",
+ exception_object, stopResult);
+ if (stopResult != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "stopped by stop function\n",
+ exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if (c->personality != NULL) {
+ __personality_routine p = (__personality_routine) c->personality;
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "calling personality function %p\n",
+ exception_object, p);
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)c);
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned _URC_CONTINUE_UNWIND\n",
+ exception_object);
+ // destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned _URC_INSTALL_CONTEXT\n",
+ exception_object);
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ break;
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned %d, "
+ "_URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // call stop function one last time and tell it we've reached the end of the
+ // stack
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+ "function with _UA_END_OF_STACK\n",
+ exception_object);
+ _Unwind_Action lastAction =
+ (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)c, stop_parameter);
+
+ // clean up phase did not resume at the frame that the search phase said it
+ // would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+/// Called by __cxa_throw. Only returns if there is a fatal error
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object);
+
+ // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
+ // thing
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
+ if (phase1 != _URC_NO_REASON)
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(exception_object);
+}
+
+
+
+/// When _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame. The personality
+/// may force a jump to a landing pad in that function, the landing
+/// pad code may then call _Unwind_Resume() to continue with the
+/// unwinding. Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code. All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Re-throwing an exception is implemented by having the code call
+/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object);
+
+ if (exception_object->private_1 != 0)
+ unwind_phase2_forced(exception_object,
+ (_Unwind_Stop_Fn) exception_object->private_1,
+ (void *)exception_object->private_2);
+ else
+ unwind_phase2(exception_object);
+
+ // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
+}
+
+
+/// Called by __cxa_rethrow().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
+ "private_1=%ld\n",
+ exception_object, exception_object->private_1);
+ // If this is non-forced and a stopping place was found, then this is a
+ // re-throw.
+ // Call _Unwind_RaiseException() as if this was a new exception.
+ if (exception_object->private_1 == 0) {
+ return _Unwind_SjLj_RaiseException(exception_object);
+ // should return if there is no catch clause, so that __cxa_rethrow can call
+ // std::terminate()
+ }
+
+ // Call through to _Unwind_Resume() which distiguishes between forced and
+ // regular exceptions.
+ _Unwind_SjLj_Resume(exception_object);
+ _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
+ "_Unwind_SjLj_Resume() which unexpectedly returned");
+}
+
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
+ "=> 0x%0lX\n", context, ufc->lsda);
+ return ufc->lsda;
+}
+
+
+/// Called by personality handler during phase 2 to get register values.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
+ int index) {
+ _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)\n",
+ context, index);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ return ufc->resumeParameters[index];
+}
+
+
+/// Called by personality handler during phase 2 to alter register values.
+_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+ uintptr_t new_value) {
+ _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n"
+ , context, index, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ ufc->resumeParameters[index] = new_value;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context,
+ ufc->resumeLocation + 1);
+ return ufc->resumeLocation + 1;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+/// ipBefore is a boolean that says if IP is already adjusted to be the call
+/// site address. Normally IP is the return address.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+ int *ipBefore) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ *ipBefore = 0;
+ _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n",
+ context, ipBefore, ufc->resumeLocation + 1);
+ return ufc->resumeLocation + 1;
+}
+
+
+/// Called by personality handler during phase 2 to alter instruction pointer.
+_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
+ uintptr_t new_value) {
+ _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n",
+ context, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ ufc->resumeLocation = new_value - 1;
+}
+
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+ // Not supported or needed for sjlj based unwinding
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)\n", context);
+ return 0;
+}
+
+
+/// Called by personality handler during phase 2 if a foreign exception
+/// is caught.
+_LIBUNWIND_EXPORT void
+_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n",
+ exception_object);
+ if (exception_object->exception_cleanup != NULL)
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+ exception_object);
+}
+
+
+
+/// Called by personality handler during phase 2 to get base address for data
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
+ // Not supported or needed for sjlj based unwinding
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for text
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
+ // Not supported or needed for sjlj based unwinding
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+/// Called by personality handler to get "Call Frame Area" for current frame.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
+ _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)\n", context);
+ if (context != NULL) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ // Setjmp/longjmp based exceptions don't have a true CFA.
+ // Instead, the SP in the jmpbuf is the closest approximation.
+ return (uintptr_t) ufc->jbuf[2];
+ }
+ return 0;
+}
+
+#endif // _LIBUNWIND_BUILD_SJLJ_APIS
diff --git a/system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp b/system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp
new file mode 100644
index 00000000..256a72da
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp
@@ -0,0 +1,1063 @@
+//===------------------------- UnwindCursor.hpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// C++ interface to lower levels of libuwind
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWINDCURSOR_HPP__
+#define __UNWINDCURSOR_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#if __APPLE__
+ #include <mach-o/dyld.h>
+#endif
+
+#include "libunwind.h"
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfInstructions.hpp"
+#include "CompactUnwinder.hpp"
+#include "config.h"
+
+namespace libunwind {
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+/// Cache of recently found FDEs.
+template <typename A>
+class _LIBUNWIND_HIDDEN DwarfFDECache {
+ typedef typename A::pint_t pint_t;
+public:
+ static pint_t findFDE(pint_t mh, pint_t pc);
+ static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
+ static void removeAllIn(pint_t mh);
+ static void iterateCacheEntries(void (*func)(unw_word_t ip_start,
+ unw_word_t ip_end,
+ unw_word_t fde, unw_word_t mh));
+
+private:
+
+ struct entry {
+ pint_t mh;
+ pint_t ip_start;
+ pint_t ip_end;
+ pint_t fde;
+ };
+
+ // These fields are all static to avoid needing an initializer.
+ // There is only one instance of this class per process.
+ static pthread_rwlock_t _lock;
+#if __APPLE__
+ static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
+ static bool _registeredForDyldUnloads;
+#endif
+ // Can't use std::vector<> here because this code is below libc++.
+ static entry *_buffer;
+ static entry *_bufferUsed;
+ static entry *_bufferEnd;
+ static entry _initialBuffer[64];
+};
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_buffer = _initialBuffer;
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_bufferUsed = _initialBuffer;
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64];
+
+template <typename A>
+typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
+
+template <typename A>
+pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+#if __APPLE__
+template <typename A>
+bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
+#endif
+
+template <typename A>
+typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
+ pint_t result = 0;
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock));
+ for (entry *p = _buffer; p < _bufferUsed; ++p) {
+ if ((mh == p->mh) || (mh == 0)) {
+ if ((p->ip_start <= pc) && (pc < p->ip_end)) {
+ result = p->fde;
+ break;
+ }
+ }
+ }
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+ return result;
+}
+
+template <typename A>
+void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
+ pint_t fde) {
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ if (_bufferUsed >= _bufferEnd) {
+ size_t oldSize = (size_t)(_bufferEnd - _buffer);
+ size_t newSize = oldSize * 4;
+ // Can't use operator new (we are below it).
+ entry *newBuffer = (entry *)malloc(newSize * sizeof(entry));
+ memcpy(newBuffer, _buffer, oldSize * sizeof(entry));
+ if (_buffer != _initialBuffer)
+ free(_buffer);
+ _buffer = newBuffer;
+ _bufferUsed = &newBuffer[oldSize];
+ _bufferEnd = &newBuffer[newSize];
+ }
+ _bufferUsed->mh = mh;
+ _bufferUsed->ip_start = ip_start;
+ _bufferUsed->ip_end = ip_end;
+ _bufferUsed->fde = fde;
+ ++_bufferUsed;
+#if __APPLE__
+ if (!_registeredForDyldUnloads) {
+ _dyld_register_func_for_remove_image(&dyldUnloadHook);
+ _registeredForDyldUnloads = true;
+ }
+#endif
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+}
+
+template <typename A>
+void DwarfFDECache<A>::removeAllIn(pint_t mh) {
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ entry *d = _buffer;
+ for (const entry *s = _buffer; s < _bufferUsed; ++s) {
+ if (s->mh != mh) {
+ if (d != s)
+ *d = *s;
+ ++d;
+ }
+ }
+ _bufferUsed = d;
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+}
+
+template <typename A>
+void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
+ removeAllIn((pint_t) mh);
+}
+
+template <typename A>
+void DwarfFDECache<A>::iterateCacheEntries(void (*func)(
+ unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ for (entry *p = _buffer; p < _bufferUsed; ++p) {
+ (*func)(p->ip_start, p->ip_end, p->fde, p->mh);
+ }
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+}
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+
+#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
+
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+template <typename A> class UnwindSectionHeader {
+public:
+ UnwindSectionHeader(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t version() const {
+ return _addressSpace.get32(_addr +
+ offsetof(unwind_info_section_header, version));
+ }
+ uint32_t commonEncodingsArraySectionOffset() const {
+ return _addressSpace.get32(_addr +
+ offsetof(unwind_info_section_header,
+ commonEncodingsArraySectionOffset));
+ }
+ uint32_t commonEncodingsArrayCount() const {
+ return _addressSpace.get32(_addr + offsetof(unwind_info_section_header,
+ commonEncodingsArrayCount));
+ }
+ uint32_t personalityArraySectionOffset() const {
+ return _addressSpace.get32(_addr + offsetof(unwind_info_section_header,
+ personalityArraySectionOffset));
+ }
+ uint32_t personalityArrayCount() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_section_header, personalityArrayCount));
+ }
+ uint32_t indexSectionOffset() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_section_header, indexSectionOffset));
+ }
+ uint32_t indexCount() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_section_header, indexCount));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionIndexArray {
+public:
+ UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+ functionOffset));
+ }
+ uint32_t secondLevelPagesSectionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+ secondLevelPagesSectionOffset));
+ }
+ uint32_t lsdaIndexArraySectionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+ lsdaIndexArraySectionOffset));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionRegularPageHeader {
+public:
+ UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t kind() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_regular_second_level_page_header, kind));
+ }
+ uint16_t entryPageOffset() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_regular_second_level_page_header,
+ entryPageOffset));
+ }
+ uint16_t entryCount() const {
+ return _addressSpace.get16(
+ _addr +
+ offsetof(unwind_info_regular_second_level_page_header, entryCount));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionRegularArray {
+public:
+ UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index,
+ functionOffset));
+ }
+ uint32_t encoding(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr +
+ arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionCompressedPageHeader {
+public:
+ UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t kind() const {
+ return _addressSpace.get32(
+ _addr +
+ offsetof(unwind_info_compressed_second_level_page_header, kind));
+ }
+ uint16_t entryPageOffset() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_compressed_second_level_page_header,
+ entryPageOffset));
+ }
+ uint16_t entryCount() const {
+ return _addressSpace.get16(
+ _addr +
+ offsetof(unwind_info_compressed_second_level_page_header, entryCount));
+ }
+ uint16_t encodingsPageOffset() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_compressed_second_level_page_header,
+ encodingsPageOffset));
+ }
+ uint16_t encodingsCount() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_compressed_second_level_page_header,
+ encodingsCount));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionCompressedArray {
+public:
+ UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(
+ _addressSpace.get32(_addr + index * sizeof(uint32_t)));
+ }
+ uint16_t encodingIndex(uint32_t index) const {
+ return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(
+ _addressSpace.get32(_addr + index * sizeof(uint32_t)));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionLsdaArray {
+public:
+ UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry,
+ index, functionOffset));
+ }
+ uint32_t lsdaOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry,
+ index, lsdaOffset));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+
+class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
+public:
+ virtual bool validReg(int) = 0;
+ virtual unw_word_t getReg(int) = 0;
+ virtual void setReg(int, unw_word_t) = 0;
+ virtual bool validFloatReg(int) = 0;
+ virtual double getFloatReg(int) = 0;
+ virtual void setFloatReg(int, double) = 0;
+ virtual int step() = 0;
+ virtual void getInfo(unw_proc_info_t *) = 0;
+ virtual void jumpto() = 0;
+ virtual bool isSignalFrame() = 0;
+ virtual bool getFunctionName(char *bf, size_t ln, unw_word_t *off) = 0;
+ virtual void setInfoBasedOnIPRegister(bool isReturnAddr = false) = 0;
+ virtual const char *getRegisterName(int num) = 0;
+};
+
+
+/// UnwindCursor contains all state (including all register values) during
+/// an unwind. This is normally stack allocated inside a unw_cursor_t.
+template <typename A, typename R>
+class UnwindCursor : public AbstractUnwindCursor{
+ typedef typename A::pint_t pint_t;
+public:
+ UnwindCursor(unw_context_t *context, A &as);
+ UnwindCursor(A &as, void *threadArg);
+ virtual ~UnwindCursor() {}
+ virtual bool validReg(int);
+ virtual unw_word_t getReg(int);
+ virtual void setReg(int, unw_word_t);
+ virtual bool validFloatReg(int);
+ virtual double getFloatReg(int);
+ virtual void setFloatReg(int, double);
+ virtual int step();
+ virtual void getInfo(unw_proc_info_t *);
+ virtual void jumpto();
+ virtual bool isSignalFrame();
+ virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off);
+ virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false);
+ virtual const char *getRegisterName(int num);
+
+ void operator delete(void *, size_t) {}
+
+private:
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
+ uint32_t fdeSectionOffsetHint=0);
+ int stepWithDwarfFDE() {
+ return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace,
+ (pint_t)this->getReg(UNW_REG_IP),
+ (pint_t)_info.unwind_info,
+ _registers);
+ }
+#endif
+
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ bool getInfoFromCompactEncodingSection(pint_t pc,
+ const UnwindInfoSections &sects);
+ int stepWithCompactEncoding() {
+ #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ if ( compactSaysUseDwarf() )
+ return stepWithDwarfFDE();
+ #endif
+ R dummy;
+ return stepWithCompactEncoding(dummy);
+ }
+
+ int stepWithCompactEncoding(Registers_x86_64 &) {
+ return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+ _info.format, _info.start_ip, _addressSpace, _registers);
+ }
+
+ int stepWithCompactEncoding(Registers_x86 &) {
+ return CompactUnwinder_x86<A>::stepWithCompactEncoding(
+ _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers);
+ }
+
+ int stepWithCompactEncoding(Registers_ppc &) {
+ return UNW_EINVAL;
+ }
+
+ int stepWithCompactEncoding(Registers_arm64 &) {
+ return CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+ _info.format, _info.start_ip, _addressSpace, _registers);
+ }
+
+ bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
+ R dummy;
+ return compactSaysUseDwarf(dummy, offset);
+ }
+
+ bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const {
+ if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) {
+ if (offset)
+ *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ return true;
+ }
+ return false;
+ }
+
+ bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const {
+ if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) {
+ if (offset)
+ *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET);
+ return true;
+ }
+ return false;
+ }
+
+ bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const {
+ return true;
+ }
+
+ bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const {
+ if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) {
+ if (offset)
+ *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET);
+ return true;
+ }
+ return false;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding() const {
+ R dummy;
+ return dwarfEncoding(dummy);
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const {
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const {
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const {
+ return 0;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const {
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+
+ A &_addressSpace;
+ R _registers;
+ unw_proc_info_t _info;
+ bool _unwindInfoMissing;
+ bool _isSignalFrame;
+};
+
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
+ : _addressSpace(as), _registers(context), _unwindInfoMissing(false),
+ _isSignalFrame(false) {
+ static_assert(sizeof(UnwindCursor<A, R>) < sizeof(unw_cursor_t),
+ "UnwindCursor<> does not fit in unw_cursor_t");
+
+ bzero(&_info, sizeof(_info));
+}
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(A &as, void *)
+ : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
+ bzero(&_info, sizeof(_info));
+ // FIXME
+ // fill in _registers from thread arg
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validReg(int regNum) {
+ return _registers.validRegister(regNum);
+}
+
+template <typename A, typename R>
+unw_word_t UnwindCursor<A, R>::getReg(int regNum) {
+ return _registers.getRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) {
+ _registers.setRegister(regNum, (typename A::pint_t)value);
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validFloatReg(int regNum) {
+ return _registers.validFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+double UnwindCursor<A, R>::getFloatReg(int regNum) {
+ return _registers.getFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setFloatReg(int regNum, double value) {
+ _registers.setFloatRegister(regNum, value);
+}
+
+template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
+ _registers.jumpto();
+}
+
+template <typename A, typename R>
+const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
+ return _registers.getRegisterName(regNum);
+}
+
+template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
+ return _isSignalFrame;
+}
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
+ const UnwindInfoSections &sects,
+ uint32_t fdeSectionOffsetHint) {
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ bool foundFDE = false;
+ bool foundInCache = false;
+ // If compact encoding table gave offset into dwarf section, go directly there
+ if (fdeSectionOffsetHint != 0) {
+ foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+ (uint32_t)sects.dwarf_section_length,
+ sects.dwarf_section + fdeSectionOffsetHint,
+ &fdeInfo, &cieInfo);
+ }
+#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ if (!foundFDE && (sects.dwarf_index_section != 0)) {
+ // Have eh_frame_hdr section which is index into dwarf section.
+ // TO DO: implement index search
+ }
+#endif
+ if (!foundFDE) {
+ // otherwise, search cache of previously found FDEs.
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(sects.dso_base, pc);
+ if (cachedFDE != 0) {
+ foundFDE =
+ CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+ (uint32_t)sects.dwarf_section_length,
+ cachedFDE, &fdeInfo, &cieInfo);
+ foundInCache = foundFDE;
+ }
+ }
+ if (!foundFDE) {
+ // Still not found, do full scan of __eh_frame section.
+ foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+ (uint32_t)sects.dwarf_section_length, 0,
+ &fdeInfo, &cieInfo);
+ }
+ if (foundFDE) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
+ &prolog)) {
+ // Save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ _info.gp = prolog.spExtraArgSize;
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
+ _info.extra = (unw_word_t) sects.dso_base;
+
+ // Add to cache (to make next lookup faster) if we had no hint
+ // and there was no index.
+ if (!foundInCache && (fdeSectionOffsetHint == 0)) {
+ #if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ if (sects.dwarf_index_section == 0)
+ #endif
+ DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd,
+ fdeInfo.fdeStart);
+ }
+ return true;
+ }
+ }
+ //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
+ return false;
+}
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
+ const UnwindInfoSections &sects) {
+ const bool log = false;
+ if (log)
+ fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n",
+ (uint64_t)pc, (uint64_t)sects.dso_base);
+
+ const UnwindSectionHeader<A> sectionHeader(_addressSpace,
+ sects.compact_unwind_section);
+ if (sectionHeader.version() != UNWIND_SECTION_VERSION)
+ return false;
+
+ // do a binary search of top level index to find page with unwind info
+ pint_t targetFunctionOffset = pc - sects.dso_base;
+ const UnwindSectionIndexArray<A> topIndex(_addressSpace,
+ sects.compact_unwind_section
+ + sectionHeader.indexSectionOffset());
+ uint32_t low = 0;
+ uint32_t high = sectionHeader.indexCount();
+ uint32_t last = high - 1;
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n",
+ //mid, low, high, topIndex.functionOffset(mid));
+ if (topIndex.functionOffset(mid) <= targetFunctionOffset) {
+ if ((mid == last) ||
+ (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) {
+ low = mid;
+ break;
+ } else {
+ low = mid + 1;
+ }
+ } else {
+ high = mid;
+ }
+ }
+ const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
+ const uint32_t firstLevelNextPageFunctionOffset =
+ topIndex.functionOffset(low + 1);
+ const pint_t secondLevelAddr =
+ sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low);
+ const pint_t lsdaArrayStartAddr =
+ sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low);
+ const pint_t lsdaArrayEndAddr =
+ sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1);
+ if (log)
+ fprintf(stderr, "\tfirst level search for result index=%d "
+ "to secondLevelAddr=0x%llX\n",
+ low, (uint64_t) secondLevelAddr);
+ // do a binary search of second level page index
+ uint32_t encoding = 0;
+ pint_t funcStart = 0;
+ pint_t funcEnd = 0;
+ pint_t lsda = 0;
+ pint_t personality = 0;
+ uint32_t pageKind = _addressSpace.get32(secondLevelAddr);
+ if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) {
+ // regular page
+ UnwindSectionRegularPageHeader<A> pageHeader(_addressSpace,
+ secondLevelAddr);
+ UnwindSectionRegularArray<A> pageIndex(
+ _addressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ // binary search looks for entry with e where index[e].offset <= pc <
+ // index[e+1].offset
+ if (log)
+ fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in "
+ "regular page starting at secondLevelAddr=0x%llX\n",
+ (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr);
+ low = 0;
+ high = pageHeader.entryCount();
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ if (pageIndex.functionOffset(mid) <= targetFunctionOffset) {
+ if (mid == (uint32_t)(pageHeader.entryCount() - 1)) {
+ // at end of table
+ low = mid;
+ funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base;
+ break;
+ } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) {
+ // next is too big, so we found it
+ low = mid;
+ funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base;
+ break;
+ } else {
+ low = mid + 1;
+ }
+ } else {
+ high = mid;
+ }
+ }
+ encoding = pageIndex.encoding(low);
+ funcStart = pageIndex.functionOffset(low) + sects.dso_base;
+ if (pc < funcStart) {
+ if (log)
+ fprintf(
+ stderr,
+ "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n",
+ (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd);
+ return false;
+ }
+ if (pc > funcEnd) {
+ if (log)
+ fprintf(
+ stderr,
+ "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n",
+ (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd);
+ return false;
+ }
+ } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) {
+ // compressed page
+ UnwindSectionCompressedPageHeader<A> pageHeader(_addressSpace,
+ secondLevelAddr);
+ UnwindSectionCompressedArray<A> pageIndex(
+ _addressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ const uint32_t targetFunctionPageOffset =
+ (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset);
+ // binary search looks for entry with e where index[e].offset <= pc <
+ // index[e+1].offset
+ if (log)
+ fprintf(stderr, "\tbinary search of compressed page starting at "
+ "secondLevelAddr=0x%llX\n",
+ (uint64_t) secondLevelAddr);
+ low = 0;
+ last = pageHeader.entryCount() - 1;
+ high = pageHeader.entryCount();
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) {
+ if ((mid == last) ||
+ (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) {
+ low = mid;
+ break;
+ } else {
+ low = mid + 1;
+ }
+ } else {
+ high = mid;
+ }
+ }
+ funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset
+ + sects.dso_base;
+ if (low < last)
+ funcEnd =
+ pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset
+ + sects.dso_base;
+ else
+ funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base;
+ if (pc < funcStart) {
+ _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second "
+ "level compressed unwind table. funcStart=0x%llX\n",
+ (uint64_t) pc, (uint64_t) funcStart);
+ return false;
+ }
+ if (pc > funcEnd) {
+ _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second "
+ "level compressed unwind table. funcEnd=0x%llX\n",
+ (uint64_t) pc, (uint64_t) funcEnd);
+ return false;
+ }
+ uint16_t encodingIndex = pageIndex.encodingIndex(low);
+ if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) {
+ // encoding is in common table in section header
+ encoding = _addressSpace.get32(
+ sects.compact_unwind_section +
+ sectionHeader.commonEncodingsArraySectionOffset() +
+ encodingIndex * sizeof(uint32_t));
+ } else {
+ // encoding is in page specific table
+ uint16_t pageEncodingIndex =
+ encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount();
+ encoding = _addressSpace.get32(secondLevelAddr +
+ pageHeader.encodingsPageOffset() +
+ pageEncodingIndex * sizeof(uint32_t));
+ }
+ } else {
+ _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second "
+ "level page\n",
+ (uint64_t) sects.compact_unwind_section);
+ return false;
+ }
+
+ // look up LSDA, if encoding says function has one
+ if (encoding & UNWIND_HAS_LSDA) {
+ UnwindSectionLsdaArray<A> lsdaIndex(_addressSpace, lsdaArrayStartAddr);
+ uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base);
+ low = 0;
+ high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) /
+ sizeof(unwind_info_section_header_lsda_index_entry);
+ // binary search looks for entry with exact match for functionOffset
+ if (log)
+ fprintf(stderr,
+ "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n",
+ funcStartOffset);
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ if (lsdaIndex.functionOffset(mid) == funcStartOffset) {
+ lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base;
+ break;
+ } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ if (lsda == 0) {
+ _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for "
+ "pc=0x%0llX, but lsda table has no entry\n",
+ encoding, (uint64_t) pc);
+ return false;
+ }
+ }
+
+ // extact personality routine, if encoding says function has one
+ uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >>
+ (__builtin_ctz(UNWIND_PERSONALITY_MASK));
+ if (personalityIndex != 0) {
+ --personalityIndex; // change 1-based to zero-based index
+ if (personalityIndex > sectionHeader.personalityArrayCount()) {
+ _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, "
+ "but personality table has only %d entires\n",
+ encoding, personalityIndex,
+ sectionHeader.personalityArrayCount());
+ return false;
+ }
+ uint32_t personalityDelta = _addressSpace.get32(
+ sects.compact_unwind_section + sectionHeader.personalityArraySectionOffset() +
+ personalityIndex * sizeof(uint32_t));
+ pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
+ personality = _addressSpace.getP(personalityPointer);
+ if (log)
+ fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
+ "personalityDelta=0x%08X, personality=0x%08llX\n",
+ (uint64_t) pc, personalityDelta, (uint64_t) personality);
+ }
+
+ if (log)
+ fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
+ "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
+ (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart);
+ _info.start_ip = funcStart;
+ _info.end_ip = funcEnd;
+ _info.lsda = lsda;
+ _info.handler = personality;
+ _info.gp = 0;
+ _info.flags = 0;
+ _info.format = encoding;
+ _info.unwind_info = 0;
+ _info.unwind_info_size = 0;
+ _info.extra = sects.dso_base;
+ return true;
+}
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
+ pint_t pc = (pint_t)this->getReg(UNW_REG_IP);
+
+ // If the last line of a function is a "throw" the compiler sometimes
+ // emits no instructions after the call to __cxa_throw. This means
+ // the return address is actually the start of the next function.
+ // To disambiguate this, back up the pc when we know it is a return
+ // address.
+ if (isReturnAddress)
+ --pc;
+
+ // Ask address space object to find unwind sections for this pc.
+ UnwindInfoSections sects;
+ if (_addressSpace.findUnwindSections(pc, sects)) {
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ // If there is a compact unwind encoding table, look there first.
+ if (sects.compact_unwind_section != 0) {
+ if (this->getInfoFromCompactEncodingSection(pc, sects)) {
+ #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ // Found info in table, done unless encoding says to use dwarf.
+ uint32_t dwarfOffset;
+ if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) {
+ if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+ #endif
+ // If unwind table has entry, but entry says there is no unwind info,
+ // record that we have no unwind info.
+ if (_info.format == 0)
+ _unwindInfoMissing = true;
+ return;
+ }
+ }
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ // If there is dwarf unwind info, look there next.
+ if (sects.dwarf_section != 0) {
+ if (this->getInfoFromDwarfSection(pc, sects)) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+#endif
+ }
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ // There is no static unwind info for this pc. Look to see if an FDE was
+ // dynamically registered for it.
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
+ if (cachedFDE != 0) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace,
+ cachedFDE, &fdeInfo, &cieInfo);
+ if (msg == NULL) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
+ pc, &prolog)) {
+ // save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ _info.gp = prolog.spExtraArgSize;
+ // Some frameless functions need SP
+ // altered when resuming in function.
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
+ _info.extra = 0;
+ return;
+ }
+ }
+ }
+
+ // Lastly, ask AddressSpace object about platform specific ways to locate
+ // other FDEs.
+ pint_t fde;
+ if (_addressSpace.findOtherFDE(pc, fde)) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) {
+ // Double check this FDE is for a function that includes the pc.
+ if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo,
+ cieInfo, pc, &prolog)) {
+ // save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ _info.gp = prolog.spExtraArgSize;
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
+ _info.extra = 0;
+ return;
+ }
+ }
+ }
+ }
+#endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+ // no unwind info, flag that we can't reliably unwind
+ _unwindInfoMissing = true;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A, R>::step() {
+ // Bottom of stack is defined is when no unwind info cannot be found.
+ if (_unwindInfoMissing)
+ return UNW_STEP_END;
+
+ // Use unwinding info to modify register set as if function returned.
+ int result;
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ result = this->stepWithCompactEncoding();
+#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ result = this->stepWithDwarfFDE();
+#else
+ #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif
+
+ // update info based on new PC
+ if (result == UNW_STEP_SUCCESS) {
+ this->setInfoBasedOnIPRegister(true);
+ if (_unwindInfoMissing)
+ return UNW_STEP_END;
+ }
+
+ return result;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
+ *info = _info;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
+ unw_word_t *offset) {
+ return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
+ buf, bufLen, offset);
+}
+
+}; // namespace libunwind
+
+#endif // __UNWINDCURSOR_HPP__
diff --git a/system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c b/system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c
new file mode 100644
index 00000000..c84db76c
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c
@@ -0,0 +1,268 @@
+//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Implements gcc extensions to the C++ ABI Exception Handling Level 1.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "libunwind_ext.h"
+#include "config.h"
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+/// Called by __cxa_rethrow().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), "
+ "private_1=%ld\n",
+ exception_object, exception_object->private_1);
+ // If this is non-forced and a stopping place was found, then this is a
+ // re-throw.
+ // Call _Unwind_RaiseException() as if this was a new exception
+ if (exception_object->private_1 == 0) {
+ return _Unwind_RaiseException(exception_object);
+ // Will return if there is no catch clause, so that __cxa_rethrow can call
+ // std::terminate().
+ }
+
+ // Call through to _Unwind_Resume() which distiguishes between forced and
+ // regular exceptions.
+ _Unwind_Resume(exception_object);
+ _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
+ " which unexpectedly returned");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for data
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for text
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+/// Scans unwind information to find the function that contains the
+/// specified code address "pc".
+_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
+ _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
+ // This is slow, but works.
+ // We create an unwind cursor then alter the IP to be pc
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_proc_info_t info;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
+ if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
+ return (void *)(long) info.start_ip;
+ else
+ return NULL;
+}
+
+
+/// Walk every frame and call trace function at each one. If trace function
+/// returns anything other than _URC_NO_REASON, then walk is terminated.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+
+ _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n", callback);
+
+ // walk each frame
+ while (true) {
+
+ // ask libuwind to get next frame (skip over first frame which is
+ // _Unwind_Backtrace())
+ if (unw_step(&cursor) <= 0) {
+ _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
+ "bottom of stack, returning %d\n",
+ _URC_END_OF_STACK);
+ return _URC_END_OF_STACK;
+ }
+
+ // debugging
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ char functionName[512];
+ unw_proc_info_t frameInfo;
+ unw_word_t offset;
+ unw_get_proc_name(&cursor, functionName, 512, &offset);
+ unw_get_proc_info(&cursor, &frameInfo);
+ _LIBUNWIND_TRACE_UNWINDING(
+ " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
+ frameInfo.start_ip, functionName, frameInfo.lsda, &cursor);
+ }
+
+ // call trace function with this frame
+ _Unwind_Reason_Code result =
+ (*callback)((struct _Unwind_Context *)(&cursor), ref);
+ if (result != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because callback "
+ "returned %d\n",
+ result);
+ return result;
+ }
+ }
+}
+
+
+/// Find dwarf unwind info for an address 'pc' in some function.
+_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
+ struct dwarf_eh_bases *bases) {
+ // This is slow, but works.
+ // We create an unwind cursor then alter the IP to be pc
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_proc_info_t info;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
+ unw_get_proc_info(&cursor, &info);
+ bases->tbase = (uintptr_t)info.extra;
+ bases->dbase = 0; // dbase not used on Mac OS X
+ bases->func = (uintptr_t)info.start_ip;
+ _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc,
+ (void *)(long) info.unwind_info);
+ return (void *)(long) info.unwind_info;
+}
+
+/// Returns the CFA (call frame area, or stack pointer at start of function)
+/// for the current context.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_word_t result;
+ unw_get_reg(cursor, UNW_REG_SP, &result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context,
+ (uint64_t) result);
+ return (uintptr_t)result;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+/// ipBefore is a boolean that says if IP is already adjusted to be the call
+/// site address. Normally IP is the return address.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+ int *ipBefore) {
+ _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)\n", context);
+ *ipBefore = 0;
+ return _Unwind_GetIP(context);
+}
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+/// Called by programs with dynamic code generators that want
+/// to register a dynamically generated FDE.
+/// This function has existed on Mac OS X since 10.4, but
+/// was broken until 10.6.
+_LIBUNWIND_EXPORT void __register_frame(const void *fde) {
+ _LIBUNWIND_TRACE_API("__register_frame(%p)\n", fde);
+ _unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde);
+}
+
+
+/// Called by programs with dynamic code generators that want
+/// to unregister a dynamically generated FDE.
+/// This function has existed on Mac OS X since 10.4, but
+/// was broken until 10.6.
+_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
+ _LIBUNWIND_TRACE_API("__deregister_frame(%p)\n", fde);
+ _unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde);
+}
+
+
+// The following register/deregister functions are gcc extensions.
+// They have existed on Mac OS X, but have never worked because Mac OS X
+// before 10.6 used keymgr to track known FDEs, but these functions
+// never got updated to use keymgr.
+// For now, we implement these as do-nothing functions to keep any existing
+// applications working. We also add the not in 10.6 symbol so that nwe
+// application won't be able to use them.
+
+#if _LIBUNWIND_SUPPORT_FRAME_APIS
+_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
+ void *tb, void *db) {
+ (void)fde;
+ (void)ob;
+ (void)tb;
+ (void)db;
+ _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)\n",
+ fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {
+ (void)fde;
+ (void)ob;
+ _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)\n", fde, ob);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
+ void *ob, void *tb,
+ void *db) {
+ (void)fde;
+ (void)ob;
+ (void)tb;
+ (void)db;
+ _LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
+ "(%p,%p, %p, %p)\n", fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {
+ (void)fde;
+ (void)ob;
+ _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)\n", fde, ob);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {
+ (void)fde;
+ _LIBUNWIND_TRACE_API("__register_frame_table(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {
+ (void)fde;
+ _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+
+_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
+ (void)fde;
+ _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)\n", fde);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+#endif // _LIBUNWIND_SUPPORT_FRAME_APIS
+
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
diff --git a/system/lib/libcxxabi/src/Unwind/UnwindLevel1.c b/system/lib/libcxxabi/src/Unwind/UnwindLevel1.c
new file mode 100644
index 00000000..b2e93c7e
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/UnwindLevel1.c
@@ -0,0 +1,495 @@
+//===------------------------- UnwindLevel1.c -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Implements C++ ABI Exception Handling Level 1 as documented at:
+// http://mentorembedded.github.io/cxx-abi/abi-eh.html
+// using libunwind
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "config.h"
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+static _Unwind_Reason_Code
+unwind_phase1(unw_context_t *uc, struct _Unwind_Exception *exception_object) {
+ unw_cursor_t cursor1;
+ unw_init_local(&cursor1, uc);
+
+ // Walk each frame looking for a place to stop.
+ for (bool handlerNotFound = true; handlerNotFound;) {
+
+ // Ask libuwind to get next frame (skip over first which is
+ // _Unwind_RaiseException).
+ int stepResult = unw_step(&cursor1);
+ if (stepResult == 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_END_OF_STACK;
+ } else if (stepResult < 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => "
+ "_URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // See if frame has code to run (has personality routine).
+ unw_proc_info_t frameInfo;
+ unw_word_t sp;
+ if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
+ "failed => _URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // When tracing, print state information.
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ char functionName[512];
+ unw_word_t offset;
+ if ((unw_get_proc_name(&cursor1, functionName, 512, &offset) !=
+ UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
+ strcpy(functionName, ".anonymous.");
+ unw_word_t pc;
+ unw_get_reg(&cursor1, UNW_REG_IP, &pc);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, "
+ "lsda=0x%llX, personality=0x%llX\n",
+ exception_object, pc, frameInfo.start_ip, functionName,
+ frameInfo.lsda, frameInfo.handler);
+ }
+
+ // If there is a personality routine, ask it if it will want to stop at
+ // this frame.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(frameInfo.handler);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): calling personality function %p\n",
+ exception_object, p);
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
+ exception_object, (struct _Unwind_Context *)(&cursor1));
+ switch (personalityResult) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember stack pointer at the frame
+ handlerNotFound = false;
+ unw_get_reg(&cursor1, UNW_REG_SP, &sp);
+ exception_object->private_2 = (uintptr_t)sp;
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+ "_URC_HANDLER_FOUND \n",
+ exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2(unw_context_t *uc, struct _Unwind_Exception *exception_object) {
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+
+ // Walk each frame until we reach where search phase said to stop.
+ while (true) {
+
+ // Ask libuwind to get next frame (skip over first which is
+ // _Unwind_RaiseException).
+ int stepResult = unw_step(&cursor2);
+ if (stepResult == 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_END_OF_STACK;
+ } else if (stepResult < 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => "
+ "_URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // Get info about this frame.
+ unw_word_t sp;
+ unw_proc_info_t frameInfo;
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
+ "failed => _URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // When tracing, print state information.
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ char functionName[512];
+ unw_word_t offset;
+ if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
+ UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
+ strcpy(functionName, ".anonymous.");
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, "
+ "lsda=0x%llX, personality=0x%llX\n",
+ exception_object, frameInfo.start_ip, functionName, sp,
+ frameInfo.lsda, frameInfo.handler);
+ }
+
+ // If there is a personality routine, tell it we are unwinding.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(frameInfo.handler);
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if (sp == exception_object->private_2) {
+ // Tell personality this was the frame it marked in phase 1.
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
+ }
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2));
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ // Continue unwinding
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ exception_object);
+ if (sp == exception_object->private_2) {
+ // Phase 1 said we would stop at this frame, but we did not...
+ _LIBUNWIND_ABORT("during phase1 personality function said it would "
+ "stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
+ exception_object);
+ // Personality routine says to transfer control to landing pad.
+ // We may get control back if landing pad calls _Unwind_Resume().
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ unw_word_t pc;
+ unw_get_reg(&cursor2, UNW_REG_IP, &pc);
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
+ "user code with ip=0x%llX, sp=0x%llX\n",
+ exception_object, pc, sp);
+ }
+ unw_resume(&cursor2);
+ // unw_resume() only returns if there was an error.
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // Personality routine returned an unknown result code.
+ _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+ personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // Clean up phase did not resume at the frame that the search phase
+ // said it would...
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(unw_context_t *uc,
+ struct _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter) {
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ // Walk each frame until we reach where search phase said to stop
+ while (unw_step(&cursor2) > 0) {
+
+ // Update info about this frame.
+ unw_proc_info_t frameInfo;
+ if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step "
+ "failed => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // When tracing, print state information.
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ char functionName[512];
+ unw_word_t offset;
+ if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
+ UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
+ strcpy(functionName, ".anonymous.");
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "start_ip=0x%llX, func=%s, lsda=0x%llX, "
+ " personality=0x%llX\n",
+ exception_object, frameInfo.start_ip,
+ functionName, frameInfo.lsda,
+ frameInfo.handler);
+ }
+
+ // Call stop function at each frame.
+ _Unwind_Action action =
+ (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult =
+ (*stop)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2), stop_parameter);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n",
+ exception_object, stopResult);
+ if (stopResult != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n",
+ exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // If there is a personality routine, tell it we are unwinding.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(frameInfo.handler);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n",
+ exception_object, p);
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2));
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned _URC_CONTINUE_UNWIND\n",
+ exception_object);
+ // Destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned _URC_INSTALL_CONTEXT\n",
+ exception_object);
+ // We may get control back if landing pad calls _Unwind_Resume().
+ unw_resume(&cursor2);
+ break;
+ default:
+ // Personality routine returned an unknown result code.
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned %d, "
+ "_URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // Call stop function one last time and tell it we've reached the end
+ // of the stack.
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+ "function with _UA_END_OF_STACK\n",
+ exception_object);
+ _Unwind_Action lastAction =
+ (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2), stop_parameter);
+
+ // Clean up phase did not resume at the frame that the search phase said it
+ // would.
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+/// Called by __cxa_throw. Only returns if there is a fatal error.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_RaiseException(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n",
+ exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // Mark that this is a non-forced unwind, so _Unwind_Resume()
+ // can do the right thing.
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
+ if (phase1 != _URC_NO_REASON)
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(&uc, exception_object);
+}
+
+
+
+/// When _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame. The personality
+/// may force a jump to a landing pad in that function, the landing
+/// pad code may then call _Unwind_Resume() to continue with the
+/// unwinding. Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code. All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call __cxa_rethrow() which
+/// in turn calls _Unwind_Resume_or_Rethrow().
+_LIBUNWIND_EXPORT void
+_Unwind_Resume(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ if (exception_object->private_1 != 0)
+ unwind_phase2_forced(&uc, exception_object,
+ (_Unwind_Stop_Fn) exception_object->private_1,
+ (void *)exception_object->private_2);
+ else
+ unwind_phase2(&uc, exception_object);
+
+ // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
+}
+
+
+
+/// Not used by C++.
+/// Unwinds stack, calling "stop" function at each frame.
+/// Could be used to implement longjmp().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter) {
+ _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n",
+ exception_object, stop);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // Mark that this is a forced unwind, so _Unwind_Resume() can do
+ // the right thing.
+ exception_object->private_1 = (uintptr_t) stop;
+ exception_object->private_2 = (uintptr_t) stop_parameter;
+
+ // do it
+ return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
+}
+
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+ result = (uintptr_t)frameInfo.lsda;
+ _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p)"
+ "=> 0x%lX\n", context, result);
+ if (result != 0) {
+ if (*((uint8_t *)result) != 0xFF)
+ _LIBUNWIND_DEBUG_LOG("lsda at 0x%lX does not start with 0xFF\n", result);
+ }
+ return result;
+}
+
+
+
+/// Called by personality handler during phase 2 to get register values.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
+ int index) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_word_t result;
+ unw_get_reg(cursor, index, &result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n",
+ context,
+ index, (uint64_t) result);
+ return (uintptr_t)result;
+}
+
+
+
+/// Called by personality handler during phase 2 to alter register values.
+_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+ uintptr_t new_value) {
+ _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, "
+ "value=0x%0llX)\n", context,
+ index, (uint64_t) new_value);
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_set_reg(cursor, index, new_value);
+}
+
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_word_t result;
+ unw_get_reg(cursor, UNW_REG_IP, &result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context,
+ (uint64_t) result);
+ return (uintptr_t)result;
+}
+
+
+
+/// Called by personality handler during phase 2 to alter instruction pointer,
+/// such as setting where the landing pad is, so _Unwind_Resume() will
+/// start executing in the landing pad.
+_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
+ uintptr_t new_value) {
+ _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n",
+ context, (uint64_t) new_value);
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_set_reg(cursor, UNW_REG_IP, new_value);
+}
+
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+ result = (uintptr_t)frameInfo.start_ip;
+ _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n",
+ context, result);
+ return result;
+}
+
+
+/// Called by personality handler during phase 2 if a foreign exception
+// is caught.
+_LIBUNWIND_EXPORT void
+_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n",
+ exception_object);
+ if (exception_object->exception_cleanup != NULL)
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+ exception_object);
+}
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
diff --git a/system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S b/system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S
new file mode 100644
index 00000000..15e2072f
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S
@@ -0,0 +1,329 @@
+//===-------------------- UnwindRegistersRestore.S ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+ .text
+
+#if __i386__
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
+#
+# void libunwind::Registers_x86::jumpto()
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+ movl 4(%esp), %eax
+ # set up eax and ret on new stack location
+ movl 28(%eax), %edx # edx holds new stack pointer
+ subl $8,%edx
+ movl %edx, 28(%eax)
+ movl 0(%eax), %ebx
+ movl %ebx, 0(%edx)
+ movl 40(%eax), %ebx
+ movl %ebx, 4(%edx)
+ # we now have ret and eax pushed onto where new stack will be
+ # restore all registers
+ movl 4(%eax), %ebx
+ movl 8(%eax), %ecx
+ movl 12(%eax), %edx
+ movl 16(%eax), %edi
+ movl 20(%eax), %esi
+ movl 24(%eax), %ebp
+ movl 28(%eax), %esp
+ # skip ss
+ # skip eflags
+ pop %eax # eax was already pushed on new stack
+ ret # eip was already pushed on new stack
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+
+#elif __x86_64__
+
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
+#
+# void libunwind::Registers_x86_64::jumpto()
+#
+# On entry, thread_state pointer is in rdi
+
+ movq 56(%rdi), %rax # rax holds new stack pointer
+ subq $16, %rax
+ movq %rax, 56(%rdi)
+ movq 32(%rdi), %rbx # store new rdi on new stack
+ movq %rbx, 0(%rax)
+ movq 128(%rdi), %rbx # store new rip on new stack
+ movq %rbx, 8(%rax)
+ # restore all registers
+ movq 0(%rdi), %rax
+ movq 8(%rdi), %rbx
+ movq 16(%rdi), %rcx
+ movq 24(%rdi), %rdx
+ # restore rdi later
+ movq 40(%rdi), %rsi
+ movq 48(%rdi), %rbp
+ # restore rsp later
+ movq 64(%rdi), %r8
+ movq 72(%rdi), %r9
+ movq 80(%rdi), %r10
+ movq 88(%rdi), %r11
+ movq 96(%rdi), %r12
+ movq 104(%rdi), %r13
+ movq 112(%rdi), %r14
+ movq 120(%rdi), %r15
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ movq 56(%rdi), %rsp # cut back rsp to new location
+ pop %rdi # rdi was saved here earlier
+ ret # rip was saved here
+
+
+#elif __ppc__
+
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
+;
+; void libunwind::Registers_ppc::jumpto()
+;
+; On entry:
+; thread_state pointer is in r3
+;
+
+ ; restore integral registerrs
+ ; skip r0 for now
+ ; skip r1 for now
+ lwz r2, 16(r3)
+ ; skip r3 for now
+ ; skip r4 for now
+ ; skip r5 for now
+ lwz r6, 32(r3)
+ lwz r7, 36(r3)
+ lwz r8, 40(r3)
+ lwz r9, 44(r3)
+ lwz r10, 48(r3)
+ lwz r11, 52(r3)
+ lwz r12, 56(r3)
+ lwz r13, 60(r3)
+ lwz r14, 64(r3)
+ lwz r15, 68(r3)
+ lwz r16, 72(r3)
+ lwz r17, 76(r3)
+ lwz r18, 80(r3)
+ lwz r19, 84(r3)
+ lwz r20, 88(r3)
+ lwz r21, 92(r3)
+ lwz r22, 96(r3)
+ lwz r23,100(r3)
+ lwz r24,104(r3)
+ lwz r25,108(r3)
+ lwz r26,112(r3)
+ lwz r27,116(r3)
+ lwz r28,120(r3)
+ lwz r29,124(r3)
+ lwz r30,128(r3)
+ lwz r31,132(r3)
+
+ ; restore float registers
+ lfd f0, 160(r3)
+ lfd f1, 168(r3)
+ lfd f2, 176(r3)
+ lfd f3, 184(r3)
+ lfd f4, 192(r3)
+ lfd f5, 200(r3)
+ lfd f6, 208(r3)
+ lfd f7, 216(r3)
+ lfd f8, 224(r3)
+ lfd f9, 232(r3)
+ lfd f10,240(r3)
+ lfd f11,248(r3)
+ lfd f12,256(r3)
+ lfd f13,264(r3)
+ lfd f14,272(r3)
+ lfd f15,280(r3)
+ lfd f16,288(r3)
+ lfd f17,296(r3)
+ lfd f18,304(r3)
+ lfd f19,312(r3)
+ lfd f20,320(r3)
+ lfd f21,328(r3)
+ lfd f22,336(r3)
+ lfd f23,344(r3)
+ lfd f24,352(r3)
+ lfd f25,360(r3)
+ lfd f26,368(r3)
+ lfd f27,376(r3)
+ lfd f28,384(r3)
+ lfd f29,392(r3)
+ lfd f30,400(r3)
+ lfd f31,408(r3)
+
+ ; restore vector registers if any are in use
+ lwz r5,156(r3) ; test VRsave
+ cmpwi r5,0
+ beq Lnovec
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+ ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+
+
+#define LOAD_VECTOR_UNALIGNEDl(_index) \
+ andis. r0,r5,(1<<(15-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+Ldone ## _index:
+
+#define LOAD_VECTOR_UNALIGNEDh(_index) \
+ andi. r0,r5,(1<<(31-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+ Ldone ## _index:
+
+
+ LOAD_VECTOR_UNALIGNEDl(0)
+ LOAD_VECTOR_UNALIGNEDl(1)
+ LOAD_VECTOR_UNALIGNEDl(2)
+ LOAD_VECTOR_UNALIGNEDl(3)
+ LOAD_VECTOR_UNALIGNEDl(4)
+ LOAD_VECTOR_UNALIGNEDl(5)
+ LOAD_VECTOR_UNALIGNEDl(6)
+ LOAD_VECTOR_UNALIGNEDl(7)
+ LOAD_VECTOR_UNALIGNEDl(8)
+ LOAD_VECTOR_UNALIGNEDl(9)
+ LOAD_VECTOR_UNALIGNEDl(10)
+ LOAD_VECTOR_UNALIGNEDl(11)
+ LOAD_VECTOR_UNALIGNEDl(12)
+ LOAD_VECTOR_UNALIGNEDl(13)
+ LOAD_VECTOR_UNALIGNEDl(14)
+ LOAD_VECTOR_UNALIGNEDl(15)
+ LOAD_VECTOR_UNALIGNEDh(16)
+ LOAD_VECTOR_UNALIGNEDh(17)
+ LOAD_VECTOR_UNALIGNEDh(18)
+ LOAD_VECTOR_UNALIGNEDh(19)
+ LOAD_VECTOR_UNALIGNEDh(20)
+ LOAD_VECTOR_UNALIGNEDh(21)
+ LOAD_VECTOR_UNALIGNEDh(22)
+ LOAD_VECTOR_UNALIGNEDh(23)
+ LOAD_VECTOR_UNALIGNEDh(24)
+ LOAD_VECTOR_UNALIGNEDh(25)
+ LOAD_VECTOR_UNALIGNEDh(26)
+ LOAD_VECTOR_UNALIGNEDh(27)
+ LOAD_VECTOR_UNALIGNEDh(28)
+ LOAD_VECTOR_UNALIGNEDh(29)
+ LOAD_VECTOR_UNALIGNEDh(30)
+ LOAD_VECTOR_UNALIGNEDh(31)
+
+Lnovec:
+ lwz r0, 136(r3) ; __cr
+ mtocrf 255,r0
+ lwz r0, 148(r3) ; __ctr
+ mtctr r0
+ lwz r0, 0(r3) ; __ssr0
+ mtctr r0
+ lwz r0, 8(r3) ; do r0 now
+ lwz r5,28(r3) ; do r5 now
+ lwz r4,24(r3) ; do r4 now
+ lwz r1,12(r3) ; do sp now
+ lwz r3,20(r3) ; do r3 last
+ bctr
+
+#elif __arm64__
+
+;
+; void libunwind::Registers_arm64::jumpto()
+;
+; On entry:
+; thread_state pointer is in x0
+;
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
+ ; skip restore of x0,x1 for now
+ ldp x2, x3, [x0, #0x010]
+ ldp x4, x5, [x0, #0x020]
+ ldp x6, x7, [x0, #0x030]
+ ldp x8, x9, [x0, #0x040]
+ ldp x10,x11, [x0, #0x050]
+ ldp x12,x13, [x0, #0x060]
+ ldp x14,x15, [x0, #0x070]
+ ldp x16,x17, [x0, #0x080]
+ ldp x18,x19, [x0, #0x090]
+ ldp x20,x21, [x0, #0x0A0]
+ ldp x22,x23, [x0, #0x0B0]
+ ldp x24,x25, [x0, #0x0C0]
+ ldp x26,x27, [x0, #0x0D0]
+ ldp x28,fp, [x0, #0x0E0]
+ ldr lr, [x0, #0x100] ; restore pc into lr
+ ldr x1, [x0, #0x0F8]
+ mov sp,x1 ; restore sp
+
+ ldp d0, d1, [x0, #0x110]
+ ldp d2, d3, [x0, #0x120]
+ ldp d4, d5, [x0, #0x130]
+ ldp d6, d7, [x0, #0x140]
+ ldp d8, d9, [x0, #0x150]
+ ldp d10,d11, [x0, #0x160]
+ ldp d12,d13, [x0, #0x170]
+ ldp d14,d15, [x0, #0x180]
+ ldp d16,d17, [x0, #0x190]
+ ldp d18,d19, [x0, #0x1A0]
+ ldp d20,d21, [x0, #0x1B0]
+ ldp d22,d23, [x0, #0x1C0]
+ ldp d24,d25, [x0, #0x1D0]
+ ldp d26,d27, [x0, #0x1E0]
+ ldp d28,d29, [x0, #0x1F0]
+ ldr d30, [x0, #0x200]
+ ldr d31, [x0, #0x208]
+
+ ldp x0, x1, [x0, #0x000] ; restore x0,x1
+ ret lr ; jump to pc
+
+#elif __arm__
+
+@
+@ void libunwind::Registers_arm::jumpto()
+@
+@ On entry:
+@ thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm6jumptoEv)
+ @ Use lr as base so that r0 can be restored.
+ mov lr, r0
+ @ 32bit thumb-2 restrictions for ldm:
+ @ . the sp (r13) cannot be in the list
+ @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
+ ldm lr, {r0-r12}
+ ldr sp, [lr, #52]
+ ldr lr, [lr, #60] @ restore pc into lr
+ mov pc, lr
+
+#endif
diff --git a/system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S b/system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S
new file mode 100644
index 00000000..6f19f6c6
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S
@@ -0,0 +1,301 @@
+//===------------------------ UnwindRegistersSave.S -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+ .text
+
+#if __i386__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ push %eax
+ movl 8(%esp), %eax
+ movl %ebx, 4(%eax)
+ movl %ecx, 8(%eax)
+ movl %edx, 12(%eax)
+ movl %edi, 16(%eax)
+ movl %esi, 20(%eax)
+ movl %ebp, 24(%eax)
+ movl %esp, %edx
+ addl $8, %edx
+ movl %edx, 28(%eax) # store what sp was at call site as esp
+ # skip ss
+ # skip eflags
+ movl 4(%esp), %edx
+ movl %edx, 40(%eax) # store return address as eip
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+ movl (%esp), %edx
+ movl %edx, (%eax) # store original eax
+ popl %eax
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif __x86_64__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in rdi
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ movq %rax, (%rdi)
+ movq %rbx, 8(%rdi)
+ movq %rcx, 16(%rdi)
+ movq %rdx, 24(%rdi)
+ movq %rdi, 32(%rdi)
+ movq %rsi, 40(%rdi)
+ movq %rbp, 48(%rdi)
+ movq %rsp, 56(%rdi)
+ addq $8, 56(%rdi)
+ movq %r8, 64(%rdi)
+ movq %r9, 72(%rdi)
+ movq %r10, 80(%rdi)
+ movq %r11, 88(%rdi)
+ movq %r12, 96(%rdi)
+ movq %r13,104(%rdi)
+ movq %r14,112(%rdi)
+ movq %r15,120(%rdi)
+ movq (%rsp),%rsi
+ movq %rsi,128(%rdi) # store return address as rip
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif __ppc__
+
+;
+; extern int unw_getcontext(unw_context_t* thread_state)
+;
+; On entry:
+; thread_state pointer is in r3
+;
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ stw r0, 8(r3)
+ mflr r0
+ stw r0, 0(r3) ; store lr as ssr0
+ stw r1, 12(r3)
+ stw r2, 16(r3)
+ stw r3, 20(r3)
+ stw r4, 24(r3)
+ stw r5, 28(r3)
+ stw r6, 32(r3)
+ stw r7, 36(r3)
+ stw r8, 40(r3)
+ stw r9, 44(r3)
+ stw r10, 48(r3)
+ stw r11, 52(r3)
+ stw r12, 56(r3)
+ stw r13, 60(r3)
+ stw r14, 64(r3)
+ stw r15, 68(r3)
+ stw r16, 72(r3)
+ stw r17, 76(r3)
+ stw r18, 80(r3)
+ stw r19, 84(r3)
+ stw r20, 88(r3)
+ stw r21, 92(r3)
+ stw r22, 96(r3)
+ stw r23,100(r3)
+ stw r24,104(r3)
+ stw r25,108(r3)
+ stw r26,112(r3)
+ stw r27,116(r3)
+ stw r28,120(r3)
+ stw r29,124(r3)
+ stw r30,128(r3)
+ stw r31,132(r3)
+
+ ; save VRSave register
+ mfspr r0,256
+ stw r0,156(r3)
+ ; save CR registers
+ mfcr r0
+ stw r0,136(r3)
+ ; save CTR register
+ mfctr r0
+ stw r0,148(r3)
+
+ ; save float registers
+ stfd f0, 160(r3)
+ stfd f1, 168(r3)
+ stfd f2, 176(r3)
+ stfd f3, 184(r3)
+ stfd f4, 192(r3)
+ stfd f5, 200(r3)
+ stfd f6, 208(r3)
+ stfd f7, 216(r3)
+ stfd f8, 224(r3)
+ stfd f9, 232(r3)
+ stfd f10,240(r3)
+ stfd f11,248(r3)
+ stfd f12,256(r3)
+ stfd f13,264(r3)
+ stfd f14,272(r3)
+ stfd f15,280(r3)
+ stfd f16,288(r3)
+ stfd f17,296(r3)
+ stfd f18,304(r3)
+ stfd f19,312(r3)
+ stfd f20,320(r3)
+ stfd f21,328(r3)
+ stfd f22,336(r3)
+ stfd f23,344(r3)
+ stfd f24,352(r3)
+ stfd f25,360(r3)
+ stfd f26,368(r3)
+ stfd f27,376(r3)
+ stfd f28,384(r3)
+ stfd f29,392(r3)
+ stfd f30,400(r3)
+ stfd f31,408(r3)
+
+
+ ; save vector registers
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+
+#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
+ stvx _vec,0,r4 @\
+ lwz r5, 0(r4) @\
+ stw r5, _offset(r3) @\
+ lwz r5, 4(r4) @\
+ stw r5, _offset+4(r3) @\
+ lwz r5, 8(r4) @\
+ stw r5, _offset+8(r3) @\
+ lwz r5, 12(r4) @\
+ stw r5, _offset+12(r3)
+
+ SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
+ SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
+ SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
+ SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
+ SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
+ SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
+ SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
+ SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
+ SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
+ SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
+ SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
+ SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
+ SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
+ SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
+ SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
+ SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
+ SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
+ SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
+ SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
+ SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
+ SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
+ SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
+ SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
+ SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
+ SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
+ SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
+ SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
+ SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
+ SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
+ SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
+ SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
+ SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
+
+ li r3, 0 ; return UNW_ESUCCESS
+ blr
+
+
+#elif __arm64__
+
+;
+; extern int unw_getcontext(unw_context_t* thread_state)
+;
+; On entry:
+; thread_state pointer is in x0
+;
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ stp x0, x1, [x0, #0x000]
+ stp x2, x3, [x0, #0x010]
+ stp x4, x5, [x0, #0x020]
+ stp x6, x7, [x0, #0x030]
+ stp x8, x9, [x0, #0x040]
+ stp x10,x11, [x0, #0x050]
+ stp x12,x13, [x0, #0x060]
+ stp x14,x15, [x0, #0x070]
+ stp x16,x17, [x0, #0x080]
+ stp x18,x19, [x0, #0x090]
+ stp x20,x21, [x0, #0x0A0]
+ stp x22,x23, [x0, #0x0B0]
+ stp x24,x25, [x0, #0x0C0]
+ stp x26,x27, [x0, #0x0D0]
+ stp x28,fp, [x0, #0x0E0]
+ str lr, [x0, #0x0F0]
+ mov x1,sp
+ str x1, [x0, #0x0F8]
+ str lr, [x0, #0x100] ; store return address as pc
+ ; skip cpsr
+ stp d0, d1, [x0, #0x110]
+ stp d2, d3, [x0, #0x120]
+ stp d4, d5, [x0, #0x130]
+ stp d6, d7, [x0, #0x140]
+ stp d8, d9, [x0, #0x150]
+ stp d10,d11, [x0, #0x160]
+ stp d12,d13, [x0, #0x170]
+ stp d14,d15, [x0, #0x180]
+ stp d16,d17, [x0, #0x190]
+ stp d18,d19, [x0, #0x1A0]
+ stp d20,d21, [x0, #0x1B0]
+ stp d22,d23, [x0, #0x1C0]
+ stp d24,d25, [x0, #0x1D0]
+ stp d26,d27, [x0, #0x1E0]
+ stp d28,d29, [x0, #0x1F0]
+ str d30, [x0, #0x200]
+ str d31, [x0, #0x208]
+ ldr x0, #0 ; return UNW_ESUCCESS
+ ret
+
+#elif __arm__ && !__APPLE__
+
+@
+@ extern int unw_getcontext(unw_context_t* thread_state)
+@
+@ On entry:
+@ thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ @ 32bit thumb-2 restrictions for stm:
+ @ . the sp (r13) cannot be in the list
+ @ . the pc (r15) cannot be in the list in an STM instruction
+ stm r0, {r0-r12}
+ str sp, [r0, #52]
+ str lr, [r0, #56]
+ str lr, [r0, #60] @ store return address as pc
+ mov r0, #0 @ return UNW_ESUCCESS
+ mov pc, lr
+
+#endif
diff --git a/system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp b/system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp
new file mode 100644
index 00000000..6d02a66b
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp
@@ -0,0 +1,205 @@
+//===--------------------- Unwind_AppleExtras.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "config.h"
+#include "DwarfParser.hpp"
+#include "unwind_ext.h"
+
+
+// private keymgr stuff
+#define KEYMGR_GCC3_DW2_OBJ_LIST 302
+extern "C" {
+ extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr);
+ extern void *_keymgr_get_and_lock_processwide_ptr(int key);
+}
+
+// undocumented libgcc "struct object"
+struct libgcc_object {
+ void *start;
+ void *unused1;
+ void *unused2;
+ void *fde;
+ unsigned long encoding;
+ void *fde_end;
+ libgcc_object *next;
+};
+
+// undocumented libgcc "struct km_object_info" referenced by
+// KEYMGR_GCC3_DW2_OBJ_LIST
+struct libgcc_object_info {
+ libgcc_object *seen_objects;
+ libgcc_object *unseen_objects;
+ unsigned spare[2];
+};
+
+
+// static linker symbols to prevent wrong two level namespace for _Unwind symbols
+#if __arm__
+ #define NOT_HERE_BEFORE_5_0(sym) \
+ extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \
+ extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \
+ extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\
+ __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \
+ extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \
+ extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \
+ extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \
+ extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp43 = 0;
+#elif __arm64__
+ #define NOT_HERE_BEFORE_10_6(sym)
+ #define NEVER_HERE(sym)
+#else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in
+// earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
+NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
+NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
+NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume)
+NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
+NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
+NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
+NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
+NOT_HERE_BEFORE_10_6(__register_frame)
+NOT_HERE_BEFORE_10_6(__deregister_frame)
+
+//
+// symbols in libSystem.dylib for compatibility, but we don't want any new code
+// using them
+//
+NEVER_HERE(__register_frame_info_bases)
+NEVER_HERE(__register_frame_info)
+NEVER_HERE(__register_frame_info_table_bases)
+NEVER_HERE(__register_frame_info_table)
+NEVER_HERE(__register_frame_table)
+NEVER_HERE(__deregister_frame_info)
+NEVER_HERE(__deregister_frame_info_bases)
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+
+
+
+#if _LIBUNWIND_BUILD_SJLJ_APIS
+//
+// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
+// earlier versions
+//
+NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_5_0(_Unwind_GetIP)
+NOT_HERE_BEFORE_5_0(_Unwind_SetGR)
+NOT_HERE_BEFORE_5_0(_Unwind_SetIP)
+NOT_HERE_BEFORE_5_0(_Unwind_DeleteException)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register)
+NOT_HERE_BEFORE_5_0(_Unwind_GetGR)
+NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo)
+NOT_HERE_BEFORE_5_0(_Unwind_GetCFA)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
+
+#endif // _LIBUNWIND_BUILD_SJLJ_APIS
+
+
+namespace libunwind {
+
+_LIBUNWIND_HIDDEN
+bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ // lastly check for old style keymgr registration of dynamically generated
+ // FDEs acquire exclusive access to libgcc_object_info
+ libgcc_object_info *head = (libgcc_object_info *)
+ _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
+ if (head != NULL) {
+ // look at each FDE in keymgr
+ for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char *msg = CFI_Parser<LocalAddressSpace>::decodeFDE(
+ LocalAddressSpace::sThisAddressSpace,
+ (uintptr_t)ob->fde, &fdeInfo, &cieInfo);
+ if (msg == NULL) {
+ // Check if this FDE is for a function that includes the pc
+ if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
+ fde = (void*)fdeInfo.pcStart;
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,
+ head);
+ return true;
+ }
+ }
+ }
+ }
+ // release libgcc_object_info
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
+#else
+ (void)pc;
+ (void)fde;
+#endif
+ return false;
+}
+
+}
+
+
+#if !FOR_DYLD && _LIBUNWIND_BUILD_SJLJ_APIS
+
+#include <System/pthread_machdep.h>
+
+// Accessors to get get/set linked list of frames for sjlj based execeptions.
+_LIBUNWIND_HIDDEN
+struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
+ return (struct _Unwind_FunctionContext *)
+ _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
+}
+
+_LIBUNWIND_HIDDEN
+void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
+ _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
+}
+#endif
+
+
+
+
diff --git a/system/lib/libcxxabi/src/Unwind/assembly.h b/system/lib/libcxxabi/src/Unwind/assembly.h
new file mode 100644
index 00000000..d282de8c
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/assembly.h
@@ -0,0 +1,44 @@
+/* ===-- assembly.h - libUnwind assembler support macros -------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in libUnwind assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef UNWIND_ASSEMBLY_H
+#define UNWIND_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN_DIRECTIVE .private_extern
+#else
+#define HIDDEN_DIRECTIVE .hidden
+#endif
+
+#define GLUE2(a, b) a ## b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#define DEFINE_LIBUNWIND_FUNCTION(name) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#endif /* UNWIND_ASSEMBLY_H */
diff --git a/system/lib/libcxxabi/src/Unwind/config.h b/system/lib/libcxxabi/src/Unwind/config.h
new file mode 100644
index 00000000..2b924641
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/config.h
@@ -0,0 +1,108 @@
+//===----------------------------- config.h -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Defines macros used within libuwind project.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LIBUNWIND_CONFIG_H
+#define LIBUNWIND_CONFIG_H
+
+#include <assert.h>
+
+// Define static_assert() unless already defined by compiler.
+#ifndef __has_feature
+ #define __has_feature(__x) 0
+#endif
+#if !(__has_feature(cxx_static_assert))
+ #define static_assert(__b, __m) \
+ extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \
+ __attribute__( ( unused ) );
+#endif
+
+// Platform specific configuration defines.
+#if __APPLE__
+ #include <Availability.h>
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ void __assert_rtn(const char *, const char *, int, const char *)
+ __attribute__((noreturn));
+ #ifdef __cplusplus
+ }
+ #endif
+
+ #define _LIBUNWIND_BUILD_ZERO_COST_APIS (__i386__ || __x86_64__ || __arm64__)
+ #define _LIBUNWIND_BUILD_SJLJ_APIS (__arm__)
+ #define _LIBUNWIND_SUPPORT_FRAME_APIS (__i386__ || __x86_64__)
+ #define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
+ #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
+ #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+ #define _LIBUNWIND_ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
+
+ #if FOR_DYLD
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
+ #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
+ #else
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
+ #endif
+
+#else
+ // #define _LIBUNWIND_BUILD_ZERO_COST_APIS
+ // #define _LIBUNWIND_BUILD_SJLJ_APIS
+ // #define _LIBUNWIND_SUPPORT_FRAME_APIS
+ // #define _LIBUNWIND_EXPORT
+ // #define _LIBUNWIND_HIDDEN
+ // #define _LIBUNWIND_LOG()
+ // #define _LIBUNWIND_ABORT()
+ // #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ // #define _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ // #define _LIBUNWIND_SUPPORT_DWARF_INDEX
+#endif
+
+
+// Macros that define away in non-Debug builds
+#ifdef NDEBUG
+ #define _LIBUNWIND_DEBUG_LOG(msg, ...)
+ #define _LIBUNWIND_TRACE_API(msg, ...)
+ #define _LIBUNWIND_TRACING_UNWINDING 0
+ #define _LIBUNWIND_TRACE_UNWINDING(msg, ...)
+ #define _LIBUNWIND_LOG_NON_ZERO(x) x
+#else
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern bool logAPIs();
+ extern bool logUnwinding();
+ #ifdef __cplusplus
+ }
+ #endif
+ #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__)
+ #define _LIBUNWIND_LOG_NON_ZERO(x) \
+ do { \
+ int _err = x; \
+ if ( _err != 0 ) \
+ _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \
+ } while (0)
+ #define _LIBUNWIND_TRACE_API(msg, ...) \
+ do { \
+ if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \
+ } while(0)
+ #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \
+ do { \
+ if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \
+ } while(0)
+ #define _LIBUNWIND_TRACING_UNWINDING logUnwinding()
+#endif
+
+
+#endif // LIBUNWIND_CONFIG_H
diff --git a/system/lib/libcxxabi/src/Unwind/dwarf2.h b/system/lib/libcxxabi/src/Unwind/dwarf2.h
new file mode 100644
index 00000000..0dcd2ca9
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/dwarf2.h
@@ -0,0 +1,237 @@
+//===------------------------------- dwarf2.h -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+/*
+ These constants were taken from version 3 of the DWARF standard,
+ which is Copyright (c) 2005 Free Standards Group, and
+ Copyright (c) 1992, 1993 UNIX International, Inc.
+*/
+
+#ifndef __DWARF2__
+#define __DWARF2__
+
+// DWARF unwind instructions
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_set_loc = 0x1,
+ DW_CFA_advance_loc1 = 0x2,
+ DW_CFA_advance_loc2 = 0x3,
+ DW_CFA_advance_loc4 = 0x4,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_restore_extended = 0x6,
+ DW_CFA_undefined = 0x7,
+ DW_CFA_same_value = 0x8,
+ DW_CFA_register = 0x9,
+ DW_CFA_remember_state = 0xA,
+ DW_CFA_restore_state = 0xB,
+ DW_CFA_def_cfa = 0xC,
+ DW_CFA_def_cfa_register = 0xD,
+ DW_CFA_def_cfa_offset = 0xE,
+ DW_CFA_def_cfa_expression = 0xF,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+ DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+ DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+
+ // GNU extensions
+ DW_CFA_GNU_window_save = 0x2D,
+ DW_CFA_GNU_args_size = 0x2E,
+ DW_CFA_GNU_negative_offset_extended = 0x2F
+};
+
+
+// FSF exception handling Pointer-Encoding constants
+// Used in CFI augmentation by GCC
+enum {
+ DW_EH_PE_ptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_signed = 0x08,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80,
+ DW_EH_PE_omit = 0xFF
+};
+
+
+// DWARF expressions
+enum {
+ DW_OP_addr = 0x03, // constant address (size target specific)
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08, // 1-byte constant
+ DW_OP_const1s = 0x09, // 1-byte constant
+ DW_OP_const2u = 0x0A, // 2-byte constant
+ DW_OP_const2s = 0x0B, // 2-byte constant
+ DW_OP_const4u = 0x0C, // 4-byte constant
+ DW_OP_const4s = 0x0D, // 4-byte constant
+ DW_OP_const8u = 0x0E, // 8-byte constant
+ DW_OP_const8s = 0x0F, // 8-byte constant
+ DW_OP_constu = 0x10, // ULEB128 constant
+ DW_OP_consts = 0x11, // SLEB128 constant
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15, // 1-byte stack index
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1A,
+ DW_OP_div = 0x1B,
+ DW_OP_minus = 0x1C,
+ DW_OP_mod = 0x1D,
+ DW_OP_mul = 0x1E,
+ DW_OP_neg = 0x1F,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23, // ULEB128 addend
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_skip = 0x2F, // signed 2-byte constant
+ DW_OP_bra = 0x28, // signed 2-byte constant
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2A,
+ DW_OP_gt = 0x2B,
+ DW_OP_le = 0x2C,
+ DW_OP_lt = 0x2D,
+ DW_OP_ne = 0x2E,
+ DW_OP_lit0 = 0x30, // Literal 0
+ DW_OP_lit1 = 0x31, // Literal 1
+ DW_OP_lit2 = 0x32, // Literal 2
+ DW_OP_lit3 = 0x33, // Literal 3
+ DW_OP_lit4 = 0x34, // Literal 4
+ DW_OP_lit5 = 0x35, // Literal 5
+ DW_OP_lit6 = 0x36, // Literal 6
+ DW_OP_lit7 = 0x37, // Literal 7
+ DW_OP_lit8 = 0x38, // Literal 8
+ DW_OP_lit9 = 0x39, // Literal 9
+ DW_OP_lit10 = 0x3A, // Literal 10
+ DW_OP_lit11 = 0x3B, // Literal 11
+ DW_OP_lit12 = 0x3C, // Literal 12
+ DW_OP_lit13 = 0x3D, // Literal 13
+ DW_OP_lit14 = 0x3E, // Literal 14
+ DW_OP_lit15 = 0x3F, // Literal 15
+ DW_OP_lit16 = 0x40, // Literal 16
+ DW_OP_lit17 = 0x41, // Literal 17
+ DW_OP_lit18 = 0x42, // Literal 18
+ DW_OP_lit19 = 0x43, // Literal 19
+ DW_OP_lit20 = 0x44, // Literal 20
+ DW_OP_lit21 = 0x45, // Literal 21
+ DW_OP_lit22 = 0x46, // Literal 22
+ DW_OP_lit23 = 0x47, // Literal 23
+ DW_OP_lit24 = 0x48, // Literal 24
+ DW_OP_lit25 = 0x49, // Literal 25
+ DW_OP_lit26 = 0x4A, // Literal 26
+ DW_OP_lit27 = 0x4B, // Literal 27
+ DW_OP_lit28 = 0x4C, // Literal 28
+ DW_OP_lit29 = 0x4D, // Literal 29
+ DW_OP_lit30 = 0x4E, // Literal 30
+ DW_OP_lit31 = 0x4F, // Literal 31
+ DW_OP_reg0 = 0x50, // Contents of reg0
+ DW_OP_reg1 = 0x51, // Contents of reg1
+ DW_OP_reg2 = 0x52, // Contents of reg2
+ DW_OP_reg3 = 0x53, // Contents of reg3
+ DW_OP_reg4 = 0x54, // Contents of reg4
+ DW_OP_reg5 = 0x55, // Contents of reg5
+ DW_OP_reg6 = 0x56, // Contents of reg6
+ DW_OP_reg7 = 0x57, // Contents of reg7
+ DW_OP_reg8 = 0x58, // Contents of reg8
+ DW_OP_reg9 = 0x59, // Contents of reg9
+ DW_OP_reg10 = 0x5A, // Contents of reg10
+ DW_OP_reg11 = 0x5B, // Contents of reg11
+ DW_OP_reg12 = 0x5C, // Contents of reg12
+ DW_OP_reg13 = 0x5D, // Contents of reg13
+ DW_OP_reg14 = 0x5E, // Contents of reg14
+ DW_OP_reg15 = 0x5F, // Contents of reg15
+ DW_OP_reg16 = 0x60, // Contents of reg16
+ DW_OP_reg17 = 0x61, // Contents of reg17
+ DW_OP_reg18 = 0x62, // Contents of reg18
+ DW_OP_reg19 = 0x63, // Contents of reg19
+ DW_OP_reg20 = 0x64, // Contents of reg20
+ DW_OP_reg21 = 0x65, // Contents of reg21
+ DW_OP_reg22 = 0x66, // Contents of reg22
+ DW_OP_reg23 = 0x67, // Contents of reg23
+ DW_OP_reg24 = 0x68, // Contents of reg24
+ DW_OP_reg25 = 0x69, // Contents of reg25
+ DW_OP_reg26 = 0x6A, // Contents of reg26
+ DW_OP_reg27 = 0x6B, // Contents of reg27
+ DW_OP_reg28 = 0x6C, // Contents of reg28
+ DW_OP_reg29 = 0x6D, // Contents of reg29
+ DW_OP_reg30 = 0x6E, // Contents of reg30
+ DW_OP_reg31 = 0x6F, // Contents of reg31
+ DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
+ DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
+ DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
+ DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
+ DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
+ DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
+ DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
+ DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
+ DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
+ DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
+ DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
+ DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
+ DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
+ DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
+ DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
+ DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
+ DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
+ DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
+ DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
+ DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
+ DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
+ DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
+ DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
+ DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
+ DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
+ DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
+ DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
+ DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
+ DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
+ DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
+ DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
+ DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
+ DW_OP_regx = 0x90, // ULEB128 register
+ DW_OP_fbreg = 0x91, // SLEB128 offset
+ DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
+ DW_OP_nop = 0x96,
+ DW_OP_push_object_addres = 0x97,
+ DW_OP_call2 = 0x98, // 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 4-byte offset of DIE
+ DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
+ DW_OP_lo_user = 0xE0,
+ DW_OP_APPLE_uninit = 0xF0,
+ DW_OP_hi_user = 0xFF
+};
+
+
+#endif
diff --git a/system/lib/libcxxabi/src/Unwind/libunwind.cpp b/system/lib/libcxxabi/src/Unwind/libunwind.cpp
new file mode 100644
index 00000000..2043ac23
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/libunwind.cpp
@@ -0,0 +1,353 @@
+//===--------------------------- libuwind.cpp -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Implements unw_* functions from <libunwind.h>
+//
+//===----------------------------------------------------------------------===//
+
+#include <libunwind.h>
+
+#include <new>
+
+#include "libunwind_ext.h"
+#include "config.h"
+
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+#include "UnwindCursor.hpp"
+
+using namespace libunwind;
+
+/// internal object to represent this processes address space
+LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
+
+/// record the registers and stack position of the caller
+extern int unw_getcontext(unw_context_t *);
+// note: unw_getcontext() implemented in assembly
+
+/// Create a cursor of a thread in this process given 'context' recorded by
+/// unw_getcontext().
+_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
+ unw_context_t *context) {
+ _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n",
+ cursor, context);
+ // Use "placement new" to allocate UnwindCursor in the cursor buffer.
+#if __i386__
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif __x86_64__
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif __ppc__
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif __arm64__
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#endif
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->setInfoBasedOnIPRegister();
+
+ return UNW_ESUCCESS;
+}
+
+#if UNW_REMOTE
+
+_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
+ (unw_addr_space_t) & sThisAddressSpace;
+
+/// Create a cursor into a thread in another process.
+_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
+ unw_addr_space_t as,
+ void *arg) {
+ // special case: unw_init_remote(xx, unw_local_addr_space, xx)
+ if (as == (unw_addr_space_t) & sThisAddressSpace)
+ return unw_init_local(cursor, NULL); //FIXME
+
+ // use "placement new" to allocate UnwindCursor in the cursor buffer
+ switch (as->cpuType) {
+ case CPU_TYPE_I386:
+ new ((void *)cursor)
+ UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >,
+ Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
+ break;
+ case CPU_TYPE_X86_64:
+ new ((void *)cursor) UnwindCursor<
+ OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(
+ ((unw_addr_space_x86_64 *)as)->oas, arg);
+ break;
+ case CPU_TYPE_POWERPC:
+ new ((void *)cursor)
+ UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
+ ((unw_addr_space_ppc *)as)->oas, arg);
+ break;
+ default:
+ return UNW_EUNSPEC;
+ }
+ return UNW_ESUCCESS;
+}
+
+
+static bool is64bit(task_t task) {
+ return false; // FIXME
+}
+
+/// Create an address_space object for use in examining another task.
+_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
+#if __i386__
+ if (is64bit(task)) {
+ unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
+ as->taskPort = task;
+ as->cpuType = CPU_TYPE_X86_64;
+ //as->oas
+ } else {
+ unw_addr_space_i386 *as = new unw_addr_space_i386(task);
+ as->taskPort = task;
+ as->cpuType = CPU_TYPE_I386;
+ //as->oas
+ }
+#else
+// FIXME
+#endif
+}
+
+
+/// Delete an address_space object.
+_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
+ switch (asp->cpuType) {
+#if __i386__ || __x86_64__
+ case CPU_TYPE_I386: {
+ unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
+ delete as;
+ }
+ break;
+ case CPU_TYPE_X86_64: {
+ unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
+ delete as;
+ }
+ break;
+#endif
+ case CPU_TYPE_POWERPC: {
+ unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
+ delete as;
+ }
+ break;
+ }
+}
+#endif // UNW_REMOTE
+
+
+/// Get value of specified register at cursor position in stack frame.
+_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
+ unw_word_t *value) {
+ _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n",
+ cursor, regNum, value);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validReg(regNum)) {
+ *value = co->getReg(regNum);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// Set value of specified register at cursor position in stack frame.
+_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
+ unw_word_t value) {
+ _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n",
+ cursor, regNum, value);
+ typedef LocalAddressSpace::pint_t pint_t;
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validReg(regNum)) {
+ co->setReg(regNum, (pint_t)value);
+ // specical case altering IP to re-find info (being called by personality
+ // function)
+ if (regNum == UNW_REG_IP) {
+ unw_proc_info_t info;
+ co->getInfo(&info);
+ pint_t orgArgSize = (pint_t)info.gp;
+ uint64_t orgFuncStart = info.start_ip;
+ co->setInfoBasedOnIPRegister(false);
+ // and adjust REG_SP if there was a DW_CFA_GNU_args_size
+ if ((orgFuncStart == info.start_ip) && (orgArgSize != 0))
+ co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize);
+ }
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// Get value of specified float register at cursor position in stack frame.
+_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
+ unw_fpreg_t *value) {
+ _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n",
+ cursor, regNum, value);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validFloatReg(regNum)) {
+ *value = co->getFloatReg(regNum);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// Set value of specified float register at cursor position in stack frame.
+_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
+ unw_fpreg_t value) {
+ _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n",
+ cursor, regNum, value);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validFloatReg(regNum)) {
+ co->setFloatReg(regNum, value);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// Move cursor to next frame.
+_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
+ _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", cursor);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->step();
+}
+
+
+/// Get unwind info at cursor position in stack frame.
+_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
+ unw_proc_info_t *info) {
+ _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n",
+ cursor, info);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->getInfo(info);
+ if (info->end_ip == 0)
+ return UNW_ENOINFO;
+ else
+ return UNW_ESUCCESS;
+}
+
+
+/// Resume execution at cursor position (aka longjump).
+_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
+ _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", cursor);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->jumpto();
+ return UNW_EUNSPEC;
+}
+
+
+/// Get name of function at cursor position in stack frame.
+_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
+ size_t bufLen, unw_word_t *offset) {
+ _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p,"
+ "bufLen=%ld)\n", cursor, buf, bufLen);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->getFunctionName(buf, bufLen, offset))
+ return UNW_ESUCCESS;
+ else
+ return UNW_EUNSPEC;
+}
+
+
+/// Checks if a register is a floating-point register.
+_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
+ _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n",
+ cursor, regNum);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->validFloatReg(regNum);
+}
+
+
+/// Checks if a register is a floating-point register.
+_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
+ unw_regnum_t regNum) {
+ _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n",
+ cursor, regNum);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->getRegisterName(regNum);
+}
+
+
+/// Checks if current frame is signal trampoline.
+_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
+ _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", cursor);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->isSignalFrame();
+}
+
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+/// SPI: walks cached dwarf entries
+_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
+ unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
+ _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func);
+ DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
+}
+
+
+/// IPI: for __register_frame()
+void _unw_add_dynamic_fde(unw_word_t fde) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
+ LocalAddressSpace::sThisAddressSpace,
+ (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
+ if (message == NULL) {
+ // dynamically registered FDEs don't have a mach_header group they are in.
+ // Use fde as mh_group
+ unw_word_t mh_group = fdeInfo.fdeStart;
+ DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
+ fdeInfo.pcStart, fdeInfo.pcEnd,
+ fdeInfo.fdeStart);
+ } else {
+ _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
+ }
+}
+
+/// IPI: for __deregister_frame()
+void _unw_remove_dynamic_fde(unw_word_t fde) {
+ // fde is own mh_group
+ DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
+}
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+
+
+// Add logging hooks in Debug builds only
+#ifndef NDEBUG
+
+_LIBUNWIND_HIDDEN
+bool logAPIs() {
+ // do manual lock to avoid use of _cxa_guard_acquire or initializers
+ static bool checked = false;
+ static bool log = false;
+ if (!checked) {
+ log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
+ checked = true;
+ }
+ return log;
+}
+
+_LIBUNWIND_HIDDEN
+bool logUnwinding() {
+ // do manual lock to avoid use of _cxa_guard_acquire or initializers
+ static bool checked = false;
+ static bool log = false;
+ if (!checked) {
+ log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
+ checked = true;
+ }
+ return log;
+}
+
+#endif // NDEBUG
+
diff --git a/system/lib/libcxxabi/src/Unwind/libunwind_ext.h b/system/lib/libcxxabi/src/Unwind/libunwind_ext.h
new file mode 100644
index 00000000..38d71cce
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/libunwind_ext.h
@@ -0,0 +1,38 @@
+//===------------------------ libunwind_ext.h -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Extensions to libunwind API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND_EXT__
+#define __LIBUNWIND_EXT__
+
+#include <libunwind.h>
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// SPI
+extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start,
+ unw_word_t ip_end,
+ unw_word_t fde,
+ unw_word_t mh));
+
+// IPI
+extern void _unw_add_dynamic_fde(unw_word_t fde);
+extern void _unw_remove_dynamic_fde(unw_word_t fde);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LIBUNWIND_EXT__
diff --git a/system/lib/libcxxabi/src/Unwind/unwind_ext.h b/system/lib/libcxxabi/src/Unwind/unwind_ext.h
new file mode 100644
index 00000000..c40ce6a1
--- /dev/null
+++ b/system/lib/libcxxabi/src/Unwind/unwind_ext.h
@@ -0,0 +1,37 @@
+//===-------------------------- unwind_ext.h ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Extensions to unwind API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_EXT__
+#define __UNWIND_EXT__
+
+#include "unwind.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// These platform specific functions to get and set the top context are
+// implemented elsewhere.
+
+extern struct _Unwind_FunctionContext *
+__Unwind_SjLj_GetTopOfFunctionStack();
+
+extern void
+__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UNWIND_EXT__
+
+
diff --git a/system/lib/libcxxabi/src/cxa_default_handlers.cpp b/system/lib/libcxxabi/src/cxa_default_handlers.cpp
new file mode 100644
index 00000000..27ffb719
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_default_handlers.cpp
@@ -0,0 +1,120 @@
+//===------------------------- cxa_default_handlers.cpp -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the default terminate_handler and unexpected_handler.
+//===----------------------------------------------------------------------===//
+
+#include <stdexcept>
+#include <new>
+#include <exception>
+#include "abort_message.h"
+#include "cxxabi.h"
+#include "cxa_handlers.hpp"
+#include "cxa_exception.hpp"
+#include "private_typeinfo.h"
+
+static const char* cause = "uncaught";
+
+__attribute__((noreturn))
+static void default_terminate_handler()
+{
+ // If there might be an uncaught exception
+ using namespace __cxxabiv1;
+ __cxa_eh_globals* globals = __cxa_get_globals_fast();
+ if (globals)
+ {
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ // If there is an uncaught exception
+ if (exception_header)
+ {
+ _Unwind_Exception* unwind_exception =
+ reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
+ bool native_exception =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ if (native_exception)
+ {
+ void* thrown_object =
+ unwind_exception->exception_class == kOurDependentExceptionClass ?
+ ((__cxa_dependent_exception*)exception_header)->primaryException :
+ exception_header + 1;
+ const __shim_type_info* thrown_type =
+ static_cast<const __shim_type_info*>(exception_header->exceptionType);
+ // Try to get demangled name of thrown_type
+ int status;
+ char buf[1024];
+ size_t len = sizeof(buf);
+ const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
+ if (status != 0)
+ name = thrown_type->name();
+ // If the uncaught exception can be caught with std::exception&
+ const __shim_type_info* catch_type =
+ static_cast<const __shim_type_info*>(&typeid(std::exception));
+ if (catch_type->can_catch(thrown_type, thrown_object))
+ {
+ // Include the what() message from the exception
+ const std::exception* e = static_cast<const std::exception*>(thrown_object);
+ abort_message("terminating with %s exception of type %s: %s",
+ cause, name, e->what());
+ }
+ else
+ // Else just note that we're terminating with an exception
+ abort_message("terminating with %s exception of type %s",
+ cause, name);
+ }
+ else
+ // Else we're terminating with a foreign exception
+ abort_message("terminating with %s foreign exception", cause);
+ }
+ }
+ // Else just note that we're terminating
+ abort_message("terminating");
+}
+
+__attribute__((noreturn))
+static void default_unexpected_handler()
+{
+ cause = "unexpected";
+ std::terminate();
+}
+
+
+//
+// Global variables that hold the pointers to the current handler
+//
+std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
+std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
+
+// In the future these will become:
+// std::atomic<std::terminate_handler> __cxa_terminate_handler(default_terminate_handler);
+// std::atomic<std::unexpected_handler> __cxa_unexpected_handler(default_unexpected_handler);
+
+namespace std
+{
+
+unexpected_handler
+set_unexpected(unexpected_handler func) _NOEXCEPT
+{
+ if (func == 0)
+ func = default_unexpected_handler;
+ return __sync_swap(&__cxa_unexpected_handler, func);
+// Using of C++11 atomics this should be rewritten
+// return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel);
+}
+
+terminate_handler
+set_terminate(terminate_handler func) _NOEXCEPT
+{
+ if (func == 0)
+ func = default_terminate_handler;
+ return __sync_swap(&__cxa_terminate_handler, func);
+// Using of C++11 atomics this should be rewritten
+// return __cxa_terminate_handler.exchange(func, memory_order_acq_rel);
+}
+
+}
diff --git a/system/lib/libcxxabi/src/cxa_demangle.cpp b/system/lib/libcxxabi/src/cxa_demangle.cpp
index c1e12603..839aebec 100644
--- a/system/lib/libcxxabi/src/cxa_demangle.cpp
+++ b/system/lib/libcxxabi/src/cxa_demangle.cpp
@@ -7,6438 +7,317 @@
//
//===----------------------------------------------------------------------===//
-#include "cxa_demangle.h"
+#define _LIBCPP_EXTERN_TEMPLATE(...)
+#define _LIBCPP_NO_EXCEPTIONS
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <new>
+#include <vector>
#include <algorithm>
-#include <assert.h>
-
-#ifdef DEBUGGING
-
#include <string>
-#include <typeinfo>
-
-#endif
+#include <numeric>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
namespace __cxxabiv1
{
-namespace __libcxxabi
-{
-
-#pragma GCC visibility push(hidden)
-
-class __node
-{
- __node(const __node&);
- __node& operator=(const __node&);
-public:
- const char* __name_;
- size_t __size_;
- __node* __left_;
- __node* __right_;
- long __cached_size_;
- long double __value_;
-public:
- __node()
- : __name_(0), __size_(0), __left_(0), __right_(0), __cached_size_(-1)
- {}
- virtual ~__node() {};
-
- void reset_cached_size()
- {
- __cached_size_ = -1;
- if (__left_)
- __left_->reset_cached_size();
- if (__right_)
- __right_->reset_cached_size();
- }
-
- virtual size_t first_size() const {return 0;}
- virtual size_t second_size() const {return 0;}
- virtual size_t size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(first_size() + second_size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const {return buf;}
- virtual char* second_demangled_name(char* buf) const {return buf;}
- virtual char* get_demangled_name(char* buf) const
- {
- return second_demangled_name(first_demangled_name(buf));
- }
- virtual size_t base_size() const {return size();}
- virtual char* get_base_name(char* buf) const
- {
- return get_demangled_name(buf);
- }
-
- virtual bool ends_with_template(bool /*parsing*/ = false) const
- {
- return false;
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return false;
- }
- virtual __node* base_name() const
- {
- return const_cast<__node*>(this);
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return false;
- }
- virtual bool is_function() const
- {
- return false;
- }
- virtual bool is_cv_qualifer() const
- {
- return false;
- }
- virtual bool is_array() const
- {
- return false;
- }
-
- virtual bool fix_forward_references(__node**, __node**)
- {
- return true;
- }
- virtual __node* extract_cv(__node*&) const
- {
- return 0;
- }
- virtual size_t list_len() const
- {
- return 0;
- }
- virtual bool is_sub() const
- {
- return false;
- }
-};
-
-#ifdef DEBUGGING
-
-void display(__node* x, int indent = 0)
-{
- if (x)
- {
- for (int i = 0; i < 2*indent; ++i)
- printf(" ");
- size_t sz = x->size();
- char* buf = (char*)calloc(sz+10, 1);
- x->get_demangled_name(buf);
- printf("%s [%ld] %s, %p\n", typeid(*x).name(), sz, buf, x);
- if (strlen(buf) != sz)
- {
- printf("strlen(buf) = %ld and size = %ld\n", strlen(buf), sz);
- }
- free(buf);
- display(x->__left_, indent+1);
- display(x->__right_, indent+1);
- }
-}
-
-#endif
-
-class __vtable
- : public __node
-{
- static const ptrdiff_t n = sizeof("vtable for ") - 1;
-public:
- __vtable(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "vtable for ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __VTT
- : public __node
-{
- static const ptrdiff_t n = sizeof("VTT for ") - 1;
-public:
- __VTT(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "VTT for ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __construction_vtable
- : public __node
-{
- static const ptrdiff_t n = sizeof("construction vtable for ") - 1 + 4;
-public:
- __construction_vtable(__node* left, __node* right)
- {
- __left_ = left;
- __right_ = right;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = n + static_cast<long>(__left_->size()
- + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "construction vtable for ", n-4);
- buf = __left_->get_demangled_name(buf+n-4);
- *buf++ = '-';
- *buf++ = 'i';
- *buf++ = 'n';
- *buf++ = '-';
- return __right_->get_demangled_name(buf);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = __left_->fix_forward_references(t_begin, t_end);
- return r && __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __typeinfo
- : public __node
-{
- static const ptrdiff_t n = sizeof("typeinfo for ") - 1;
-public:
- __typeinfo(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "typeinfo for ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __typeinfo_name
- : public __node
-{
- static const ptrdiff_t n = sizeof("typeinfo name for ") - 1;
-public:
- __typeinfo_name(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "typeinfo name for ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __covariant_return_thunk
- : public __node
-{
- static const ptrdiff_t n = sizeof("covariant return thunk to ") - 1;
-public:
- __covariant_return_thunk(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "covariant return thunk to ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __virtual_thunk
- : public __node
-{
- static const size_t n = sizeof("virtual thunk to ") - 1;
-public:
- __virtual_thunk(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "virtual thunk to ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __non_virtual_thunk
- : public __node
-{
- static const size_t n = sizeof("non-virtual thunk to ") - 1;
-public:
- __non_virtual_thunk(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "non-virtual thunk to ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __guard_variable
- : public __node
-{
- static const size_t n = sizeof("guard variable for ") - 1;
-public:
- __guard_variable(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "guard variable for ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __reference_temporary
- : public __node
-{
- static const size_t n = sizeof("reference temporary for ") - 1;
-public:
- __reference_temporary(__node* type)
- {
- __right_ = type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "reference temporary for ", n);
- return __right_->get_demangled_name(buf+n);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __source_name
- : public __node
-{
-public:
- __source_name(const char* __name, size_t __size)
- {
- __name_ = __name;
- __size_ = __size;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0)
- const_cast<long&>(__cached_size_) = 21;
- else
- const_cast<long&>(__cached_size_) = static_cast<long>(__size_);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0)
- return strncpy(buf, "(anonymous namespace)", 21) + 21;
- return strncpy(buf, __name_, __size_) + __size_;
- }
-};
-
-class __operator_new
- : public __node
-{
-public:
-
- virtual size_t first_size() const {return sizeof("operator new") - 1;}
- virtual char* first_demangled_name(char* buf) const
- {
- return strncpy(buf, "operator new", sizeof("operator new") - 1) +
- sizeof("operator new") - 1;
- }
-};
-
-class __operator_new_array
- : public __node
-{
-public:
-
- virtual size_t first_size() const {return sizeof("operator new[]") - 1;}
- virtual char* first_demangled_name(char* buf) const
- {
- return strncpy(buf, "operator new[]", sizeof("operator new[]") - 1) +
- sizeof("operator new[]") - 1;
- }
-};
-
-class __operator_delete
- : public __node
-{
-public:
-
- virtual size_t first_size() const {return sizeof("operator delete") - 1;}
- virtual char* first_demangled_name(char* buf) const
- {
- return strncpy(buf, "operator delete", sizeof("operator delete") - 1) +
- sizeof("operator delete") - 1;
- }
-};
-
-class __operator_delete_array
- : public __node
-{
-public:
-
- virtual size_t first_size() const {return sizeof("operator delete[]") - 1;}
- virtual char* first_demangled_name(char* buf) const
- {
- return strncpy(buf, "operator delete[]", sizeof("operator delete[]") - 1) +
- sizeof("operator delete[]") - 1;
- }
-};
-
-class __operator_logical_and
- : public __node
-{
-public:
-
- __operator_logical_and() {}
- __operator_logical_and(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator&&") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") && (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator&&", sizeof("operator&&") - 1);
- buf += sizeof("operator&&") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_addressof
- : public __node
-{
-public:
-
- __operator_addressof() {}
- explicit __operator_addressof(__node* op)
- {
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator&") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '&';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator&", sizeof("operator&") - 1);
- buf += sizeof("operator&") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_bit_and
- : public __node
-{
-public:
-
- __operator_bit_and() {}
- __operator_bit_and(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator&") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") & (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator&", sizeof("operator&") - 1);
- buf += sizeof("operator&") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_and_equal
- : public __node
-{
-public:
-
- __operator_and_equal() {}
- __operator_and_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator&=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") &= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator&=", sizeof("operator&=") - 1);
- buf += sizeof("operator&=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_equal
- : public __node
-{
-public:
-
- __operator_equal() {}
- __operator_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") = (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator=", sizeof("operator=") - 1);
- buf += sizeof("operator=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_alignof_type
- : public __node
-{
-public:
-
- __operator_alignof_type() {}
- __operator_alignof_type(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__right_)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 10);
- else
- const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__right_)
- {
- strncpy(buf, "alignof (", 9);
- buf += 9;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator alignof", sizeof("operator alignof") - 1);
- buf += sizeof("operator alignof") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__right_)
- return __right_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_alignof_expression
- : public __node
-{
-public:
-
- __operator_alignof_expression() {}
- __operator_alignof_expression(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__right_)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 10);
- else
- const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__right_)
- {
- strncpy(buf, "alignof (", 9);
- buf += 9;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator alignof", sizeof("operator alignof") - 1);
- buf += sizeof("operator alignof") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__right_)
- return __right_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_paren
- : public __node
-{
-public:
-
- virtual size_t first_size() const {return sizeof("operator()") - 1;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "operator()", sizeof("operator()") - 1);
- return buf + sizeof("operator()") - 1;
- }
-};
-
-class __operator_comma
- : public __node
-{
-public:
-
- __operator_comma() {}
- __operator_comma(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator,") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") , (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator,", sizeof("operator,") - 1);
- buf += sizeof("operator,") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_tilda
- : public __node
+namespace
{
-public:
- __operator_tilda() {}
- explicit __operator_tilda(__node* op)
- {
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator~") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '~';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator~", sizeof("operator~") - 1);
- buf += sizeof("operator~") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_cast
- : public __node
+enum
{
- static const size_t n = sizeof("operator ") - 1;
-public:
-
- explicit __operator_cast(__node* type)
- {
- __right_ = type;
- }
- __operator_cast(__node* type, __node* arg)
- {
- __size_ = 1;
- __right_ = type;
- __left_ = arg;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t off;
- if (__size_)
- {
- off = 4;
- off += __right_->size();
- if (__left_)
- off += __left_->size();
- }
- else
- off = n + __right_->size();;
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_)
- {
- *buf++ = '(';
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- *buf++ = '(';
- if (__left_)
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator ", n);
- buf = __right_->get_demangled_name(buf+n);
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return true;
- }
-};
-
-class __cast_literal
- : public __node
-{
-public:
-
- __cast_literal(__node* type, const char* f, const char* l)
- {
- __left_ = type;
- __name_ = f;
- __size_ = static_cast<size_t>(l - f);
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(2 +
- __left_->size() + __size_);
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- strncpy(buf, __name_, __size_);
- return buf + __size_;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
+ unknown_error = -4,
+ invalid_args = -3,
+ invalid_mangled_name,
+ memory_alloc_failure,
+ success
};
-class __operator_dereference
- : public __node
-{
-public:
-
- __operator_dereference() {}
- explicit __operator_dereference(__node* op)
- {
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator*") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '*';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator*", sizeof("operator*") - 1);
- buf += sizeof("operator*") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
+template <class C>
+ const char* parse_type(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_encoding(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_expression(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_template_args(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_operator_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_unqualified_name(const char* first, const char* last, C& db);
+template <class C>
+ const char* parse_decltype(const char* first, const char* last, C& db);
-class __operator_divide
- : public __node
-{
-public:
-
- __operator_divide() {}
- __operator_divide(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator/") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") / (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator/", sizeof("operator/") - 1);
- buf += sizeof("operator/") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_divide_equal
- : public __node
-{
-public:
-
- __operator_divide_equal() {}
- __operator_divide_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator/=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") /= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator/=", sizeof("operator/=") - 1);
- buf += sizeof("operator/=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_xor
- : public __node
-{
-public:
-
- __operator_xor() {}
- __operator_xor(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator^") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") ^ (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator^", sizeof("operator^") - 1);
- buf += sizeof("operator^") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_xor_equal
- : public __node
-{
-public:
-
- __operator_xor_equal() {}
- __operator_xor_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator^=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '('; // strncpy(buf, "(", 1);
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") ^= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator^=", sizeof("operator^=") - 1);
- buf += sizeof("operator^=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_equality
- : public __node
-{
-public:
-
- __operator_equality() {}
- __operator_equality(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator==") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") == (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator==", sizeof("operator==") - 1);
- buf += sizeof("operator==") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_greater_equal
- : public __node
-{
-public:
-
- __operator_greater_equal() {}
- __operator_greater_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator>=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") >= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator>=", sizeof("operator>=") - 1);
- buf += sizeof("operator>=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_greater
- : public __node
-{
-public:
-
- __operator_greater() {}
- __operator_greater(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 9 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator>") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") > (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator>", sizeof("operator>") - 1);
- buf += sizeof("operator>") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_brackets
- : public __node
-{
-public:
-
- virtual size_t first_size() const {return sizeof("operator[]") - 1;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "operator[]", sizeof("operator[]") - 1);
- return buf + sizeof("operator[]") - 1;
- }
-};
-
-class __operator_less_equal
- : public __node
-{
-public:
-
- __operator_less_equal() {}
- __operator_less_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator<=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") <= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator<=", sizeof("operator<=") - 1);
- buf += sizeof("operator<=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_less
- : public __node
-{
-public:
-
- __operator_less() {}
- __operator_less(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator<") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") < (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator<", sizeof("operator<") - 1);
- buf += sizeof("operator<") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_left_shift
- : public __node
-{
-public:
-
- __operator_left_shift() {}
- __operator_left_shift(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator<<") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") << (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator<<", sizeof("operator<<") - 1);
- buf += sizeof("operator<<") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_left_shift_equal
- : public __node
-{
-public:
-
- __operator_left_shift_equal() {}
- __operator_left_shift_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 9 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator<<=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") <<= (", 7);
- buf += 7;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator<<=", sizeof("operator<<=") - 1);
- buf += sizeof("operator<<=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_minus
- : public __node
-{
-public:
-
- __operator_minus() {}
- __operator_minus(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator-") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") - (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator-", sizeof("operator-") - 1);
- buf += sizeof("operator-") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_minus_equal
- : public __node
-{
-public:
-
- __operator_minus_equal() {}
- __operator_minus_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator-=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") -= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator-=", sizeof("operator-=") - 1);
- buf += sizeof("operator-=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_times
- : public __node
-{
-public:
-
- __operator_times() {}
- __operator_times(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator*") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") * (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator*", sizeof("operator*") - 1);
- buf += sizeof("operator*") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_times_equal
- : public __node
-{
-public:
-
- __operator_times_equal() {}
- __operator_times_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator*=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") *= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator*=", sizeof("operator*=") - 1);
- buf += sizeof("operator*=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_decrement
- : public __node
-{
-public:
-
- __operator_decrement() {}
- explicit __operator_decrement(bool prefix, __node* op)
- {
- __size_ = prefix;
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(4 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator--") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- if (__size_)
- {
- *buf++ = '-';
- *buf++ = '-';
- *buf++ = '(';
- }
- else
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- if (__size_)
- *buf++ = ')';
- else
- {
- *buf++ = ')';
- *buf++ = '-';
- *buf++ = '-';
- }
- }
- else
- {
- strncpy(buf, "operator--", sizeof("operator--") - 1);
- buf += sizeof("operator--") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_not_equal
- : public __node
-{
-public:
-
- __operator_not_equal() {}
- __operator_not_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator!=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") != (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator!=", sizeof("operator!=") - 1);
- buf += sizeof("operator!=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_negate
- : public __node
-{
-public:
-
- __operator_negate() {}
- explicit __operator_negate(__node* op)
- {
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator-") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '-';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator-", sizeof("operator-") - 1);
- buf += sizeof("operator-") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_logical_not
- : public __node
-{
-public:
-
- __operator_logical_not() {}
- explicit __operator_logical_not(__node* op)
- {
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator!") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '!';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator!", sizeof("operator!") - 1);
- buf += sizeof("operator!") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_logical_or
- : public __node
-{
-public:
-
- __operator_logical_or() {}
- __operator_logical_or(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator||") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") || (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator||", sizeof("operator||") - 1);
- buf += sizeof("operator||") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_bit_or
- : public __node
-{
-public:
-
- __operator_bit_or() {}
- __operator_bit_or(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator|") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") | (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator|", sizeof("operator|") - 1);
- buf += sizeof("operator|") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_or_equal
- : public __node
-{
-public:
-
- __operator_or_equal() {}
- __operator_or_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator|=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") |= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator|=", sizeof("operator|=") - 1);
- buf += sizeof("operator|=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_pointer_to_member
- : public __node
-{
-public:
-
- __operator_pointer_to_member() {}
- __operator_pointer_to_member(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 9 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator->*") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") ->* (", 7);
- buf += 7;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator->*", sizeof("operator->*") - 1);
- buf += sizeof("operator->*") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_plus
- : public __node
-{
-public:
-
- __operator_plus() {}
- __operator_plus(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator+") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") + (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator+", sizeof("operator+") - 1);
- buf += sizeof("operator+") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_plus_equal
- : public __node
-{
-public:
-
- __operator_plus_equal() {}
- __operator_plus_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator+=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") += (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator+=", sizeof("operator+=") - 1);
- buf += sizeof("operator+=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_increment
- : public __node
-{
-public:
-
- __operator_increment() {}
- explicit __operator_increment(bool prefix, __node* op)
- {
- __size_ = prefix;
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(4 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator++") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- if (__size_)
- {
- *buf++ = '+';
- *buf++ = '+';
- *buf++ = '(';
- }
- else
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- if (__size_)
- *buf++ = ')';
- else
- {
- *buf++ = ')';
- *buf++ = '+';
- *buf++ = '+';
- }
- }
- else
- {
- strncpy(buf, "operator++", sizeof("operator++") - 1);
- buf += sizeof("operator++") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_unary_plus
- : public __node
-{
-public:
-
- __operator_unary_plus() {}
- explicit __operator_unary_plus(__node* op)
- {
- __left_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator+") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '+';
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator+", sizeof("operator+") - 1);
- buf += sizeof("operator+") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_)
- return __left_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_arrow
- : public __node
-{
-public:
-
- __operator_arrow() {}
- __operator_arrow(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator->") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") -> (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator->", sizeof("operator->") - 1);
- buf += sizeof("operator->") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_conditional
- : public __node
-{
-public:
-
- __operator_conditional() {}
- __operator_conditional(__node* op1, __node* op2, __node* op3)
- {
- __name_ = (const char*)op1;
- __left_ = op2;
- __right_ = op3;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- {
- __node* op1 = (__node*)__name_;
- const_cast<long&>(__cached_size_) = static_cast<long>(
- op1->size() +
- __left_->size() + 12 +
- __right_->size());
- }
- else
- const_cast<long&>(__cached_size_) = sizeof("operator?") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- __node* op1 = (__node*)__name_;
- *buf++ = '(';
- buf = op1->get_demangled_name(buf);
- strncpy(buf, ") ? (", 5);
- buf += 5;
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") : (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator?", sizeof("operator?") - 1);
- buf += sizeof("operator?") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__name_)
- r = r && ((__node*)__name_)->fix_forward_references(t_begin, t_end);
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_mod
- : public __node
-{
-public:
-
- __operator_mod() {}
- __operator_mod(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 7 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator%") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") % (", 5);
- buf += 5;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator%", sizeof("operator%") - 1);
- buf += sizeof("operator%") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_mod_equal
- : public __node
-{
-public:
-
- __operator_mod_equal() {}
- __operator_mod_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator%=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") %= (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator%=", sizeof("operator%=") - 1);
- buf += sizeof("operator%=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_right_shift
- : public __node
-{
-public:
-
- __operator_right_shift() {}
- __operator_right_shift(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 8 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator>>") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") >> (", 6);
- buf += 6;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator>>", sizeof("operator>>") - 1);
- buf += sizeof("operator>>") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_right_shift_equal
- : public __node
-{
-public:
-
- __operator_right_shift_equal() {}
- __operator_right_shift_equal(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_)
- const_cast<long&>(__cached_size_) = static_cast<long>(
- __left_->size() + 9 +
- __right_->size());
- else
- const_cast<long&>(__cached_size_) = sizeof("operator>>=") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, ") >>= (", 7);
- buf += 7;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator>>=", sizeof("operator>>=") - 1);
- buf += sizeof("operator>>=") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __operator_sizeof_type
- : public __node
-{
-public:
-
- __operator_sizeof_type() {}
- __operator_sizeof_type(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__right_)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 9);
- else
- const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__right_)
- {
- strncpy(buf, "sizeof (", 8);
- buf += 8;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
+template <class C>
+void
+print_stack(const C& db)
+{
+ printf("---------\n");
+ printf("names:\n");
+ for (auto& s : db.names)
+ printf("{%s#%s}\n", s.first.c_str(), s.second.c_str());
+ int i = -1;
+ printf("subs:\n");
+ for (auto& v : db.subs)
+ {
+ if (i >= 0)
+ printf("S%i_ = {", i);
else
- {
- strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1);
- buf += sizeof("operator sizeof") - 1;
- }
- return buf;
+ printf("S_ = {");
+ for (auto& s : v)
+ printf("{%s#%s}", s.first.c_str(), s.second.c_str());
+ printf("}\n");
+ ++i;
}
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ printf("template_param:\n");
+ for (auto& t : db.template_param)
{
- if (__right_)
- return __right_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __operator_sizeof_expression
- : public __node
-{
-public:
-
- __operator_sizeof_expression() {}
- __operator_sizeof_expression(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
+ printf("--\n");
+ i = -1;
+ for (auto& v : t)
{
- if (__right_)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 9);
+ if (i >= 0)
+ printf("T%i_ = {", i);
else
- const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__right_)
- {
- strncpy(buf, "sizeof (", 8);
- buf += 8;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- else
- {
- strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1);
- buf += sizeof("operator sizeof") - 1;
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__right_)
- return __right_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __typeid
- : public __node
-{
-public:
-
- __typeid(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 8);
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "typeid(", 7);
- buf += 7;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __throw
- : public __node
-{
-public:
-
- __throw(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 6);
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "throw ", 6);
- return __right_->get_demangled_name(buf+6);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __rethrow
- : public __node
-{
- static const ptrdiff_t n = sizeof("throw") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "throw", n);
- return buf+n;
- }
-};
-
-class __operator_sizeof_param_pack
- : public __node
-{
-public:
-
- __operator_sizeof_param_pack(__node* op)
- {
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 11);
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "sizeof...(", 10);
- buf += 10;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __const_cast
- : public __node
-{
-public:
-
- __const_cast(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 14 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "const_cast<", 11);
- buf += 11;
- buf = __left_->get_demangled_name(buf);
- *buf++ = '>';
- *buf++ = '(';
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __dynamic_cast
- : public __node
-{
-public:
-
- __dynamic_cast(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 16 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "dynamic_cast<", 13);
- buf += 13;
- buf = __left_->get_demangled_name(buf);
- *buf++ = '>';
- *buf++ = '(';
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __reinterpret_cast
- : public __node
-{
-public:
-
- __reinterpret_cast(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 20 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "reinterpret_cast<", 17);
- buf += 17;
- buf = __left_->get_demangled_name(buf);
- *buf++ = '>';
- *buf++ = '(';
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __static_cast
- : public __node
-{
-public:
-
- __static_cast(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 15 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "static_cast<", 12);
- buf += 12;
- buf = __left_->get_demangled_name(buf);
- *buf++ = '>';
- *buf++ = '(';
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __call_expr
- : public __node
-{
-public:
-
- __call_expr(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t off = __left_->size() + 2;
- if (__right_)
- off += __right_->size();
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = '(';
- if (__right_)
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __delete_array_expr
- : public __node
-{
-public:
-
- __delete_array_expr(bool global, __node* op)
- {
- __size_ = global;
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>((__size_ ? 2 : 0) +
- 9 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_)
- {
- *buf++ = ':';
- *buf++ = ':';
+ printf("T_ = {");
+ for (auto& s : v)
+ printf("{%s#%s}", s.first.c_str(), s.second.c_str());
+ printf("}\n");
+ ++i;
}
- strncpy(buf, "delete[] ", 9);
- return __right_->get_demangled_name(buf+9);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
}
-};
+ printf("---------\n\n");
+}
-class __delete_expr
- : public __node
+template <class C>
+void
+print_state(const char* msg, const char* first, const char* last, const C& db)
{
-public:
+ printf("%s: ", msg);
+ for (; first != last; ++first)
+ printf("%c", *first);
+ printf("\n");
+ print_stack(db);
+}
- __delete_expr(bool global, __node* op)
- {
- __size_ = global;
- __right_ = op;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>((__size_ ? 2 : 0) +
- 7 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_)
- {
- *buf++ = ':';
- *buf++ = ':';
- }
- strncpy(buf, "delete ", 7);
- return __right_->get_demangled_name(buf+7);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
+// <number> ::= [n] <non-negative decimal integer>
-class __new_expr
- : public __node
+const char*
+parse_number(const char* first, const char* last)
{
-public:
-
- __new_expr(bool global, bool is_array, bool has_init,
- __node* expr, __node* type, __node* init)
- {
- __size_ = (unsigned)global |
- ((unsigned)is_array << 1) |
- ((unsigned)has_init << 2);
- __left_ = expr;
- __name_ = (const char*)type;
- __right_ = init;
- }
- virtual size_t first_size() const
+ if (first != last)
{
- if (__cached_size_ == -1)
+ const char* t = first;
+ if (*t == 'n')
+ ++t;
+ if (t != last)
{
- size_t off = 4;
- if (__size_ & 1)
- off += 2;
- if (__size_ & 2)
- off += 2;
- if (__left_)
+ if (*t == '0')
{
- off += 2;
- off += __left_->size();
+ first = t+1;
}
- __node* type = (__node*)__name_;
- off += type->size();
- if (__size_ & 4)
+ else if ('1' <= *t && *t <= '9')
{
- off += 2;
- if (__right_)
- off += __right_->size();
+ first = t+1;
+ while (first != last && std::isdigit(*first))
+ ++first;
}
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
}
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_ & 1)
- {
- *buf++ = ':';
- *buf++ = ':';
- }
- *buf++ = 'n';
- *buf++ = 'e';
- *buf++ = 'w';
- if (__size_ & 2)
- {
- *buf++ = '[';
- *buf++ = ']';
- }
- if (__left_)
- {
- *buf++ = '(';
- buf = __left_->get_demangled_name(buf);
- *buf++ = ')';
- }
- *buf++ = ' ';
- __node* type = (__node*)__name_;
- buf = type->get_demangled_name(buf);
- if (__size_ & 4)
- {
- *buf++ = '(';
- if (__right_)
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- }
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- __node* type = (__node*)__name_;
- bool r = type->fix_forward_references(t_begin, t_end);
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);;
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);;
- return r;
- }
-};
-
-class __dot_star_expr
- : public __node
-{
-public:
-
- __dot_star_expr(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 2 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = '.';
- *buf++ = '*';
- return __right_->get_demangled_name(buf);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __dot_expr
- : public __node
-{
-public:
-
- __dot_expr(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 1 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = '.';
- return __right_->get_demangled_name(buf);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __arrow_expr
- : public __node
-{
-public:
-
- __arrow_expr(__node* op1, __node* op2)
- {
- __left_ = op1;
- __right_ = op2;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- 2 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = '-';
- *buf++ = '>';
- return __right_->get_demangled_name(buf);
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __std_qualified_name
- : public __node
-{
- static const ptrdiff_t n = sizeof("std") - 1;
-public:
-
- __std_qualified_name()
- {
- }
- virtual size_t first_size() const
- {
- return n;
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- *buf++ = 's';
- *buf++ = 't';
- *buf++ = 'd';
- return buf;
}
-};
-
-class __sub_allocator
- : public __node
-{
- static const ptrdiff_t n = sizeof("std::allocator") - 1;
-public:
-
- virtual size_t first_size() const
- {
- return n;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "std::allocator", n);
- return buf + n;
- }
-};
-
-class __sub_basic_string
- : public __node
-{
- static const ptrdiff_t n = sizeof("std::basic_string") - 1;
-public:
+ return first;
+}
- virtual size_t first_size() const
- {
- return n;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "std::basic_string", n);
- return buf + n;
- }
-};
+template <class Float>
+struct float_data;
-class __sub_string
- : public __node
+template <>
+struct float_data<float>
{
- static const size_t n = sizeof("std::string") - 1;
- static const size_t ne = sizeof("std::basic_string<char, std::char_traits<char>, std::allocator<char> >") - 1;
-public:
-
- virtual size_t first_size() const
- {
- if (__size_)
- return ne;
- return n;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_)
- {
- strncpy(buf, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >", ne);
- buf += ne;
- }
- else
- {
- strncpy(buf, "std::string", n);
- buf += n;
- }
- return buf;
- }
-
- virtual size_t base_size() const
- {
- return 12;
- }
- virtual char* get_base_name(char* buf) const
- {
- strncpy(buf, "basic_string", 12);
- return buf + 12;
- }
-
- virtual __node* base_name() const
- {
- const_cast<size_t&>(__size_) = true;
- return const_cast<__node*>(static_cast<const __node*>(this));
- }
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static constexpr const char* spec = "%af";
};
-class __sub_istream
- : public __node
-{
- static const ptrdiff_t n = sizeof("std::istream") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "std::istream", n);
- return buf + n;
- }
-};
+constexpr const char* float_data<float>::spec;
-class __sub_ostream
- : public __node
+template <>
+struct float_data<double>
{
- static const ptrdiff_t n = sizeof("std::ostream") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "std::ostream", n);
- return buf + n;
- }
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static constexpr const char* spec = "%a";
};
-class __sub_iostream
- : public __node
-{
- static const ptrdiff_t n = sizeof("std::iostream") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "std::iostream", n);
- return buf + n;
- }
-};
+constexpr const char* float_data<double>::spec;
-class __sub
- : public __node
+template <>
+struct float_data<long double>
{
-public:
-
- explicit __sub(__node* arg)
- {
- __left_ = arg;
- }
- explicit __sub(size_t arg)
- {
- __size_ = arg;
- }
- virtual size_t first_size() const
- {
- return __left_->first_size();
- }
- virtual char* first_demangled_name(char* buf) const
- {
- return __left_->first_demangled_name(buf);
- }
- virtual size_t second_size() const
- {
- return __left_->second_size();
- }
- virtual char* second_demangled_name(char* buf) const
- {
- return __left_->second_demangled_name(buf);
- }
- virtual bool ends_with_template(bool parsing = false) const
- {
- return __left_->ends_with_template(parsing);
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __left_->is_reference_or_pointer_to_function_or_array();
- }
- virtual bool is_function() const
- {
- if (__left_ == 0)
- return false;
- return __left_->is_function();
- }
- virtual bool is_cv_qualifer() const
- {
- return __left_->is_cv_qualifer();
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __left_->is_ctor_dtor_conv();
- }
- virtual bool is_array() const
- {
- return __left_->is_array();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__left_ == 0)
- {
- if (__size_ < static_cast<size_t>(t_end - t_begin))
- {
- __left_ = t_begin[__size_];
- __size_ = 0;
- }
- else
- return false;
- }
- return true;
- }
- virtual size_t list_len() const
- {
- return __left_->list_len();
- }
- virtual bool is_sub() const
- {
- return true;
- }
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+ static const size_t max_demangled_size = 40;
+ static constexpr const char* spec = "%LaL";
};
-class __unscoped_template_name
- : public __node
-{
-public:
- __unscoped_template_name(__node* name, __node* args)
- {__left_ = name; __right_ = args;}
+constexpr const char* float_data<long double>::spec;
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- return __right_->get_demangled_name(buf);
- }
- virtual bool ends_with_template(bool parsing = false) const
- {
- return __right_->ends_with_template(parsing);
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-// length == 0: __left_ == NULL
-// length == 1: __left_ != NULL, __right_ == NULL
-// length > 1: __left_ != NULL, __right_ != NULL
-class __list
- : public __node
-{
-public:
- explicit __list(__node* type)
- {__left_ = type;}
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- if (__left_ == NULL)
- const_cast<long&>(__cached_size_) = 0;
- else if (__right_ == NULL)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size());
- else
- {
- size_t off = __right_->size();
- if (off > 0)
- off += 2;
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + off);
- }
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_ != NULL)
- {
- char* t = __left_->get_demangled_name(buf + (__size_ ? 2 : 0));
- if (__size_ == 0)
- buf = t;
- else if (t != buf+2)
- {
- *buf++ = ',';
- *buf++ = ' ';
- buf = t;
- }
- if (__right_)
- buf = __right_->get_demangled_name(buf);
- }
- return buf;
- }
- virtual bool ends_with_template(bool parsing = false) const
- {
- if (__right_ && __right_->size() > 0)
- {
- return __right_->ends_with_template(parsing);
- }
- else if (__left_ && __left_->size() > 0)
- {
- return __left_->ends_with_template(parsing);
- }
- return false;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
- virtual size_t list_len() const
- {
- if (!__left_)
- return 0;
- if (!__right_)
- return 1;
- return 1 + __right_->list_len();
- }
-};
-
-class __template_args
- : public __node
-{
-public:
- __template_args(__node* name, __node* list)
- {
- __left_ = name;
- __right_ = list;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t off = 2;
- if (__right_)
- {
- if (__right_->ends_with_template())
- ++off;
- off += __right_->size();
- }
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + off);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = '<';
- if (__right_)
- {
- buf = __right_->get_demangled_name(buf);
- if (buf[-1] == '>')
- *buf++ = ' ';
- }
- *buf++ = '>';
- return buf;
- }
- virtual bool ends_with_template(bool /*parsing*/ = false) const
- {
- return true;
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __left_->is_ctor_dtor_conv();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __function_args
- : public __node
-{
-public:
- __function_args(__node* list)
- {__right_ = list;}
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(2 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- *buf++ = '(';
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class ___lambda_node
- : public __node
-{
-public:
- ___lambda_node(__node* params, const char *number, size_t number_size)
- {
- __right_ = params;
- __name_ = number;
- __size_ = number_size;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t r = 2;
- r += sizeof("'lambda'")-1;
- if (__right_)
- r += __right_->size();
- r += __size_;
- const_cast<long&>(__cached_size_) = static_cast<long>(r);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- size_t n = sizeof("'lambda") - 1;
- strncpy(buf, "'lambda", n);
- buf += n;
- if (__size_)
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- *buf++ = '\'';
- *buf++ = '(';
- if (__right_)
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- if (__right_)
- return __right_->fix_forward_references(t_begin, t_end);
- return true;
- }
-};
-
-class __unnamed
- : public __node
-{
-public:
- __unnamed(const char *number, size_t number_size)
- {
- __name_ = number;
- __size_ = number_size;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t r = 0;
- r += sizeof("'unnamed'")-1;
- r += __size_;
- const_cast<long&>(__cached_size_) = static_cast<long>(r);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- size_t n = sizeof("'unnamed") - 1;
- strncpy(buf, "'unnamed", n);
- buf += n;
- if (__size_)
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- *buf++ = '\'';
- return buf;
- }
-};
-
-class __cv_qualifiers
- : public __node
+template <class Float, class C>
+const char*
+parse_floating_number(const char* first, const char* last, C& db)
{
-public:
- __cv_qualifiers(size_t cv, __node* type)
- {
- __left_ = type;
- __size_ = __left_->is_function() ? cv << 5 : cv;
- }
-
- virtual size_t first_size() const
- {
- size_t s = __left_->first_size();
- if (__size_ & 4)
- s += sizeof(" restrict")-1;
- if (__size_ & 2)
- s += sizeof(" volatile")-1;
- if (__size_ & 1)
- s += sizeof(" const")-1;
- if (__size_ & 8)
- s += sizeof(" &")-1;
- if (__size_ & 16)
- s += sizeof(" &&")-1;
- return s;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->first_demangled_name(buf);
- if (__size_ & 1)
- {
- const size_t n = sizeof(" const")-1;
- strncpy(buf, " const", n);
- buf += n;
- }
- if (__size_ & 2)
- {
- const size_t n = sizeof(" volatile")-1;
- strncpy(buf, " volatile", n);
- buf += n;
- }
- if (__size_ & 4)
- {
- const size_t n = sizeof(" restrict")-1;
- strncpy(buf, " restrict", n);
- buf += n;
- }
- if (__size_ & 8)
- {
- *buf++ = ' ';
- *buf++ = '&';
- }
- if (__size_ & 16)
- {
- *buf++ = ' ';
- *buf++ = '&';
- *buf++ = '&';
- }
- return buf;
- }
- virtual size_t second_size() const
- {
- size_t s = __left_->second_size();
- if (__size_ & 128)
- s += sizeof(" restrict")-1;
- if (__size_ & 64)
- s += sizeof(" volatile")-1;
- if (__size_ & 32)
- s += sizeof(" const")-1;
- if (__size_ & 256)
- s += sizeof(" &")-1;
- if (__size_ & 512)
- s += sizeof(" &&")-1;
- return s;
- }
- virtual char* second_demangled_name(char* buf) const
+ const size_t N = float_data<Float>::mangled_size;
+ if (static_cast<std::size_t>(last - first) > N)
{
- buf = __left_->second_demangled_name(buf);
- if (__size_ & 32)
- {
- const size_t n = sizeof(" const")-1;
- strncpy(buf, " const", n);
- buf += n;
- }
- if (__size_ & 64)
+ last = first + N;
+ union
{
- const size_t n = sizeof(" volatile")-1;
- strncpy(buf, " volatile", n);
- buf += n;
- }
- if (__size_ & 128)
- {
- const size_t n = sizeof(" restrict")-1;
- strncpy(buf, " restrict", n);
- buf += n;
- }
- if (__size_ & 256)
+ Float value;
+ char buf[sizeof(Float)];
+ };
+ const char* t = first;
+ char* e = buf;
+ for (; t != last; ++t, ++e)
{
- *buf++ = ' ';
- *buf++ = '&';
+ if (!isxdigit(*t))
+ return first;
+ unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ ++t;
+ unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :
+ static_cast<unsigned>(*t - 'a' + 10);
+ *e = static_cast<char>((d1 << 4) + d0);
}
- if (__size_ & 512)
+ if (*t == 'E')
{
- *buf++ = ' ';
- *buf++ = '&';
- *buf++ = '&';
- }
- return buf;
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __left_->is_reference_or_pointer_to_function_or_array();
- }
- virtual bool is_function() const
- {
- return __left_->is_function();
- }
- virtual bool is_cv_qualifer() const
- {
- return true;
- }
- virtual __node* extract_cv(__node*& rt) const
- {
- if (rt == this)
- {
- rt = __left_;
- return const_cast<__node*>(static_cast<const __node*>(this));
+#if __LITTLE_ENDIAN__
+ std::reverse(buf, e);
+#endif
+ char num[float_data<Float>::max_demangled_size] = {0};
+ int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);
+ if (static_cast<std::size_t>(n) >= sizeof(num))
+ return first;
+ db.names.push_back(typename C::String(num, static_cast<std::size_t>(n)));
+ first = t+1;
}
- return 0;
- }
- virtual bool ends_with_template(bool parsing = false) const
- {
- if (parsing)
- return __left_->ends_with_template(parsing);
- return false;
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __left_->is_ctor_dtor_conv();
- }
- virtual bool is_array() const
- {
- return __left_->is_array();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
- virtual size_t list_len() const
- {
- return __left_->list_len();
- }
-};
-
-class __extended_qualifier
- : public __node
-{
-public:
- __extended_qualifier(__node* name, __node* type)
- {
- __left_ = type;
- __right_ = name;
- __size_ = __left_->is_function() ? 1 : 0;
}
+ return first;
+}
- virtual size_t first_size() const
- {
- size_t s = __left_->first_size();
- if (__size_ == 0)
- s += __right_->size() + 1;
- return s;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->first_demangled_name(buf);
- if (__size_ == 0)
- {
- *buf++ = ' ';
- buf = __right_->get_demangled_name(buf);
- }
- return buf;
- }
- virtual size_t second_size() const
- {
- size_t s = __left_->second_size();
- if (__size_ == 1)
- s += __right_->size() + 1;
- return s;
- }
- virtual char* second_demangled_name(char* buf) const
- {
- buf = __left_->second_demangled_name(buf);
- if (__size_ == 1)
- {
- *buf++ = ' ';
- buf = __right_->get_demangled_name(buf);
- }
- return buf;
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __left_->is_reference_or_pointer_to_function_or_array();
- }
- virtual bool is_function() const
- {
- return __left_->is_function();
- }
- virtual bool is_cv_qualifer() const
- {
- return true;
- }
- virtual __node* extract_cv(__node*& rt) const
- {
- if (rt == this)
- {
- rt = __left_;
- return const_cast<__node*>(static_cast<const __node*>(this));
- }
- return 0;
- }
- virtual bool ends_with_template(bool parsing = false) const
- {
- return __left_->ends_with_template(parsing);
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __left_->is_ctor_dtor_conv();
- }
- virtual bool is_array() const
- {
- return __left_->is_array();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
- virtual size_t list_len() const
- {
- return __left_->list_len();
- }
-};
+// <source-name> ::= <positive length number> <identifier>
-class __function
- : public __node
+template <class C>
+const char*
+parse_source_name(const char* first, const char* last, C& db)
{
-public:
-
- __function(__node* name, __node* signature, size_t ret_goes_first = true)
- {
- __size_ = ret_goes_first;
- __left_ = name;
- __right_ = signature;
- }
-
- virtual size_t first_size() const
- {
- size_t off = 0;
- if (__size_)
- {
- off = __right_->first_size();
- if (off > 0 && (__left_ == NULL ||
- !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
- ++off;
- }
- else
- off = 5;
- if (__left_)
- off += __left_->first_size();
- else
- ++off;
- return off;
- }
-
- virtual size_t second_size() const
- {
- size_t off = 0;
- if (__left_ == NULL)
- off = 1;
- off += __right_->second_size();
- if (!__size_)
- {
- off += 2;
- off += __right_->first_size();
- }
- return off;
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_)
- {
- const char* t = buf;
- buf = __right_->first_demangled_name(buf);
- if (buf != t && (__left_ == NULL ||
- !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
- *buf++ = ' ';
- }
- else
- {
- strncpy(buf, "auto ", 5);
- buf += 5;
- }
- if (__left_)
- buf = __left_->first_demangled_name(buf);
- else
- *buf++ = '(';
- return buf;
- }
- virtual char* second_demangled_name(char* buf) const
- {
- if (__left_ == NULL)
- *buf++ = ')';
- buf = __right_->second_demangled_name(buf);
- if (!__size_)
- {
- *buf++ = '-';
- *buf++ = '>';
- buf = __right_->first_demangled_name(buf);
- }
- return buf;
- }
- virtual char* get_demangled_name(char* buf) const
- {
- if (__size_)
- {
- const char* t = buf;
- buf = __right_->first_demangled_name(buf);
- if (buf != t && (__left_ == NULL ||
- !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
- *buf++ = ' ';
- }
- else
- {
- strncpy(buf, "auto ", 5);
- buf += 5;
- }
- if (__left_)
- buf = __left_->first_demangled_name(buf);
- buf = __right_->second_demangled_name(buf);
- if (!__size_)
- {
- *buf++ = '-';
- *buf++ = '>';
- buf = __right_->first_demangled_name(buf);
- }
- return buf;
- }
-
- virtual size_t size() const
+ if (first != last)
{
- if (__cached_size_ == -1)
+ char c = *first;
+ if (isdigit(c) && first+1 != last)
{
- size_t off = 0;
- if (__size_)
- {
- off = __right_->first_size();
- if (off > 0 && (__left_ == NULL ||
- !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
- ++off;
- }
- else
- off = 5;
- if (__left_)
- off += __left_->first_size();
- off += __right_->second_size();
- if (!__size_)
+ const char* t = first+1;
+ size_t n = static_cast<size_t>(c - '0');
+ for (c = *t; isdigit(c); c = *t)
{
- off += 2;
- off += __right_->first_size();
+ n = n * 10 + static_cast<size_t>(c - '0');
+ if (++t == last)
+ return first;
}
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
- }
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual bool is_function() const
- {
- return true;
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __left_->is_ctor_dtor_conv();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __function_signature
- : public __node
-{
-public:
- __function_signature(__node* ret, __node* args)
- {
- __left_ = ret;
- __right_ = args;
- }
- virtual size_t first_size() const
- {
- return __left_ ? __left_->first_size() : 0;
- }
-
- virtual size_t second_size() const
- {
- return 2 + (__right_ ? __right_->size() : 0)
- + (__left_ ? __left_->second_size() : 0);
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- buf = __left_->first_demangled_name(buf);
- return buf;
- }
-
- virtual char* second_demangled_name(char* buf) const
- {
- *buf++ = '(';
- if (__right_)
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- if (__left_)
- buf = __left_->second_demangled_name(buf);
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = r && __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __pointer_to
- : public __node
-{
-public:
-
- explicit __pointer_to(__node* type)
- {
- __left_ = type;
- }
- virtual size_t first_size() const
- {
- return __left_->first_size() + (__left_->is_array() ? 3 : 1);
- }
- virtual size_t second_size() const
- {
- return __left_->second_size() + (__left_->is_array() ? 1 : 0);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->first_demangled_name(buf);
- if (__left_->is_array())
- {
- *buf++ = ' ';
- *buf++ = '(';
- *buf++ = '*';
- }
- else
- *buf++ = '*';
- return buf;
- }
- virtual char* second_demangled_name(char* buf) const
- {
- if (__left_->is_array())
- *buf++ = ')';
- return __left_->second_demangled_name(buf);
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __left_->is_function() ||
- __left_->is_reference_or_pointer_to_function_or_array();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
- virtual size_t list_len() const
- {
- return __left_->list_len();
- }
-};
-
-class __lvalue_reference_to
- : public __node
-{
-public:
-
- explicit __lvalue_reference_to(__node* type)
- {
- __left_ = type;
- }
- virtual size_t first_size() const
- {
- return __left_->first_size() + (__left_->is_array() ? 3 : 1);
- }
- virtual size_t second_size() const
- {
- return __left_->second_size() + (__left_->is_array() ? 1 : 0);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->first_demangled_name(buf);
- if (__left_->is_array())
- {
- *buf++ = ' ';
- *buf++ = '(';
- *buf++ = '&';
- }
- else
- *buf++ = '&';
- return buf;
- }
- virtual char* second_demangled_name(char* buf) const
- {
- if (__left_->is_array())
- *buf++ = ')';
- return __left_->second_demangled_name(buf);
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __left_->is_function();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
- virtual size_t list_len() const
- {
- return __left_->list_len();
- }
-};
-
-class __rvalue_reference_to
- : public __node
-{
-public:
-
- explicit __rvalue_reference_to(__node* type)
- {
- __left_ = type;
- }
- virtual size_t first_size() const
- {
- return __left_->first_size() + (__left_->is_array() ? 4 : 2);
- }
- virtual size_t second_size() const
- {
- return __left_->second_size() + (__left_->is_array() ? 1 : 0);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->first_demangled_name(buf);
- if (__left_->is_array())
- {
- strncpy(buf, " (&&", 4);
- buf += 4;
- }
- else
- {
- *buf++ = '&';
- *buf++ = '&';
- }
- return buf;
- }
- virtual char* second_demangled_name(char* buf) const
- {
- if (__left_->is_array())
- *buf++ = ')';
- return __left_->second_demangled_name(buf);
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __left_->is_function();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
- virtual size_t list_len() const
- {
- return __left_->list_len();
- }
-};
-
-class __d_complex
- : public __node
-{
- static const size_t n = sizeof(" complex") - 1;
-public:
-
- explicit __d_complex(__node* type)
- {
- __left_ = type;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(n + __left_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, " complex", n);
- return buf + n;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __imaginary
- : public __node
-{
- static const size_t n = sizeof(" imaginary") - 1;
-public:
-
- explicit __imaginary(__node* type)
- {
- __left_ = type;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(n + __left_->size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- strncpy(buf, " imaginary", n);
- return buf + n;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __pack_expansion
- : public __node
-{
-public:
-
- explicit __pack_expansion(__node* type)
- {
- __left_ = type;
- }
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t len = __left_->list_len();
- size_t off = 0;
- if (len != 0)
+ if (static_cast<size_t>(last - t) >= n)
{
- if (__left_->is_sub() || len == 1)
- off = __left_->size();
+ typename C::String r(t, n);
+ if (r.substr(0, 10) == "_GLOBAL__N")
+ db.names.push_back("(anonymous namespace)");
else
- {
- __node* top = __left_;
- __node* bottom = top;
- while (!bottom->__left_->is_sub())
- bottom = bottom->__left_;
- __node* sub = bottom->__left_;
- __node* i = sub->__left_;
- bool first = true;
- top->reset_cached_size();
- while (i)
- {
- if (!first)
- off += 2;
- bottom->__left_ = i->__left_;
- off += top->size();
- top->reset_cached_size();
- i = i->__right_;
- first = false;
- }
- bottom->__left_ = sub;
- }
- }
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- size_t len = __left_->list_len();
- if (len != 0)
- {
- if (__left_->is_sub() || len == 1)
- buf = __left_->get_demangled_name(buf);
- else
- {
- __node* top = __left_;
- __node* bottom = top;
- while (!bottom->__left_->is_sub())
- bottom = bottom->__left_;
- __node* sub = bottom->__left_;
- __node* i = sub->__left_;
- bool first = true;
- top->reset_cached_size();
- while (i)
- {
- if (!first)
- {
- *buf++ = ',';
- *buf++ = ' ';
- }
- bottom->__left_ = i->__left_;
- buf = top->get_demangled_name(buf);
- top->reset_cached_size();
- i = i->__right_;
- first = false;
- }
- bottom->__left_ = sub;
+ db.names.push_back(std::move(r));
+ first = t + n;
}
}
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __void
- : public __node
-{
- static const size_t n = sizeof("void") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "void", n);
- return buf + n;
- }
-};
-
-class __wchar_t
- : public __node
-{
- static const size_t n = sizeof("wchar_t") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "wchar_t", n);
- return buf + n;
- }
-};
-
-class __wchar_t_literal
- : public __node
-{
-public:
- explicit __wchar_t_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+9;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(wchar_t)", 9);
- buf += 9;
- strncpy(buf, __name_, __size_);
- return buf + __size_;
- }
-};
-
-class __bool
- : public __node
-{
- static const size_t n = sizeof("bool") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "bool", n);
- return buf + n;
- }
-};
-
-class __bool_literal
- : public __node
-{
-public:
- explicit __bool_literal(const char* __name, unsigned __size)
- {
- __name_ = __name;
- __size_ = __size;
- }
-
- virtual size_t first_size() const
- {
- return __size_;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, __name_, __size_);
- return buf + __size_;
- }
-};
-
-class __char
- : public __node
-{
- static const size_t n = sizeof("char") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "char", n);
- return buf + n;
- }
-};
-
-class __char_literal
- : public __node
-{
-public:
- explicit __char_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+6;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(char)", 6);
- buf += 6;
- if (*__name_ == 'n')
- {
- *buf++ = '-'; // strncpy(buf+6, "-", 1);
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- return buf;
- }
-};
-
-class __signed_char
- : public __node
-{
- static const size_t n = sizeof("signed char") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "signed char", n);
- return buf + n;
- }
-};
-
-class __signed_char_literal
- : public __node
-{
-public:
- explicit __signed_char_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+13;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(signed char)", 13);
- buf += 13;
- if (*__name_ == 'n')
- {
- *buf++ = '-';
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- return buf;
- }
-};
-
-class __unsigned_char
- : public __node
-{
- static const size_t n = sizeof("unsigned char") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "unsigned char", n);
- return buf + n;
- }
-};
-
-class __unsigned_char_literal
- : public __node
-{
-public:
- explicit __unsigned_char_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+15;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(unsigned char)", 15);
- buf += 15;
- strncpy(buf, __name_, __size_);
- return buf + __size_;
- }
-};
-
-class __short
- : public __node
-{
- static const size_t n = sizeof("short") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "short", n);
- return buf + n;
- }
-};
-
-class __short_literal
- : public __node
-{
-public:
- explicit __short_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+7;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(short)", 7);
- buf += 7;
- if (*__name_ == 'n')
- {
- *buf++ = '-';
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- return buf;
- }
-};
-
-class __unsigned_short
- : public __node
-{
- static const size_t n = sizeof("unsigned short") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "unsigned short", n);
- return buf + n;
- }
-};
-
-class __unsigned_short_literal
- : public __node
-{
-public:
- explicit __unsigned_short_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+16;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(unsigned short)", 16);
- buf += 16;
- strncpy(buf, __name_, __size_);
- return buf + __size_;
- }
-};
-
-class __int
- : public __node
-{
- static const size_t n = sizeof("int") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- *buf++ = 'i';
- *buf++ = 'n';
- *buf++ = 't';
- return buf;
- }
-};
-
-class __int_literal
- : public __node
-{
-public:
- explicit __int_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (*__name_ == 'n')
- {
- *buf++ = '-';
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- return buf;
- }
-};
-
-class __unsigned_int
- : public __node
-{
- static const size_t n = sizeof("unsigned int") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "unsigned int", n);
- return buf + n;
- }
-};
-
-class __unsigned_int_literal
- : public __node
-{
-public:
- explicit __unsigned_int_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+1;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- *buf++ = 'u';
- return buf;
- }
-};
-
-class __long
- : public __node
-{
- static const size_t n = sizeof("long") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "long", n);
- return buf + n;
- }
-};
-
-class __long_literal
- : public __node
-{
-public:
- explicit __long_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+1;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (*__name_ == 'n')
- {
- *buf++ = '-'; // strncpy(buf, "-", 1);
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- *buf++ = 'l';
- return buf;
- }
-};
-
-class __unsigned_long
- : public __node
-{
- static const size_t n = sizeof("unsigned long") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "unsigned long", n);
- return buf + n;
- }
-};
-
-class __unsigned_long_literal
- : public __node
-{
-public:
- explicit __unsigned_long_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+2;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- *buf++ = 'u';
- *buf++ = 'l';
- return buf;
- }
-};
-
-class __long_long
- : public __node
-{
- static const size_t n = sizeof("long long") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "long long", n);
- return buf + n;
- }
-};
-
-class __long_long_literal
- : public __node
-{
-public:
- explicit __long_long_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+2;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (*__name_ == 'n')
- {
- *buf++ = '-';
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- *buf++ = 'l';
- *buf++ = 'l';
- return buf;
- }
-};
-
-class __unsigned_long_long
- : public __node
-{
- static const size_t n = sizeof("unsigned long long") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "unsigned long long", n);
- return buf + n;
- }
-};
-
-class __unsigned_long_long_literal
- : public __node
-{
-public:
- explicit __unsigned_long_long_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+3;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- *buf++ = 'u';
- *buf++ = 'l';
- *buf++ = 'l';
- return buf;
- }
-};
-
-class __signed_int128
- : public __node
-{
- static const size_t n = sizeof("__int128") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "__int128", n);
- return buf + n;
- }
-};
-
-class __int128_literal
- : public __node
-{
-public:
- explicit __int128_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+10;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(__int128)", 10);
- buf += 10;
- if (*__name_ == 'n')
- {
- *buf++ = '-';
- strncpy(buf, __name_+1, __size_-1);
- buf += __size_ - 1;
- }
- else
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- return buf;
- }
-};
-
-class __unsigned_int128
- : public __node
-{
- static const size_t n = sizeof("unsigned __int128") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "unsigned __int128", n);
- return buf + n;
- }
-};
-
-class __unsigned_int128_literal
- : public __node
-{
-public:
- explicit __unsigned_int128_literal(const char* __first, const char* __last)
- {
- __name_ = __first;
- __size_ = static_cast<size_t>(__last - __first);
- }
-
- virtual size_t first_size() const
- {
- return __size_+19;
- }
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "(unsigned __int128)", 19);
- buf += 19;
- strncpy(buf, __name_, __size_);
- return buf + __size_;
- }
-};
-
-class __float_literal
- : public __node
-{
-public:
- explicit __float_literal(float value)
- {
- __value_ = value;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- char num[20] = {0};
- float v = static_cast<float>(__value_);
- const_cast<long&>(__cached_size_) = sprintf(num, "%a", v)+1;
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- char num[20] = {0};
- float v = static_cast<float>(__value_);
- int n = sprintf(num, "%a", v);
- strncpy(buf, num, static_cast<size_t>(n));
- buf += n;
- *buf++ = 'f';
- return buf;
- }
-};
-
-class __float
- : public __node
-{
- static const size_t n = sizeof("float") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "float", n);
- return buf + n;
- }
-};
-
-class __double_literal
- : public __node
-{
-public:
- explicit __double_literal(double value)
- {
- __value_ = value;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- char num[30] = {0};
- double v = static_cast<double>(__value_);
- const_cast<long&>(__cached_size_) = sprintf(num, "%a", v);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- char num[30] = {0};
- double v = static_cast<double>(__value_);
- int n = sprintf(num, "%a", v);
- strncpy(buf, num, static_cast<size_t>(n));
- return buf + n;
- }
-};
-
-class __double
- : public __node
-{
- static const size_t n = sizeof("double") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "double", n);
- return buf + n;
- }
-};
-
-class __long_double
- : public __node
-{
- static const size_t n = sizeof("long double") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "long double", n);
- return buf + n;
- }
-};
-
-class __float128
- : public __node
-{
- static const size_t n = sizeof("__float128") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "__float128", n);
- return buf + n;
- }
-};
-
-class __ellipsis
- : public __node
-{
- static const size_t n = sizeof("...") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- *buf++ = '.';
- *buf++ = '.';
- *buf++ = '.';
- return buf;
- }
-};
-
-class __decimal64
- : public __node
-{
- static const size_t n = sizeof("decimal64") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "decimal64", n);
- return buf + n;
- }
-};
-
-class __decimal128
- : public __node
-{
- static const size_t n = sizeof("decimal128") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "decimal128", n);
- return buf + n;
- }
-};
-
-class __decimal32
- : public __node
-{
- static const size_t n = sizeof("decimal32") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "decimal32", n);
- return buf + n;
- }
-};
-
-class __decimal16
- : public __node
-{
- static const size_t n = sizeof("decimal16") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "decimal16", n);
- return buf + n;
- }
-};
-
-class __d_char32_t
- : public __node
-{
- static const size_t n = sizeof("char32_t") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "char32_t", n);
- return buf + n;
- }
-};
-
-class __d_char16_t
- : public __node
-{
- static const size_t n = sizeof("char16_t") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "char16_t", n);
- return buf + n;
- }
-};
-
-class __auto
- : public __node
-{
- static const size_t n = sizeof("auto") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "auto", n);
- return buf + n;
- }
-};
-
-class __nullptr_t
- : public __node
-{
- static const size_t n = sizeof("std::nullptr_t") - 1;
-public:
-
- virtual size_t first_size() const {return n;}
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "std::nullptr_t", n);
- return buf + n;
- }
-};
-
-class __array
- : public __node
-{
-public:
-
- explicit __array(__node* type)
- {
- __left_ = type;
- }
-
- __array(__node* type, size_t dim)
- {
- __left_ = type;
- __size_ = dim;
- }
-
- __array(__node* type, __node* dim)
- {
- __left_ = type;
- __right_ = dim;
- }
-
- virtual size_t size() const
- {
- if (__cached_size_ == -1)
- {
- size_t r = __left_->size() + 3;
- if (__right_ != 0)
- r += __right_->size();
- else if (__size_ != 0)
- r += static_cast<size_t>(snprintf(0, 0, "%ld", __size_));
- const_cast<long&>(__cached_size_) = static_cast<long>(r);
- }
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual char* get_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = ' ';
- *buf++ = '[';
- if (__right_ != 0)
- buf = __right_->get_demangled_name(buf);
- else if (__size_ != 0)
- {
- int rs = sprintf(buf, "%ld", __size_);
- buf += rs;
- }
- *buf++ = ']';
- return buf;
- }
-
- virtual size_t first_size() const
- {
- return __left_->first_size();
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- return __left_->first_demangled_name(buf);
- }
-
- virtual size_t second_size() const
- {
- size_t r = 2 + __left_->second_size();
- if (!__left_->is_array())
- ++r;
- if (__right_ != 0)
- r += __right_->size();
- else if (__size_ != 0)
- r += static_cast<size_t>(snprintf(0, 0, "%ld", __size_));
- return r;
- }
-
- virtual char* second_demangled_name(char* buf) const
- {
- *buf++ = ' ';
- *buf++ = '[';
- if (__right_ != 0)
- buf = __right_->get_demangled_name(buf);
- else if (__size_ != 0)
- {
- int off = sprintf(buf, "%ld", __size_);
- buf += off;
- }
- char* t = buf;
- buf = __left_->second_demangled_name(buf);
- *t = ']';
- if (buf == t)
- ++buf;
- return buf;
- }
- virtual bool is_array() const
- {
- return true;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-class __pointer_to_member_type
- : public __node
-{
-public:
-
- __pointer_to_member_type(__node* class_type, __node* member_type)
- {
- __left_ = class_type;
- __right_ = member_type;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + 3
- + __right_->first_size()
- + __right_->second_size());
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __right_->first_demangled_name(buf);
- buf = __left_->get_demangled_name(buf);
- *buf++ = ':';
- *buf++ = ':';
- *buf++ = '*';
- return __right_->second_demangled_name(buf);
}
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool is_reference_or_pointer_to_function_or_array() const
- {
- return __right_->is_function();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __decltype_node
- : public __node
-{
-public:
-
- explicit __decltype_node(__node* expr)
- {
- __right_ = expr;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(10 + __right_->size());
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "decltype(", 9);
- buf += 9;
- buf = __right_->get_demangled_name(buf);
- *buf++ = ')';
- return buf;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __nested_delimeter
- : public __node
-{
-public:
-
- explicit __nested_delimeter(__node* prev, __node* arg)
- {
- __left_ = prev;
- __right_ = arg;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() +
- __right_->size() + 2);
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = ':';
- *buf++ = ':';
- return __right_->get_demangled_name(buf);
- }
-
- virtual bool ends_with_template(bool parsing = false) const
- {
- return __right_->ends_with_template(parsing);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __right_->is_ctor_dtor_conv();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end) &&
- __right_->fix_forward_references(t_begin, t_end);
- }
- virtual __node* extract_cv(__node*&) const
- {
- return __right_->extract_cv(const_cast<__node*&>(__right_));
- }
-};
-
-class __unresolved_name
- : public __node
-{
-public:
-
- __unresolved_name(__node* prev, __node* arg)
- {
- __left_ = prev;
- __right_ = arg;
- }
-
- __unresolved_name(bool global, __node* prev, __node* arg)
- {
- __size_ = global;
- __left_ = prev;
- __right_ = arg;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>((__left_ ?
- __left_->size() + 2 : 0) +
- __right_->size() + __size_ * 2);
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- if (__size_)
- {
- *buf++ = ':';
- *buf++ = ':';
- }
- if (__left_)
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = ':';
- *buf++ = ':';
- }
- return __right_->get_demangled_name(buf);
- }
-
- virtual bool ends_with_template(bool parsing = false) const
- {
- return __right_->ends_with_template(parsing);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return __right_->is_ctor_dtor_conv();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = __left_->fix_forward_references(t_begin, t_end);
- return r && __right_->fix_forward_references(t_begin, t_end);
- }
- virtual __node* extract_cv(__node*&) const
- {
- return __right_->extract_cv(const_cast<__node*&>(__right_));
- }
-};
-
-class __string_literal
- : public __node
-{
-public:
-
- virtual size_t first_size() const
- {
- return 14;
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- strncpy(buf, "string literal", 14);
- return buf + 14;
- }
-};
-
-class __constructor
- : public __node
-{
-public:
-
- explicit __constructor(__node* name)
- {
- __right_ = name;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->base_size());
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- return __right_->get_base_name(buf);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool ends_with_template(bool parsing = false) const
- {
- return __right_->ends_with_template(parsing);
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return true;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __destructor
- : public __node
-{
-public:
-
- explicit __destructor(__node* name)
- {
- __right_ = name;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- const_cast<long&>(__cached_size_) = static_cast<long>(__right_->base_size() + 1);
- return static_cast<size_t>(__cached_size_);
- }
-
- virtual char* first_demangled_name(char* buf) const
- {
- *buf++ = '~';
- return __right_->get_base_name(buf);
- }
- virtual __node* base_name() const
- {
- return __right_->base_name();
- }
- virtual bool is_ctor_dtor_conv() const
- {
- return true;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __right_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __dot_suffix
- : public __node
-{
-public:
- __dot_suffix(__node* name, const char* suffix, size_t sz)
- {
- __left_ = name;
- __name_ = suffix;
- __size_ = sz;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t off = __left_->size();
- off += __size_ + 3;
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- buf = __left_->get_demangled_name(buf);
- *buf++ = ' ';
- *buf++ = '(';
- strncpy(buf, __name_, __size_);
- buf += __size_;
- *buf++ = ')';
- return buf;
- }
- virtual __node* base_name() const
- {
- return __left_->base_name();
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- return __left_->fix_forward_references(t_begin, t_end);
- }
-};
-
-class __vector_type
- : public __node
-{
-public:
- __vector_type(__node* type, const char* num, size_t sz)
- {
- __left_ = type;
- __name_ = num;
- __size_ = sz;
- }
-
- __vector_type(__node* type, __node* num)
- {
- __left_ = type;
- __right_ = num;
- }
-
- virtual size_t first_size() const
- {
- if (__cached_size_ == -1)
- {
- size_t off = 5;
- if (__left_)
- off = __left_->size();
- off += 9;
- if (__right_)
- off += __right_->size();
- else if (__size_ > 0)
- off += __size_;
- const_cast<long&>(__cached_size_) = static_cast<long>(off);
- }
- return static_cast<size_t>(__cached_size_);
- }
- virtual char* first_demangled_name(char* buf) const
- {
- if (__left_)
- buf = __left_->get_demangled_name(buf);
- else
- {
- strncpy(buf, "pixel", 5);
- buf += 5;
- }
- strncpy(buf, " vector[", 8);
- buf += 8;
- if (__right_)
- buf = __right_->get_demangled_name(buf);
- else if (__size_ > 0)
- {
- strncpy(buf, __name_, __size_);
- buf += __size_;
- }
- *buf++ = ']';
- return buf;
- }
- virtual __node* base_name() const
- {
- if (__left_)
- return __left_->base_name();
- return __left_;
- }
- virtual bool fix_forward_references(__node** t_begin, __node** t_end)
- {
- bool r = true;
- if (__left_)
- r = __left_->fix_forward_references(t_begin, t_end);
- if (__right_)
- r = r && __right_->fix_forward_references(t_begin, t_end);
- return r;
- }
-};
-
-
-enum {invalid_args = -3, invalid_mangled_name, memory_alloc_failure, success,
- not_yet_implemented};
-
-__demangle_tree::__demangle_tree(const char* mangled_name, char* buf, size_t bs)
- : __mangled_name_begin_(0), __mangled_name_end_(0),
- __status_(invalid_mangled_name), __root_(0),
- __node_begin_(0), __node_end_(0), __node_cap_(0),
- __sub_begin_(0), __sub_end_(0), __sub_cap_(0),
- __t_begin_(0), __t_end_(0), __t_cap_(0),
- __tag_templates_(true),
- __fix_forward_references_(false)
-{
- size_t n = strlen(mangled_name);
- size_t ms = n + 2*n*sizeof(__node) + 2*n*sizeof(__node*);
- char* m;
- if (ms <= bs)
- {
- m = buf;
- __owns_buf_ = false;
- }
- else
- {
- m = static_cast<char*>(malloc(ms));
- __owns_buf_ = true;
- }
- if (m == NULL)
- {
- __status_ = memory_alloc_failure;
- return;
- }
- __node_begin_ = __node_end_ = (__node*)(m);
- __node_cap_ = __node_begin_ + 2*n;
- __sub_begin_ = __sub_end_ = (__node**)(__node_cap_);
- __sub_cap_ = __sub_begin_ + n;
- __t_begin_ = __t_end_ = (__node**)(__sub_cap_);
- __t_cap_ = __t_begin_ + n;
- __mangled_name_begin_ = (const char*)(__t_cap_);
- __mangled_name_end_ = __mangled_name_begin_ + n;
- strncpy(const_cast<char*>(__mangled_name_begin_), mangled_name, n);
-}
-
-__demangle_tree::~__demangle_tree()
-{
- if (__owns_buf_)
- free(__node_begin_);
-}
-
-__demangle_tree::__demangle_tree(__demangle_tree& t)
- : __mangled_name_begin_(t.__mangled_name_begin_),
- __mangled_name_end_(t.__mangled_name_end_),
- __status_(t.__status_), __root_(t.__root_),
- __node_begin_(t.__node_begin_), __node_end_(t.__node_end_),
- __node_cap_(t.__node_cap_),
- __sub_begin_(t.__sub_begin_), __sub_end_(t.__sub_end_),
- __sub_cap_(t.__sub_cap_),
- __t_begin_(t.__t_begin_), __t_end_(t.__t_end_),
- __t_cap_(t.__t_cap_),
- __tag_templates_(t.__tag_templates_),
- __fix_forward_references_(t.__fix_forward_references_),
- __owns_buf_(t.__owns_buf_)
-{
- t.__mangled_name_begin_ = 0;
- t.__mangled_name_end_ = 0;
- t.__status_ = invalid_mangled_name;
- t.__root_ = 0;
- t.__node_begin_ = t.__node_end_ = t.__node_cap_ = 0;
- t.__sub_begin_ = t.__sub_end_ = t.__sub_cap_ = 0;
- t.__t_begin_ = t.__t_end_ = t.__t_cap_ = 0;
- t.__owns_buf_ = false;
-}
-
-__demangle_tree::__demangle_tree(__demangle_tree_rv rv)
- : __mangled_name_begin_(rv.ptr_->__mangled_name_begin_),
- __mangled_name_end_(rv.ptr_->__mangled_name_end_),
- __status_(rv.ptr_->__status_), __root_(rv.ptr_->__root_),
- __node_begin_(rv.ptr_->__node_begin_), __node_end_(rv.ptr_->__node_end_),
- __node_cap_(rv.ptr_->__node_cap_),
- __sub_begin_(rv.ptr_->__sub_begin_), __sub_end_(rv.ptr_->__sub_end_),
- __sub_cap_(rv.ptr_->__sub_cap_),
- __t_begin_(rv.ptr_->__t_begin_), __t_end_(rv.ptr_->__t_end_),
- __t_cap_(rv.ptr_->__t_cap_),
- __tag_templates_(rv.ptr_->__tag_templates_),
- __fix_forward_references_(rv.ptr_->__fix_forward_references_),
- __owns_buf_(rv.ptr_->__owns_buf_)
-{
- rv.ptr_->__mangled_name_begin_ = 0;
- rv.ptr_->__mangled_name_end_ = 0;
- rv.ptr_->__status_ = invalid_mangled_name;
- rv.ptr_->__root_ = 0;
- rv.ptr_->__node_begin_ = rv.ptr_->__node_end_ = rv.ptr_->__node_cap_ = 0;
- rv.ptr_->__sub_begin_ = rv.ptr_->__sub_end_ = rv.ptr_->__sub_cap_ = 0;
- rv.ptr_->__t_begin_ = rv.ptr_->__t_end_ = rv.ptr_->__t_cap_ = 0;
- rv.ptr_->__owns_buf_ = false;
-}
-
-int
-__demangle_tree::__status() const
-{
- return __status_;
-}
-
-size_t
-__demangle_tree::size() const
-{
- return __status_ == success ? __root_->size() : 0;
-}
-
-char*
-__demangle_tree::__get_demangled_name(char* buf) const
-{
- if (__status_ == success)
- return __root_->get_demangled_name(buf);
- return 0;
-}
-
-template <class _Tp>
-bool
-__demangle_tree::__make()
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp();
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
-}
-
-template <class _Tp, class _A0>
-bool
-__demangle_tree::__make(_A0 __a0)
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp(__a0);
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
-}
-
-template <class _Tp, class _A0, class _A1>
-bool
-__demangle_tree::__make(_A0 __a0, _A1 __a1)
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp(__a0, __a1);
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
-}
-
-template <class _Tp, class _A0, class _A1, class _A2>
-bool
-__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2)
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp(__a0, __a1, __a2);
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
-}
-
-template <class _Tp, class _A0, class _A1, class _A2, class _A3>
-bool
-__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3)
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3);
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
-}
-
-template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4>
-bool
-__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4)
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4);
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
-}
-
-template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4,
- class _A5>
-bool
-__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4,
- _A5 __a5)
-{
- if (__node_end_ < __node_cap_)
- {
- ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4, __a5);
- __root_ = __node_end_;
- ++__node_end_;
- return true;
- }
- __status_ = memory_alloc_failure;
- return false;
+ return first;
}
-// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
-// [R | O] # & or &&
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+// ::std::char_traits<char>,
+// ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+template <class C>
const char*
-__demangle_tree::__parse_cv_qualifiers(const char* first, const char* last,
- unsigned& cv, bool look_for_ref_quals)
+parse_substitution(const char* first, const char* last, C& db)
{
- if (look_for_ref_quals)
+ if (last - first >= 2)
{
- for (; first != last; ++first)
+ if (*first == 'S')
{
- switch (*first)
+ switch (first[1])
{
- case 'r':
- cv |= 4;
- break;
- case 'V':
- cv |= 2;
+ case 'a':
+ db.names.push_back("std::allocator");
+ first += 2;
break;
- case 'K':
- cv |= 1;
+ case 'b':
+ db.names.push_back("std::basic_string");
+ first += 2;
break;
- case 'R':
- cv |= 8;
+ case 's':
+ db.names.push_back("std::string");
+ first += 2;
break;
- case 'O':
- cv |= 16;
+ case 'i':
+ db.names.push_back("std::istream");
+ first += 2;
break;
- default:
- return first;
- }
- }
- }
- else
- {
- for (; first != last; ++first)
- {
- switch (*first)
- {
- case 'r':
- cv |= 4;
+ case 'o':
+ db.names.push_back("std::ostream");
+ first += 2;
break;
- case 'V':
- cv |= 2;
+ case 'd':
+ db.names.push_back("std::iostream");
+ first += 2;
break;
- case 'K':
- cv |= 1;
+ case '_':
+ if (!db.subs.empty())
+ {
+ for (const auto& n : db.subs.front())
+ db.names.push_back(n);
+ first += 2;
+ }
break;
default:
- return first;
+ if (std::isdigit(first[1]) || std::isupper(first[1]))
+ {
+ size_t sub = 0;
+ const char* t = first+1;
+ if (std::isdigit(*t))
+ sub = static_cast<size_t>(*t - '0');
+ else
+ sub = static_cast<size_t>(*t - 'A') + 10;
+ for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
+ {
+ sub *= 36;
+ if (std::isdigit(*t))
+ sub += static_cast<size_t>(*t - '0');
+ else
+ sub += static_cast<size_t>(*t - 'A') + 10;
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < db.subs.size())
+ {
+ for (const auto& n : db.subs[sub])
+ db.names.push_back(n);
+ first = t+1;
+ }
+ }
+ break;
}
}
}
@@ -6476,96 +355,104 @@ __demangle_tree::__parse_cv_qualifiers(const char* first, const char* last,
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
// ::= u <source-name> # vendor extended type
+template <class C>
const char*
-__demangle_tree::__parse_builtin_type(const char* first, const char* last)
+parse_builtin_type(const char* first, const char* last, C& db)
{
if (first != last)
{
switch (*first)
{
case 'v':
- if (__make<__void>())
- ++first;
+ db.names.push_back("void");
+ ++first;
break;
case 'w':
- if (__make<__wchar_t>())
- ++first;
+ db.names.push_back("wchar_t");
+ ++first;
break;
case 'b':
- if (__make<__bool>())
- ++first;
+ db.names.push_back("bool");
+ ++first;
break;
case 'c':
- if (__make<__char>())
- ++first;
+ db.names.push_back("char");
+ ++first;
break;
case 'a':
- if (__make<__signed_char>())
- ++first;
+ db.names.push_back("signed char");
+ ++first;
break;
case 'h':
- if (__make<__unsigned_char>())
- ++first;
+ db.names.push_back("unsigned char");
+ ++first;
break;
case 's':
- if (__make<__short>())
- ++first;
+ db.names.push_back("short");
+ ++first;
break;
case 't':
- if (__make<__unsigned_short>())
- ++first;
+ db.names.push_back("unsigned short");
+ ++first;
break;
case 'i':
- if (__make<__int>())
- ++first;
+ db.names.push_back("int");
+ ++first;
break;
case 'j':
- if (__make<__unsigned_int>())
- ++first;
+ db.names.push_back("unsigned int");
+ ++first;
break;
case 'l':
- if (__make<__long>())
- ++first;
+ db.names.push_back("long");
+ ++first;
break;
case 'm':
- if (__make<__unsigned_long>())
- ++first;
+ db.names.push_back("unsigned long");
+ ++first;
break;
case 'x':
- if (__make<__long_long>())
- ++first;
+ db.names.push_back("long long");
+ ++first;
break;
case 'y':
- if (__make<__unsigned_long_long>())
- ++first;
+ db.names.push_back("unsigned long long");
+ ++first;
break;
case 'n':
- if (__make<__signed_int128>())
- ++first;
+ db.names.push_back("__int128");
+ ++first;
break;
case 'o':
- if (__make<__unsigned_int128>())
- ++first;
+ db.names.push_back("unsigned __int128");
+ ++first;
break;
case 'f':
- if (__make<__float>())
- ++first;
+ db.names.push_back("float");
+ ++first;
break;
case 'd':
- if (__make<__double>())
- ++first;
+ db.names.push_back("double");
+ ++first;
break;
case 'e':
- if (__make<__long_double>())
- ++first;
+ db.names.push_back("long double");
+ ++first;
break;
case 'g':
- if (__make<__float128>())
- ++first;
+ db.names.push_back("__float128");
+ ++first;
break;
case 'z':
- if (__make<__ellipsis>())
- ++first;
+ db.names.push_back("...");
+ ++first;
+ break;
+ case 'u':
+ {
+ const char*t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ first = t;
+ }
break;
case 'D':
if (first+1 != last)
@@ -6573,36 +460,36 @@ __demangle_tree::__parse_builtin_type(const char* first, const char* last)
switch (first[1])
{
case 'd':
- if (__make<__decimal64>())
- first += 2;
+ db.names.push_back("decimal64");
+ first += 2;
break;
case 'e':
- if (__make<__decimal128>())
- first += 2;
+ db.names.push_back("decimal128");
+ first += 2;
break;
case 'f':
- if (__make<__decimal32>())
- first += 2;
+ db.names.push_back("decimal32");
+ first += 2;
break;
case 'h':
- if (__make<__decimal16>())
- first += 2;
+ db.names.push_back("decimal16");
+ first += 2;
break;
case 'i':
- if (__make<__d_char32_t>())
- first += 2;
+ db.names.push_back("char32_t");
+ first += 2;
break;
case 's':
- if (__make<__d_char16_t>())
- first += 2;
+ db.names.push_back("char16_t");
+ first += 2;
break;
case 'a':
- if (__make<__auto>())
- first += 2;
+ db.names.push_back("auto");
+ first += 2;
break;
case 'n':
- if (__make<__nullptr_t>())
- first += 2;
+ db.names.push_back("std::nullptr_t");
+ first += 2;
break;
}
}
@@ -6612,794 +499,316 @@ __demangle_tree::__parse_builtin_type(const char* first, const char* last)
return first;
}
-// <bare-function-type> ::= <signature type>+
-// # types are possible return type, then parameter types
+// <CV-qualifiers> ::= [r] [V] [K]
const char*
-__demangle_tree::__parse_bare_function_type(const char* first, const char* last)
+parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)
{
+ cv = 0;
if (first != last)
{
- bool prev_tag_templates = __tag_templates_;
- __tag_templates_ = false;
- const char* t = __parse_type(first, last);
- if (t != first && __make<__list>(__root_))
+ if (*first == 'r')
{
- const char* t0 = t;
- __node* head = __root_;
- __node* prev = head;
- while (true)
- {
- t = __parse_type(t0, last);
- if (t != t0)
- {
- if (__make<__list>(__root_))
- {
- t0 = t;
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
- prev = __root_;
- }
- else
- break;
- }
- else
- {
- first = t;
- __root_ = head;
- break;
- }
- }
+ cv |= 4;
+ ++first;
}
- __tag_templates_ = prev_tag_templates;
- }
- return first;
-}
-
-// <function-type> ::= F [Y] <bare-function-type> E
-
-const char*
-__demangle_tree::__parse_function_type(const char* first, const char* last)
-{
- if (first != last && *first == 'F')
- {
- const char* t = first+1;
- if (t != last)
+ if (*first == 'V')
{
- bool externC = false;
- if (*t == 'Y')
- {
- externC = true;
- if (++t == last)
- return first;
- }
- const char* t1 = __parse_type(t, last);
- if (t1 != t)
- {
- __node* ret = __root_;
- t = t1;
- t1 = __parse_bare_function_type(t, last);
- if (t1 != t && t1 != last && *t1 == 'E')
- {
- if (dynamic_cast<__void*>(__root_->__left_) != NULL)
- __root_->__left_ = NULL;
- if (__make<__function_signature>(ret, __root_))
- {
- if (__make<__function>((__node*)0, __root_))
- first = t1+1;
- }
- }
- }
+ cv |= 2;
+ ++first;
+ }
+ if (*first == 'K')
+ {
+ cv |= 1;
+ ++first;
}
}
return first;
}
-const char*
-__demangle_tree::__parse_hex_number(const char* first, const char* last, unsigned long long& n)
-{
- const char* t = first;
- for (; t != last && isxdigit(*t); ++t)
- {
- if (t == first)
- n = 0;
- if (isdigit(*t))
- n = n * 16 + static_cast<unsigned long long>(*t - '0');
- else if (isupper(*t))
- n = n * 16 + static_cast<unsigned long long>(*t - 'A') + 10;
- else
- n = n * 16 + static_cast<unsigned long long>(*t - 'a') + 10;
- }
- first = t;
- return first;
-}
-
-// <expr-primary> ::= L <type> <value number> E # integer literal
-// ::= L <type> <value float> E # floating literal
-// ::= L <string type> E # string literal
-// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
-// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
-// ::= L <mangled-name> E # external name
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+template <class C>
const char*
-__demangle_tree::__parse_expr_primary(const char* first, const char* last)
+parse_template_param(const char* first, const char* last, C& db)
{
- if (last - first >= 4 && *first == 'L')
+ if (last - first >= 2)
{
- switch (first[1])
+ if (*first == 'T')
{
- case 'w':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__wchar_t_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'b':
- if (first[3] == 'E')
- {
- switch (first[2])
- {
- case '0':
- if (__make<__bool_literal>("false", 5u))
- first += 4;
- break;
- case '1':
- if (__make<__bool_literal>("true", 4u))
- first += 4;
- break;
- }
- }
- break;
- case 'c':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__char_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'a':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__signed_char_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'h':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__unsigned_char_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 's':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__short_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 't':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__unsigned_short_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'i':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__int_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'j':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__unsigned_int_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'l':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__long_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'm':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__unsigned_long_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'x':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (__make<__long_long_literal>(first+2, t))
- first = t+1;
- }
- }
- break;
- case 'y':
+ if (first[1] == '_')
{
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
+ if (db.template_param.empty())
+ return first;
+ if (!db.template_param.back().empty())
{
- if (__make<__unsigned_long_long_literal>(first+2, t))
- first = t+1;
+ for (auto& t : db.template_param.back().front())
+ db.names.push_back(t);
+ first += 2;
}
- }
- break;
- case 'n':
- {
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
+ else
{
- if (__make<__int128_literal>(first+2, t))
- first = t+1;
+ db.names.push_back("T_");
+ first += 2;
+ db.fix_forward_references = true;
}
}
- break;
- case 'o':
+ else if (isdigit(first[1]))
{
- const char* t = __parse_number(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
+ const char* t = first+1;
+ size_t sub = static_cast<size_t>(*t - '0');
+ for (++t; t != last && isdigit(*t); ++t)
{
- if (__make<__unsigned_int128_literal>(first+2, t))
- first = t+1;
+ sub *= 10;
+ sub += static_cast<size_t>(*t - '0');
}
- }
- break;
- case 'f':
- {
- if (last - (first+2) <= 8)
+ if (t == last || *t != '_' || db.template_param.empty())
return first;
- unsigned long long j;
- const char* t = __parse_hex_number(first+2, first+10, j);
- if (t != first+2 && t != last && *t == 'E')
+ ++sub;
+ if (sub < db.template_param.back().size())
{
- unsigned i = static_cast<unsigned>(j);
- float value = *(float*)&i;
- if (__make<__float_literal>(value))
- first = t+1;
+ for (auto& temp : db.template_param.back()[sub])
+ db.names.push_back(temp);
+ first = t+1;
}
- }
- break;
- case 'd':
- {
- if (last - (first+2) <= 16)
- return first;
- unsigned long long j;
- const char* t = __parse_hex_number(first+2, first+18, j);
- if (t != first+2 && t != last && *t == 'E')
+ else
{
- double value = *(double*)&j;
- if (__make<__double_literal>(value))
- first = t+1;
- }
- }
- break;
- case 'e':
- break;
- case '_':
- if (first[2] == 'Z')
- {
- const char* t = __parse_encoding(first+3, last);
- if (t != first+3 && t != last && *t == 'E')
+ db.names.push_back(typename C::String(first, t+1));
first = t+1;
- }
- break;
- case 'T':
- // Invalid mangled name per
- // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
- break;
- default:
- {
- // might be named type
- const char* t = __parse_type(first+1, last);
- if (t != first+1 && t != last)
- {
- if (*t != 'E')
- {
- const char* n = t;
- for (; n != last && isdigit(*n); ++n)
- ;
- if (n != t && n != last && *n == 'E')
- {
- if (__make<__cast_literal>(__root_, t, n))
- {
- first = n+1;
- break;
- }
- }
- }
- else
- {
- first = t+1;
- break;
- }
+ db.fix_forward_references = true;
}
}
-// assert(!"case in __parse_expr_primary not implemented");
- __status_ = not_yet_implemented;
}
}
return first;
}
-// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
-// ::= <closure-type-name>
-//
-// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
-//
-// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+// cc <type> <expression> # const_cast<type> (expression)
+template <class C>
const char*
-__demangle_tree::__parse_unnamed_type_name(const char* first, const char* last)
+parse_const_cast_expr(const char* first, const char* last, C& db)
{
- if (last - first > 2 && first[0] == 'U')
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
{
- char type = first[1];
- switch (type)
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
{
- case 't':
- case 'l':
- {
- const char* t = first + 2;
- __node* params = 0;
- if (type == 'l')
- {
- if (*t == 'v')
- {
- // void lambda
- ++t;
- if (t != last && *t == 'E')
- ++t;
- else
- return first;
- }
- else
- {
- const char* t1 = __parse_type(t, last);
- if (t1 == t || !__make<__list>(__root_))
- return first;
- params = __root_;
- __node* prev = params;
- t = t1;
- while (true)
- {
- t1 = __parse_type(t, last);
- if (t1 == t)
- break;
- if (!__make<__list>(__root_))
- return first;
- t = t1;
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
- prev = __root_;
- }
- if (t == last || *t != 'E')
- return first;
- ++t;
- }
- }
- const char* number_start = t;
- const char* number_end = __parse_number(t, last);
- if (number_end == last || *number_end != '_')
- return first;
- t = number_end + 1;
- if (type == 'l')
- {
- if (!__make<___lambda_node>(params, number_start, static_cast<size_t>(number_end - number_start)))
- return first;
- }
- else
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
{
- if (!__make<__unnamed>(number_start, static_cast<size_t>(number_end - number_start)))
+ if (db.names.size() < 2)
return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
}
- first = t;
- }
- break;
}
}
return first;
}
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
+// dc <type> <expression> # dynamic_cast<type> (expression)
+template <class C>
const char*
-__demangle_tree::__parse_ctor_dtor_name(const char* first, const char* last)
+parse_dynamic_cast_expr(const char* first, const char* last, C& db)
{
- if (last-first >= 2 && __root_)
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
{
- switch (first[0])
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
{
- case 'C':
- switch (first[1])
- {
- case '1':
- case '2':
- case '3':
- if (__make<__constructor>(__root_->base_name()))
- first += 2;
- break;
- }
- break;
- case 'D':
- switch (first[1])
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
{
- case '0':
- case '1':
- case '2':
- if (__make<__destructor>(__root_->base_name()))
- first += 2;
- break;
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
}
- break;
}
}
return first;
}
-const char*
-__demangle_tree::__parse_unscoped_template_name(const char* first, const char*)
-{
-// assert(!"__parse_unscoped_template_name not implemented");
- __status_ = not_yet_implemented;
- return first;
-}
-
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+
+// rc <type> <expression> # reinterpret_cast<type> (expression)
+template <class C>
const char*
-__demangle_tree::__parse_discriminator(const char* first, const char* last)
+parse_reinterpret_cast_expr(const char* first, const char* last, C& db)
{
- // parse but ignore discriminator
- if (first != last)
+ if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
{
- if (*first == '_')
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
{
- const char* t1 = first+1;
- if (t1 != last)
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
{
- if (isdigit(*t1))
- first = t1+1;
- else if (*t1 == '_')
- {
- for (++t1; t1 != last && isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
}
}
- else if (isdigit(*first))
- {
- const char* t1 = first+1;
- for (; t1 != last && isdigit(*t1); ++t1)
- ;
- first = t1;
- }
}
return first;
}
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-// := Z <function encoding> E s [<discriminator>]
-// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+// sc <type> <expression> # static_cast<type> (expression)
+template <class C>
const char*
-__demangle_tree::__parse_local_name(const char* first, const char* last)
+parse_static_cast_expr(const char* first, const char* last, C& db)
{
- if (first != last && *first == 'Z')
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
{
- const char* t = __parse_encoding(first+1, last);
- if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
{
- __node* encoding = __root_;
- switch (*t)
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 != t)
{
- case 's':
- {
- const char*t1 = __parse_discriminator(t+1, last);
- if (__make<__string_literal>())
- {
- if (__make<__nested_delimeter>(encoding, __root_))
- first = t1;
- }
- }
- break;
- case 'd':
-// assert(!"__parse_local_name d not implemented");
- __status_ = not_yet_implemented;
- break;
- default:
- {
- const char*t1 = __parse_name(t, last);
- if (t1 != t)
- {
- // parse but ignore discriminator
- t1 = __parse_discriminator(t1, last);
- if (__make<__nested_delimeter>(encoding, __root_))
- first = t1;
- }
- }
- break;
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
+ first = t1;
}
}
}
return first;
}
-// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
-// ::= <simple-id> # e.g., ~A<2*N>
+// sp <expression> # pack expansion
+template <class C>
const char*
-__demangle_tree::__parse_destructor_name(const char* first, const char* last)
+parse_pack_expansion(const char* first, const char* last, C& db)
{
- if (first != last)
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
{
- const char* t = __parse_unresolved_type(first, last);
- if (t == first)
- t = __parse_simple_id(first, last);
- if (t != first && __make<__destructor>(__root_))
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
first = t;
}
return first;
}
-// <simple-id> ::= <source-name> [ <template-args> ]
+// st <type> # sizeof (a type)
+template <class C>
const char*
-__demangle_tree::__parse_simple_id(const char* first, const char* last)
+parse_sizeof_type_expr(const char* first, const char* last, C& db)
{
- if (first != last)
+ if (last - first >= 3 && first[0] == 's' && first[1] == 't')
{
- const char* t = __parse_source_name(first, last);
- if (t != first)
- first = __parse_template_args(t, last);
- else
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
first = t;
+ }
}
return first;
}
-// <base-unresolved-name> ::= <simple-id> # unresolved name
-// extension ::= <operator-name> # unresolved operator-function-id
-// extension ::= <operator-name> <template-args> # unresolved operator template-id
-// ::= on <operator-name> # unresolved operator-function-id
-// ::= on <operator-name> <template-args> # unresolved operator template-id
-// ::= dn <destructor-name> # destructor or pseudo-destructor;
-// # e.g. ~X or ~X<N-1>
+// sz <expr> # sizeof (a expression)
+template <class C>
const char*
-__demangle_tree::__parse_base_unresolved_name(const char* first, const char* last)
+parse_sizeof_expr_expr(const char* first, const char* last, C& db)
{
- if (last - first >= 2)
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
{
- if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
- {
- if (first[0] == 'o')
- {
- const char* t = __parse_operator_name(first+2, last);
- if (t != first+2)
- first = __parse_template_args(t, last);
- else
- first = t;
- }
- else
- {
- const char* t = __parse_destructor_name(first+2, last);
- if (t != first+2)
- first = t;
- }
- }
- else
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
{
- const char* t = __parse_simple_id(first, last);
- if (t == first)
- {
- t = __parse_operator_name(first, last);
- if (t != first)
- t = __parse_template_args(t, last);
- }
- if (t != first)
- first = t;
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
+ first = t;
}
}
return first;
}
-// <unresolved-type> ::= <template-param>
-// ::= <decltype>
-// ::= <substitution>
+// sZ <template-param> # size of a parameter pack
+template <class C>
const char*
-__demangle_tree::__parse_unresolved_type(const char* first, const char* last)
+parse_sizeof_param_pack_expr(const char* first, const char* last, C& db)
{
- if (first != last)
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
{
- const char* t;
- switch (*first)
+ size_t k0 = db.names.size();
+ const char* t = parse_template_param(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
{
- case 'T':
- t = __parse_template_param(first, last);
- if (t != first)
+ typename C::String tmp("sizeof...(");
+ size_t k = k0;
+ if (k != k1)
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
- break;
- case 'D':
- t = __parse_decltype(first, last);
- if (t != first)
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
+ tmp += db.names[k].move_full();
+ for (++k; k != k1; ++k)
+ tmp += ", " + db.names[k].move_full();
}
- break;
- case 'S':
- t = __parse_substitution(first, last);
- if (t != first)
- first = t;
- break;
+ tmp += ")";
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ db.names.push_back(std::move(tmp));
+ first = t;
}
}
return first;
}
-// <unresolved-qualifier-level> ::= <source-name> [ <template-args> ]
-
-const char*
-__demangle_tree::__parse_unresolved_qualifier_level(const char* first, const char* last)
-{
- if (first != last)
- {
- const char* t = __parse_source_name(first, last);
- if (t != first)
- first = __parse_template_args(t, last);
- }
- return first;
-}
-
-// <unresolved-name>
-// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
-// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
-// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
-// # A::x, N::y, A<T>::z; "gs" means leading "::"
-// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
-// # T::N::x /decltype(p)::N::x
-// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+template <class C>
const char*
-__demangle_tree::__parse_unresolved_name(const char* first, const char* last)
+parse_function_param(const char* first, const char* last, C& db)
{
- if (last - first > 2)
+ if (last - first >= 3 && *first == 'f')
{
- const char* t = first;
- bool global = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- global = true;
- t += 2;
- }
- const char* t2 = __parse_base_unresolved_name(t, last);
- if (t2 != t)
- {
- if (__make<__unresolved_name>(global, (__node*)0, __root_))
- first = t2;
- }
- else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ if (first[1] == 'p')
{
- if (!global && t[2] == 'N')
+ unsigned cv;
+ const char* t = parse_cv_qualifiers(first+2, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
{
- t2 = __parse_unresolved_type(t+3, last);
- if (t2 != t+3 && t2 != last)
- {
- t = __parse_template_args(t2, last);
- if (t == last)
- return first;
- __node* name = __root_;
- while (*t != 'E')
- {
- t2 = __parse_unresolved_qualifier_level(t, last);
- if (t2 == t || t2 == last)
- return first;
- if (!__make<__nested_delimeter>(name, __root_))
- return first;
- name = __root_;
- t = t2;
- }
- t2 = __parse_base_unresolved_name(++t, last);
- if (t2 != t && __make<__unresolved_name>(false, name, __root_))
- first = t2;
- }
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
}
- else
+ }
+ else if (first[1] == 'L')
+ {
+ unsigned cv;
+ const char* t0 = parse_number(first+2, last);
+ if (t0 != last && *t0 == 'p')
{
- if (!global)
- {
- t2 = __parse_unresolved_type(t+2, last);
- if (t2 != t+2)
- {
- t = t2;
- __node* name = __root_;
- t2 = __parse_base_unresolved_name(t, last);
- if (t2 != t && __make<__unresolved_name>(false, name, __root_))
- return t2;
- return first;
- }
- }
- t2 = __parse_unresolved_qualifier_level(t+2, last);
- if (t2 != t+2 && t2 != last)
+ ++t0;
+ const char* t = parse_cv_qualifiers(t0, last, cv);
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
{
- __node* name = __root_;
- t = t2;
- while (*t != 'E')
- {
- t2 = __parse_unresolved_qualifier_level(t, last);
- if (t2 == t || t2 == last)
- return first;
- if (!__make<__nested_delimeter>(name, __root_))
- return first;
- name = __root_;
- t = t2;
- }
- t2 = __parse_base_unresolved_name(++t, last);
- if (t2 != t && __make<__unresolved_name>(global, name, __root_))
- first = t2;
+ db.names.push_back("fp" + typename C::String(t, t1));
+ first = t1+1;
}
}
}
@@ -7407,256 +816,438 @@ __demangle_tree::__parse_unresolved_name(const char* first, const char* last)
return first;
}
-// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
-// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers>
+// sZ <function-param> # size of a function parameter pack
+template <class C>
const char*
-__demangle_tree::__parse_function_param(const char* first, const char* last)
+parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && *first == 'f')
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
{
- if (first[1] == 'p')
+ const char* t = parse_function_param(first+2, last, db);
+ if (t != first+2)
{
-// assert(!"__parse_function_param not implemented");
- __status_ = not_yet_implemented;
+ if (db.names.empty())
+ return first;
+ db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
+ first = t;
}
- else if (first[1] == 'L')
+ }
+ return first;
+}
+
+// te <expression> # typeid (expression)
+// ti <type> # typeid (type)
+
+template <class C>
+const char*
+parse_typeid_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
+ {
+ const char* t;
+ if (first[1] == 'e')
+ t = parse_expression(first+2, last, db);
+ else
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
{
-// assert(!"__parse_function_param not implemented");
- __status_ = not_yet_implemented;
+ if (db.names.empty())
+ return first;
+ db.names.back() = "typeid(" + db.names.back().move_full() + ")";
+ first = t;
}
}
return first;
}
-// at <type> # alignof (a type)
+// tw <expression> # throw expression
+template <class C>
const char*
-__demangle_tree::__parse_alignof_expr(const char* first, const char* last)
+parse_throw_expr(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
{
- const char* t = __parse_type(first+2, last);
+ const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
- if (__make<__operator_alignof_expression>(__root_))
- first = t;
+ if (db.names.empty())
+ return first;
+ db.names.back() = "throw " + db.names.back().move_full();
+ first = t;
}
}
return first;
}
-// cc <type> <expression> # const_cast<type> (expression)
+// ds <expression> <expression> # expr.*expr
+template <class C>
const char*
-__demangle_tree::__parse_const_cast_expr(const char* first, const char* last)
+parse_dot_star_expr(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
{
- const char* t = __parse_type(first+2, last);
+ const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
- __node* type = __root_;
- const char* t1 = __parse_expression(t, last);
+ const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
- if (__make<__const_cast>(type, __root_))
- first = t1;
+ if (db.names.size() < 2)
+ return first;
+ auto expr = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += ".*" + expr;
+ first = t1;
}
}
}
return first;
}
-// cl <expression>+ E # call
+// <simple-id> ::= <source-name> [ <template-args> ]
+template <class C>
const char*
-__demangle_tree::__parse_call_expr(const char* first, const char* last)
+parse_simple_id(const char* first, const char* last, C& db)
{
- if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+ if (first != last)
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ const char* t = parse_source_name(first, last, db);
+ if (t != first)
{
- if (t == last)
- return first;
- __node* name = __root_;
- __node* args = 0;
- __node* prev = 0;
- while (*t != 'E')
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
{
- const char* t1 = __parse_expression(t, last);
- if (t1 == t || t1 == last)
- return first;
- if (!__make<__list>(__root_))
+ if (db.names.size() < 2)
return first;
- if (args == 0)
- args = __root_;
- if (prev)
- {
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
- }
- prev = __root_;
- t = t1;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
}
- ++t;
- if (__make<__call_expr>(name, args))
- first = t;
+ first = t1;
}
+ else
+ first = t;
}
return first;
}
-// cv <type> <expression> # conversion with one argument
-// cv <type> _ <expression>* E # conversion with a different number of arguments
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+template <class C>
const char*
-__demangle_tree::__parse_conversion_expr(const char* first, const char* last)
+parse_unresolved_type(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+ if (first != last)
{
- const char* t = __parse_type(first+2, last);
- if (t != first+2 && t != last)
+ const char* t = first;
+ switch (*first)
{
- __node* type = __root_;
- __node* args = 0;
- if (*t != '_')
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first && k1 == k0 + 1)
{
- const char* t1 = __parse_expression(t, last);
- if (t1 == t)
- return first;
- args = __root_;
- t = t1;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
}
else
{
- ++t;
- if (t == last)
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ }
+ break;
+ }
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
return first;
- __node* prev = 0;
- while (*t != 'E')
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ break;
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ first = t;
+ else
+ {
+ if (last - first > 2 && first[1] == 't')
{
- const char* t1 = __parse_expression(t, last);
- if (t1 == t || t1 == last)
- return first;
- if (!__make<__list>(__root_))
- return first;
- if (args == 0)
- args = __root_;
- if (prev)
+ t = parse_unqualified_name(first+2, last, db);
+ if (t != first+2)
{
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
}
- prev = __root_;
- t = t1;
}
- ++t;
}
- if (__make<__operator_cast>(type, args))
- first = t;
- }
+ break;
+ }
}
return first;
}
-// [gs] da <expression> # delete[] expression
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+template <class C>
const char*
-__demangle_tree::__parse_delete_array_expr(const char* first, const char* last)
+parse_destructor_name(const char* first, const char* last, C& db)
{
- if (last - first >= 4)
+ if (first != last)
{
- const char* t = first;
- bool parsed_gs = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- if (t[0] == 'd' && t[1] == 'a')
+ const char* t = parse_unresolved_type(first, last, db);
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+ if (t != first)
{
- t += 2;
- const char* t1 = __parse_expression(t, last);
- if (t1 != t)
- {
- if (__make<__delete_array_expr>(parsed_gs, __root_))
- first = t1;
- }
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "~");
+ first = t;
}
}
return first;
}
-// dc <type> <expression> # dynamic_cast<type> (expression)
+// <base-unresolved-name> ::= <simple-id> # unresolved name
+// extension ::= <operator-name> # unresolved operator-function-id
+// extension ::= <operator-name> <template-args> # unresolved operator template-id
+// ::= on <operator-name> # unresolved operator-function-id
+// ::= on <operator-name> <template-args> # unresolved operator template-id
+// ::= dn <destructor-name> # destructor or pseudo-destructor;
+// # e.g. ~X or ~X<N-1>
+template <class C>
const char*
-__demangle_tree::__parse_dynamic_cast_expr(const char* first, const char* last)
+parse_base_unresolved_name(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+ if (last - first >= 2)
{
- const char* t = __parse_type(first+2, last);
- if (t != first+2)
+ if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
{
- __node* type = __root_;
- const char* t1 = __parse_expression(t, last);
- if (t1 != t)
+ if (first[0] == 'o')
{
- if (__make<__dynamic_cast>(type, __root_))
- first = t1;
+ const char* t = parse_operator_name(first+2, last, db);
+ if (t != first+2)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
+ }
+ else
+ {
+ const char* t = parse_destructor_name(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = parse_simple_id(first, last, db);
+ if (t == first)
+ {
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ {
+ first = parse_template_args(t, last, db);
+ if (first != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ }
+ }
}
+ else
+ first = t;
}
}
return first;
}
-// [gs] dl <expression> # delete expression
+// <unresolved-qualifier-level> ::= <simple-id>
+template <class C>
const char*
-__demangle_tree::__parse_delete_expr(const char* first, const char* last)
+parse_unresolved_qualifier_level(const char* first, const char* last, C& db)
{
- if (last - first >= 4)
+ return parse_simple_id(first, last, db);
+}
+
+// <unresolved-name>
+// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+// # T::N::x /decltype(p)::N::x
+// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+template <class C>
+const char*
+parse_unresolved_name(const char* first, const char* last, C& db)
+{
+ if (last - first > 2)
{
const char* t = first;
- bool parsed_gs = false;
+ bool global = false;
if (t[0] == 'g' && t[1] == 's')
{
+ global = true;
t += 2;
- parsed_gs = true;
}
- if (t[0] == 'd' && t[1] == 'l')
+ const char* t2 = parse_base_unresolved_name(t, last, db);
+ if (t2 != t)
{
- t += 2;
- const char* t1 = __parse_expression(t, last);
- if (t1 != t)
+ if (global)
{
- if (__make<__delete_expr>(parsed_gs, __root_))
- first = t1;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
}
+ first = t2;
}
- }
- return first;
-}
-
-// ds <expression> <expression> # expr.*expr
-
-const char*
-__demangle_tree::__parse_dot_star_expr(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
{
- __node* expr = __root_;
- const char* t1 = __parse_expression(t, last);
- if (t1 != t)
+ if (t[2] == 'N')
+ {
+ t += 3;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
+ else
{
- if (__make<__dot_star_expr>(expr, __root_))
+ t += 2;
+ const char* t1 = parse_unresolved_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ t = t1;
+ }
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
first = t1;
+ }
+ else
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ if (global)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "::");
+ }
+ while (*t != 'E')
+ {
+ t1 = parse_unresolved_qualifier_level(t, last, db);
+ if (t1 == t || t1 == last || db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ t = t1;
+ }
+ ++t;
+ t1 = parse_base_unresolved_name(t, last, db);
+ if (t1 == t)
+ {
+ if (!db.names.empty())
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto s = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "::" + std::move(s);
+ first = t1;
+ }
}
}
}
@@ -7665,55 +1256,76 @@ __demangle_tree::__parse_dot_star_expr(const char* first, const char* last)
// dt <expression> <unresolved-name> # expr.name
+template <class C>
const char*
-__demangle_tree::__parse_dot_expr(const char* first, const char* last)
+parse_dot_expr(const char* first, const char* last, C& db)
{
if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
{
- const char* t = __parse_expression(first+2, last);
+ const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
- __node* expr = __root_;
- const char* t1 = __parse_unresolved_name(t, last);
+ const char* t1 = parse_unresolved_name(t, last, db);
if (t1 != t)
{
- if (__make<__dot_expr>(expr, __root_))
- first = t1;
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "." + name;
+ first = t1;
}
}
}
return first;
}
-// mm_ <expression> # prefix --
-
-const char*
-__demangle_tree::__parse_decrement_expr(const char* first, const char* last)
-{
- if (last - first > 3 && first[0] == 'm' && first[1] == 'm' && first[2] == '_')
- {
- const char* t = __parse_expression(first+3, last);
- if (t != first+3)
- {
- if (__make<__operator_decrement>(true, __root_))
- first = t;
- }
- }
- return first;
-}
-
-// pp_ <expression> # prefix ++
+// cl <expression>+ E # call
+template <class C>
const char*
-__demangle_tree::__parse_increment_expr(const char* first, const char* last)
+parse_call_expr(const char* first, const char* last, C& db)
{
- if (last - first > 3 && first[0] == 'p' && first[1] == 'p' && first[2] == '_')
+ if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
{
- const char* t = __parse_expression(first+3, last);
- if (t != first+3)
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
{
- if (__make<__operator_increment>(true, __root_))
- first = t;
+ if (t == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += db.names.back().second;
+ db.names.back().second = typename C::String();
+ db.names.back().first.append("(");
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_expr)
+ {
+ db.names.back().first.append(", ");
+ first_expr = false;
+ }
+ db.names.back().first.append(tmp);
+ }
+ t = t1;
+ }
+ ++t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(")");
+ first = t;
}
}
return first;
@@ -7725,8 +1337,9 @@ __demangle_tree::__parse_increment_expr(const char* first, const char* last)
// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
// <initializer> ::= pi <expression>* E # parenthesized initialization
+template <class C>
const char*
-__demangle_tree::__parse_new_expr(const char* first, const char* last)
+parse_new_expr(const char* first, const char* last, C& db)
{
if (last - first >= 4)
{
@@ -7743,419 +1356,325 @@ __demangle_tree::__parse_new_expr(const char* first, const char* last)
t += 2;
if (t == last)
return first;
- __node* expr = 0;
- __node* prev = 0;
+ bool has_expr_list = false;
+ bool first_expr = true;
while (*t != '_')
{
- const char* t1 = __parse_expression(t, last);
+ const char* t1 = parse_expression(t, last, db);
if (t1 == t || t1 == last)
return first;
- if (!__make<__list>(__root_))
- return first;
- if (expr == 0)
- expr = __root_;
- if (prev)
+ has_expr_list = true;
+ if (!first_expr)
{
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
}
- prev = __root_;
t = t1;
}
++t;
- const char* t1 = __parse_type(t, last);
+ const char* t1 = parse_type(t, last, db);
if (t1 == t || t1 == last)
return first;
t = t1;
- __node* type = __root_;
- __node* init = 0;
- prev = 0;
bool has_init = false;
if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
{
t += 2;
has_init = true;
+ first_expr = true;
while (*t != 'E')
{
- t1 = __parse_expression(t, last);
+ t1 = parse_expression(t, last, db);
if (t1 == t || t1 == last)
return first;
- if (!__make<__list>(__root_))
- return first;
- if (init == 0)
- init = __root_;
- if (prev)
+ if (!first_expr)
{
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
}
- prev = __root_;
t = t1;
}
}
if (*t != 'E')
return first;
- if (__make<__new_expr>(parsed_gs, is_array, has_init,
- expr, type, init))
- first = t;
- }
- }
- return first;
-}
-
-// pt <expression> <unresolved-name> # expr->name
-
-const char*
-__demangle_tree::__parse_arrow_expr(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* expr = __root_;
- const char* t1 = __parse_unresolved_name(t, last);
- if (t1 != t)
+ typename C::String init_list;
+ if (has_init)
{
- if (__make<__arrow_expr>(expr, __root_))
- first = t1;
+ if (db.names.empty())
+ return first;
+ init_list = db.names.back().move_full();
+ db.names.pop_back();
}
+ if (db.names.empty())
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ typename C::String expr_list;
+ if (has_expr_list)
+ {
+ if (db.names.empty())
+ return first;
+ expr_list = db.names.back().move_full();
+ db.names.pop_back();
+ }
+ typename C::String r;
+ if (parsed_gs)
+ r = "::";
+ if (is_array)
+ r += "[] ";
+ else
+ r += " ";
+ if (has_expr_list)
+ r += "(" + expr_list + ") ";
+ r += type;
+ if (has_init)
+ r += " (" + init_list + ")";
+ db.names.push_back(std::move(r));
+ first = t+1;
}
}
return first;
}
-// rc <type> <expression> # reinterpret_cast<type> (expression)
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+template <class C>
const char*
-__demangle_tree::__parse_reinterpret_cast_expr(const char* first, const char* last)
+parse_conversion_expr(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
{
- const char* t = __parse_type(first+2, last);
- if (t != first+2)
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2 && t != last)
{
- __node* type = __root_;
- const char* t1 = __parse_expression(t, last);
- if (t1 != t)
+ if (*t != '_')
{
- if (__make<__reinterpret_cast>(type, __root_))
- first = t1;
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return first;
+ t = t1;
+ }
+ else
+ {
+ ++t;
+ if (t == last)
+ return first;
+ if (*t == 'E')
+ db.names.emplace_back();
+ else
+ {
+ bool first_expr = true;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_expression(t, last, db);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!first_expr)
+ {
+ if (db.names.empty())
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ first_expr = false;
+ }
+ }
+ t = t1;
+ }
+ }
+ ++t;
}
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
+ first = t;
}
}
return first;
}
-// sc <type> <expression> # static_cast<type> (expression)
+// pt <expression> <expression> # expr->name
+template <class C>
const char*
-__demangle_tree::__parse_static_cast_expr(const char* first, const char* last)
+parse_arrow_expr(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+ if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
{
- const char* t = __parse_type(first+2, last);
+ const char* t = parse_expression(first+2, last, db);
if (t != first+2)
{
- __node* type = __root_;
- const char* t1 = __parse_expression(t, last);
+ const char* t1 = parse_expression(t, last, db);
if (t1 != t)
{
- if (__make<__static_cast>(type, __root_))
- first = t1;
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += "->";
+ db.names.back().first += tmp;
+ first = t1;
}
}
}
return first;
}
-// st <type> # sizeof (a type)
-
-const char*
-__demangle_tree::__parse_sizeof_type_expr(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 't')
- {
- const char* t = __parse_type(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_sizeof_expression>(__root_))
- first = t;
- }
- }
- return first;
-}
-
-// sZ <template-param> # size of a parameter pack
-
-const char*
-__demangle_tree::__parse_sizeof_param_pack_expr(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
- {
- const char* t = __parse_template_param(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_sizeof_param_pack>(__root_))
- first = t;
- }
- }
- return first;
-}
-
-// sZ <function-param> # size of a function parameter pack
-
-const char*
-__demangle_tree::__parse_sizeof_function_param_pack_expr(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
- {
- const char* t = __parse_function_param(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_sizeof_param_pack>(__root_))
- first = t;
- }
- }
- return first;
-}
-
-// sp <expression> # pack expansion
-
-const char*
-__demangle_tree::__parse_pack_expansion(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__pack_expansion>(__root_))
- first = t;
- }
- }
- return first;
-}
-
-// te <expression> # typeid (expression)
-// ti <type> # typeid (type)
-
-const char*
-__demangle_tree::__parse_typeid_expr(const char* first, const char* last)
-{
- if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
- {
- const char* t;
- if (first[1] == 'e')
- t = __parse_expression(first+2, last);
- else
- t = __parse_type(first+2, last);
- if (t != first+2)
- {
- if (__make<__typeid>(__root_))
- first = t;
- }
- }
- return first;
-}
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
-// tw <expression> # throw expression
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+template <class C>
const char*
-__demangle_tree::__parse_throw_expr(const char* first, const char* last)
+parse_function_type(const char* first, const char* last, C& db)
{
- if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+ if (first != last && *first == 'F')
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ const char* t = first+1;
+ if (t != last)
{
- if (__make<__throw>(__root_))
+ bool externC = false;
+ if (*t == 'Y')
+ {
+ externC = true;
+ if (++t == last)
+ return first;
+ }
+ const char* t1 = parse_type(t, last, db);
+ if (t1 != t)
+ {
+ t = t1;
+ typename C::String sig("(");
+ int ref_qual = 0;
+ while (true)
+ {
+ if (t == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (*t == 'E')
+ {
+ ++t;
+ break;
+ }
+ if (*t == 'v')
+ {
+ ++t;
+ continue;
+ }
+ if (*t == 'R' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 1;
+ ++t;
+ continue;
+ }
+ if (*t == 'O' && t+1 != last && t[1] == 'E')
+ {
+ ref_qual = 2;
+ ++t;
+ continue;
+ }
+ size_t k0 = db.names.size();
+ t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 == t || t1 == last)
+ return first;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (sig.size() > 1)
+ sig += ", ";
+ sig += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ t = t1;
+ }
+ sig += ")";
+ switch (ref_qual)
+ {
+ case 1:
+ sig += " &";
+ break;
+ case 2:
+ sig += " &&";
+ break;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " ";
+ db.names.back().second.insert(0, sig);
first = t;
+ }
}
}
return first;
}
-// <expression> ::= <unary operator-name> <expression>
-// ::= <binary operator-name> <expression> <expression>
-// ::= <ternary operator-name> <expression> <expression> <expression>
-// ::= cl <expression>+ E # call
-// ::= cv <type> <expression> # conversion with one argument
-// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
-// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
-// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// ::= [gs] dl <expression> # delete expression
-// ::= [gs] da <expression> # delete[] expression
-// ::= pp_ <expression> # prefix ++
-// ::= mm_ <expression> # prefix --
-// ::= ti <type> # typeid (type)
-// ::= te <expression> # typeid (expression)
-// ::= dc <type> <expression> # dynamic_cast<type> (expression)
-// ::= sc <type> <expression> # static_cast<type> (expression)
-// ::= cc <type> <expression> # const_cast<type> (expression)
-// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
-// ::= st <type> # sizeof (a type)
-// ::= at <type> # alignof (a type)
-// ::= <template-param>
-// ::= <function-param>
-// ::= dt <expression> <unresolved-name> # expr.name
-// ::= pt <expression> <unresolved-name> # expr->name
-// ::= ds <expression> <expression> # expr.*expr
-// ::= sZ <template-param> # size of a parameter pack
-// ::= sZ <function-param> # size of a function parameter pack
-// ::= sp <expression> # pack expansion
-// ::= tw <expression> # throw expression
-// ::= tr # throw with no operand (rethrow)
-// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
-// # freestanding dependent name (e.g., T::x),
-// # objectless nonstatic member reference
-// ::= <expr-primary>
+// <pointer-to-member-type> ::= M <class type> <member type>
+template <class C>
const char*
-__demangle_tree::__parse_expression(const char* first, const char* last)
+parse_pointer_to_member_type(const char* first, const char* last, C& db)
{
- if (last - first >= 2)
+ if (first != last && *first == 'M')
{
- const char* t = first;
- bool parsed_gs = false;
- if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- switch (*t)
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1)
{
- case 'L':
- t = __parse_expr_primary(first, last);
- break;
- case 'T':
- t = __parse_template_param(first, last);
- break;
- case 'f':
- t = __parse_function_param(first, last);
- break;
- case 'a':
- if (t[1] == 't')
- t = __parse_alignof_expr(first, last);
- break;
- case 'c':
- switch (t[1])
- {
- case 'c':
- t = __parse_const_cast_expr(first, last);
- break;
- case 'l':
- t = __parse_call_expr(first, last);
- break;
- case 'v':
- t = __parse_conversion_expr(first, last);
- break;
- }
- break;
- case 'd':
- switch (t[1])
- {
- case 'a':
- t = __parse_delete_array_expr(first, last);
- break;
- case 'c':
- t = __parse_dynamic_cast_expr(first, last);
- break;
- case 'l':
- t = __parse_delete_expr(first, last);
- break;
- case 's':
- t = __parse_dot_star_expr(first, last);
- break;
- case 't':
- t = __parse_dot_expr(first, last);
- break;
- }
- break;
- case 'm':
- t = __parse_decrement_expr(first, last);
- break;
- case 'n':
- switch (t[1])
- {
- case 'a':
- case 'w':
- t = __parse_new_expr(first, last);
- break;
- }
- break;
- case 'p':
- switch (t[1])
- {
- case 'p':
- t = __parse_increment_expr(first, last);
- break;
- case 't':
- t = __parse_arrow_expr(first, last);
- break;
- }
- break;
- case 'r':
- t = __parse_reinterpret_cast_expr(first, last);
- break;
- case 's':
- switch (t[1])
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
{
- case 'c':
- t = __parse_static_cast_expr(first, last);
- break;
- case 'p':
- t = __parse_pack_expansion(first, last);
- break;
- case 't':
- t = __parse_sizeof_type_expr(first, last);
- break;
- case 'Z':
- if (last - t >= 3)
+ if (db.names.size() < 2)
+ return first;
+ auto func = std::move(db.names.back());
+ db.names.pop_back();
+ auto class_type = std::move(db.names.back());
+ if (func.second.front() == '(')
{
- switch (t[2])
- {
- case 'T':
- t = __parse_sizeof_param_pack_expr(first, last);
- break;
- case 'f':
- t = __parse_sizeof_function_param_pack_expr(first, last);
- break;
- }
+ db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";
+ db.names.back().second = ")" + std::move(func.second);
}
- break;
- }
- break;
- case 't':
- switch (t[1])
- {
- case 'e':
- case 'i':
- t = __parse_typeid_expr(first, last);
- break;
- case 'r':
- if (__make<__rethrow>())
- t = first +2;
- break;
- case 'w':
- t = __parse_throw_expr(first, last);
- break;
+ else
+ {
+ db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";
+ db.names.back().second = std::move(func.second);
+ }
+ first = t2;
}
- break;
- }
- if ((!parsed_gs && t == first) || (parsed_gs && t == first+2))
- {
- int op;
- t = __parse_operator_name(first, last, &op);
- if (t == first)
- first = __parse_unresolved_name(first, last);
- else
- first = t;
}
- else
- first = t;
}
return first;
}
@@ -8163,78 +1682,61 @@ __demangle_tree::__parse_expression(const char* first, const char* last)
// <array-type> ::= A <positive dimension number> _ <element type>
// ::= A [<dimension expression>] _ <element type>
+template <class C>
const char*
-__demangle_tree::__parse_array_type(const char* first, const char* last)
+parse_array_type(const char* first, const char* last, C& db)
{
if (first != last && *first == 'A' && first+1 != last)
{
if (first[1] == '_')
{
- const char* t = __parse_type(first+2, last);
+ const char* t = parse_type(first+2, last, db);
if (t != first+2)
{
- if (__make<__array>(__root_))
- first = t;
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " []");
+ first = t;
}
}
else if ('1' <= first[1] && first[1] <= '9')
{
- size_t dim = static_cast<size_t>(first[1] - '0');
- const char* t = first+2;
- for (; t != last && isdigit(*t); ++t)
- dim = dim * 10 + static_cast<size_t>(*t - '0');
+ const char* t = parse_number(first+1, last);
if (t != last && *t == '_')
{
- const char* t2 = __parse_type(t+1, last);
+ const char* t2 = parse_type(t+1, last, db);
if (t2 != t+1)
{
- if (__make<__array>(__root_, dim))
- first = t2;
+ if (db.names.empty())
+ return first;
+ if (db.names.back().second.substr(0, 2) == " [")
+ db.names.back().second.erase(0, 1);
+ db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
+ first = t2;
}
}
}
else
{
- const char* t = __parse_expression(first+1, last);
+ const char* t = parse_expression(first+1, last, db);
if (t != first+1 && t != last && *t == '_')
{
- __node* dim = __root_;
- const char* t2 = __parse_type(++t, last);
+ const char* t2 = parse_type(++t, last, db);
if (t2 != t)
{
- if (__make<__array>(__root_, dim))
- first = t2;
- }
- }
- }
- }
- return first;
-}
-
-// <class-enum-type> ::= <name>
-
-const char*
-__demangle_tree::__parse_class_enum_type(const char* first, const char* last)
-{
- return __parse_name(first, last);
-}
-
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-const char*
-__demangle_tree::__parse_pointer_to_member_type(const char* first, const char* last)
-{
- if (first != last && *first == 'M')
- {
- const char* t = __parse_type(first+1, last);
- if (t != first+1)
- {
- __node* class_type = __root_;
- const char* t2 = __parse_type(t, last, true, true);
- if (t2 != t)
- {
- if (__make<__pointer_to_member_type>(class_type, __root_))
+ if (db.names.size() < 2)
+ return first;
+ auto type = std::move(db.names.back());
+ db.names.pop_back();
+ auto expr = std::move(db.names.back());
+ db.names.back().first = std::move(type.first);
+ if (type.second.substr(0, 2) == " [")
+ type.second.erase(0, 1);
+ db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);
first = t2;
+ }
}
}
}
@@ -8244,8 +1746,9 @@ __demangle_tree::__parse_pointer_to_member_type(const char* first, const char* l
// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
// ::= DT <expression> E # decltype of an expression (C++0x)
+template <class C>
const char*
-__demangle_tree::__parse_decltype(const char* first, const char* last)
+parse_decltype(const char* first, const char* last, C& db)
{
if (last - first >= 4 && first[0] == 'D')
{
@@ -8254,11 +1757,13 @@ __demangle_tree::__parse_decltype(const char* first, const char* last)
case 't':
case 'T':
{
- const char* t = __parse_expression(first+2, last);
+ const char* t = parse_expression(first+2, last, db);
if (t != first+2 && t != last && *t == 'E')
{
- if (__make<__decltype_node>(__root_))
- first = t+1;
+ if (db.names.empty())
+ return first;
+ db.names.back() = "decltype(" + db.names.back().move_full() + ")";
+ first = t+1;
}
}
break;
@@ -8267,63 +1772,6 @@ __demangle_tree::__parse_decltype(const char* first, const char* last)
return first;
}
-// <template-param> ::= T_ # first template parameter
-// ::= T <parameter-2 non-negative number> _
-
-const char*
-__demangle_tree::__parse_template_param(const char* first, const char* last)
-{
- if (last - first >= 2)
- {
- if (*first == 'T')
- {
- if (first[1] == '_')
- {
- if (__t_begin_ != __t_end_)
- {
- if (__make<__sub>(*__t_begin_))
- first += 2;
- }
- else
- {
- if (__make<__sub>(size_t(0)))
- {
- first += 2;
- __fix_forward_references_ = true;
- }
- }
- }
- else if (isdigit(first[1]))
- {
- const char* t = first+1;
- size_t sub = static_cast<size_t>(*t - '0');
- for (++t; t != last && isdigit(*t); ++t)
- {
- sub *= 10;
- sub += static_cast<size_t>(*t - '0');
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < static_cast<size_t>(__t_end_ - __t_begin_))
- {
- if (__make<__sub>(__t_begin_[sub]))
- first = t+1;
- }
- else
- {
- if (__make<__sub>(sub))
- {
- first = t+1;
- __fix_forward_references_ = true;
- }
- }
- }
- }
- }
- return first;
-}
-
// extension:
// <vector-type> ::= Dv <positive dimension number> _
// <extended element type>
@@ -8331,58 +1779,65 @@ __demangle_tree::__parse_template_param(const char* first, const char* last)
// <extended element type> ::= <element type>
// ::= p # AltiVec vector pixel
+template <class C>
const char*
-__demangle_tree::__parse_vector_type(const char* first, const char* last)
+parse_vector_type(const char* first, const char* last, C& db)
{
if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
{
if ('1' <= first[2] && first[2] <= '9')
{
- const char* t = first+3;
- while (*t != '_')
- {
- if (!isdigit(*t) || ++t == last)
- return first;
- }
+ const char* t = parse_number(first+2, last);
+ if (t == last || *t != '_')
+ return first;
const char* num = first + 2;
size_t sz = static_cast<size_t>(t - num);
if (++t != last)
{
if (*t != 'p')
{
- const char* t1 = __parse_type(t, last);
+ const char* t1 = parse_type(t, last, db);
if (t1 != t)
{
- if (__make<__vector_type>(__root_, num, sz))
- first = t1;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
+ first = t1;
}
}
else
{
++t;
- if (__make<__vector_type>((__node*)0, num, sz))
- first = t;
+ db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]");
+ first = t;
}
}
}
else
{
- __node* num = 0;
+ typename C::String num;
const char* t1 = first+2;
if (*t1 != '_')
{
- const char* t = __parse_expression(t1, last);
+ const char* t = parse_expression(t1, last, db);
if (t != t1)
- num = __root_;
- t1 = t;
+ {
+ if (db.names.empty())
+ return first;
+ num = db.names.back().move_full();
+ db.names.pop_back();
+ t1 = t;
+ }
}
if (t1 != last && *t1 == '_' && ++t1 != last)
{
- const char* t = __parse_type(t1, last);
+ const char* t = parse_type(t1, last, db);
if (t != t1)
{
- if (__make<__vector_type>(__root_, num))
- first = t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " vector[" + num + "]";
+ first = t;
}
}
}
@@ -8407,1905 +1862,2016 @@ __demangle_tree::__parse_vector_type(const char* first, const char* last)
// ::= G <type> # imaginary (C 2000)
// ::= Dp <type> # pack expansion (C++0x)
// ::= U <source-name> <type> # vendor extended type qualifier
+// extension := U <objc-name> <objc-type> # objc-type<identifier>
// extension := <vector-type> # <vector-type> starts with Dv
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+
+template <class C>
const char*
-__demangle_tree::__parse_type(const char* first, const char* last,
- bool try_to_parse_template_args,
- bool look_for_ref_quals)
+parse_type(const char* first, const char* last, C& db)
{
- unsigned cv = 0;
- const char* t = __parse_cv_qualifiers(first, last, cv, look_for_ref_quals);
- if (t != first)
+ if (first != last)
{
- const char* t2 = __parse_type(t, last, try_to_parse_template_args);
- if (t2 != t)
+ switch (*first)
{
- if (__make<__cv_qualifiers>(cv, __root_))
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
+ case 'r':
+ case 'V':
+ case 'K':
+ {
+ unsigned cv = 0;
+ const char* t = parse_cv_qualifiers(first, last, cv);
+ if (t != first)
{
- *__sub_end_++ = __root_;
- first = t2;
+ bool is_function = *t == 'F';
+ size_t k0 = db.names.size();
+ const char* t1 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t1 != t)
+ {
+ if (is_function)
+ db.subs.pop_back();
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (is_function)
+ {
+ size_t p = db.names[k].second.size();
+ if (db.names[k].second[p-2] == '&')
+ p -= 3;
+ else if (db.names[k].second.back() == '&')
+ p -= 2;
+ if (cv & 1)
+ {
+ db.names[k].second.insert(p, " const");
+ p += 6;
+ }
+ if (cv & 2)
+ {
+ db.names[k].second.insert(p, " volatile");
+ p += 9;
+ }
+ if (cv & 4)
+ db.names[k].second.insert(p, " restrict");
+ }
+ else
+ {
+ if (cv & 1)
+ db.names[k].first.append(" const");
+ if (cv & 2)
+ db.names[k].first.append(" volatile");
+ if (cv & 4)
+ db.names[k].first.append(" restrict");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t1;
+ }
}
+ }
+ break;
+ default:
+ {
+ const char* t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ switch (*first)
+ {
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'C':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" complex");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'F':
+ t = parse_function_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'G':
+ t = parse_type(first+1, last, db);
+ if (t != first+1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append(" imaginary");
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'M':
+ t = parse_pointer_to_member_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ first = t;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ }
+ break;
+ case 'O':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'P':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")
+ {
+ db.names[k].first.append("*");
+ }
+ else
+ {
+ db.names[k].first.replace(0, 11, "id");
+ }
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'R':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+1, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+1)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (db.names[k].second.substr(0, 2) == " [")
+ {
+ db.names[k].first += " (";
+ db.names[k].second.insert(0, ")");
+ }
+ else if (db.names[k].second.front() == '(')
+ {
+ db.names[k].first += "(";
+ db.names[k].second.insert(0, ")");
+ }
+ db.names[k].first.append("&");
+ db.subs.back().push_back(db.names[k]);
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'T':
+ {
+ size_t k0 = db.names.size();
+ t = parse_template_param(first, last, db);
+ size_t k1 = db.names.size();
+ if (t != first)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ if (db.try_to_parse_template_args && k1 == k0+1)
+ {
+ const char* t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ {
+ auto args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += std::move(args);
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t = t1;
+ }
+ }
+ first = t;
+ }
+ break;
+ }
+ case 'U':
+ if (first+1 != last)
+ {
+ t = parse_source_name(first+1, last, db);
+ if (t != first+1)
+ {
+ const char* t2 = parse_type(t, last, db);
+ if (t2 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto type = db.names.back().move_full();
+ db.names.pop_back();
+ if (db.names.back().first.substr(0, 9) != "objcproto")
+ {
+ db.names.back() = type + " " + db.names.back().move_full();
+ }
+ else
+ {
+ auto proto = db.names.back().move_full();
+ db.names.pop_back();
+ t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);
+ if (t != proto.data() + 9)
+ {
+ db.names.back() = type + "<" + db.names.back().move_full() + ">";
+ }
+ else
+ {
+ db.names.push_back(type + " " + proto);
+ }
+ }
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t2;
+ }
+ }
+ }
+ break;
+ case 'S':
+ if (first+1 != last && first[1] == 't')
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ else
+ {
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ // Parsed a substitution. If the substitution is a
+ // <template-param> it might be followed by <template-args>.
+ t = parse_template_args(first, last, db);
+ if (t != first)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto template_args = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += template_args;
+ // Need to create substitution for <template-template-param> <template-args>
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'p':
+ {
+ size_t k0 = db.names.size();
+ t = parse_type(first+2, last, db);
+ size_t k1 = db.names.size();
+ if (t != first+2)
+ {
+ db.subs.emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.subs.back().push_back(db.names[k]);
+ first = t;
+ return first;
+ }
+ break;
+ }
+ case 't':
+ case 'T':
+ t = parse_decltype(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ case 'v':
+ t = parse_vector_type(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ return first;
+ }
+ break;
+ }
+ }
+ // drop through
+ default:
+ // must check for builtin-types before class-enum-types to avoid
+ // ambiguities with operator-names
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ t = parse_name(first, last, db);
+ if (t != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ first = t;
+ }
+ }
+ break;
+ }
+ }
+ break;
}
}
- return first;
}
- if (first != last)
+ return first;
+}
+
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= v <digit> <source-name> # vendor extended operator
+
+template <class C>
+const char*
+parse_operator_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
{
- switch (*first)
+ switch (first[0])
{
- case 'A':
- t = __parse_array_type(first, last);
- if (t != first)
+ case 'a':
+ switch (first[1])
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
+ case 'a':
+ db.names.push_back("operator&&");
+ first += 2;
+ break;
+ case 'd':
+ case 'n':
+ db.names.push_back("operator&");
+ first += 2;
+ break;
+ case 'N':
+ db.names.push_back("operator&=");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator=");
+ first += 2;
+ break;
}
break;
- case 'C':
- t = __parse_type(first+1, last, try_to_parse_template_args);
- if (t != first+1)
+ case 'c':
+ switch (first[1])
{
- if (__make<__d_complex>(__root_))
+ case 'l':
+ db.names.push_back("operator()");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator,");
+ first += 2;
+ break;
+ case 'o':
+ db.names.push_back("operator~");
+ first += 2;
+ break;
+ case 'v':
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
+ bool try_to_parse_template_args = db.try_to_parse_template_args;
+ db.try_to_parse_template_args = false;
+ const char* t = parse_type(first+2, last, db);
+ db.try_to_parse_template_args = try_to_parse_template_args;
+ if (t != first+2)
{
- *__sub_end_++ = __root_;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
+ db.parsed_ctor_dtor_cv = true;
first = t;
}
}
- return first;
+ break;
}
break;
- case 'F':
- t = __parse_function_type(first, last);
- if (t != first)
+ case 'd':
+ switch (first[1])
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
+ case 'a':
+ db.names.push_back("operator delete[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator delete");
+ first += 2;
+ break;
+ case 'v':
+ db.names.push_back("operator/");
+ first += 2;
+ break;
+ case 'V':
+ db.names.push_back("operator/=");
+ first += 2;
+ break;
}
break;
- case 'G':
- t = __parse_type(first+1, last, try_to_parse_template_args);
- if (t != first+1)
+ case 'e':
+ switch (first[1])
{
- if (__make<__imaginary>(__root_))
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
- return first;
+ case 'o':
+ db.names.push_back("operator^");
+ first += 2;
+ break;
+ case 'O':
+ db.names.push_back("operator^=");
+ first += 2;
+ break;
+ case 'q':
+ db.names.push_back("operator==");
+ first += 2;
+ break;
}
break;
- case 'M':
- t = __parse_pointer_to_member_type(first, last);
- if (t != first)
+ case 'g':
+ switch (first[1])
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
+ case 'e':
+ db.names.push_back("operator>=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator>");
+ first += 2;
+ break;
}
break;
- case 'O':
- t = __parse_type(first+1, last, try_to_parse_template_args);
- if (t != first+1)
+ case 'i':
+ if (first[1] == 'x')
{
- if (__make<__rvalue_reference_to>(__root_))
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
- return first;
+ db.names.push_back("operator[]");
+ first += 2;
}
break;
- case 'P':
- t = __parse_type(first+1, last, try_to_parse_template_args);
- if (t != first+1)
+ case 'l':
+ switch (first[1])
{
- if (__make<__pointer_to>(__root_))
+ case 'e':
+ db.names.push_back("operator<=");
+ first += 2;
+ break;
+ case 'i':
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
{
- *__sub_end_++ = __root_;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator\"\" ");
first = t;
}
}
- return first;
+ break;
+ case 's':
+ db.names.push_back("operator<<");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator<<=");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator<");
+ first += 2;
+ break;
}
break;
- case 'R':
- t = __parse_type(first+1, last, try_to_parse_template_args);
- if (t != first+1)
+ case 'm':
+ switch (first[1])
{
- if (__make<__lvalue_reference_to>(__root_))
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
- return first;
+ case 'i':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 'I':
+ db.names.push_back("operator-=");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator*");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator*=");
+ first += 2;
+ break;
+ case 'm':
+ db.names.push_back("operator--");
+ first += 2;
+ break;
}
break;
- case 'T':
- t = __parse_template_param(first, last);
- if (t != first)
+ case 'n':
+ switch (first[1])
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- if (try_to_parse_template_args)
- {
- const char* t2 = __parse_template_args(t, last);
- if (t2 != t)
- {
- if (__sub_end_ < __sub_cap_)
- {
- *__sub_end_++ = __root_;
- first = t2;
- }
- else
- __status_ = memory_alloc_failure;
- }
- else
- {
- first = t;
- }
- }
- else
- {
- first = t;
- }
- }
+ case 'a':
+ db.names.push_back("operator new[]");
+ first += 2;
+ break;
+ case 'e':
+ db.names.push_back("operator!=");
+ first += 2;
+ break;
+ case 'g':
+ db.names.push_back("operator-");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator!");
+ first += 2;
+ break;
+ case 'w':
+ db.names.push_back("operator new");
+ first += 2;
+ break;
}
break;
- case 'U':
- if (first+1 != last)
+ case 'o':
+ switch (first[1])
{
- t = __parse_source_name(first+1, last);
- if (t != first+1)
- {
- __node* name = __root_;
- const char* t2 = __parse_type(t, last, try_to_parse_template_args);
- if (t2 != t)
- {
- if (__make<__extended_qualifier>(name, __root_))
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t2;
- }
- }
- return first;
- }
- }
+ case 'o':
+ db.names.push_back("operator||");
+ first += 2;
+ break;
+ case 'r':
+ db.names.push_back("operator|");
+ first += 2;
+ break;
+ case 'R':
+ db.names.push_back("operator|=");
+ first += 2;
+ break;
}
break;
- case 'S':
- if (first+1 != last && first[1] == 't')
+ case 'p':
+ switch (first[1])
{
- t = __parse_class_enum_type(first, last);
- if (t != first)
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
+ case 'm':
+ db.names.push_back("operator->*");
+ first += 2;
+ break;
+ case 'l':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 'L':
+ db.names.push_back("operator+=");
+ first += 2;
+ break;
+ case 'p':
+ db.names.push_back("operator++");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator+");
+ first += 2;
+ break;
+ case 't':
+ db.names.push_back("operator->");
+ first += 2;
+ break;
}
- else
+ break;
+ case 'q':
+ if (first[1] == 'u')
{
- t = __parse_substitution(first, last);
- if (t != first)
+ db.names.push_back("operator?");
+ first += 2;
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ db.names.push_back("operator%");
+ first += 2;
+ break;
+ case 'M':
+ db.names.push_back("operator%=");
+ first += 2;
+ break;
+ case 's':
+ db.names.push_back("operator>>");
+ first += 2;
+ break;
+ case 'S':
+ db.names.push_back("operator>>=");
+ first += 2;
+ break;
+ }
+ break;
+ case 'v':
+ if (std::isdigit(first[1]))
+ {
+ const char* t = parse_source_name(first+2, last, db);
+ if (t != first+2)
{
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "operator ");
first = t;
- // Parsed a substitution. If the substitution is a
- // <template-param> it might be followed by <template-args>.
- t = __parse_template_args(first, last);
- if (t != first)
- {
- // Need to create substitution for <template-template-param> <template-args>
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
}
}
break;
- case 'D':
- if (first+1 != last)
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db)
+{
+ const char* t = parse_number(first, last);
+ if (t != first && t != last && *t == 'E')
+ {
+ if (lit.size() > 3)
+ db.names.push_back("(" + lit + ")");
+ else
+ db.names.emplace_back();
+ if (*first == 'n')
+ {
+ db.names.back().first += '-';
+ ++first;
+ }
+ db.names.back().first.append(first, t);
+ if (lit.size() <= 3)
+ db.names.back().first += lit;
+ first = t+1;
+ }
+ return first;
+}
+
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+
+template <class C>
+const char*
+parse_expr_primary(const char* first, const char* last, C& db)
+{
+ if (last - first >= 4 && *first == 'L')
+ {
+ switch (first[1])
+ {
+ case 'w':
{
- switch (first[1])
+ const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'b':
+ if (first[3] == 'E')
+ {
+ switch (first[2])
{
- case 'p':
- t = __parse_type(first+2, last, try_to_parse_template_args);
- if (t != first+1)
- {
- if (__make<__pack_expansion>(__root_))
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- }
- return first;
- }
- break;
- case 't':
- case 'T':
- t = __parse_decltype(first, last);
- if (t != first)
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- return first;
- }
+ case '0':
+ db.names.push_back("false");
+ first += 4;
break;
- case 'v':
- t = __parse_vector_type(first, last);
- if (t != first)
- {
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
- else
- {
- *__sub_end_++ = __root_;
- first = t;
- }
- return first;
- }
+ case '1':
+ db.names.push_back("true");
+ first += 4;
break;
}
}
- // drop through
- default:
- // must check for builtin-types before class-enum-types to avoid
- // ambiguities with operator-names
- t = __parse_builtin_type(first, last);
- if (t != first)
+ break;
+ case 'c':
{
+ const char* t = parse_integer_literal(first+2, last, "char", db);
+ if (t != first+2)
first = t;
}
- else
+ break;
+ case 'a':
{
- t = __parse_class_enum_type(first, last);
- if (t != first)
+ const char* t = parse_integer_literal(first+2, last, "signed char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'h':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 's':
+ {
+ const char* t = parse_integer_literal(first+2, last, "short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 't':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'i':
+ {
+ const char* t = parse_integer_literal(first+2, last, "", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'j':
+ {
+ const char* t = parse_integer_literal(first+2, last, "u", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'l':
+ {
+ const char* t = parse_integer_literal(first+2, last, "l", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'm':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ul", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'x':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ll", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'y':
+ {
+ const char* t = parse_integer_literal(first+2, last, "ull", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'n':
+ {
+ const char* t = parse_integer_literal(first+2, last, "__int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'o':
+ {
+ const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'f':
+ {
+ const char* t = parse_floating_number<float>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'd':
+ {
+ const char* t = parse_floating_number<double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case 'e':
+ {
+ const char* t = parse_floating_number<long double>(first+2, last, db);
+ if (t != first+2)
+ first = t;
+ }
+ break;
+ case '_':
+ if (first[2] == 'Z')
+ {
+ const char* t = parse_encoding(first+3, last, db);
+ if (t != first+3 && t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ break;
+ default:
+ {
+ // might be named type
+ const char* t = parse_type(first+1, last, db);
+ if (t != first+1 && t != last)
{
- if (__sub_end_ == __sub_cap_)
- __status_ = memory_alloc_failure;
+ if (*t != 'E')
+ {
+ const char* n = t;
+ for (; n != last && isdigit(*n); ++n)
+ ;
+ if (n != t && n != last && *n == 'E')
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
+ first = n+1;
+ break;
+ }
+ }
else
{
- *__sub_end_++ = __root_;
- first = t;
+ first = t+1;
+ break;
}
}
}
- break;
}
}
return first;
}
-// <number> ::= [n] <non-negative decimal integer>
+template <class String>
+String
+base_name(String& s)
+{
+ if (s.empty())
+ return s;
+ if (s == "std::string")
+ {
+ s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
+ return "basic_string";
+ }
+ if (s == "std::istream")
+ {
+ s = "std::basic_istream<char, std::char_traits<char> >";
+ return "basic_istream";
+ }
+ if (s == "std::ostream")
+ {
+ s = "std::basic_ostream<char, std::char_traits<char> >";
+ return "basic_ostream";
+ }
+ if (s == "std::iostream")
+ {
+ s = "std::basic_iostream<char, std::char_traits<char> >";
+ return "basic_iostream";
+ }
+ const char* const pf = s.data();
+ const char* pe = pf + s.size();
+ if (pe[-1] == '>')
+ {
+ unsigned c = 1;
+ while (true)
+ {
+ if (--pe == pf)
+ return String();
+ if (pe[-1] == '<')
+ {
+ if (--c == 0)
+ {
+ --pe;
+ break;
+ }
+ }
+ else if (pe[-1] == '>')
+ ++c;
+ }
+ }
+ const char* p0 = pe - 1;
+ for (; p0 != pf; --p0)
+ {
+ if (*p0 == ':')
+ {
+ ++p0;
+ break;
+ }
+ }
+ return String(p0, pe);
+}
+
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+template <class C>
const char*
-__demangle_tree::__parse_number(const char* first, const char* last)
+parse_ctor_dtor_name(const char* first, const char* last, C& db)
{
- if (first != last)
+ if (last-first >= 2 && !db.names.empty())
{
- const char* t = first;
- if (*t == 'n')
- ++t;
- if (t != last)
+ switch (first[0])
{
- if (*t == '0')
+ case 'C':
+ switch (first[1])
{
- first = t+1;
+ case '1':
+ case '2':
+ case '3':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back(base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
}
- else if ('1' <= *t && *t <= '9')
+ break;
+ case 'D':
+ switch (first[1])
{
- first = t+1;
- while (first != last && isdigit(*first))
- ++first;
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ if (db.names.empty())
+ return first;
+ db.names.push_back("~" + base_name(db.names.back().first));
+ first += 2;
+ db.parsed_ctor_dtor_cv = true;
+ break;
}
+ break;
}
}
return first;
}
-// <call-offset> ::= h <nv-offset> _
-// ::= v <v-offset> _
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+// ::= <closure-type-name>
//
-// <nv-offset> ::= <offset number>
-// # non-virtual base override
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
//
-// <v-offset> ::= <offset number> _ <virtual offset number>
-// # virtual base override, with vcall offset
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+template <class C>
const char*
-__demangle_tree::__parse_call_offset(const char* first, const char* last)
+parse_unnamed_type_name(const char* first, const char* last, C& db)
{
- if (first != last)
+ if (last - first > 2 && first[0] == 'U')
{
- switch (*first)
+ char type = first[1];
+ switch (type)
{
- case 'h':
+ case 't':
+ {
+ db.names.push_back(typename C::String("'unnamed"));
+ const char* t0 = first+2;
+ if (t0 == last)
{
- const char* t = __parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- first = t + 1;
+ db.names.pop_back();
+ return first;
}
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.append(t0, t1);
+ t0 = t1;
+ }
+ db.names.back().first.push_back('\'');
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ first = t0 + 1;
+ }
break;
- case 'v':
+ case 'l':
+ {
+ db.names.push_back(typename C::String("'lambda'("));
+ const char* t0 = first+2;
+ if (first[2] == 'v')
{
- const char* t = __parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
+ db.names.back().first += ')';
+ ++t0;
+ }
+ else
{
- const char* t2 = __parse_number(++t, last);
- if (t2 != t && t2 != last && *t2 == '_')
- first = t2 + 1;
+ const char* t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append(tmp);
+ t0 = t1;
+ while (true)
+ {
+ t1 = parse_type(t0, last, db);
+ if (t1 == t0)
+ break;
+ if (db.names.size() < 2)
+ return first;
+ tmp = db.names.back().move_full();
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ db.names.back().first.append(", ");
+ db.names.back().first.append(tmp);
+ }
+ t0 = t1;
+ }
+ db.names.back().first.append(")");
+ }
+ if (t0 == last || *t0 != 'E')
+ {
+ db.names.pop_back();
+ return first;
+ }
+ ++t0;
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
+ }
+ if (std::isdigit(*t0))
+ {
+ const char* t1 = t0 + 1;
+ while (t1 != last && std::isdigit(*t1))
+ ++t1;
+ db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1);
+ t0 = t1;
}
+ if (t0 == last || *t0 != '_')
+ {
+ db.names.pop_back();
+ return first;
}
+ first = t0 + 1;
+ }
break;
}
}
return first;
}
-// <special-name> ::= TV <type> # virtual table
-// ::= TT <type> # VTT structure (construction vtable index)
-// ::= TI <type> # typeinfo structure
-// ::= TS <type> # typeinfo name (null-terminated byte string)
-// ::= Tc <call-offset> <call-offset> <base encoding>
-// # base is the nominal target function of thunk
-// # first call-offset is 'this' adjustment
-// # second call-offset is result adjustment
-// ::= T <call-offset> <base encoding>
-// # base is the nominal target function of thunk
-// ::= GV <object name> # Guard variable for one-time initialization
-// # No <type>
-// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
-// extension ::= GR <object name> # reference temporary for object
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+template <class C>
const char*
-__demangle_tree::__parse_special_name(const char* first, const char* last)
+parse_unqualified_name(const char* first, const char* last, C& db)
{
- if (last - first > 2)
+ if (first != last)
{
const char* t;
switch (*first)
{
- case 'T':
- switch (first[1])
- {
- case 'V':
- // TV <type> # virtual table
- t = __parse_type(first+2, last);
- if (t != first+2 && __make<__vtable>(__root_))
- first = t;
- break;
- case 'T':
- // TT <type> # VTT structure (construction vtable index)
- t = __parse_type(first+2, last);
- if (t != first+2 && __make<__VTT>(__root_))
- first = t;
- break;
- case 'I':
- // TI <type> # typeinfo structure
- t = __parse_type(first+2, last);
- if (t != first+2 && __make<__typeinfo>(__root_))
- first = t;
- break;
- case 'S':
- // TS <type> # typeinfo name (null-terminated byte string)
- t = __parse_type(first+2, last);
- if (t != first+2 && __make<__typeinfo_name>(__root_))
- first = t;
- break;
- case 'c':
- // Tc <call-offset> <call-offset> <base encoding>
- {
- const char* t0 = __parse_call_offset(first+2, last);
- if (t0 == first+2)
- break;
- const char* t1 = __parse_call_offset(t0, last);
- if (t1 == t0)
- break;
- t = __parse_encoding(t1, last);
- if (t != t1 && __make<__covariant_return_thunk>(__root_))
- first = t;
- }
- break;
- case 'C':
- // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
- t = __parse_type(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t0 = __parse_number(t, last);
- if (t0 != t && t0 != last && *t0 == '_')
- {
- const char* t1 = __parse_type(++t0, last);
- if (t1 != t0)
- {
- if (__make<__construction_vtable>(__root_, op1))
- first = t1;
- }
- }
- }
- break;
- default:
- // T <call-offset> <base encoding>
- {
- const char* t0 = __parse_call_offset(first+1, last);
- if (t0 == first+1)
- break;
- t = __parse_encoding(t0, last);
- if (t != t0)
- {
- if (first[2] == 'v')
- {
- if (__make<__virtual_thunk>(__root_))
- first = t;
- }
- else
- {
- if (__make<__non_virtual_thunk>(__root_))
- first = t;
- }
- }
- }
- break;
- }
+ case 'C':
+ case 'D':
+ t = parse_ctor_dtor_name(first, last, db);
+ if (t != first)
+ first = t;
break;
- case 'G':
- switch (first[1])
+ case 'U':
+ t = parse_unnamed_type_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = parse_source_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ default:
+ t = parse_operator_name(first, last, db);
+ if (t != first)
+ first = t;
+ break;
+ };
+ }
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+template <class C>
+const char*
+parse_unscoped_name(const char* first, const char* last, C& db)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ bool St = false;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ St = true;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0)
+ {
+ if (St)
{
- case 'V':
- // GV <object name> # Guard variable for one-time initialization
- t = __parse_name(first+2, last);
- if (t != first+2 && __make<__guard_variable>(__root_))
- first = t;
- break;
- case 'R':
- // extension ::= GR <object name> # reference temporary for object
- t = __parse_name(first+2, last);
- if (t != first+2 && __make<__reference_temporary>(__root_))
- first = t;
- break;
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "std::");
}
- break;
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// at <type> # alignof (a type)
+
+template <class C>
+const char*
+parse_alignof_type(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ {
+ const char* t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
}
}
return first;
}
-// <operator-name>
-// ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= at # alignof (a type)
-// ::= az # alignof (an expression)
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
-// ::= ls # <<
-// ::= lS # <<=
-// ::= lt # <
-// ::= mi # -
-// ::= mI # -=
-// ::= ml # *
-// ::= mL # *=
-// ::= mm # -- (postfix in <expression> context)
-// ::= na # new[]
-// ::= ne # !=
-// ::= ng # - (unary)
-// ::= nt # !
-// ::= nw # new
-// ::= oo # ||
-// ::= or # |
-// ::= oR # |=
-// ::= pm # ->*
-// ::= pl # +
-// ::= pL # +=
-// ::= pp # ++ (postfix in <expression> context)
-// ::= ps # + (unary)
-// ::= pt # ->
-// ::= qu # ?
-// ::= rm # %
-// ::= rM # %=
-// ::= rs # >>
-// ::= rS # >>=
-// ::= st # sizeof (a type)
-// ::= sz # sizeof (an expression)
-// ::= v <digit> <source-name> # vendor extended operator
+// az <expression> # alignof (a expression)
+
+template <class C>
+const char*
+parse_alignof_expr(const char* first, const char* last, C& db)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
+ {
+ const char* t = parse_expression(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
+ first = t;
+ }
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_noexcept_expression(const char* first, const char* last, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+
+template <class C>
+const char*
+parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = op + "(" + db.names.back().move_full() + ")";
+ first = t1;
+ }
+ return first;
+}
+template <class C>
const char*
-__demangle_tree::__parse_operator_name(const char* first, const char* last, int* type)
+parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db)
+{
+ const char* t1 = parse_expression(first, last, db);
+ if (t1 != first)
+ {
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ auto& nm = db.names.back().first;
+ nm.clear();
+ if (op == ">")
+ nm += '(';
+ nm += "(" + op1 + ") " + op + " (" + op2 + ")";
+ if (op == ">")
+ nm += ')';
+ first = t2;
+ }
+ else
+ db.names.pop_back();
+ }
+ return first;
+}
+
+// <expression> ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <ternary operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E # call
+// ::= cv <type> <expression> # conversion with one argument
+// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
+// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// ::= [gs] dl <expression> # delete expression
+// ::= [gs] da <expression> # delete[] expression
+// ::= pp_ <expression> # prefix ++
+// ::= mm_ <expression> # prefix --
+// ::= ti <type> # typeid (type)
+// ::= te <expression> # typeid (expression)
+// ::= dc <type> <expression> # dynamic_cast<type> (expression)
+// ::= sc <type> <expression> # static_cast<type> (expression)
+// ::= cc <type> <expression> # const_cast<type> (expression)
+// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+// ::= st <type> # sizeof (a type)
+// ::= sz <expression> # sizeof (an expression)
+// ::= at <type> # alignof (a type)
+// ::= az <expression> # alignof (an expression)
+// ::= nx <expression> # noexcept (expression)
+// ::= <template-param>
+// ::= <function-param>
+// ::= dt <expression> <unresolved-name> # expr.name
+// ::= pt <expression> <unresolved-name> # expr->name
+// ::= ds <expression> <expression> # expr.*expr
+// ::= sZ <template-param> # size of a parameter pack
+// ::= sZ <function-param> # size of a function parameter pack
+// ::= sp <expression> # pack expansion
+// ::= tw <expression> # throw expression
+// ::= tr # throw with no operand (rethrow)
+// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
+// # freestanding dependent name (e.g., T::x),
+// # objectless nonstatic member reference
+// ::= <expr-primary>
+
+template <class C>
+const char*
+parse_expression(const char* first, const char* last, C& db)
{
if (last - first >= 2)
{
- switch (*first)
+ const char* t = first;
+ bool parsed_gs = false;
+ if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
{
+ t += 2;
+ parsed_gs = true;
+ }
+ switch (*t)
+ {
+ case 'L':
+ first = parse_expr_primary(first, last, db);
+ break;
+ case 'T':
+ first = parse_template_param(first, last, db);
+ break;
+ case 'f':
+ first = parse_function_param(first, last, db);
+ break;
case 'a':
- switch (first[1])
+ switch (t[1])
{
case 'a':
- // &&
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_logical_and>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_logical_and>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "&&", db);
+ if (t != first+2)
+ first = t;
break;
case 'd':
- // & (unary)
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_addressof>(__root_))
- {
- *type = 1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_addressof>())
- first += 2;
- }
+ t = parse_prefix_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
break;
case 'n':
- // &
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_bit_and>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_bit_and>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "&", db);
+ if (t != first+2)
+ first = t;
break;
case 'N':
- // &=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_and_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_and_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "&=", db);
+ if (t != first+2)
+ first = t;
break;
case 'S':
- // =
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "=", db);
+ if (t != first+2)
+ first = t;
break;
case 't':
- // alignof (a type)
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_alignof_type>(__root_))
- {
- *type = -1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_alignof_type>())
- first += 2;
- }
+ first = parse_alignof_type(first, last, db);
break;
case 'z':
- // alignof (an expression)
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_alignof_expression>(__root_))
- {
- *type = -1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_alignof_expression>())
- first += 2;
- }
+ first = parse_alignof_expr(first, last, db);
break;
}
break;
case 'c':
- switch (first[1])
+ switch (t[1])
{
+ case 'c':
+ first = parse_const_cast_expr(first, last, db);
+ break;
case 'l':
- // ()
- if (__make<__operator_paren>())
- {
- first += 2;
- if (type)
- *type = -1;
- }
+ first = parse_call_expr(first, last, db);
break;
case 'm':
- // ,
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_comma>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_comma>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, ",", db);
+ if (t != first+2)
+ first = t;
break;
case 'o':
- // ~
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_tilda>(__root_))
- {
- *type = 1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_tilda>())
- first += 2;
- }
+ t = parse_prefix_expression(first+2, last, "~", db);
+ if (t != first+2)
+ first = t;
break;
case 'v':
- // cast <type>
- {
- const char* t = __parse_type(first+2, last, false, true);
- if (t != first+2)
- {
- __node* cast_type = __root_;
- if (type)
- {
- const char* t2 = __parse_expression(t, last);
- if (t2 != t)
- {
- if (__make<__operator_cast>(cast_type, __root_))
- {
- *type = -1;
- first = t2;
- }
- }
- }
- else
- {
- if (__make<__operator_cast>(cast_type))
- first = t;
- }
- }
- }
+ first = parse_conversion_expr(first, last, db);
break;
}
break;
case 'd':
- switch (first[1])
+ switch (t[1])
{
case 'a':
- // delete[]
- if (__make<__operator_delete_array>())
{
- first += 2;
- if (type)
- *type = -1;
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete[] " + db.names.back().move_full();
+ first = t1;
+ }
}
break;
+ case 'c':
+ first = parse_dynamic_cast_expr(first, last, db);
+ break;
case 'e':
- // * (unary)
- if (type)
+ t = parse_prefix_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
+ break;
+ case 'l':
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ const char* t1 = parse_expression(t+2, last, db);
+ if (t1 != t+2)
{
- if (__make<__operator_dereference>(__root_))
- {
- *type = 1;
- first = t;
- }
+ if (db.names.empty())
+ return first;
+ db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
+ "delete " + db.names.back().move_full();
+ first = t1;
}
}
- else
- {
- if (__make<__operator_dereference>())
- first += 2;
- }
break;
- case 'l':
- // delete
- if (__make<__operator_delete>())
- {
- first += 2;
- if (type)
- *type = -1;
- }
+ case 'n':
+ return parse_unresolved_name(first, last, db);
+ case 's':
+ first = parse_dot_star_expr(first, last, db);
+ break;
+ case 't':
+ first = parse_dot_expr(first, last, db);
break;
case 'v':
- // /
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_divide>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_divide>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "/", db);
+ if (t != first+2)
+ first = t;
break;
case 'V':
- // /=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_divide_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_divide_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "/=", db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 'e':
- switch (first[1])
+ switch (t[1])
{
case 'o':
- // ^
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_xor>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_xor>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "^", db);
+ if (t != first+2)
+ first = t;
break;
case 'O':
- // ^=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_xor_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_xor_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "^=", db);
+ if (t != first+2)
+ first = t;
break;
case 'q':
- // ==
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_equality>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_equality>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "==", db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 'g':
- switch (first[1])
+ switch (t[1])
{
case 'e':
- // >=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_greater_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_greater_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, ">=", db);
+ if (t != first+2)
+ first = t;
break;
case 't':
- // >
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_greater>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_greater>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, ">", db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 'i':
- // []
- if (first[1] == 'x' && __make<__operator_brackets>())
+ if (t[1] == 'x')
+ {
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
{
- first += 2;
- if (type)
- *type = -1;
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ")[" + op2 + "]";
+ first = t2;
+ }
+ else
+ db.names.pop_back();
}
+ }
break;
case 'l':
- switch (first[1])
+ switch (t[1])
{
case 'e':
- // <=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_less_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_less_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "<=", db);
+ if (t != first+2)
+ first = t;
break;
case 's':
- // <<
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_left_shift>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_left_shift>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "<<", db);
+ if (t != first+2)
+ first = t;
break;
case 'S':
- // <<=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_left_shift_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_left_shift_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "<<=", db);
+ if (t != first+2)
+ first = t;
break;
case 't':
- // <
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_less>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_less>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "<", db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 'm':
- switch (first[1])
+ switch (t[1])
{
case 'i':
- // -
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_minus>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_minus>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
break;
case 'I':
- // -=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_minus_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_minus_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "-=", db);
+ if (t != first+2)
+ first = t;
break;
case 'l':
- // *
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_times>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_times>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "*", db);
+ if (t != first+2)
+ first = t;
break;
case 'L':
- // *=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_times_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_times_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "*=", db);
+ if (t != first+2)
+ first = t;
break;
case 'm':
- // -- (postfix in <expression> context)
- if (type)
+ if (first+2 != last && first[2] == '_')
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_decrement>(false, __root_))
- {
- *type = 1;
- first = t;
- }
- }
+ t = parse_prefix_expression(first+3, last, "--", db);
+ if (t != first+3)
+ first = t;
}
else
{
- if (__make<__operator_decrement>())
- first += 2;
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")--";
+ first = t1;
+ }
}
break;
}
break;
case 'n':
- switch (first[1])
+ switch (t[1])
{
case 'a':
- // new[]
- if (__make<__operator_new_array>())
- {
- first += 2;
- if (type)
- *type = -1;
- }
+ case 'w':
+ first = parse_new_expr(first, last, db);
break;
case 'e':
- // !=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_not_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_not_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "!=", db);
+ if (t != first+2)
+ first = t;
break;
case 'g':
- // - (unary)
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_negate>(__root_))
- {
- *type = 1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_negate>())
- first += 2;
- }
+ t = parse_prefix_expression(first+2, last, "-", db);
+ if (t != first+2)
+ first = t;
break;
case 't':
- // !
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_logical_not>(__root_))
- {
- *type = 1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_logical_not>())
- first += 2;
- }
+ t = parse_prefix_expression(first+2, last, "!", db);
+ if (t != first+2)
+ first = t;
break;
- case 'w':
- // new
- if (__make<__operator_new>())
- {
- first += 2;
- if (type)
- *type = -1;
- }
+ case 'x':
+ t = parse_noexcept_expression(first+2, last, db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 'o':
- switch (first[1])
+ switch (t[1])
{
+ case 'n':
+ return parse_unresolved_name(first, last, db);
case 'o':
- // ||
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_logical_or>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_logical_or>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "||", db);
+ if (t != first+2)
+ first = t;
break;
case 'r':
- // |
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_bit_or>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_bit_or>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "|", db);
+ if (t != first+2)
+ first = t;
break;
case 'R':
- // |=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_or_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_or_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "|=", db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 'p':
- switch (first[1])
+ switch (t[1])
{
case 'm':
- // ->*
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_pointer_to_member>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_pointer_to_member>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "->*", db);
+ if (t != first+2)
+ first = t;
break;
case 'l':
- // +
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_plus>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_plus>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
break;
case 'L':
- // +=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_plus_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_plus_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "+=", db);
+ if (t != first+2)
+ first = t;
break;
case 'p':
- // ++ (postfix in <expression> context)
- if (type)
+ if (first+2 != last && first[2] == '_')
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_increment>(false, __root_))
- {
- *type = 1;
- first = t;
- }
- }
+ t = parse_prefix_expression(first+3, last, "++", db);
+ if (t != first+3)
+ first = t;
}
else
{
- if (__make<__operator_increment>())
- first += 2;
- }
- break;
- case 's':
- // + (unary)
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
{
- if (__make<__operator_unary_plus>(__root_))
- {
- *type = 1;
- first = t;
- }
+ if (db.names.empty())
+ return first;
+ db.names.back() = "(" + db.names.back().move_full() + ")++";
+ first = t1;
}
}
- else
- {
- if (__make<__operator_unary_plus>())
- first += 2;
- }
+ break;
+ case 's':
+ t = parse_prefix_expression(first+2, last, "+", db);
+ if (t != first+2)
+ first = t;
break;
case 't':
- // ->
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_arrow>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_arrow>())
- first += 2;
- }
+ first = parse_arrow_expr(first, last, db);
break;
}
break;
case 'q':
- // ?
- if (first[1] == 'u')
+ if (t[1] == 'u')
{
- if (type)
+ const char* t1 = parse_expression(first+2, last, db);
+ if (t1 != first+2)
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ const char* t2 = parse_expression(t1, last, db);
+ if (t2 != t1)
{
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
+ const char* t3 = parse_expression(t2, last, db);
+ if (t3 != t2)
{
- __node* op2 = __root_;
- const char* t3 = __parse_expression(t2, last);
- if (t3 != t2)
- {
- if (__make<__operator_conditional>(op1, op2, __root_))
- {
- *type = 3;
- first = t3;
- }
- }
+ if (db.names.size() < 3)
+ return first;
+ auto op3 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op2 = db.names.back().move_full();
+ db.names.pop_back();
+ auto op1 = db.names.back().move_full();
+ db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";
+ first = t3;
+ }
+ else
+ {
+ db.names.pop_back();
+ db.names.pop_back();
}
}
- }
- else
- {
- if (__make<__operator_conditional>())
- first += 2;
+ else
+ db.names.pop_back();
}
}
break;
case 'r':
- switch (first[1])
+ switch (t[1])
{
+ case 'c':
+ first = parse_reinterpret_cast_expr(first, last, db);
+ break;
case 'm':
- // %
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_mod>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_mod>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "%", db);
+ if (t != first+2)
+ first = t;
break;
case 'M':
- // %=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_mod_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_mod_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, "%=", db);
+ if (t != first+2)
+ first = t;
break;
case 's':
- // >>
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_right_shift>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_right_shift>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, ">>", db);
+ if (t != first+2)
+ first = t;
break;
case 'S':
- // >>=
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- __node* op1 = __root_;
- const char* t2 = __parse_expression(t, last);
- if (t != t2)
- {
- if (__make<__operator_right_shift_equal>(op1, __root_))
- {
- *type = 2;
- first = t2;
- }
- }
- }
- }
- else
- {
- if (__make<__operator_right_shift_equal>())
- first += 2;
- }
+ t = parse_binary_expression(first+2, last, ">>=", db);
+ if (t != first+2)
+ first = t;
break;
}
break;
case 's':
- switch (first[1])
+ switch (t[1])
{
+ case 'c':
+ first = parse_static_cast_expr(first, last, db);
+ break;
+ case 'p':
+ first = parse_pack_expansion(first, last, db);
+ break;
+ case 'r':
+ return parse_unresolved_name(first, last, db);
case 't':
- // sizeof (a type)
- if (type)
- {
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
- {
- if (__make<__operator_sizeof_type>(__root_))
- {
- *type = -1;
- first = t;
- }
- }
- }
- else
- {
- if (__make<__operator_sizeof_type>())
- first += 2;
- }
+ first = parse_sizeof_type_expr(first, last, db);
break;
case 'z':
- // sizeof (an expression)
- if (type)
+ first = parse_sizeof_expr_expr(first, last, db);
+ break;
+ case 'Z':
+ if (last - t >= 3)
{
- const char* t = __parse_expression(first+2, last);
- if (t != first+2)
+ switch (t[2])
{
- if (__make<__operator_sizeof_expression>(__root_))
- {
- *type = -1;
- first = t;
- }
+ case 'T':
+ first = parse_sizeof_param_pack_expr(first, last, db);
+ break;
+ case 'f':
+ first = parse_sizeof_function_param_pack_expr(first, last, db);
+ break;
}
}
- else
- {
- if (__make<__operator_sizeof_expression>())
- first += 2;
- }
break;
}
break;
+ case 't':
+ switch (t[1])
+ {
+ case 'e':
+ case 'i':
+ first = parse_typeid_expr(first, last, db);
+ break;
+ case 'r':
+ db.names.push_back("throw");
+ first += 2;
+ break;
+ case 'w':
+ first = parse_throw_expr(first, last, db);
+ break;
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return parse_unresolved_name(first, last, db);
}
}
return first;
}
-// <source-name> ::= <positive length number> <identifier>
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
+template <class C>
const char*
-__demangle_tree::__parse_source_name(const char* first, const char* last)
+parse_template_arg(const char* first, const char* last, C& db)
{
if (first != last)
{
- char c = *first;
- if ('1' <= c && c <= '9' && first+1 != last)
+ const char* t;
+ switch (*first)
{
- const char* t = first+1;
- size_t n = static_cast<size_t>(c - '0');
- for (c = *t; '0' <= c && c <= '9'; c = *t)
+ case 'X':
+ t = parse_expression(first+1, last, db);
+ if (t != first+1)
{
- n = n * 10 + static_cast<size_t>(c - '0');
- if (++t == last)
+ if (t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'J':
+ t = first+1;
+ if (t == last)
+ return first;
+ while (*t != 'E')
+ {
+ const char* t1 = parse_template_arg(t, last, db);
+ if (t1 == t)
return first;
+ t = t1;
+ }
+ first = t+1;
+ break;
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
}
- if (static_cast<size_t>(last - t) >= n && __make<__source_name>(t, n))
- first = t + n;
- }
- }
- return first;
-}
-
-// <unqualified-name> ::= <operator-name>
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
-
-const char*
-__demangle_tree::__parse_unqualified_name(const char* first, const char* last)
-{
- const char* t = __parse_source_name(first, last);
- if (t == first)
- {
- t = __parse_ctor_dtor_name(first, last);
- if (t == first)
- {
- t = __parse_operator_name(first, last);
- if (t == first)
- first = __parse_unnamed_type_name(first, last);
else
- first = t;
+ first = parse_expr_primary(first, last, db);
+ break;
+ default:
+ // <type>
+ first = parse_type(first, last, db);
+ break;
}
- else
- first = t;
}
- else
- first = t;
return first;
}
-// <unscoped-name> ::= <unqualified-name>
-// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+template <class C>
const char*
-__demangle_tree::__parse_unscoped_name(const char* first, const char* last)
+parse_template_args(const char* first, const char* last, C& db)
{
- if (last - first >= 2)
+ if (last - first >= 2 && *first == 'I')
{
- const char* t0 = first;
- if (first[0] == 'S' && first[1] == 't')
- {
- t0 += 2;
- if (t0 != last && *t0 == 'L')
- ++t0;
- }
- const char* t1 = __parse_unqualified_name(t0, last);
- if (t1 != t0)
+ if (db.tag_templates)
+ db.template_param.back().clear();
+ const char* t = first+1;
+ typename C::String args("<");
+ while (*t != 'E')
{
- if (t0 != first)
+ if (db.tag_templates)
+ db.template_param.emplace_back(db.names.get_allocator());
+ size_t k0 = db.names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.names.size();
+ if (db.tag_templates)
+ db.template_param.pop_back();
+ if (t1 == t || t1 == last)
+ return first;
+ if (db.tag_templates)
{
- __node* name = __root_;
- if (__make<__std_qualified_name>())
- {
- if (__make<__nested_delimeter>(__root_, name))
- first = t1;
- }
+ db.template_param.back().emplace_back(db.names.get_allocator());
+ for (size_t k = k0; k < k1; ++k)
+ db.template_param.back().back().push_back(db.names[k]);
}
- else
- first = t1;
+ for (size_t k = k0; k < k1; ++k)
+ {
+ if (args.size() > 1)
+ args += ", ";
+ args += db.names[k].move_full();
+ }
+ for (; k1 != k0; --k1)
+ db.names.pop_back();
+ t = t1;
}
+ first = t + 1;
+ if (args.back() != '>')
+ args += ">";
+ else
+ args += " >";
+ db.names.push_back(std::move(args));
+
}
return first;
}
-// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
-// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
//
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
@@ -10320,717 +3886,1052 @@ __demangle_tree::__parse_unscoped_name(const char* first, const char* last)
// ::= <template-param>
// ::= <substitution>
+template <class C>
const char*
-__demangle_tree::__parse_nested_name(const char* first, const char* last)
+parse_nested_name(const char* first, const char* last, C& db)
{
if (first != last && *first == 'N')
{
- unsigned cv = 0;
- const char* t0 = __parse_cv_qualifiers(first+1, last, cv, true);
- __node* prev = NULL;
+ unsigned cv;
+ const char* t0 = parse_cv_qualifiers(first+1, last, cv);
+ if (t0 == last)
+ return first;
+ db.ref = 0;
+ if (*t0 == 'R')
+ {
+ db.ref = 1;
+ ++t0;
+ }
+ else if (*t0 == 'O')
+ {
+ db.ref = 2;
+ ++t0;
+ }
+ db.names.emplace_back();
if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
{
t0 += 2;
- if (!__make<__std_qualified_name>())
- return first;
- prev = __root_;
+ db.names.back().first = "std";
+ }
+ if (t0 == last)
+ {
+ db.names.pop_back();
+ return first;
}
- while (t0 != last)
+ bool pop_subs = false;
+ while (*t0 != 'E')
{
- bool can_sub = true;
- bool make_nested = true;
- const char* t1 = NULL;
+ const char* t1;
switch (*t0)
{
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- t1 = __parse_source_name(t0, last);
- if (t1 == t0 || t1 == last)
- return first;
- if (*t1 == 'M')
- {
- // This is a data-member-prefix
- ++t1;
- }
- else if (*t1 == 'I')
- {
- // has following <template-args>
- if (prev)
+ case 'S':
+ if (t0 + 1 != last && t0[1] == 't')
+ goto do_parse_unqualified_name;
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
{
- if (!__make<__nested_delimeter>(prev, __root_))
- return first;
- make_nested = false;
- }
- if (__sub_end_ == __sub_cap_)
- {
- __status_ = memory_alloc_failure;
- return first;
+ db.names.back().first += "::" + name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
}
else
- *__sub_end_++ = __root_;
- const char* t2 = __parse_template_args(t1, last);
- if (t2 == t1)
- return first;
- t1 = t2;
- }
- break;
- case 'D':
- if (t0+1 != last && (t0[1] == 't' || t0[1] == 'T'))
- {
- t1 = __parse_decltype(t0, last);
- break;
+ db.names.back().first = name;
+ pop_subs = true;
+ t0 = t1;
}
- // check for Dt, DT here, else drop through
- case 'C':
- t1 = __parse_ctor_dtor_name(t0, last);
- if (t1 == t0 || t1 == last)
+ else
return first;
- if (*t1 == 'I')
- {
- // has following <template-args>
- if (prev)
- {
- if (!__make<__nested_delimeter>(prev, __root_))
- return first;
- make_nested = false;
- }
- if (__sub_end_ == __sub_cap_)
- {
- __status_ = memory_alloc_failure;
- return first;
- }
- else
- *__sub_end_++ = __root_;
- const char* t2 = __parse_template_args(t1, last);
- if (t2 == t1)
- return first;
- t1 = t2;
- }
- break;
- case 'U':
- t1 = __parse_unnamed_type_name(t0, last);
- if (t1 == t0 || t1 == last)
- return first;
break;
case 'T':
- t1 = __parse_template_param(t0, last);
- if (t1 == t0 || t1 == last)
- return first;
- if (*t1 == 'I')
+ t1 = parse_template_param(t0, last, db);
+ if (t1 != t0 && t1 != last)
{
- // has following <template-args>
- if (prev)
- {
- if (!__make<__nested_delimeter>(prev, __root_))
- return first;
- make_nested = false;
- }
- if (__sub_end_ == __sub_cap_)
- {
- __status_ = memory_alloc_failure;
- return first;
- }
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
else
- *__sub_end_++ = __root_;
- const char* t2 = __parse_template_args(t1, last);
- if (t2 == t1)
- return first;
- t1 = t2;
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
}
+ else
+ return first;
break;
- case 'S':
- t1 = __parse_substitution(t0, last);
- if (t1 == t0 || t1 == last)
+ case 'D':
+ if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
+ goto do_parse_unqualified_name;
+ t1 = parse_decltype(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
+ else
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
+ }
+ else
return first;
- if (*t1 == 'I')
+ break;
+ case 'I':
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0 && t1 != last)
{
- const char* t2 = __parse_template_args(t1, last);
- if (t2 == t1)
- return first;
- t1 = t2;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
}
else
- can_sub = false;
+ return first;
break;
case 'L':
- // extension: ignore L here
- ++t0;
- continue;
- default:
- t1 = __parse_operator_name(t0, last);
- if (t1 == t0 || t1 == last)
+ if (++t0 == last)
return first;
- if (*t1 == 'I')
- {
- // has following <template-args>
- if (prev)
- {
- if (!__make<__nested_delimeter>(prev, __root_))
- return first;
- make_nested = false;
- }
- if (__sub_end_ == __sub_cap_)
- {
- __status_ = memory_alloc_failure;
- return first;
- }
+ break;
+ default:
+ do_parse_unqualified_name:
+ t1 = parse_unqualified_name(t0, last, db);
+ if (t1 != t0 && t1 != last)
+ {
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ if (!db.names.back().first.empty())
+ db.names.back().first += "::" + name;
else
- *__sub_end_++ = __root_;
- const char* t2 = __parse_template_args(t1, last);
- if (t2 == t1)
- return first;
- t1 = t2;
+ db.names.back().first = name;
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ pop_subs = true;
+ t0 = t1;
}
- break;
- }
- if (t1 == t0 || t1 == last)
- return first;
- if (prev && make_nested)
- {
- if (!__make<__nested_delimeter>(prev, __root_))
+ else
return first;
- can_sub = true;
}
- if (can_sub && *t1 != 'E')
+ }
+ first = t0 + 1;
+ db.cv = cv;
+ if (pop_subs && !db.subs.empty())
+ db.subs.pop_back();
+ }
+ return first;
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+
+
+const char*
+parse_discriminator(const char* first, const char* last)
+{
+ // parse but ignore discriminator
+ if (first != last)
+ {
+ if (*first == '_')
+ {
+ const char* t1 = first+1;
+ if (t1 != last)
{
- if (__sub_end_ == __sub_cap_)
+ if (std::isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
{
- __status_ = memory_alloc_failure;
- return first;
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
}
- else
- *__sub_end_++ = __root_;
}
- if (*t1 == 'E')
+ }
+ else if (std::isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+
+template <class C>
+const char*
+parse_local_name(const char* first, const char* last, C& db)
+{
+ if (first != last && *first == 'Z')
+ {
+ const char* t = parse_encoding(first+1, last, db);
+ if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ {
+ switch (*t)
{
- if (cv != 0)
+ case 's':
+ first = parse_discriminator(t+1, last);
+ if (db.names.empty())
+ return first;
+ db.names.back().first.append("::string literal");
+ break;
+ case 'd':
+ if (++t != last)
{
- if (!__make<__cv_qualifiers>(cv, __root_))
- return first;
+ const char* t1 = parse_number(t, last);
+ if (t1 != last && *t1 == '_')
+ {
+ t = t1 + 1;
+ t1 = parse_name(t, last, db);
+ if (t1 != t)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ first = t1;
+ }
+ else
+ db.names.pop_back();
+ }
+ }
+ break;
+ default:
+ {
+ const char* t1 = parse_name(t, last, db);
+ if (t1 != t)
+ {
+ // parse but ignore discriminator
+ first = parse_discriminator(t1, last);
+ if (db.names.size() < 2)
+ return first;
+ auto name = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first.append("::");
+ db.names.back().first.append(name);
+ }
+ else
+ db.names.pop_back();
}
- first = t1+1;
break;
}
- prev = __root_;
- t0 = t1;
}
}
return first;
}
-// <template-arg> ::= <type> # type or template
-// ::= X <expression> E # expression
-// ::= <expr-primary> # simple expressions
-// ::= J <template-arg>* E # argument pack
-// ::= LZ <encoding> E # extension
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+template <class C>
const char*
-__demangle_tree::__parse_template_arg(const char* first, const char* last)
+parse_name(const char* first, const char* last, C& db)
{
- if (first != last)
+ if (last - first >= 2)
{
- const char* t;
- switch (*first)
+ const char* t0 = first;
+ // extension: ignore L here
+ if (*t0 == 'L')
+ ++t0;
+ switch (*t0)
{
- case 'X':
- t = __parse_expression(first+1, last);
- if (t != first+1)
- {
- if (t != last && *t == 'E')
- first = t+1;
- }
+ case 'N':
+ {
+ const char* t1 = parse_nested_name(t0, last, db);
+ if (t1 != t0)
+ first = t1;
break;
- case 'J':
- t = first+1;
- if (t == last)
- return first;
- if (*t == 'E')
- {
- if (__make<__list>((__node*)0))
- first = t+1;
- }
- else
+ }
+ case 'Z':
+ {
+ const char* t1 = parse_local_name(t0, last, db);
+ if (t1 != t0)
+ first = t1;
+ break;
+ }
+ default:
+ {
+ const char* t1 = parse_unscoped_name(t0, last, db);
+ if (t1 != t0)
{
- __node* list = NULL;
- __node* prev = NULL;
- do
+ if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
{
- const char* t2 = __parse_template_arg(t, last);
- if (t2 == t || !__make<__list>(__root_))
+ if (db.names.empty())
return first;
- if (list == 0)
- list = __root_;
- if (prev)
+ db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
{
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
}
- prev = __root_;
- t = t2;
- } while (t != last && *t != 'E');
- first = t+1;
- __root_ = list;
- }
- break;
- case 'L':
- // <expr-primary> or LZ <encoding> E
- if (first+1 != last && first[1] == 'Z')
- {
- t = __parse_encoding(first+2, last);
- if (t != first+2 && t != last && *t == 'E')
- first = t+1;
+ }
+ else // <unscoped-name>
+ first = t1;
}
else
- first = __parse_expr_primary(first, last);
- break;
- default:
- // <type>
- first = __parse_type(first, last);
+ { // try <substitution> <template-args>
+ t1 = parse_substitution(t0, last, db);
+ if (t1 != t0 && t1 != last && *t1 == 'I')
+ {
+ t0 = t1;
+ t1 = parse_template_args(t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto tmp = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first += tmp;
+ first = t1;
+ }
+ }
+ }
break;
+ }
}
}
return first;
}
-// <template-args> ::= I <template-arg>* E
-// extension, the abi says <template-arg>+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+//
+// <nv-offset> ::= <offset number>
+// # non-virtual base override
+//
+// <v-offset> ::= <offset number> _ <virtual offset number>
+// # virtual base override, with vcall offset
const char*
-__demangle_tree::__parse_template_args(const char* first, const char* last)
+parse_call_offset(const char* first, const char* last)
{
- if (last - first >= 2 && *first == 'I')
+ if (first != last)
{
- __node* args = NULL;
- __node* prev = NULL;
- __node* name = __root_;
- if (__tag_templates_)
- __t_end_ = __t_begin_;
- const char* t = first+1;
- while (*t != 'E')
+ switch (*first)
{
- bool prev_tag_templates = __tag_templates_;
- __node** prev_t_begin = __t_begin_;
- __node** prev_t_end = __t_end_;
- if (__tag_templates_)
- __t_begin_ = __t_end_;
- const char* t2 = __parse_template_arg(t, last);
- if (prev_tag_templates)
+ case 'h':
{
- __tag_templates_ = prev_tag_templates;
- __t_begin_ = prev_t_begin;
- __t_end_ = prev_t_end;
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
+ first = t + 1;
}
- if (t2 == t || t2 == last)
- break;
- if (!__make<__list>(__root_))
- return first;
- if (args == 0)
- args = __root_;
- if (prev)
+ break;
+ case 'v':
{
- prev->__right_ = __root_;
- __root_->__size_ = prev->__size_ + 1;
- }
- prev = __root_;
- if (__tag_templates_)
+ const char* t = parse_number(first + 1, last);
+ if (t != first + 1 && t != last && *t == '_')
{
- if (__t_end_ == __t_cap_)
- {
- __status_ = memory_alloc_failure;
- return first;
- }
- if (__root_->__left_)
- *__t_end_++ = __root_->__left_;
- else
- *__t_end_++ = __root_;
+ const char* t2 = parse_number(++t, last);
+ if (t2 != t && t2 != last && *t2 == '_')
+ first = t2 + 1;
}
- t = t2;
- }
- if (t != last && *t == 'E')
- {
- if (__make<__template_args>(name, args))
- first = t+1;
+ }
+ break;
}
}
return first;
}
-// <substitution> ::= S <seq-id> _
-// ::= S_
-// <substitution> ::= Sa # ::std::allocator
-// <substitution> ::= Sb # ::std::basic_string
-// <substitution> ::= Ss # ::std::basic_string < char,
-// ::std::char_traits<char>,
-// ::std::allocator<char> >
-// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
-// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
-// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+// <special-name> ::= TV <type> # virtual table
+// ::= TT <type> # VTT structure (construction vtable index)
+// ::= TI <type> # typeinfo structure
+// ::= TS <type> # typeinfo name (null-terminated byte string)
+// ::= Tc <call-offset> <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// # first call-offset is 'this' adjustment
+// # second call-offset is result adjustment
+// ::= T <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+template <class C>
const char*
-__demangle_tree::__parse_substitution(const char* first, const char* last)
+parse_special_name(const char* first, const char* last, C& db)
{
- if (last - first >= 2)
+ if (last - first > 2)
{
- if (*first == 'S')
+ const char* t;
+ switch (*first)
{
+ case 'T':
switch (first[1])
{
- case 'a':
- if (__make<__sub_allocator>())
- first += 2;
- break;
- case 'b':
- if (__make<__sub_basic_string>())
- first += 2;
+ case 'V':
+ // TV <type> # virtual table
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "vtable for ");
+ first = t;
+ }
break;
- case 's':
- if (__make<__sub_string>())
- first += 2;
+ case 'T':
+ // TT <type> # VTT structure (construction vtable index)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "VTT for ");
+ first = t;
+ }
break;
- case 'i':
- if (__make<__sub_istream>())
- first += 2;
+ case 'I':
+ // TI <type> # typeinfo structure
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo for ");
+ first = t;
+ }
break;
- case 'o':
- if (__make<__sub_ostream>())
- first += 2;
+ case 'S':
+ // TS <type> # typeinfo name (null-terminated byte string)
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "typeinfo name for ");
+ first = t;
+ }
break;
- case 'd':
- if (__make<__sub_iostream>())
- first += 2;
+ case 'c':
+ // Tc <call-offset> <call-offset> <base encoding>
+ {
+ const char* t0 = parse_call_offset(first+2, last);
+ if (t0 == first+2)
+ break;
+ const char* t1 = parse_call_offset(t0, last);
+ if (t1 == t0)
+ break;
+ t = parse_encoding(t1, last, db);
+ if (t != t1)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "covariant return thunk to ");
+ first = t;
+ }
+ }
break;
- case '_':
- if (__sub_begin_ != __sub_end_)
+ case 'C':
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+ t = parse_type(first+2, last, db);
+ if (t != first+2)
{
- if (__make<__sub>(*__sub_begin_))
- first += 2;
+ const char* t0 = parse_number(t, last);
+ if (t0 != t && t0 != last && *t0 == '_')
+ {
+ const char* t1 = parse_type(++t0, last, db);
+ if (t1 != t0)
+ {
+ if (db.names.size() < 2)
+ return first;
+ auto left = db.names.back().move_full();
+ db.names.pop_back();
+ db.names.back().first = "construction vtable for " +
+ std::move(left) + "-in-" +
+ db.names.back().move_full();
+ first = t1;
+ }
+ }
}
break;
default:
- if (isdigit(first[1]) || isupper(first[1]))
+ // T <call-offset> <base encoding>
{
- size_t sub = 0;
- const char* t = first+1;
- if (isdigit(*t))
- sub = static_cast<size_t>(*t - '0');
- else
- sub = static_cast<size_t>(*t - 'A') + 10;
- for (++t; t != last && (isdigit(*t) || isupper(*t)); ++t)
+ const char* t0 = parse_call_offset(first+1, last);
+ if (t0 == first+1)
+ break;
+ t = parse_encoding(t0, last, db);
+ if (t != t0)
+ {
+ if (db.names.empty())
+ return first;
+ if (first[2] == 'v')
{
- sub *= 36;
- if (isdigit(*t))
- sub += static_cast<size_t>(*t - '0');
- else
- sub += static_cast<size_t>(*t - 'A') + 10;
+ db.names.back().first.insert(0, "virtual thunk to ");
+ first = t;
}
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < static_cast<size_t>(__sub_end_ - __sub_begin_))
+ else
{
- if (__make<__sub>(__sub_begin_[sub]))
- first = t+1;
+ db.names.back().first.insert(0, "non-virtual thunk to ");
+ first = t;
}
}
+ }
+ break;
+ }
+ break;
+ case 'G':
+ switch (first[1])
+ {
+ case 'V':
+ // GV <object name> # Guard variable for one-time initialization
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "guard variable for ");
+ first = t;
+ }
+ break;
+ case 'R':
+ // extension ::= GR <object name> # reference temporary for object
+ t = parse_name(first+2, last, db);
+ if (t != first+2)
+ {
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "reference temporary for ");
+ first = t;
+ }
break;
}
+ break;
}
}
return first;
}
-// <name> ::= <nested-name>
-// ::= <local-name> # See Scope Encoding below
-// ::= <unscoped-template-name> <template-args>
-// ::= <unscoped-name>
+template <class T>
+class save_value
+{
+ T& restore_;
+ T original_value_;
+public:
+ save_value(T& restore)
+ : restore_(restore),
+ original_value_(restore)
+ {}
+
+ ~save_value()
+ {
+ restore_ = std::move(original_value_);
+ }
+
+ save_value(const save_value&) = delete;
+ save_value& operator=(const save_value&) = delete;
+};
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+template <class C>
const char*
-__demangle_tree::__parse_name(const char* first, const char* last)
+parse_encoding(const char* first, const char* last, C& db)
{
if (first != last)
{
- const char* t0 = first;
- // extension: ignore L here
- if (*t0 == 'L')
- ++t0;
- const char* t = __parse_nested_name(t0, last);
- if (t == t0)
+ save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+ ++db.encoding_depth;
+ save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+ if (db.encoding_depth > 1)
+ db.tag_templates = true;
+ switch (*first)
{
- t = __parse_local_name(t0, last);
- if (t == t0)
- {
- // not <nested-name> nor <local-name>
- // Try to parse <unscoped-template-name> <template-args> or
- // <unscoped-name> which are nearly ambiguous.
- // This logic occurs nowhere else.
- if (last - t0 >= 2)
+ case 'G':
+ case 'T':
+ first = parse_special_name(first, last, db);
+ break;
+ default:
+ {
+ const char* t = parse_name(first, last, db);
+ unsigned cv = db.cv;
+ unsigned ref = db.ref;
+ if (t != first)
+ {
+ if (t != last && *t != 'E' && *t != '.')
{
- if (t0[0] == 'S' && (t0[1] == '_' ||
- isdigit(t0[1]) ||
- isupper(t0[1]) ||
- t0[1] == 'a' ||
- t0[1] == 'b'))
+ save_value<bool> sb2(db.tag_templates);
+ db.tag_templates = false;
+ const char* t2;
+ typename C::String ret2;
+ if (db.names.empty())
+ return first;
+ const typename C::String& nm = db.names.back().first;
+ if (nm.empty())
+ return first;
+ if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
+ && nm[nm.size()-2] != '>')
{
- t = __parse_substitution(t0, last);
- if (t != t0)
- {
- const char* t2 = __parse_template_args(t, last);
- if (t2 != t)
- first = t2;
- }
+ t2 = parse_type(t, last, db);
+ if (t2 == t)
+ return first;
+ if (db.names.size() < 2)
+ return first;
+ auto ret1 = std::move(db.names.back().first);
+ ret2 = std::move(db.names.back().second);
+ if (ret2.empty())
+ ret1 += ' ';
+ db.names.pop_back();
+ db.names.back().first.insert(0, ret1);
+ t = t2;
}
- else // Not a substitution, except maybe St
+ db.names.back().first += '(';
+ if (t != last && *t == 'v')
{
- t = __parse_unscoped_name(t0, last);
- if (t != t0)
+ ++t;
+ }
+ else
+ {
+ bool first_arg = true;
+ while (true)
{
- // unscoped-name might be <unscoped-template-name>
- if (t != last && *t == 'I')
+ size_t k0 = db.names.size();
+ t2 = parse_type(t, last, db);
+ size_t k1 = db.names.size();
+ if (t2 == t)
+ break;
+ if (k1 > k0)
{
- if (__sub_end_ == __sub_cap_)
+ typename C::String tmp;
+ for (size_t k = k0; k < k1; ++k)
{
- __status_ = memory_alloc_failure;
- return first;
+ if (!tmp.empty())
+ tmp += ", ";
+ tmp += db.names[k].move_full();
+ }
+ for (size_t k = k0; k < k1; ++k)
+ db.names.pop_back();
+ if (!tmp.empty())
+ {
+ if (db.names.empty())
+ return first;
+ if (!first_arg)
+ db.names.back().first += ", ";
+ else
+ first_arg = false;
+ db.names.back().first += tmp;
}
- *__sub_end_++ = __root_;
- const char* t2 = __parse_template_args(t, last);
- if (t2 != t)
- first = t2;
- }
- else
- {
- // <unscoped-name>
- first = t;
}
+ t = t2;
}
}
+ if (db.names.empty())
+ return first;
+ db.names.back().first += ')';
+ if (cv & 1)
+ db.names.back().first.append(" const");
+ if (cv & 2)
+ db.names.back().first.append(" volatile");
+ if (cv & 4)
+ db.names.back().first.append(" restrict");
+ if (ref == 1)
+ db.names.back().first.append(" &");
+ else if (ref == 2)
+ db.names.back().first.append(" &&");
+ db.names.back().first += ret2;
+ first = t;
}
+ else
+ first = t;
}
- else
- first = t;
+ break;
+ }
}
- else
- first = t;
}
return first;
}
-// extension
-// <dot-suffix> := .<anything and everything>
+// _block_invoke
+// _block_invoke<decimal-digit>+
+// _block_invoke_<decimal-digit>+
+template <class C>
const char*
-__demangle_tree::__parse_dot_suffix(const char* first, const char* last)
+parse_block_invoke(const char* first, const char* last, C& db)
{
- if (first != last && *first == '.')
+ if (last - first >= 13)
{
- if (__make<__dot_suffix>(__root_, first, static_cast<size_t>(last-first)))
- first = last;
+ const char test[] = "_block_invoke";
+ const char* t = first;
+ for (int i = 0; i < 13; ++i, ++t)
+ {
+ if (*t != test[i])
+ return first;
+ }
+ if (t != last)
+ {
+ if (*t == '_')
+ {
+ // must have at least 1 decimal digit
+ if (++t == last || !std::isdigit(*t))
+ return first;
+ ++t;
+ }
+ // parse zero or more digits
+ while (t != last && isdigit(*t))
+ ++t;
+ }
+ if (db.names.empty())
+ return first;
+ db.names.back().first.insert(0, "invocation function for block in ");
+ first = t;
}
return first;
}
-// <encoding> ::= <function name> <bare-function-type>
-// ::= <data name>
-// ::= <special-name>
+// extension
+// <dot-suffix> := .<anything and everything>
+template <class C>
const char*
-__demangle_tree::__parse_encoding(const char* first, const char* last)
+parse_dot_suffix(const char* first, const char* last, C& db)
{
- const char* t = __parse_name(first, last);
- if (t != first)
+ if (first != last && *first == '.')
{
- if (t != last && *t != 'E' && *t != '.')
- {
- __node* name = __root_;
- bool has_return = name->ends_with_template(true) &&
- !name->is_ctor_dtor_conv();
- __node* ret = NULL;
- const char* t2;
- bool prev_tag_templates = __tag_templates_;
- __tag_templates_ = false;
- if (has_return)
- {
- t2 = __parse_type(t, last);
- if (t2 != t)
- {
- ret = __root_;
- t = t2;
- }
- else
- return first;
- }
- t2 = __parse_bare_function_type(t, last);
- if (t2 != t)
- {
- if (dynamic_cast<__void*>(__root_->__left_) != NULL)
- __root_->__left_ = NULL;
- if (__make<__function_signature>(ret, __root_))
- {
- __node* cv = name->extract_cv(name);
- if (__make<__function>(name, __root_))
- {
- if (cv)
- {
- cv->__left_ = __root_;
- cv->__size_ <<= 5;
- __root_ = cv;
- }
- first = t2;
- }
- }
- }
- __tag_templates_ = prev_tag_templates;
- }
- else
- first = t;
+ if (db.names.empty())
+ return first;
+ db.names.back().first += " (" + typename C::String(first, last) + ")";
+ first = last;
}
- else
- first = __parse_special_name(first, last);
return first;
}
+// <block-involcaton-function> ___Z<encoding>_block_invoke
+// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
+// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
// <mangled-name> ::= _Z<encoding>
// ::= <type>
+template <class C>
void
-__demangle_tree::__parse()
+demangle(const char* first, const char* last, C& db, int& status)
{
- if (__mangled_name_begin_ == __mangled_name_end_)
+ if (first >= last)
{
- __status_ = invalid_mangled_name;
+ status = invalid_mangled_name;
return;
}
- const char* t = NULL;
- if (__mangled_name_end_ - __mangled_name_begin_ >= 2 &&
- __mangled_name_begin_[0] == '_' &&
- __mangled_name_begin_[1] == 'Z')
- {
- t = __parse_encoding(__mangled_name_begin_+2, __mangled_name_end_);
- if (t != __mangled_name_begin_+2 && t != __mangled_name_end_ && *t == '.')
- t = __parse_dot_suffix(t, __mangled_name_end_);
- }
- else
- t = __parse_type(__mangled_name_begin_, __mangled_name_end_);
- if (t == __mangled_name_end_ && __root_)
+ if (*first == '_')
{
- if (__fix_forward_references_)
+ if (last - first >= 4)
{
- if (__root_->fix_forward_references(__t_begin_, __t_end_))
- __status_ = success;
+ if (first[1] == 'Z')
+ {
+ const char* t = parse_encoding(first+2, last, db);
+ if (t != first+2 && t != last && *t == '.')
+ t = parse_dot_suffix(t, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
+ }
+ else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+ {
+ const char* t = parse_encoding(first+4, last, db);
+ if (t != first+4 && t != last)
+ {
+ const char* t1 = parse_block_invoke(t, last, db);
+ if (t1 != last)
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
+ }
+ else
+ status = invalid_mangled_name;
}
else
- __status_ = success;
+ status = invalid_mangled_name;
+ }
+ else
+ {
+ const char* t = parse_type(first, last, db);
+ if (t != last)
+ status = invalid_mangled_name;
}
+ if (status == success && db.names.empty())
+ status = invalid_mangled_name;
}
-__demangle_tree
-__demangle(const char* mangled_name, char* buf, size_t bs)
+template <std::size_t N>
+class arena
{
- __demangle_tree t(mangled_name, buf, bs);
- if (t.__status() == invalid_mangled_name)
- t.__parse();
- return t;
-}
+ static const std::size_t alignment = 16;
+ alignas(alignment) char buf_[N];
+ char* ptr_;
+
+ std::size_t
+ align_up(std::size_t n) noexcept
+ {return n + (alignment-1) & ~(alignment-1);}
-__demangle_tree
-__demangle(const char* mangled_name)
+ bool
+ pointer_in_buffer(char* p) noexcept
+ {return buf_ <= p && p <= buf_ + N;}
+
+public:
+ arena() noexcept : ptr_(buf_) {}
+ ~arena() {ptr_ = nullptr;}
+ arena(const arena&) = delete;
+ arena& operator=(const arena&) = delete;
+
+ char* allocate(std::size_t n);
+ void deallocate(char* p, std::size_t n) noexcept;
+
+ static constexpr std::size_t size() {return N;}
+ std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
+ void reset() {ptr_ = buf_;}
+};
+
+template <std::size_t N>
+char*
+arena<N>::allocate(std::size_t n)
{
- return __demangle(mangled_name, 0, 0);
+ n = align_up(n);
+ if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
+ {
+ char* r = ptr_;
+ ptr_ += n;
+ return r;
+ }
+ return static_cast<char*>(std::malloc(n));
}
-char*
-__demangle(__demangle_tree dmg_tree, char* buf, size_t* n, int* status)
+template <std::size_t N>
+void
+arena<N>::deallocate(char* p, std::size_t n) noexcept
{
- if (dmg_tree.__status() != success)
+ if (pointer_in_buffer(p))
{
- if (status)
- *status = dmg_tree.__status();
- return NULL;
+ n = align_up(n);
+ if (p + n == ptr_)
+ ptr_ = p;
}
-#ifdef DEBUGGING
-display(dmg_tree.__root_);
-printf("\n");
-#endif
- const size_t bs = buf == NULL ? 0 : *n;
- ptrdiff_t sm = dmg_tree.__mangled_name_end_ - dmg_tree.__mangled_name_begin_;
- ptrdiff_t est = sm + 60 * (
- (dmg_tree.__node_end_ - dmg_tree.__node_begin_) +
- (dmg_tree.__sub_end_ - dmg_tree.__sub_begin_) +
- (dmg_tree.__t_end_ - dmg_tree.__t_begin_));
- const unsigned N = 4096;
- char tmp[N];
- ptrdiff_t s;
- if (static_cast<size_t>(est) <= bs)
+ else
+ std::free(p);
+}
+
+template <class T, std::size_t N>
+class short_alloc
+{
+ arena<N>& a_;
+public:
+ typedef T value_type;
+
+public:
+ template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
+
+ short_alloc(arena<N>& a) noexcept : a_(a) {}
+ template <class U>
+ short_alloc(const short_alloc<U, N>& a) noexcept
+ : a_(a.a_) {}
+ short_alloc(const short_alloc&) = default;
+ short_alloc& operator=(const short_alloc&) = delete;
+
+ T* allocate(std::size_t n)
{
- char* e = dmg_tree.__get_demangled_name(buf);
- *e++ = '\0';
- s = e - buf;
+ return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
}
- else if (static_cast<size_t>(est) <= N)
+ void deallocate(T* p, std::size_t n) noexcept
{
- char* e = dmg_tree.__get_demangled_name(tmp);
- *e++ = '\0';
- s = e - tmp;
+ a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
}
- else
- s = static_cast<ptrdiff_t>(dmg_tree.size() + 1);
- if (static_cast<size_t>(s) > bs)
+
+ template <class T1, std::size_t N1, class U, std::size_t M>
+ friend
+ bool
+ operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
+
+ template <class U, std::size_t M> friend class short_alloc;
+};
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+ return N == M && &x.a_ == &y.a_;
+}
+
+template <class T, std::size_t N, class U, std::size_t M>
+inline
+bool
+operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
+{
+ return !(x == y);
+}
+
+template <class T>
+class malloc_alloc
+{
+public:
+ typedef T value_type;
+
+ malloc_alloc() = default;
+ template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}
+
+ T* allocate(std::size_t n)
{
- buf = static_cast<char*>(realloc(buf, static_cast<size_t>(s)));
- if (buf == NULL)
- {
- if (status)
- *status = memory_alloc_failure;
- return NULL;
- }
- if (n)
- *n = static_cast<size_t>(s);
+ return static_cast<T*>(std::malloc(n*sizeof(T)));
}
- if (static_cast<size_t>(est) > bs)
+ void deallocate(T* p, std::size_t) noexcept
{
- if (static_cast<size_t>(est) <= N)
- strncpy(buf, tmp, static_cast<size_t>(s));
- else
- *dmg_tree.__get_demangled_name(buf) = '\0';
+ std::free(p);
}
- if (status)
- *status = success;
- return buf;
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept
+{
+ return true;
}
-} // __libcxxabi
+template <class T, class U>
+inline
+bool
+operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept
+{
+ return !(x == y);
+}
-#pragma GCC visibility pop
-#pragma GCC visibility push(default)
+const size_t bs = 4 * 1024;
+template <class T> using Alloc = short_alloc<T, bs>;
+template <class T> using Vector = std::vector<T, Alloc<T>>;
+using String = std::basic_string<char, std::char_traits<char>, malloc_alloc<char>>;
-extern "C"
+struct string_pair
{
+ String first;
+ String second;
+
+ string_pair() = default;
+ string_pair(String f) : first(std::move(f)) {}
+ string_pair(String f, String s)
+ : first(std::move(f)), second(std::move(s)) {}
+ template <size_t N>
+ string_pair(const char (&s)[N]) : first(s, N-1) {}
+
+ size_t size() const {return first.size() + second.size();}
+ String full() const {return first + second;}
+ String move_full() {return std::move(first) + std::move(second);}
+};
+
+struct Db
+{
+ typedef String String;
+ typedef Vector<string_pair> sub_type;
+ typedef Vector<sub_type> template_param_type;
+ Vector<string_pair> names;
+ Vector<sub_type> subs;
+ Vector<template_param_type> template_param;
+ unsigned cv;
+ unsigned ref;
+ unsigned encoding_depth;
+ bool parsed_ctor_dtor_cv;
+ bool tag_templates;
+ bool fix_forward_references;
+ bool try_to_parse_template_args;
+
+ template <size_t N>
+ Db(arena<N>& ar) :
+ names(ar),
+ subs(0, names, ar),
+ template_param(0, subs, ar)
+ {}
+};
+
+} // unnamed namespace
+__attribute__ ((__visibility__("default")))
+extern "C"
char*
__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
{
- if (mangled_name == NULL || (buf != NULL && n == NULL))
+ if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
{
if (status)
- *status = __libcxxabi::invalid_args;
- return NULL;
+ *status = invalid_args;
+ return nullptr;
+ }
+ size_t internal_size = buf != nullptr ? *n : 0;
+ arena<bs> a;
+ Db db(a);
+ db.cv = 0;
+ db.ref = 0;
+ db.encoding_depth = 0;
+ db.parsed_ctor_dtor_cv = false;
+ db.tag_templates = true;
+ db.template_param.emplace_back(a);
+ db.fix_forward_references = false;
+ db.try_to_parse_template_args = true;
+ int internal_status = success;
+ size_t len = std::strlen(mangled_name);
+ demangle(mangled_name, mangled_name + len, db,
+ internal_status);
+ if (internal_status == success && db.fix_forward_references &&
+ !db.template_param.empty() && !db.template_param.front().empty())
+ {
+ db.fix_forward_references = false;
+ db.tag_templates = false;
+ db.names.clear();
+ db.subs.clear();
+ demangle(mangled_name, mangled_name + len, db, internal_status);
+ if (db.fix_forward_references)
+ internal_status = invalid_mangled_name;
+ }
+ if (internal_status == success)
+ {
+ size_t sz = db.names.back().size() + 1;
+ if (sz > internal_size)
+ {
+ char* newbuf = static_cast<char*>(std::realloc(buf, sz));
+ if (newbuf == nullptr)
+ {
+ internal_status = memory_alloc_failure;
+ buf = nullptr;
+ }
+ else
+ {
+ buf = newbuf;
+ if (n != nullptr)
+ *n = sz;
+ }
+ }
+ if (buf != nullptr)
+ {
+ db.names.back().first += db.names.back().second;
+ std::memcpy(buf, db.names.back().first.data(), sz-1);
+ buf[sz-1] = char(0);
+ }
}
- const size_t bs = 4 * 1024;
- __attribute((aligned(16))) char static_buf[bs];
-
- buf = __libcxxabi::__demangle(__libcxxabi::__demangle(mangled_name,
- static_buf, bs),
- buf, n, status);
+ else
+ buf = nullptr;
+ if (status)
+ *status = internal_status;
return buf;
}
-} // extern "C"
-
-} // abi
+} // __cxxabiv1
diff --git a/system/lib/libcxxabi/src/cxa_exception.cpp b/system/lib/libcxxabi/src/cxa_exception.cpp
index f8c38c07..c43777c2 100644
--- a/system/lib/libcxxabi/src/cxa_exception.cpp
+++ b/system/lib/libcxxabi/src/cxa_exception.cpp
@@ -15,7 +15,7 @@
#include <exception> // for std::terminate
#include <cstdlib> // for malloc, free
-#include <string> // for memset
+#include <cstring> // for memset
#include <pthread.h>
#include "cxa_exception.hpp"
diff --git a/system/lib/libcxxabi/src/cxa_exception.hpp b/system/lib/libcxxabi/src/cxa_exception.hpp
index 66f05c45..22c4da38 100644
--- a/system/lib/libcxxabi/src/cxa_exception.hpp
+++ b/system/lib/libcxxabi/src/cxa_exception.hpp
@@ -41,19 +41,19 @@ static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
- __cxa_exception *nextException;
+ __cxa_exception *nextException;
- int handlerCount;
+ int handlerCount;
#ifdef __ARM_EABI_UNWINDER__
- __cxa_exception* nextPropagatingException;
- int propagationCount;
+ __cxa_exception* nextPropagatingException;
+ int propagationCount;
#else
- int handlerSwitchValue;
- const unsigned char *actionRecord;
- const unsigned char *languageSpecificData;
- void *catchTemp;
- void *adjustedPtr;
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
#endif
#if !__LP64__
diff --git a/system/lib/libcxxabi/src/cxa_new_delete.cpp b/system/lib/libcxxabi/src/cxa_new_delete.cpp
index 7fd0b3b7..25a5454e 100644
--- a/system/lib/libcxxabi/src/cxa_new_delete.cpp
+++ b/system/lib/libcxxabi/src/cxa_new_delete.cpp
@@ -9,6 +9,8 @@
// This file implements the new and delete operators.
//===----------------------------------------------------------------------===//
+#define _LIBCPP_BUILDING_NEW
+
#include <new>
#include <cstdlib>
@@ -228,15 +230,33 @@ bad_array_new_length::what() const _NOEXCEPT
return "bad_array_new_length";
}
-#ifdef __EMSCRIPTEN__
-// We don't build the new.cpp from libcxx, so we need to define this.
-void
-__throw_bad_alloc()
+// bad_array_length
+
+#ifndef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+class _LIBCPP_EXCEPTION_ABI bad_array_length
+ : public bad_alloc
+{
+public:
+ bad_array_length() _NOEXCEPT;
+ virtual ~bad_array_length() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
+};
+
+#endif // _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+bad_array_length::bad_array_length() _NOEXCEPT
{
-#ifndef _LIBCPP_NO_EXCEPTIONS
- throw bad_alloc();
-#endif
}
-#endif
+
+bad_array_length::~bad_array_length() _NOEXCEPT
+{
+}
+
+const char*
+bad_array_length::what() const _NOEXCEPT
+{
+ return "bad_array_length";
+}
} // std
diff --git a/system/lib/libcxxabi/src/private_typeinfo.cpp b/system/lib/libcxxabi/src/private_typeinfo.cpp
index 216f796d..52326a3e 100644
--- a/system/lib/libcxxabi/src/private_typeinfo.cpp
+++ b/system/lib/libcxxabi/src/private_typeinfo.cpp
@@ -27,7 +27,7 @@
// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
// printf-like function called syslog:
//
-// void syslog(const char* format, ...);
+// void syslog(int facility_priority, const char* format, ...);
//
// If you want this functionality but your platform doesn't have syslog,
// just implement it in terms of fprintf(stderr, ...).
@@ -40,6 +40,18 @@
#include <sys/syslog.h>
#endif
+// On Windows, typeids are different between DLLs and EXEs, so comparing
+// type_info* will work for typeids from the same compiled file but fail
+// for typeids from a DLL and an executable. Among other things, exceptions
+// are not caught by handlers since can_catch() returns false.
+//
+// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls
+// is_equal() with use_strcmp=false so the string names are not compared.
+
+#ifdef _WIN32
+#include <string.h>
+#endif
+
namespace __cxxabiv1
{
@@ -62,7 +74,11 @@ inline
bool
is_equal(const std::type_info* x, const std::type_info* y, bool)
{
+#ifndef _WIN32
return x == y;
+#else
+ return (x == y) || (strcmp(x->name(), y->name()) == 0);
+#endif
}
#endif // _LIBCXX_DYNAMIC_FALLBACK
@@ -498,7 +514,7 @@ __dynamic_cast(const void* static_ptr,
// We get here only if there is some kind of visibility problem
// in client code.
syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
- "should have public visibility. At least of of them is hidden. %s"
+ "should have public visibility. At least one of them is hidden. %s"
", %s.\n", static_type->name(), dynamic_type->name());
// Redo the search comparing type_info's using strcmp
info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
diff --git a/system/lib/libcxxabi/src/stdexcept.cpp b/system/lib/libcxxabi/src/stdexcept.cpp
index de859db4..246eea4b 100644
--- a/system/lib/libcxxabi/src/stdexcept.cpp
+++ b/system/lib/libcxxabi/src/stdexcept.cpp
@@ -47,7 +47,7 @@ private:
#if __APPLE__
static
const void*
- compute_gcc_empty_string_storage() _LIBCPP_CANTTHROW
+ compute_gcc_empty_string_storage() _NOEXCEPT
{
void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
if (handle == 0)
@@ -57,7 +57,7 @@ private:
static
const void*
- get_gcc_empty_string_storage() _LIBCPP_CANTTHROW
+ get_gcc_empty_string_storage() _NOEXCEPT
{
static const void* p = compute_gcc_empty_string_storage();
return p;
@@ -66,9 +66,9 @@ private:
public:
explicit __libcpp_nmstr(const char* msg);
- __libcpp_nmstr(const __libcpp_nmstr& s) _LIBCPP_CANTTHROW;
- __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _LIBCPP_CANTTHROW;
- ~__libcpp_nmstr() _LIBCPP_CANTTHROW;
+ __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT;
+ __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT;
+ ~__libcpp_nmstr();
const char* c_str() const _NOEXCEPT {return str_;}
};
@@ -80,11 +80,11 @@ __libcpp_nmstr::__libcpp_nmstr(const char* msg)
c->len = c->cap = len;
str_ += offset;
count() = 0;
- std::strcpy(const_cast<char*>(c_str()), msg);
+ std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
}
inline
-__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s)
+__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT
: str_(s.str_)
{
#if __APPLE__
@@ -94,7 +94,7 @@ __libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s)
}
__libcpp_nmstr&
-__libcpp_nmstr::operator=(const __libcpp_nmstr& s)
+__libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT
{
const char* p = str_;
str_ = s.str_;
diff --git a/system/lib/libcxxabi/symbols b/system/lib/libcxxabi/symbols
index a02a6411..f2925e4c 100644
--- a/system/lib/libcxxabi/symbols
+++ b/system/lib/libcxxabi/symbols
@@ -31,7 +31,6 @@
T _ZN10__cxxabiv129__pointer_to_member_type_infoD0Ev
T _ZN10__cxxabiv129__pointer_to_member_type_infoD1Ev
T _ZN10__cxxabiv129__pointer_to_member_type_infoD2Ev
- C _ZN10__cxxabiv18is_equalEPKSt9type_infoS2_b
T _ZNK10__cxxabiv116__enum_type_info9can_catchEPKNS_16__shim_type_infoERPv
T _ZNK10__cxxabiv116__shim_type_info5noop1Ev
T _ZNK10__cxxabiv116__shim_type_info5noop2Ev
@@ -127,6 +126,7 @@
D _ZTIPy
D _ZTISt10bad_typeid
D _ZTISt8bad_cast
+ C _ZTISt9exception
D _ZTISt9type_info
D _ZTIa
D _ZTIb
@@ -201,6 +201,7 @@
D _ZTSPy
D _ZTSSt10bad_typeid
D _ZTSSt8bad_cast
+ C _ZTSSt9exception
D _ZTSSt9type_info
D _ZTSa
D _ZTSb
diff --git a/tests/cases/breakinthemiddle2.ll b/tests/cases/breakinthemiddle2.ll
index ba96654f..2f8c1c91 100644
--- a/tests/cases/breakinthemiddle2.ll
+++ b/tests/cases/breakinthemiddle2.ll
@@ -11,10 +11,6 @@ define linkonce_odr i32 @main() align 2 {
label555: ; preds = %0
br label %label569 ; branch should ignore all code after it in the block
; No predecessors!
- %aa472 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- cleanup
- %aa473 = extractvalue { i8*, i32 } %aa472, 0
- %aa474 = extractvalue { i8*, i32 } %aa472, 1
br label %label569
label569: ; preds = %0
@@ -23,10 +19,6 @@ label569: ; preds = %0
label990:
ret i32 0 ; ret should ignore all code after it in the block
; No predecessors!
- %a472 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- cleanup
- %a473 = extractvalue { i8*, i32 } %a472, 0
- %a474 = extractvalue { i8*, i32 } %a472, 1
br label %label569
label999: ; preds = %555
diff --git a/tests/cases/breakinthemiddle3.ll b/tests/cases/breakinthemiddle3.ll
deleted file mode 100644
index 38da15ef..00000000
--- a/tests/cases/breakinthemiddle3.ll
+++ /dev/null
@@ -1,29 +0,0 @@
-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 constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1]
-
-define linkonce_odr i32 @main() align 2 {
- %a333 = call i32 @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
- %z199 = trunc i8 1 to i1 ; [#uses=1]
- switch i32 %a333, label %label999 [
- i32 1000, label %label995
- ] ; switch should ignore all code after it in the block
- ; No predecessors!
- %a472 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- cleanup
- %a473 = extractvalue { i8*, i32 } %a472, 0
- %a474 = extractvalue { i8*, i32 } %a472, 1
- br label %label999
-
-label995:
- %b333b = call i32 @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
- br label %label999
-
-label999: ; preds = %555
- ret i32 0
-}
-
-declare i32 @printf(i8*)
-declare i32 @__gxx_personality_v0(...)
-
diff --git a/tests/cases/gepaddoverflow.ll b/tests/cases/gepaddoverflow.ll
new file mode 100644
index 00000000..11246c1d
--- /dev/null
+++ b/tests/cases/gepaddoverflow.ll
@@ -0,0 +1,37 @@
+; ModuleID = 'new.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"
+
+declare i32 @printf(i8* noalias, ...) nounwind
+
+@x = common global [4194304 x i8] zeroinitializer, align 4
+@.str = private constant [6 x i8] c"*%d*\0A\00", align 1
+
+define i8* @test_gep(i32 %y) nounwind readnone {
+ ; JavaScript uses double precision 64-bit floating point values, with
+ ; a 53 bit mantissa. The maximum precisely representable integer is
+ ; 9007199254740992. A number close to that limit is constructed here
+ ; for the constant part of the getelementptr instruction:
+ ; 4194304 * 2147483647 == 9007199250546688 == 9007199254740992 - 4194304
+ ; If that number appears in JavaScript source instead of being properly
+ ; limited to 32 bits, the %y parameter can be used to exceed the maximum
+ ; precisely representable integer, and make the computation inexact.
+ %test_res = getelementptr [4194304 x i8]* @x, i32 2147483647, i32 %y
+ ret i8* %test_res
+}
+
+define i32 @main() {
+ %res_0 = call i8* (i32)* @test_gep(i32 1000000000)
+ %res_1 = call i8* (i32)* @test_gep(i32 1000000001)
+ %res_0_i = ptrtoint i8* %res_0 to i32
+ %res_1_i = ptrtoint i8* %res_1 to i32
+
+ ; If getelementptr limited the constant part of the offset to 32 bits,
+ ; result will be 1. Otherwise, it cannot be 1 because the large numbers in
+ ; the calculation cannot be accurately represented by floating point math.
+ %res_diff = sub i32 %res_1_i, %res_0_i
+ %printf_res = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i32 %res_diff)
+
+ ret i32 0
+}
+
diff --git a/tests/cases/gepaddoverflow.txt b/tests/cases/gepaddoverflow.txt
new file mode 100644
index 00000000..10fd998b
--- /dev/null
+++ b/tests/cases/gepaddoverflow.txt
@@ -0,0 +1 @@
+*1*
diff --git a/tests/cases/invokeundef.ll b/tests/cases/invokeundef.ll
index be1dd671..2f13e7ab 100644
--- a/tests/cases/invokeundef.ll
+++ b/tests/cases/invokeundef.ll
@@ -31,6 +31,8 @@ invcont33:
ret i32 %retval1
lpad106:
+ %Z = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ cleanup
ret i32 %retval1
return: ; preds = %entry
@@ -40,3 +42,6 @@ return: ; preds = %entry
; [#uses=1]
declare i32 @puts(i8*)
+
+declare i32 @__gxx_personality_v0(...)
+
diff --git a/tests/cases/switch64_ta2.ll b/tests/cases/switch64_ta2.ll
index 4d5c6273..1a6d52f3 100644
--- a/tests/cases/switch64_ta2.ll
+++ b/tests/cases/switch64_ta2.ll
@@ -1,12 +1,14 @@
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 constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1]
+@.str = private constant [18 x i8] c"hello, world: %d\0A\00", align 1
+
+declare i32 @printf(i8*, ...)
define linkonce_odr i32 @main() align 2 {
- %a333 = call i32 @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
- %a444 = zext i32 %a333 to i64
- %a199 = trunc i8 1 to i1 ; [#uses=1]
+ %a333 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 5)
+ %a400 = zext i32 %a333 to i64
+ %a444 = udiv i64 %a400, 3
switch i64 %a444, label %label999 [
i64 1000, label %label9950
i64 1001, label %label9951
@@ -18,41 +20,35 @@ define linkonce_odr i32 @main() align 2 {
i64 1007, label %label9957
i64 1008, label %label9958
i64 1009, label %label9959
- ] ; switch should ignore all code after it in the block
- ; No predecessors!
- %a472 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
- cleanup
- %a473 = extractvalue { i8*, i32 } %a472, 0
- %a474 = extractvalue { i8*, i32 } %a472, 1
- br label %label999
+ ]
label9950:
- %a333b = call i32 @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
+ %waka = phi i32 [1000, %0], [0, %label9951], [1, %label9952], [2, %label9953], [3, %label9954], [4, %label9955], [5, %label9956], [6, %label9957], [7, %label9958], [8, %label9959]
+ %a333b = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %waka)
br label %label999
label9951:
- br label %label999
+ br label %label9950
label9952:
- br label %label999
+ br label %label9950
label9953:
- br label %label999
+ br label %label9950
label9954:
- br label %label999
+ br label %label9950
label9955:
- br label %label999
+ br label %label9950
label9956:
- br label %label999
+ br label %label9950
label9957:
- br label %label999
+ br label %label9950
label9958:
- br label %label999
+ br label %label9950
label9959:
- br label %label999
+ br label %label9950
label999: ; preds = %555
+ %last = phi i32 [1, %0], [2, %label9950]
+ %a333c = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %last)
ret i32 0
}
-declare i32 @printf(i8*)
-declare i32 @__gxx_personality_v0(...)
-
diff --git a/tests/cases/switch64_ta2.txt b/tests/cases/switch64_ta2.txt
new file mode 100644
index 00000000..72084b0c
--- /dev/null
+++ b/tests/cases/switch64_ta2.txt
@@ -0,0 +1,2 @@
+hello, world: 5
+hello, world: 1
diff --git a/tests/cases/switch64b_ta2.ll b/tests/cases/switch64b_ta2.ll
new file mode 100644
index 00000000..4364725f
--- /dev/null
+++ b/tests/cases/switch64b_ta2.ll
@@ -0,0 +1,54 @@
+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 constant [18 x i8] c"hello, world: %d\0A\00", align 1
+
+declare i32 @printf(i8*, ...)
+
+define linkonce_odr i32 @main() align 2 {
+ %a333 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 5)
+ %a400 = zext i32 %a333 to i64
+ %a444 = udiv i64 %a400, 3
+ switch i64 %a444, label %label999 [
+ i64 0, label %label9950
+ i64 1, label %label9951
+ i64 2, label %label9952
+ i64 3, label %label9953
+ i64 4, label %label9954
+ i64 5, label %label9955
+ i64 6, label %label9956
+ i64 7, label %label9957
+ i64 8, label %label9958
+ i64 9, label %label9959
+ ]
+
+label9950:
+ %waka = phi i32 [11000, %0], [10, %label9951], [11, %label9952], [12, %label9953], [13, %label9954], [14, %label9955], [15, %label9956], [16, %label9957], [17, %label9958], [18, %label9959]
+ %a333b = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %waka)
+ br label %label999
+
+label9951:
+ br label %label9950
+label9952:
+ br label %label9950
+label9953:
+ br label %label9950
+label9954:
+ br label %label9950
+label9955:
+ br label %label9950
+label9956:
+ br label %label9950
+label9957:
+ br label %label9950
+label9958:
+ br label %label9950
+label9959:
+ br label %label9950
+
+label999: ; preds = %555
+ %last = phi i32 [1, %0], [2, %label9950]
+ %a333c = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %last)
+ ret i32 0
+}
+
diff --git a/tests/cases/switch64b_ta2.txt b/tests/cases/switch64b_ta2.txt
new file mode 100644
index 00000000..917d42e5
--- /dev/null
+++ b/tests/cases/switch64b_ta2.txt
@@ -0,0 +1,3 @@
+hello, world: 5
+hello, world: 14
+hello, world: 2
diff --git a/tests/core/test_literal_negative_zero.in b/tests/core/test_literal_negative_zero.in
new file mode 100644
index 00000000..1554fbf5
--- /dev/null
+++ b/tests/core/test_literal_negative_zero.in
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <math.h>
+
+static float XXXf = -0.0f;
+static double XXXd = -0.0;
+
+struct x {
+ float f;
+ double d;
+};
+
+static struct x xx[] = {
+ -0x0p+0,
+ -0x0p+0,
+};
+
+int main(int argc, char ** argv) {
+ float YYYf = -0.0f;
+ float YYYd = -0.0;
+
+ printf("%.2f\n", XXXf);
+ printf("%.2f\n", XXXd);
+ printf("%.2f\n", YYYf);
+ printf("%.2f\n", YYYd);
+ printf("%.2f\n", xx->f);
+ printf("%.2f\n", xx->d);
+}
diff --git a/tests/core/test_literal_negative_zero.out b/tests/core/test_literal_negative_zero.out
new file mode 100644
index 00000000..d1b863b8
--- /dev/null
+++ b/tests/core/test_literal_negative_zero.out
@@ -0,0 +1,6 @@
+-0.00
+-0.00
+-0.00
+-0.00
+-0.00
+-0.00
diff --git a/tests/core/test_wprintf.c b/tests/core/test_wprintf.c
new file mode 100644
index 00000000..b5f8d6ab
--- /dev/null
+++ b/tests/core/test_wprintf.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+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);
+ wprintf (L"Preceding with zeros: %010d \n", 1977);
+ wprintf (L"Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
+ 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
new file mode 100644
index 00000000..e074743d
--- /dev/null
+++ b/tests/core/test_wprintf.out
@@ -0,0 +1,43 @@
+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
+Preceding with zeros: 0000001977
+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/math/lgamma.in b/tests/math/lgamma.in
new file mode 100644
index 00000000..e96f5610
--- /dev/null
+++ b/tests/math/lgamma.in
@@ -0,0 +1,105 @@
+#define _BSD_SOURCE 1
+#define _XOPEN_SOURCE 700
+#include <stdint.h>
+#include <stdio.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+
+#define RN 0
+#define T(...) {__FILE__, __LINE__, __VA_ARGS__},
+#define POS const char *file; int line;
+struct f_fi {POS int r; float x; float y; float dy; long long i; int e; };
+
+#define DIVBYZERO 0
+#define INEXACT 0
+#define INVALID 0
+#define OVERFLOW 0
+#define UNDERFLOW 0
+
+#define inf INFINITY
+#define nan NAN
+
+static struct f_fi t[] = {
+T(RN, -0x1.02239f3c6a8f1p+3, -0x1.0120f61b63d5ep+3, 0x1.89ccc4p-6, -1, INEXACT)
+T(RN, 0x1.161868e18bc67p+2, 0x1.1ef3b263fd60bp+1, -0x1.6d0264p-3, 1, INEXACT)
+T(RN, -0x1.0c34b3e01e6e7p+3, -0x1.46d73255263d9p+3, 0x1.e0ec76p-3, -1, INEXACT)
+T(RN, -0x1.a206f0a19dcc4p+2, -0x1.9c91f19ac48c5p+2, 0x1.c2a38cp-2, -1, INEXACT)
+T(RN, 0x1.288bbb0d6a1e6p+3, 0x1.65c60768fcc11p+3, 0x1.2f22c2p-2, 1, INEXACT)
+T(RN, 0x1.52efd0cd80497p-1, 0x1.3cc760be720b3p-2, 0x1.0527e2p-2, 1, INEXACT)
+T(RN, -0x1.a05cc754481d1p-2, 0x1.4ef387fea1014p+0, -0x1.c3b036p-2, -1, INEXACT)
+T(RN, 0x1.1f9ef934745cbp-1, 0x1.d6f0efacc5699p-2, 0x1.c0b0a8p-2, 1, INEXACT)
+T(RN, 0x1.8c5db097f7442p-1, 0x1.6c1a14cf91533p-3, 0x1.16f4cap-5, 1, INEXACT)
+T(RN, -0x1.5b86ea8118a0ep-1, 0x1.695b1e0a0a59ep+0, 0x1.ada69ep-2, -1, INEXACT)
+T(RN, 0x0p+0, inf, 0x0p+0, 1, DIVBYZERO)
+/* T(RN, -0x0p+0, inf, 0x0p+0, -1, DIVBYZERO) This one fails in native as well */
+T(RN, 0x1p+0, 0x0p+0, 0x0p+0, 1, 0)
+T(RN, -0x1p+0, inf, 0x0p+0, 1, DIVBYZERO)
+T(RN, 0x1p+1, 0x0p+0, 0x0p+0, 1, 0)
+T(RN, -0x1p+1, inf, 0x0p+0, 1, DIVBYZERO)
+T(RN, inf, inf, 0x0p+0, 1, 0)
+T(RN, -inf, inf, 0x0p+0, -1, 0)
+T(RN, nan, nan, 0x0p+0, 1, 0)
+};
+
+static int eulpf(float x)
+{
+ union { float f; uint32_t i; } u = { x };
+ int e = u.i>>23 & 0xff;
+
+ if (!e)
+ e++;
+ return e - 0x7f - 23;
+}
+
+static int checkulp(float d, int r)
+{
+ // TODO: we only care about >=1.5 ulp errors for now, should be 1.0
+ if (r == RN)
+ return fabsf(d) < 1.5;
+ return 1;
+}
+
+static float ulperrf(float got, float want, float dwant)
+{
+ if (isnan(got) && isnan(want))
+ return 0;
+ if (got == want) {
+ if (signbit(got) == signbit(want))
+ return dwant;
+ return INFINITY;
+ }
+ if (isinf(got)) {
+ got = copysignf(0x1p127, got);
+ want *= 0.5;
+ }
+ return scalbn(got - want, -eulpf(want)) + dwant;
+}
+
+int main(void)
+{
+ int yi;
+ double y;
+ float d;
+ int e, i, err = 0;
+ struct f_fi *p;
+
+ for (i = 0; i < sizeof t/sizeof *t; i++) {
+ p = t + i;
+
+ if (p->r < 0)
+ continue;
+ y = lgammaf(p->x);
+ yi = signgam;
+
+ printf("%g,%d\n", y, yi);
+
+ d = ulperrf(y, p->y, p->dy);
+ if (!checkulp(d, p->r) || (!isnan(p->x) && p->x!=-inf && !(p->e&DIVBYZERO) && yi != p->i)) {
+ /* printf("%s:%d: %d lgammaf(%g) want %g,%lld got %g,%d ulperr %.3f = %g + %g\n",
+ p->file, p->line, p->r, p->x, p->y, p->i, y, yi, d, d-p->dy, p->dy); */
+ err++;
+ }
+ }
+ return !!err;
+}
diff --git a/tests/math/lgamma.out b/tests/math/lgamma.out
new file mode 100644
index 00000000..7412ffb6
--- /dev/null
+++ b/tests/math/lgamma.out
@@ -0,0 +1,18 @@
+-8.03528,-1
+2.24181,1
+-10.2138,-1
+-6.44641,-1
+11.1804,1
+0.309354,1
+1.3084,-1
+0.459903,1
+0.177784,1
+1.41155,-1
+inf,1
+0,1
+inf,1
+0,1
+inf,1
+inf,1
+inf,1
+nan,1
diff --git a/tests/openal_buffers.c b/tests/openal_buffers.c
index 6f51a685..31104a33 100644
--- a/tests/openal_buffers.c
+++ b/tests/openal_buffers.c
@@ -26,7 +26,7 @@ unsigned int bits = 0;
ALenum format = 0;
ALuint source = 0;
-void iter(void *arg) {
+void iter() {
ALuint buffer = 0;
ALint buffersProcessed = 0;
ALint buffersWereQueued = 0;
@@ -180,7 +180,7 @@ int main(int argc, char* argv[]) {
emscripten_set_main_loop(iter, 0, 0);
#else
while (1) {
- iter(NULL);
+ iter();
usleep(16);
}
#endif
diff --git a/tests/poppler/configure b/tests/poppler/configure
index 75813bc9..ab650a30 100755
--- a/tests/poppler/configure
+++ b/tests/poppler/configure
@@ -23051,12 +23051,12 @@ if test "x$GCC" != xyes; then
fi
case "$enable_compile_warnings" in
no) ;;
- yes) CXXFLAGS="-Wall -Wno-write-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wcast-align -fno-exceptions -fno-check-new -fno-common $CXXFLAGS" ;;
+ yes) CXXFLAGS="-Wall -Wno-write-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wcast-align -fno-exceptions -fno-common $CXXFLAGS" ;;
kde) CXXFLAGS="-Wnon-virtual-dtor -Wno-long-long -Wundef \
-D_XOPEN_SOURCE=600 -D_BSD_SOURCE -Wcast-align \
-Wconversion -Wall -W -Wpointer-arith \
-Wwrite-strings -O2 -Wformat-security \
- -Wmissing-format-attribute -fno-exceptions -fno-check-new \
+ -Wmissing-format-attribute -fno-exceptions \
-fno-common $CXXFLAGS" ;;
esac
diff --git a/tests/poppler/configure.ac b/tests/poppler/configure.ac
index f1217c8e..e492fe4b 100644
--- a/tests/poppler/configure.ac
+++ b/tests/poppler/configure.ac
@@ -610,12 +610,12 @@ if test "x$GCC" != xyes; then
fi
case "$enable_compile_warnings" in
no) ;;
- yes) CXXFLAGS="-Wall -Wno-write-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wcast-align -fno-exceptions -fno-check-new -fno-common $CXXFLAGS" ;;
+ yes) CXXFLAGS="-Wall -Wno-write-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wcast-align -fno-exceptions -fno-common $CXXFLAGS" ;;
kde) CXXFLAGS="-Wnon-virtual-dtor -Wno-long-long -Wundef \
-D_XOPEN_SOURCE=600 -D_BSD_SOURCE -Wcast-align \
-Wconversion -Wall -W -Wpointer-arith \
-Wwrite-strings -O2 -Wformat-security \
- -Wmissing-format-attribute -fno-exceptions -fno-check-new \
+ -Wmissing-format-attribute -fno-exceptions \
-fno-common $CXXFLAGS" ;;
esac
diff --git a/tests/printf/output.txt b/tests/printf/output.txt
index 0155f0da..a3baed28 100644
--- a/tests/printf/output.txt
+++ b/tests/printf/output.txt
@@ -8280,4 +8280,5 @@ ffffff8000000000
1
1
+1.234568E+04
no_new_line
diff --git a/tests/printf/output_i64_1.txt b/tests/printf/output_i64_1.txt
index e38fb78f..ea85d302 100644
--- a/tests/printf/output_i64_1.txt
+++ b/tests/printf/output_i64_1.txt
@@ -8280,4 +8280,5 @@ ffffff8000000000
1
1
+1.234568E+04
no_new_line
diff --git a/tests/printf/test.c b/tests/printf/test.c
index 1c8ad9f7..adeb69db 100644
--- a/tests/printf/test.c
+++ b/tests/printf/test.c
@@ -8285,6 +8285,7 @@ int main() {
printf("%hx\n", -0xFFFF);
printf("%x\n", -0xFFFFFFFF);
printf("\n");
+ printf("%*.*E\n", 10, -1, 12345.6789123);
printf("no_new_line");
return 0;
}
diff --git a/tests/runner.py b/tests/runner.py
index 37e307e9..7f0cbaed 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -342,7 +342,7 @@ process(sys.argv[1])
if self.library_cache is not None:
if cache and self.library_cache.get(cache_name):
- print >> sys.stderr, '<load %s from cache> ' % cache_name,
+ print >> sys.stderr, '<load %s from cache> ' % cache_name
generated_libs = []
for basename, contents in self.library_cache[cache_name]:
bc_file = os.path.join(build_dir, cache_name + '_' + basename)
@@ -352,7 +352,7 @@ process(sys.argv[1])
generated_libs.append(bc_file)
return generated_libs
- print >> sys.stderr, '<building and saving %s into cache> ' % cache_name,
+ print >> sys.stderr, '<building and saving %s into cache> ' % cache_name
return Building.build_library(name, build_dir, output_dir, generated_libs, configure, configure_args, make, make_args, self.library_cache, cache_name,
copy_project=True, env_init=env_init, native=native)
@@ -649,6 +649,7 @@ class BrowserCore(RunnerCore):
def btest(self, filename, expected=None, reference=None, force_c=False, reference_slack=0, manual_reference=False, post_build=None,
args=[], outfile='test.html', message='.'): # TODO: use in all other tests
+ if os.environ.get('EMCC_FAST_COMPILER') == '1' and 'LEGACY_GL_EMULATION=1' in args: return self.skip('no legacy gl emulation in fastcomp')
# if we are provided the source and not a path, use that
filename_is_src = '\n' in filename
src = filename if filename_is_src else ''
diff --git a/tests/sdl_canvas.c b/tests/sdl_canvas.c
index 6bd659b8..cab48985 100644
--- a/tests/sdl_canvas.c
+++ b/tests/sdl_canvas.c
@@ -62,6 +62,8 @@ int main(int argc, char **argv) {
printf("you should see two lines of text in different colors and a blue rectangle\n");
+ SDL_UnlockSurface(screen);
+
SDL_Quit();
printf("done.\n");
diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py
index d84f36e4..21a47178 100644
--- a/tests/test_benchmark.py
+++ b/tests/test_benchmark.py
@@ -58,7 +58,7 @@ class NativeBenchmarker(Benchmarker):
def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder):
self.parent = parent
- if lib_builder: native_args += lib_builder(self.name, native=True, env_init={ 'CC': self.cc, 'CXX': self.cxx })
+ 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)
@@ -67,7 +67,6 @@ class NativeBenchmarker(Benchmarker):
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 "Output: " + output[0]
else:
- print '(using clang)'
shutil.copyfile(native_exec, filename + '.native')
shutil.copymode(native_exec, filename + '.native')
@@ -90,7 +89,8 @@ class JSBenchmarker(Benchmarker):
def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder):
self.filename = filename
- if lib_builder: emcc_args += lib_builder('js', native=False, env_init={})
+ llvm_root = self.env.get('LLVM') or LLVM_ROOT
+ if lib_builder: emcc_args = emcc_args + lib_builder('js_' + llvm_root, native=False, env_init=self.env)
open('hardcode.py', 'w').write('''
def process(filename):
@@ -119,16 +119,27 @@ process(sys.argv[1])
return run_js(self.filename, engine=self.engine, args=args, stderr=PIPE, full_output=True)
# Benchmarkers
-benchmarkers = [
- NativeBenchmarker('clang', CLANG_CC, CLANG),
- #NativeBenchmarker('gcc', 'gcc', 'g++'),
- #JSBenchmarker('sm-f32', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2']),
- JSBenchmarker('sm', SPIDERMONKEY_ENGINE),
- #JSBenchmarker('sm-fc', SPIDERMONKEY_ENGINE, env={ 'EMCC_FAST_COMPILER': '1' }),
- #JSBenchmarker('sm-noasm', SPIDERMONKEY_ENGINE + ['--no-asmjs']),
- #JSBenchmarker('sm-noasm-f32', SPIDERMONKEY_ENGINE + ['--no-asmjs'], ['-s', 'PRECISE_F32=2']),
- #JSBenchmarker('v8', V8_ENGINE)
-]
+try:
+ benchmarkers_error = ''
+ 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.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++'),
+ JSBenchmarker('sm-f32', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2']),
+ #JSBenchmarker('sm-f32-aggro', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2', '-s', 'AGGRESSIVE_VARIABLE_ELIMINATION=1']),
+ #JSBenchmarker('sm-f32-3.2', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2'], env={ 'LLVM': LLVM_3_2 }),
+ #JSBenchmarker('sm-f32-3.3', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2'], env={ 'LLVM': LLVM_3_3 }),
+ #JSBenchmarker('sm-f32-3.4', SPIDERMONKEY_ENGINE, ['-s', 'PRECISE_F32=2'], env={ 'LLVM': LLVM_3_4 }),
+ #JSBenchmarker('sm-fc', SPIDERMONKEY_ENGINE, env={ 'EMCC_FAST_COMPILER': '1' }),
+ #JSBenchmarker('sm-noasm', SPIDERMONKEY_ENGINE + ['--no-asmjs']),
+ #JSBenchmarker('sm-noasm-f32', SPIDERMONKEY_ENGINE + ['--no-asmjs'], ['-s', 'PRECISE_F32=2']),
+ #JSBenchmarker('v8', V8_ENGINE)
+ ]
+except Exception, e:
+ benchmarkers_error = str(e)
+ benchmarkers = []
class benchmark(RunnerCore):
save_dir = True
@@ -166,6 +177,8 @@ class benchmark(RunnerCore):
Building.COMPILER_TEST_OPTS = []
def do_benchmark(self, name, src, expected_output='FAIL', args=[], emcc_args=[], native_args=[], shared_args=[], force_c=False, reps=TEST_REPS, native_exec=None, output_parser=None, args_processor=None, lib_builder=None):
+ if len(benchmarkers) == 0: raise Exception('error, no benchmarkers: ' + benchmarkers_error)
+
args = args or [DEFAULT_ARG]
if args_processor: args = args_processor(args)
@@ -458,17 +471,15 @@ 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')
- #shutil.copyfile(path_from_root('tests', 'lua', 'binarytrees.lua'), 'binarytrees.lua')
- #shutil.copyfile(path_from_root('tests', 'lua', 'scimark.lua'), 'scimark.lua')
- emcc_args = self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None) + \
- ['--embed-file', benchmark + '.lua']
- #['--embed-file', 'binarytrees.lua', '--embed-file', 'scimark.lua'] + ['--minify', '0']
- shutil.copyfile(emcc_args[0], emcc_args[0] + '.bc')
- emcc_args[0] += '.bc'
- native_args = self.get_library('lua_native', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None, native=True)
-
+ 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)
+ if native: return ret
+ shutil.copyfile(ret[0], ret[0] + '.bc')
+ ret[0] += '.bc'
+ return ret
self.do_benchmark('lua_' + benchmark, '', expected,
- force_c=True, args=[benchmark + '.lua', DEFAULT_ARG], emcc_args=emcc_args, native_args=native_args, native_exec=os.path.join('building', 'lua_native', 'src', 'lua'),
+ force_c=True, args=[benchmark + '.lua', DEFAULT_ARG], emcc_args=['--embed-file', benchmark + '.lua'],
+ lib_builder=lib_builder, native_exec=os.path.join('building', 'lua_native', 'src', 'lua'),
output_parser=output_parser, args_processor=args_processor)
def test_zzz_lua_scimark(self):
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 920c6f8c..eed18a3d 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -120,6 +120,8 @@ If manually bisecting:
'''
def test_emscripten_log(self):
+ if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('fastcomp uses asm, where call stacks are sometimes less clear')
+
src = os.path.join(self.get_dir(), 'src.cpp')
open(src, 'w').write(self.with_report_result(open(path_from_root('tests', 'emscripten_log', 'emscripten_log.cpp')).read()))
@@ -680,10 +682,7 @@ If manually bisecting:
self.btest('sdl_stb_image_data.c', reference='screenshot.jpg', args=['-s', 'STB_IMAGE=1', '--preload-file', 'screenshot.not'])
def test_sdl_canvas(self):
- open(os.path.join(self.get_dir(), 'sdl_canvas.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas.c')).read()))
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
+ self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1'])
def test_sdl_canvas_proxy(self):
def post():
@@ -1111,6 +1110,8 @@ keydown(100);keyup(100); // trigger the end
self.run_browser('page.html', '', '/report_result?1')
def test_sdl_audio_beeps(self):
+ if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo c++ exceptions in fastcomp')
+
open(os.path.join(self.get_dir(), 'sdl_audio_beep.cpp'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio_beep.cpp')).read()))
# use closure to check for a possible bug with closure minifying away newer Audio() attributes
@@ -1194,10 +1195,7 @@ keydown(100);keyup(100); // trigger the end
self.btest('openal_buffers.c', '0', args=['--preload-file', 'the_entertainer.wav'],)
def test_glfw(self):
- open(os.path.join(self.get_dir(), 'glfw.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'glfw.c')).read()))
-
- Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
- self.run_browser('page.html', '', '/report_result?1')
+ self.btest('glfw.c', '1', args=['-s', 'LEGACY_GL_EMULATION=1'])
def test_egl(self):
open(os.path.join(self.get_dir(), 'test_egl.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl.c')).read()))
@@ -1436,6 +1434,8 @@ keydown(100);keyup(100); // trigger the end
self.btest('sdl_resize.c', '1')
def test_gc(self):
+ if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('flaky in fastcomp and also non-fastcomp -O1, timing issues')
+
self.btest('browser_gc.cpp', '1')
def test_glshaderinfo(self):
@@ -1622,11 +1622,12 @@ keydown(100);keyup(100); // trigger the end
self.btest('s3tc_crunch.c', reference='s3tc_crunch.png', reference_slack=11, args=['--pre-js', 'asset_a.js', '--pre-js', 'asset_b.js', '-s', 'LEGACY_GL_EMULATION=1'])
def test_aniso(self):
- if SPIDERMONKEY_ENGINE in JS_ENGINES:
+ if SPIDERMONKEY_ENGINE in JS_ENGINES and os.environ.get('EMCC_FAST_COMPILER') != '1':
# asm.js-ification check
Popen([PYTHON, EMCC, path_from_root('tests', 'aniso.c'), '-O2', '-g2', '-s', 'LEGACY_GL_EMULATION=1']).communicate()
Settings.ASM_JS = 1
self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js')
+ print 'passed asm test'
shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-s', 'LEGACY_GL_EMULATION=1'])
@@ -1681,6 +1682,8 @@ keydown(100);keyup(100); // trigger the end
self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')])
def test_module(self):
+ if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+
Popen([PYTHON, EMCC, path_from_root('tests', 'browser_module.cpp'), '-o', 'module.js', '-O2', '-s', 'SIDE_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two"]']).communicate()
self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1'], expected='8')
@@ -1717,3 +1720,47 @@ keydown(100);keyup(100); // trigger the end
assert 'argv[3]: 3' in stdout
assert 'hello, world!' in stdout
assert 'hello, error stream!' in stderr
+
+ def test_uuid(self):
+ # Run with ./runner.py browser.test_uuid
+ # We run this test in Node/SPIDERMONKEY and browser environments because we try to make use of
+ # high quality crypto random number generators such as crypto.getRandomValues or randomBytes (if available).
+
+ # First run tests in Node and/or SPIDERMONKEY using run_js. Use closure compiler so we can check that
+ # require('crypto').randomBytes and window.crypto.getRandomValues doesn't get minified out.
+ Popen([PYTHON, EMCC, '-O2', '--closure', '1', path_from_root('tests', 'uuid', 'test.c'), '-o', path_from_root('tests', 'uuid', 'test.js')], stdout=PIPE, stderr=PIPE).communicate()
+
+ test_js_closure = open(path_from_root('tests', 'uuid', 'test.js')).read()
+
+ # Check that test.js compiled with --closure 1 contains ").randomBytes" and "window.crypto.getRandomValues"
+ assert ").randomBytes" in test_js_closure
+ assert "window.crypto.getRandomValues" in test_js_closure
+
+ out = run_js(path_from_root('tests', 'uuid', 'test.js'), full_output=True)
+ print out
+
+ # Tidy up files that might have been created by this test.
+ try_delete(path_from_root('tests', 'uuid', 'test.js'))
+ try_delete(path_from_root('tests', 'uuid', 'test.js.map'))
+
+ # 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 c149281b..6c483069 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -477,6 +477,14 @@ 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_literal_negative_zero(self):
+ if self.emcc_args == None: return self.skip('needs emcc')
+
+ test_path = path_from_root('tests', 'core', 'test_literal_negative_zero')
+ src, output = (test_path + s for s in ('.in', '.out'))
+
+ self.do_run_from_file(src, output)
+
def test_llvm_intrinsics(self):
if self.emcc_args == None: return self.skip('needs ta2')
@@ -502,6 +510,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_cube2md5(self):
if self.emcc_args == None: return self.skip('needs emcc')
+ if not self.is_le32(): return self.skip('le32 needed for accurate math')
self.emcc_args += ['--embed-file', 'cube2md5.txt']
shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt'))
self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read())
@@ -829,6 +838,15 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read()
self.do_run(src, expected)
+ def test_math_lgamma(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ if not self.is_le32(): return self.skip('le32 needed for accurate math')
+
+ test_path = path_from_root('tests', 'math', 'lgamma')
+ src, output = (test_path + s for s in ('.in', '.out'))
+
+ self.do_run_from_file(src, output)
+
def test_frexp(self):
test_path = path_from_root('tests', 'core', 'test_frexp')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -937,6 +955,8 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
for named in (0, 1):
print named
+ if os.environ.get('EMCC_FAST_COMPILER') == '1' and named: continue # no named globals in fastcomp
+
Settings.NAMED_GLOBALS = named
self.do_run_from_file(src, output, ['wowie', 'too', '74'])
@@ -1184,7 +1204,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_exceptions(self):
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
Settings.EXCEPTION_DEBUG = 1
@@ -1273,7 +1292,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_exception_2(self):
if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
Settings.DISABLE_EXCEPTION_CATCHING = 0
test_path = path_from_root('tests', 'core', 'test_exception_2')
@@ -1281,6 +1299,7 @@ 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_white_list_exception(self):
if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
@@ -1298,7 +1317,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_uncaught_exception(self):
if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
Settings.DISABLE_EXCEPTION_CATCHING = 0
@@ -1337,8 +1355,6 @@ 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):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
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()
@@ -1357,7 +1373,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_std_exception(self):
if self.emcc_args is None: return self.skip('requires emcc')
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
Settings.DISABLE_EXCEPTION_CATCHING = 0
self.emcc_args += ['-s', 'SAFE_HEAP=0']
@@ -1367,8 +1382,6 @@ 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_async_exit(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
-
open('main.c', 'w').write(r'''
#include <stdio.h>
#include <stdlib.h>
@@ -3542,6 +3555,7 @@ ok
def test_strtod(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')
src = r'''
#include <stdio.h>
@@ -3571,6 +3585,8 @@ ok
printf("%g\n", strtod("123e-50", &endptr));
printf("%g\n", strtod("123e-250", &endptr));
printf("%g\n", strtod("123e-450", &endptr));
+ printf("%g\n", strtod("0x6", &endptr));
+ printf("%g\n", strtod("-0x0p+0", &endptr));
char str[] = " 12.34e56end";
printf("%g\n", strtod(str, &endptr));
@@ -3603,6 +3619,8 @@ ok
1.23e-48
1.23e-248
0
+ 6
+ -0
1.234e+57
10
inf
@@ -3687,6 +3705,7 @@ ok
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')
test_path = path_from_root('tests', 'core', 'test_sscanf')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -4071,6 +4090,12 @@ def process(filename):
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'])
+ def test_wprintf(self):
+ if self.emcc_args is None: return self.skip('requires libcxx')
+ test_path = path_from_root('tests', 'core', 'test_wprintf')
+ src, output = (test_path + s for s in ('.c', '.out'))
+ self.do_run_from_file(src, output)
+
def test_direct_string_constant_usage(self):
if self.emcc_args is None: return self.skip('requires libcxx')
@@ -4602,7 +4627,6 @@ return malloc(size);
def test_simd(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
test_path = path_from_root('tests', 'core', 'test_simd')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -4611,7 +4635,6 @@ return malloc(size);
def test_simd2(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
test_path = path_from_root('tests', 'core', 'test_simd2')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -4619,9 +4642,10 @@ 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
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
test_path = path_from_root('tests', 'core', 'test_simd3')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -4650,12 +4674,15 @@ return malloc(size);
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')
- self.do_run('',
- 'hello lua world!\n17\n1\n2\n3\n4\n7',
- args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
- libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None),
- includes=[path_from_root('tests', 'lua')],
- output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n'))
+ for aggro in ([0, 1] if Settings.ASM_JS and '-O2' in self.emcc_args else [0]):
+ print aggro
+ Settings.AGGRESSIVE_VARIABLE_ELIMINATION = aggro
+ self.do_run('',
+ 'hello lua world!\n17\n1\n2\n3\n4\n7',
+ args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
+ libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None),
+ includes=[path_from_root('tests', 'lua')],
+ output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n'))
def get_freetype(self):
Settings.DEAD_FUNCTIONS += ['_inflateEnd', '_inflate', '_inflateReset', '_inflateInit2_']
@@ -5033,7 +5060,7 @@ def process(filename):
'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
- 'sillyfuncast', 'sillyfuncast2', 'sillybitcast', 'atomicrmw_unaligned' # TODO XXX
+ 'sillyfuncast2', 'sillybitcast', 'atomicrmw_unaligned' # TODO XXX
]: continue
if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2:
print self.skip('case "%s" only relevant for ta2' % shortname)
diff --git a/tests/test_other.py b/tests/test_other.py
index 4bdd889b..00c42418 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -197,7 +197,7 @@ Options that are modified or new in %s include:
#(['-O2', '-g4'], lambda generated: 'var b=0' not in generated and 'var b = 0' not in generated and 'function _main' in generated, 'same as -g3 for now'),
(['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'),
(['-O3', '-s', 'INLINING_LIMIT=0', '--closure', '0'], lambda generated: 'function _dump' not in generated, 'lto/inlining'),
- (['-Os', '--llvm-lto', '1', '-s', 'ASM_JS=0'], lambda generated: 'function _dump' in generated, '-Os disables inlining'),
+ (['-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'),
([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'),
@@ -209,6 +209,7 @@ Options that are modified or new in %s include:
]:
print params, text
self.clear()
+ if os.environ.get('EMCC_FAST_COMPILER') == '1' and ['disable typed arrays', 'typed arrays 1 selected']: continue
output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop.cpp'), '-o', 'a.out.js'] + params, stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
assert os.path.exists('a.out.js'), '\n'.join(output)
@@ -1735,6 +1736,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]
@@ -2149,10 +2152,19 @@ int main()
self.assertContained('File size: 722', out)
def test_simd(self):
- if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp')
+ if get_clang_version() == '3.2':
+ simd_args = ['-O3', '-vectorize', '-vectorize-loops']
+ elif get_clang_version() == '3.3':
+ simd_args = ['-O3', '-vectorize-loops', '-vectorize-slp-aggressive', '-bb-vectorize-aligned-only'] # XXX this generates <2 x float> , '-vectorize-slp']
+ elif get_clang_version() == '3.4':
+ simd_args = ['-O3'] # vectorization on by default, SIMD=1 makes us not disable it
+ else:
+ raise Exception('unknown llvm version')
+
+ simd_args += ['-bb-vectorize-vector-bits=128', '-force-vector-width=4']
self.clear()
- Popen([PYTHON, EMCC, path_from_root('tests', 'linpack.c'), '-O2', '-DSP', '--llvm-opts', '''['-O3', '-vectorize', '-vectorize-loops', '-bb-vectorize-vector-bits=128', '-force-vector-width=4']''']).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'linpack.c'), '-O2', '-s', 'SIMD=1', '-DSP', '--llvm-opts', str(simd_args)]).communicate()
self.assertContained('Unrolled Single Precision', run_js('a.out.js'))
def test_dependency_file(self):
@@ -2208,3 +2220,36 @@ mergeInto(LibraryManager.library, {
process = Popen([PYTHON, EMCC, '-c', path_from_root('tests', 'hello_world.c'), '-o', outdir, '--default-obj-ext', 'obj'], stdout=PIPE, stderr=PIPE)
process.communicate()
assert(os.path.isfile(outdir + 'hello_world.obj'))
+
+
+ def test_doublestart_bug(self):
+ open('code.cpp', 'w').write(r'''
+#include <stdio.h>
+#include <emscripten.h>
+
+void main_loop(void) {
+ static int cnt = 0;
+ if (++cnt >= 10) emscripten_cancel_main_loop();
+}
+
+int main(void) {
+ printf("This should only appear once.\n");
+ emscripten_set_main_loop(main_loop, 10, 0);
+ return 0;
+}
+''')
+
+ 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');
+});
+''')
+
+ Popen([PYTHON, EMCC, 'code.cpp', '--pre-js', 'pre.js']).communicate()
+ output = run_js(os.path.join(self.get_dir(), 'a.out.js'), engine=NODE_JS)
+
+ assert output.count('This should only appear once.') == 1, '\n'+output
+
diff --git a/tests/test_webgl_context_attributes_common.c b/tests/test_webgl_context_attributes_common.c
index 7131203b..80506b50 100644
--- a/tests/test_webgl_context_attributes_common.c
+++ b/tests/test_webgl_context_attributes_common.c
@@ -238,9 +238,9 @@ static void draw() {
}
-extern int webglAntialiasSupported();
-extern int webglDepthSupported();
-extern int webglStencilSupported();
+extern int webglAntialiasSupported(void);
+extern int webglDepthSupported(void);
+extern int webglStencilSupported(void);
// Check attributes support in the WebGL implementation (see test_webgl_context_attributes function in test_browser.py)
// Tests will succeed if they are not.
diff --git a/tests/uuid/test.c b/tests/uuid/test.c
new file mode 100644
index 00000000..dc2c6589
--- /dev/null
+++ b/tests/uuid/test.c
@@ -0,0 +1,69 @@
+#include <uuid/uuid.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <emscripten.h>
+
+int isUUID(char* p, int upper) {
+ char* p1 = p;
+ do {
+ if (!(isxdigit(*p1) || (*p1 == '-')) || (upper && islower(*p1)) || (!upper && isupper(*p1))) {
+ return 0;
+ } else {
+ }
+ } while (*++p1 != 0);
+
+ if ((p[8] == '-') && (p[13] == '-') && (p[18] == '-') && (p[23] == '-')) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int main() {
+ uuid_t uuid;
+ uuid_t uuid1;
+ uuid_t uuid2;
+ uuid_t empty_uuid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uuid_generate(uuid);
+
+ assert(uuid_is_null(uuid) == 0);
+ assert(uuid_type(uuid) == UUID_TYPE_DCE_RANDOM);
+ assert(uuid_variant(uuid) == UUID_VARIANT_DCE);
+
+ char *generated = (char *)malloc(37*sizeof(char));
+ uuid_unparse(uuid, generated);
+ assert(isUUID(generated, 0) == 1); // Check it's a valid lower case UUID string.
+ printf("\nuuid = %s\n", generated);
+
+ assert(uuid_parse(generated, uuid1) == 0); // Check the generated UUID parses correctly into a compact UUID.
+ assert(uuid_compare(uuid1, uuid) == 0); // Compare the parsed UUID with the original.
+
+ uuid_unparse_lower(uuid, generated);
+ assert(isUUID(generated, 0) == 1); // Check it's a valid lower case UUID string.
+ printf("uuid = %s\n", generated);
+
+ uuid_unparse_upper(uuid, generated);
+ assert(isUUID(generated, 1) == 1); // Check it's a valid upper case UUID string.
+ printf("uuid = %s\n", generated);
+
+
+ uuid_copy(uuid2, uuid);
+ assert(uuid_compare(uuid2, uuid) == 0);
+
+ uuid_clear(uuid);
+ assert(uuid_compare(empty_uuid, uuid) == 0);
+
+ assert(uuid_is_null(uuid) == 1);
+
+ // The following lets the browser test exit cleanly.
+ int result = 1;
+ #if EMSCRIPTEN
+ #ifdef REPORT_RESULT
+ REPORT_RESULT();
+ #endif
+ #endif
+ exit(0);
+}
+
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 161ed59c..3a6d70bc 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1743,6 +1743,36 @@ function getStackBumpSize(ast) {
return node ? node[3][2][3][1] : 0;
}
+// Name minification
+
+var RESERVED = set('do', 'if', 'in', 'for', 'new', 'try', 'var', 'env', 'let');
+var VALID_MIN_INITS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
+var VALID_MIN_LATERS = VALID_MIN_INITS + '0123456789';
+
+var minifiedNames = [];
+var minifiedState = [0];
+
+function ensureMinifiedNames(n) { // make sure the nth index in minifiedNames exists. done 100% deterministically
+ while (minifiedNames.length < n+1) {
+ // generate the current name
+ var name = VALID_MIN_INITS[minifiedState[0]];
+ for (var i = 1; i < minifiedState.length; i++) {
+ name += VALID_MIN_LATERS[minifiedState[i]];
+ }
+ if (!(name in RESERVED)) minifiedNames.push(name);
+ // increment the state
+ var i = 0;
+ while (1) {
+ minifiedState[i]++;
+ if (minifiedState[i] < (i === 0 ? VALID_MIN_INITS : VALID_MIN_LATERS).length) break;
+ // overflow
+ minifiedState[i] = 0;
+ i++;
+ if (i === minifiedState.length) minifiedState.push(-1); // will become 0 after increment in next loop head
+ }
+ }
+}
+
// 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.)
@@ -1853,14 +1883,14 @@ function registerize(ast) {
return ret;
}
// find the next free minified name that is not used by a global that shows up in this function
- while (nextRegName < extraInfo.names.length) {
- var ret = extraInfo.names[nextRegName++];
+ while (1) {
+ ensureMinifiedNames(nextRegName);
+ var ret = minifiedNames[nextRegName++];
if (!usedGlobals[ret]) {
regTypes[ret] = type;
return ret;
}
}
- assert('ran out of names');
}
// Find the # of uses of each variable.
// While doing so, check if all a variable's uses are dominated in a simple
@@ -2847,16 +2877,16 @@ function minifyGlobals(ast) {
var vars = node[1];
for (var i = 0; i < vars.length; i++) {
var name = vars[i][0];
- assert(next < extraInfo.names.length);
- vars[i][0] = minified[name] = extraInfo.names[next++];
+ ensureMinifiedNames(next);
+ vars[i][0] = minified[name] = minifiedNames[next++];
}
}
});
// add all globals in function chunks, i.e. not here but passed to us
for (var i = 0; i < extraInfo.globals.length; i++) {
name = extraInfo.globals[i];
- assert(next < extraInfo.names.length);
- minified[name] = extraInfo.names[next++];
+ ensureMinifiedNames(next);
+ minified[name] = minifiedNames[next++];
}
// apply minification
traverse(ast, function(node, type) {
@@ -2930,162 +2960,180 @@ function relocate(ast) {
var NODES_WITHOUT_ELIMINATION_SENSITIVITY = set('name', 'num', 'binary', 'unary-prefix');
var FAST_ELIMINATION_BINARIES = setUnion(setUnion(USEFUL_BINARY_OPS, COMPARE_OPS), set('+'));
-function outline(ast) {
- function measureSize(ast) {
- var size = 0;
- traverse(ast, function() {
- size++;
- });
- return size;
- }
-
- function aggressiveVariableElimination(func, asmData) {
- // This removes as many variables as possible. This is often not the best thing because it increases
- // code size, but it is far preferable to the risk of split functions needing to do more spilling. Specifically,
- // it finds 'trivial' variables: ones with 1 definition, and that definition is not sensitive to any changes: it
- // only depends on constants and local variables that are themselves trivial. We can unquestionably eliminate
- // such variables in a trivial manner.
-
- var assignments = {};
- var appearances = {};
- var defs = {};
- var considered = {};
+function measureSize(ast) {
+ var size = 0;
+ traverse(ast, function() {
+ size++;
+ });
+ return size;
+}
- traverse(func, function(node, type) {
- if (type == 'assign' && node[2][0] == 'name') {
- var name = node[2][1];
- if (name in asmData.vars) {
- assignments[name] = (assignments[name] || 0) + 1;
- appearances[name] = (appearances[name] || 0) - 1; // this appearance is a definition, offset the counting later
- defs[name] = node;
- } else {
- if (name in asmData.params) {
- assignments[name] = (assignments[name] || 1) + 1; // init to 1 for initial parameter assignment
- considered[name] = true; // this parameter is not ssa, it must be in a hand-optimized function, so it is not trivial
- }
- }
- } else if (type == 'name') {
- var name = node[1];
- if (name in asmData.vars) {
- appearances[name] = (appearances[name] || 0) + 1;
+function aggressiveVariableEliminationInternal(func, asmData) {
+ // This removes as many variables as possible. This is often not the best thing because it increases
+ // code size, but it is far preferable to the risk of split functions needing to do more spilling, so
+ // we use it when outlining.
+ // Specifically, this finds 'trivial' variables: ones with 1 definition, and that definition is not sensitive to any changes: it
+ // only depends on constants and local variables that are themselves trivial. We can unquestionably eliminate
+ // such variables in a trivial manner.
+
+ var assignments = {};
+ var appearances = {};
+ var defs = {};
+ var considered = {};
+
+ traverse(func, function(node, type) {
+ if (type == 'assign' && node[2][0] == 'name') {
+ var name = node[2][1];
+ if (name in asmData.vars) {
+ assignments[name] = (assignments[name] || 0) + 1;
+ appearances[name] = (appearances[name] || 0) - 1; // this appearance is a definition, offset the counting later
+ defs[name] = node;
+ } else {
+ if (name in asmData.params) {
+ assignments[name] = (assignments[name] || 1) + 1; // init to 1 for initial parameter assignment
+ considered[name] = true; // this parameter is not ssa, it must be in a hand-optimized function, so it is not trivial
}
}
- });
+ } else if (type == 'name') {
+ var name = node[1];
+ if (name in asmData.vars) {
+ appearances[name] = (appearances[name] || 0) + 1;
+ }
+ }
+ });
- var allTrivials = {}; // key of a trivial var => size of its (expanded) value, at least 1
-
- // three levels of variables:
- // 1. trivial: 1 def (or less), uses nothing sensitive, can be eliminated
- // 2. safe: 1 def (or less), can be used in a trivial, but cannot itself be eliminated
- // 3. sensitive: uses a global or memory or something else that prevents trivial elimination.
-
- function assessTriviality(name) {
- // only care about vars with 0-1 assignments of (0 for parameters), and can ignore label (which is not explicitly initialized, but cannot be eliminated ever anyhow)
- if (assignments[name] > 1 || (!(name in asmData.vars) && !(name in asmData.params)) || name == 'label') return false;
- if (considered[name]) return allTrivials[name];
- considered[name] = true;
- var sensitive = false;
- var size = 0, originalSize = 0;
- var def = defs[name];
- if (def) {
- var value = def[3];
- originalSize = measureSize(value);
- if (value) {
- traverse(value, function recurseValue(node, type) {
- var one = node[1];
- if (!(type in NODES_WITHOUT_ELIMINATION_SENSITIVITY)) { // || (type == 'binary' && !(one in FAST_ELIMINATION_BINARIES))) {
- sensitive = true;
+ var allTrivials = {}; // key of a trivial var => size of its (expanded) value, at least 1
+
+ // three levels of variables:
+ // 1. trivial: 1 def (or less), uses nothing sensitive, can be eliminated
+ // 2. safe: 1 def (or less), can be used in a trivial, but cannot itself be eliminated
+ // 3. sensitive: uses a global or memory or something else that prevents trivial elimination.
+
+ function assessTriviality(name) {
+ // only care about vars with 0-1 assignments of (0 for parameters), and can ignore label (which is not explicitly initialized, but cannot be eliminated ever anyhow)
+ if (assignments[name] > 1 || (!(name in asmData.vars) && !(name in asmData.params)) || name == 'label') return false;
+ if (considered[name]) return allTrivials[name];
+ considered[name] = true;
+ var sensitive = false;
+ var size = 0, originalSize = 0;
+ var def = defs[name];
+ if (def) {
+ var value = def[3];
+ originalSize = measureSize(value);
+ if (value) {
+ traverse(value, function recurseValue(node, type) {
+ var one = node[1];
+ if (!(type in NODES_WITHOUT_ELIMINATION_SENSITIVITY)) { // || (type == 'binary' && !(one in FAST_ELIMINATION_BINARIES))) {
+ sensitive = true;
+ return true;
+ }
+ if (type == 'name' && !assessTriviality(one)) {
+ if (assignments[one] > 1 || (!(one in asmData.vars) && !(one in asmData.params))) {
+ sensitive = true; // directly using something sensitive
return true;
- }
- if (type == 'name' && !assessTriviality(one)) {
- if (assignments[one] > 1 || (!(one in asmData.vars) && !(one in asmData.params))) {
- sensitive = true; // directly using something sensitive
- return true;
- } // otherwise, not trivial, but at least safe.
- }
- // if this is a name, it must be a trivial variable (or a safe one) and we know its size
- size += ((type == 'name') ? allTrivials[one] : 1) || 1;
- });
- }
- }
- if (!sensitive) {
- size = size || 1;
- originalSize = originalSize || 1;
- var factor = ((appearances[name] - 1) || 0) * (size - originalSize); // If no size change or just one appearance, always ok to trivially eliminate. otherwise, tradeoff
- if (factor <= 12) {
- allTrivials[name] = size; // trivial!
- return true;
- }
+ } // otherwise, not trivial, but at least safe.
+ }
+ // if this is a name, it must be a trivial variable (or a safe one) and we know its size
+ size += ((type == 'name') ? allTrivials[one] : 1) || 1;
+ });
}
- return false;
}
- for (var name in asmData.vars) {
- assessTriviality(name);
+ if (!sensitive) {
+ size = size || 1;
+ originalSize = originalSize || 1;
+ var factor = ((appearances[name] - 1) || 0) * (size - originalSize); // If no size change or just one appearance, always ok to trivially eliminate. otherwise, tradeoff
+ if (factor <= 12) {
+ allTrivials[name] = size; // trivial!
+ return true;
+ }
}
- var trivials = {};
+ return false;
+ }
+ for (var name in asmData.vars) {
+ assessTriviality(name);
+ }
+ var trivials = {};
- for (var name in allTrivials) { // from now on, ignore parameters
- if (name in asmData.vars) trivials[name] = true;
- }
+ for (var name in allTrivials) { // from now on, ignore parameters
+ if (name in asmData.vars) trivials[name] = true;
+ }
- allTrivials = {};
+ allTrivials = {};
- var values = {};
+ var values = {}, recursives = {};
- function evaluate(name) {
- var node = values[name];
- if (node) return node;
- values[node] = null; // prevent infinite recursion
- var def = defs[name];
- if (def) {
- node = def[3];
- if (node[0] == 'name') {
- var name2 = node[1];
- if (name2 in trivials) {
- node = evaluate(name2);
- }
- } else {
- traverse(node, function(node, type) {
- if (type == 'name') {
- var name2 = node[1];
- if (name2 in trivials) {
- return evaluate(name2);
- }
- }
- });
+ function evaluate(name) {
+ var node = values[name];
+ if (node) return node;
+ values[name] = null; // prevent infinite recursion
+ var def = defs[name];
+ if (def) {
+ node = def[3];
+ if (node[0] == 'name') {
+ var name2 = node[1];
+ assert(name2 !== name);
+ if (name2 in trivials) {
+ node = evaluate(name2);
}
- values[name] = node;
+ } else {
+ traverse(node, function(node, type) {
+ if (type == 'name') {
+ var name2 = node[1];
+ if (name2 === name) {
+ recursives[name] = 1;
+ return false;
+ }
+ if (name2 in trivials) {
+ return evaluate(name2);
+ }
+ }
+ });
}
- return node;
+ values[name] = node;
}
+ return node;
+ }
+
+ for (var name in trivials) {
+ evaluate(name);
+ }
+ for (var name in recursives) {
+ delete trivials[name];
+ }
- for (var name in trivials) {
- evaluate(name);
+ for (var name in trivials) {
+ var def = defs[name];
+ if (def) {
+ def.length = 0;
+ def[0] = 'toplevel';
+ def[1] = [];
}
+ delete asmData.vars[name];
+ }
- for (var name in trivials) {
- var def = defs[name];
- if (def) {
- def.length = 0;
- def[0] = 'toplevel';
- def[1] = [];
+ // Perform replacements TODO: save list of uses objects before, replace directly, avoid extra traverse
+ traverse(func, function(node, type) {
+ if (type == 'name') {
+ var name = node[1];
+ if (name in trivials) {
+ var value = values[name];
+ if (value) return copy(value); // must copy, or else the same object can be used multiple times
+ else return emptyNode();
}
- delete asmData.vars[name];
}
+ });
+}
- // Perform replacements TODO: save list of uses objects before, replace directly, avoid extra traverse
- traverse(func, function(node, type) {
- if (type == 'name') {
- 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
- }
- }
- });
- }
+function aggressiveVariableElimination(ast) {
+ assert(asm, 'need ASM_JS for aggressive variable elimination');
+ traverseGeneratedFunctions(ast, function(func, type) {
+ var asmData = normalizeAsm(func);
+ aggressiveVariableEliminationInternal(func, asmData);
+ denormalizeAsm(func, asmData);
+ });
+}
+function outline(ast) {
// Try to flatten out code as much as possible, to make outlining more feasible.
function flatten(func, asmData) {
var minSize = extraInfo.sizeToOutline/4;
@@ -3740,7 +3788,7 @@ function outline(ast) {
var size = measureSize(func);
if (size >= extraInfo.sizeToOutline && maxTotalFunctions > 0) {
maxTotalFunctions--;
- aggressiveVariableElimination(func, asmData);
+ aggressiveVariableEliminationInternal(func, asmData);
flatten(func, asmData);
analyzeFunction(func, asmData);
calculateThreshold(func, asmData);
@@ -3921,6 +3969,7 @@ var passes = {
registerize: registerize,
eliminate: eliminate,
eliminateMemSafe: eliminateMemSafe,
+ aggressiveVariableElimination: aggressiveVariableElimination,
minifyGlobals: minifyGlobals,
relocate: relocate,
outline: outline,
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index dcc9cd5f..71b6f377 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -24,41 +24,16 @@ import_sig = re.compile('var ([_\w$]+) *=[^;]+;')
class Minifier:
'''
- asm.js minification support. We calculate possible names and minification of
+ 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.
'''
- def __init__(self, js, js_engine, MAX_NAMES):
+ def __init__(self, js, js_engine):
self.js = js
self.js_engine = js_engine
- MAX_NAMES = min(MAX_NAMES, 120000)
-
- # Create list of valid short names
-
- INVALID_2 = set(['do', 'if', 'in'])
- INVALID_3 = set(['for', 'new', 'try', 'var', 'env', 'let'])
-
- self.names = []
- init_possibles = string.ascii_letters + '_$'
- later_possibles = init_possibles + string.digits
- for a in init_possibles:
- if len(self.names) >= MAX_NAMES: break
- self.names.append(a)
- for a in init_possibles:
- for b in later_possibles:
- if len(self.names) >= MAX_NAMES: break
- curr = a + b
- if curr not in INVALID_2: self.names.append(curr)
- for a in init_possibles:
- for b in later_possibles:
- for c in later_possibles:
- if len(self.names) >= MAX_NAMES: break
- curr = a + b + c
- if curr not in INVALID_3: self.names.append(curr)
def minify_shell(self, shell, minify_whitespace, source_map=False):
- #print >> sys.stderr, "MINIFY SHELL 1111111111", shell, "\n222222222222222"
# Run through js-optimizer.js to find and minify the global symbols
# We send it the globals, which it parses at the proper time. JS decides how
# to minify all global names, we receive a dictionary back, which is then
@@ -91,7 +66,6 @@ class Minifier:
def serialize(self):
return {
- 'names': self.names,
'globals': self.globs
}
@@ -187,7 +161,7 @@ EMSCRIPTEN_FUNCS();
js = js[start_funcs + len(start_funcs_marker):end_funcs]
# we assume there is a maximum of one new name per line
- minifier = Minifier(js, js_engine, js.count('\n') + asm_shell.count('\n'))
+ minifier = Minifier(js, js_engine)
asm_shell_pre, asm_shell_post = minifier.minify_shell(asm_shell, 'minifyWhitespace' in passes, source_map).split('EMSCRIPTEN_FUNCS();');
asm_shell_post = asm_shell_post.replace('});', '})');
pre += asm_shell_pre + '\n' + start_funcs_marker
@@ -368,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/nativize_llvm.py b/tools/nativize_llvm.py
index 413c8d14..b327bdfc 100755
--- a/tools/nativize_llvm.py
+++ b/tools/nativize_llvm.py
@@ -23,7 +23,7 @@ libs = sys.argv[2:] # e.g.: dl for dlopen/dlclose, util for openpty/forkpty
print 'bc => clean bc'
Popen([LLVM_OPT, filename, '-strip-debug', '-o', filename + '.clean.bc']).communicate()[0]
print 'bc => s'
-for params in [[], ['-march=x86-64']]: # try x86, then x86-64 FIXME
+for params in [['-march=x86'], ['-march=x86-64']]: # try x86, then x86-64 FIXME
print 'params', params
Popen([LLVM_COMPILER] + params + [filename + '.clean.bc', '-o', filename + '.s']).communicate()[0]
print 's => o'
diff --git a/tools/shared.py b/tools/shared.py
index 5b02fa4c..2ae37f91 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -272,9 +272,17 @@ if EM_POPEN_WORKAROUND and os.name == 'nt':
EXPECTED_LLVM_VERSION = (3,2)
+actual_clang_version = None
+
+def get_clang_version():
+ global actual_clang_version
+ if actual_clang_version is None:
+ actual_clang_version = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0].split(' ')[2]
+ return actual_clang_version
+
def check_clang_version():
- expected = 'clang version ' + '.'.join(map(str, EXPECTED_LLVM_VERSION))
- actual = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0]
+ expected = '.'.join(map(str, EXPECTED_LLVM_VERSION))
+ actual = get_clang_version()
if expected in actual:
return True
logging.warning('LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected))
@@ -337,10 +345,10 @@ 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.2'
+EMSCRIPTEN_VERSION = '1.9.0'
def generate_sanity():
- return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT
+ return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version()
def check_sanity(force=False):
try:
@@ -1163,6 +1171,8 @@ class Building:
if type(opts) is int:
opts = Building.pick_llvm_opts(opts)
#opts += ['-debug-pass=Arguments']
+ if get_clang_version() == '3.4' and not Settings.SIMD:
+ opts += ['-disable-loop-vectorization', '-disable-slp-vectorization'] # llvm 3.4 has these on by default
logging.debug('emcc: LLVM opts: ' + str(opts))
target = out or (filename + '.opt.bc')
output = Popen([LLVM_OPT, filename] + opts + ['-o', target], stdout=PIPE).communicate()[0]
@@ -1404,6 +1414,8 @@ class Building:
if not os.path.exists(CLOSURE_COMPILER):
raise Exception('Closure compiler appears to be missing, looked at: ' + str(CLOSURE_COMPILER))
+ CLOSURE_EXTERNS = path_from_root('src', 'closure-externs.js')
+
# Something like this (adjust memory as needed):
# java -Xmx1024m -jar CLOSURE_COMPILER --compilation_level ADVANCED_OPTIMIZATIONS --variable_map_output_file src.cpp.o.js.vars --js src.cpp.o.js --js_output_file src.cpp.o.cc.js
args = [JAVA,
@@ -1411,6 +1423,7 @@ class Building:
'-jar', CLOSURE_COMPILER,
'--compilation_level', 'ADVANCED_OPTIMIZATIONS',
'--language_in', 'ECMASCRIPT5',
+ '--externs', CLOSURE_EXTERNS,
#'--variable_map_output_file', filename + '.vars',
'--js', filename, '--js_output_file', filename + '.cc.js']
if pretty: args += ['--formatting', 'PRETTY_PRINT']
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"]