aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--AUTHORS11
-rw-r--r--ChangeLog168
-rw-r--r--cmake/Modules/CMakeSystemSpecificInformation.cmake123
-rw-r--r--cmake/Modules/Platform/Emscripten.cmake (renamed from cmake/Platform/Emscripten.cmake)63
-rwxr-xr-xemcc78
-rwxr-xr-xemcmake2
-rw-r--r--emscripten-version.txt2
-rwxr-xr-xemscripten.py35
-rwxr-xr-xscons-tools/emscripten.py148
-rw-r--r--src/compiler.js4
-rw-r--r--src/deps_info.json1
-rw-r--r--src/deterministic.js (renamed from src/determinstic.js)7
-rw-r--r--src/embind/embind.js15
-rw-r--r--src/jsifier.js16
-rw-r--r--src/library.js103
-rw-r--r--src/library_browser.js225
-rw-r--r--src/library_fs.js34
-rw-r--r--src/library_gl.js109
-rw-r--r--src/library_glfw.js7
-rw-r--r--src/library_glut.js7
-rw-r--r--src/library_html5.js12
-rw-r--r--src/library_idbfs.js3
-rw-r--r--src/library_memfs.js168
-rw-r--r--src/library_sdl.js210
-rw-r--r--src/modules.js22
-rw-r--r--src/parseTools.js4
-rw-r--r--src/postamble.js40
-rw-r--r--src/preamble.js35
-rw-r--r--src/proxyClient.js98
-rw-r--r--src/proxyWorker.js313
-rw-r--r--src/runtime.js4
-rw-r--r--src/settings.js17
-rw-r--r--src/shell.js7
-rw-r--r--src/simd.js1643
-rw-r--r--src/struct_info.json2
-rw-r--r--src/webGLClient.js319
-rw-r--r--src/webGLWorker.js983
-rw-r--r--system/include/SDL/SDL_events.h8
-rw-r--r--system/include/emscripten/bind.h61
-rw-r--r--system/include/emscripten/emscripten.h169
-rw-r--r--system/include/emscripten/html5.h10
-rw-r--r--system/include/emscripten/val.h18
-rw-r--r--system/include/emscripten/wire.h132
-rw-r--r--system/include/libc/arpa/ftp.h4
-rw-r--r--system/include/libc/arpa/inet.h2
-rw-r--r--system/include/libc/assert.h5
-rw-r--r--system/include/libc/bits/resource.h2
-rw-r--r--system/include/libc/dlfcn.h2
-rw-r--r--system/include/libc/elf.h282
-rw-r--r--system/include/libc/fcntl.h7
-rw-r--r--system/include/libc/float.h16
-rw-r--r--system/include/libc/fnmatch.h5
-rw-r--r--system/include/libc/inttypes.h24
-rw-r--r--system/include/libc/langinfo.h4
-rw-r--r--system/include/libc/limits.h12
-rw-r--r--system/include/libc/locale.h4
-rw-r--r--system/include/libc/math.h38
-rw-r--r--system/include/libc/net/if_arp.h8
-rw-r--r--system/include/libc/netdb.h2
-rw-r--r--system/include/libc/netinet/if_ether.h1
-rw-r--r--system/include/libc/netinet/in.h83
-rw-r--r--system/include/libc/netinet/tcp.h167
-rw-r--r--system/include/libc/netinet/udp.h17
-rw-r--r--system/include/libc/paths.h1
-rw-r--r--system/include/libc/resolv.h8
-rw-r--r--system/include/libc/sched.h2
-rw-r--r--system/include/libc/search.h2
-rw-r--r--system/include/libc/signal.h15
-rw-r--r--system/include/libc/stddef.h4
-rw-r--r--system/include/libc/stdio.h4
-rw-r--r--system/include/libc/stdlib.h7
-rw-r--r--system/include/libc/string.h4
-rw-r--r--system/include/libc/sys/inotify.h2
-rw-r--r--system/include/libc/sys/mman.h2
-rw-r--r--system/include/libc/sys/mtio.h2
-rw-r--r--system/include/libc/sys/procfs.h2
-rw-r--r--system/include/libc/sys/ptrace.h2
-rw-r--r--system/include/libc/sys/resource.h12
-rw-r--r--system/include/libc/sys/sem.h17
-rw-r--r--system/include/libc/sys/shm.h21
-rw-r--r--system/include/libc/sys/signalfd.h5
-rw-r--r--system/include/libc/sys/socket.h16
-rw-r--r--system/include/libc/sys/time.h15
-rw-r--r--system/include/libc/sys/wait.h12
-rw-r--r--system/include/libc/syslog.h6
-rw-r--r--system/include/libc/time.h11
-rw-r--r--system/include/libc/unistd.h11
-rw-r--r--system/include/libc/utmp.h3
-rw-r--r--system/include/libc/utmpx.h14
-rw-r--r--system/include/libc/wchar.h4
-rwxr-xr-xsystem/lib/build_cxx_natively.sh3
-rw-r--r--system/lib/libc.symbols12
-rw-r--r--system/lib/libc/musl/arch/js/bits/signal.h (renamed from system/include/libc/bits/signal.h)6
-rw-r--r--system/lib/libc/musl/arch/js/syscall_arch.h2
-rw-r--r--system/lib/libc/musl/readme.txt2
-rw-r--r--system/lib/libc/musl/src/ctype/iswspace.c3
-rw-r--r--system/lib/libc/musl/src/internal/libc.h13
-rw-r--r--system/lib/libc/musl/src/internal/libm.h11
-rw-r--r--system/lib/libc/musl/src/internal/locale_impl.h2
-rw-r--r--system/lib/libc/musl/src/internal/stdio_impl.h8
-rw-r--r--system/lib/libc/musl/src/locale/strcasecmp_l.c1
-rw-r--r--system/lib/libc/musl/src/locale/strfmon.c1
-rw-r--r--system/lib/libc/musl/src/locale/wcsxfrm.c6
-rw-r--r--system/lib/libc/musl/src/math/frexp.c23
-rw-r--r--system/lib/libc/musl/src/math/frexpf.c23
-rw-r--r--system/lib/libc/musl/src/math/frexpl.c29
-rw-r--r--system/lib/libc/musl/src/math/lgamma.c4
-rw-r--r--system/lib/libc/musl/src/math/lgamma_r.c92
-rw-r--r--system/lib/libc/musl/src/math/lgammaf.c4
-rw-r--r--system/lib/libc/musl/src/math/lgammaf_r.c92
-rw-r--r--system/lib/libc/musl/src/math/lgammal.c96
-rw-r--r--system/lib/libc/musl/src/math/signgam.c4
-rw-r--r--system/lib/libc/musl/src/math/tgamma.c40
-rw-r--r--system/lib/libc/musl/src/misc/ffs.c7
-rw-r--r--system/lib/libc/musl/src/multibyte/internal.c2
-rw-r--r--system/lib/libc/musl/src/multibyte/internal.h1
-rw-r--r--system/lib/libc/musl/src/multibyte/mblen.c5
-rw-r--r--system/lib/libc/musl/src/multibyte/mbrlen.c5
-rw-r--r--system/lib/libc/musl/src/multibyte/mbrtowc.c3
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsinit.c5
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsnrtowcs.c6
-rw-r--r--system/lib/libc/musl/src/multibyte/mbsrtowcs.c11
-rw-r--r--system/lib/libc/musl/src/multibyte/mbtowc.c5
-rw-r--r--system/lib/libc/musl/src/multibyte/wcrtomb.c4
-rw-r--r--system/lib/libc/musl/src/multibyte/wcsnrtombs.c5
-rw-r--r--system/lib/libc/musl/src/multibyte/wcsrtombs.c27
-rw-r--r--system/lib/libc/musl/src/multibyte/wctomb.c4
-rw-r--r--system/lib/libc/musl/src/regex/fnmatch.c17
-rw-r--r--system/lib/libc/musl/src/regex/regcomp.c9
-rw-r--r--system/lib/libc/musl/src/stdio/__string_read.c16
-rw-r--r--system/lib/libc/musl/src/stdio/__toread.c12
-rw-r--r--system/lib/libc/musl/src/stdio/__towrite.c11
-rw-r--r--system/lib/libc/musl/src/stdio/asprintf.c13
-rw-r--r--system/lib/libc/musl/src/stdio/fputwc.c2
-rw-r--r--system/lib/libc/musl/src/stdio/fputws.c4
-rw-r--r--system/lib/libc/musl/src/stdio/fwrite.c41
-rw-r--r--system/lib/libc/musl/src/stdio/snprintf.c13
-rw-r--r--system/lib/libc/musl/src/stdio/sprintf.c12
-rw-r--r--system/lib/libc/musl/src/stdio/sscanf.c15
-rw-r--r--system/lib/libc/musl/src/stdio/swprintf.c1
-rw-r--r--system/lib/libc/musl/src/stdio/vasprintf.c28
-rw-r--r--system/lib/libc/musl/src/stdio/vfprintf.c689
-rw-r--r--system/lib/libc/musl/src/stdio/vfscanf.c333
-rw-r--r--system/lib/libc/musl/src/stdio/vfwprintf.c13
-rw-r--r--system/lib/libc/musl/src/stdio/vsnprintf.c45
-rw-r--r--system/lib/libc/musl/src/stdio/vsprintf.c7
-rw-r--r--system/lib/libc/musl/src/stdio/vsscanf.c20
-rw-r--r--system/lib/libc/musl/src/stdio/vswprintf.c2
-rw-r--r--system/lib/libc/musl/src/stdlib/ecvt.c1
-rw-r--r--system/lib/libc/musl/src/stdlib/gcvt.c1
-rw-r--r--system/lib/libc/musl/src/stdlib/strtod.c9
-rw-r--r--system/lib/libc/musl/src/stdlib/wcstod.c1
-rw-r--r--system/lib/libc/musl/src/string/bcmp.c1
-rw-r--r--system/lib/libc/musl/src/string/bcopy.c1
-rw-r--r--system/lib/libc/musl/src/string/bzero.c1
-rw-r--r--system/lib/libc/musl/src/string/index.c1
-rw-r--r--system/lib/libc/musl/src/string/memccpy.c1
-rw-r--r--system/lib/libc/musl/src/string/memchr.c1
-rw-r--r--system/lib/libc/musl/src/string/memmem.c4
-rw-r--r--system/lib/libc/musl/src/string/mempcpy.c1
-rw-r--r--system/lib/libc/musl/src/string/rindex.c1
-rw-r--r--system/lib/libc/musl/src/string/stpcpy.c1
-rw-r--r--system/lib/libc/musl/src/string/strchrnul.c1
-rw-r--r--system/lib/libc/musl/src/string/strcmp.c2
-rw-r--r--system/lib/libc/musl/src/string/strlcpy.c2
-rw-r--r--system/lib/libc/musl/src/string/strstr.c3
-rw-r--r--system/lib/libc/musl/src/string/strverscmp.c1
-rw-r--r--system/lib/libc/musl/src/string/wcsstr.c5
-rw-r--r--system/lib/libc/musl/src/string/wmemchr.c1
-rw-r--r--system/lib/libc/musl/src/string/wmemcmp.c1
-rw-r--r--system/lib/libc/musl/src/string/wmemcpy.c1
-rw-r--r--system/lib/libc/musl/src/string/wmemmove.c1
-rw-r--r--system/lib/libc/musl/src/string/wmemset.c1
-rw-r--r--system/lib/libcextra.symbols8
-rw-r--r--system/lib/libcxxabi/src/exception.cpp2
-rw-r--r--system/lib/libcxxabi/symbols1
-rw-r--r--system/lib/pkgconfig/egl.pc3
-rw-r--r--system/lib/pkgconfig/glesv2.pc3
-rw-r--r--system/lib/pkgconfig/libpng.pc3
-rw-r--r--system/lib/pkgconfig/sdl.pc4
-rw-r--r--system/lib/pkgconfig/zlib.pc3
-rw-r--r--system/lib/test.cpp14
-rw-r--r--system/local/include/README.txt2
-rw-r--r--tests/bullet/CMakeLists.txt2
-rw-r--r--tests/cases/floatundefinvoke_fastcomp.ll30
-rw-r--r--tests/cases/floatundefinvoke_fastcomp.txt3
-rw-r--r--tests/cmake/target_html/CMakeLists.txt30
-rw-r--r--tests/cmake/target_js/CMakeLists.txt41
-rw-r--r--tests/cmake/target_library/CMakeLists.txt43
-rw-r--r--tests/cmake/target_library/srcfile.cmake6
-rw-r--r--tests/core/test_ccall.out1
-rw-r--r--tests/core/test_exceptions_white_list_empty.out0
-rw-r--r--tests/core/test_floatvars.in9
-rw-r--r--tests/core/test_floatvars.out1
-rw-r--r--tests/core/test_i64_varargs.in1
-rw-r--r--tests/core/test_i64_varargs.out4
-rw-r--r--tests/core/test_random_device.cpp16
-rw-r--r--tests/core/test_random_device.txt1
-rw-r--r--tests/core/test_set_align.c50
-rw-r--r--tests/core/test_set_align.out8
-rw-r--r--tests/core/test_simd4.in39
-rw-r--r--tests/core/test_simd4.out1
-rw-r--r--tests/core/test_sscanf.in3
-rw-r--r--tests/embind/embind.test.js51
-rw-r--r--tests/embind/embind_test.cpp40
-rw-r--r--tests/fs/test_append.c24
-rw-r--r--tests/fs/test_emptyPath.c14
-rw-r--r--tests/fs/test_emptyPath.out2
-rw-r--r--tests/gl_teximage.c120
-rw-r--r--tests/gles2_uniform_arrays.cpp29
-rw-r--r--tests/glfw.c4
-rw-r--r--tests/hello_malloc.cpp2
-rw-r--r--tests/hello_world.c2
-rw-r--r--tests/hello_world.cpp2
-rw-r--r--tests/hello_world.ll2
-rw-r--r--tests/hello_world_file.cpp4
-rw-r--r--tests/hello_world_gles_proxy.c765
-rw-r--r--tests/hello_world_loop.cpp2
-rw-r--r--tests/hello_world_loop_malloc.cpp2
-rw-r--r--tests/mem_init.cpp3
-rw-r--r--tests/openjpeg/codec/CMakeLists.txt6
-rwxr-xr-xtests/runner.py76
-rw-r--r--tests/runtime_misuse.cpp27
-rw-r--r--tests/sdl_canvas_size.c164
-rw-r--r--tests/sdl_image.c10
-rw-r--r--tests/sdl_key.c94
-rw-r--r--tests/sdl_key_proxy.c1
-rw-r--r--tests/sdl_maprgba.c20
-rw-r--r--tests/sdl_mouse.c1
-rw-r--r--tests/sdlglshader2.c168
-rw-r--r--tests/sqlite/speedtest1.c1393
-rw-r--r--tests/test_browser.py206
-rw-r--r--tests/test_core.py356
-rw-r--r--tests/test_other.py246
-rw-r--r--tests/test_sanity.py12
-rw-r--r--tests/twopart_main.cpp2
-rwxr-xr-xtools/ffdb.py602
-rw-r--r--tools/js-optimizer.js452
-rw-r--r--tools/js_optimizer.py38
-rw-r--r--tools/jsrun.py5
-rw-r--r--tools/settings_template_readonly.py4
-rw-r--r--tools/shared.py58
-rw-r--r--tools/system_libs.py74
-rw-r--r--tools/test-js-optimizer-asm-last-output.js27
-rw-r--r--tools/test-js-optimizer-asm-last.js33
-rw-r--r--tools/test-js-optimizer-t2-output.js108
-rw-r--r--tools/test-js-optimizer-t2.js109
-rw-r--r--tools/test-js-optimizer-t2c-output.js17
-rw-r--r--tools/test-js-optimizer-t2c.js18
-rw-r--r--tools/test-js-optimizer-t3-output.js49
-rw-r--r--tools/test-js-optimizer-t3.js50
-rw-r--r--tools/validate_asmjs.py18
253 files changed, 11579 insertions, 2509 deletions
diff --git a/.gitignore b/.gitignore
index f5f3313c..952cc649 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
+# vim/emacs temporary/backup files
+*~
+*.swp
+
*.diff
*.pyc
-*~
*.bc
src/relooper*.js
diff --git a/AUTHORS b/AUTHORS
index dc848d34..441d8ad1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -9,7 +9,7 @@ a license to everyone to use it as detailed in LICENSE.)
* Max Shawabkeh <max99x@gmail.com>
* Sigmund Vik <sigmund_vik@yahoo.com>
* Jeff Terrace <jterrace@gmail.com>
-* Benoit Tremblay <benoit.tremblay@frimastudio.com>
+* Benoit Tremblay <trembl.ben@gmail.com>
* Andreas Bergmeier <abergmeier@gmx.net>
* Ben Schwartz <bens@alum.mit.edu>
* David Claughton <dave@eclecticdave.com>
@@ -86,7 +86,7 @@ a license to everyone to use it as detailed in LICENSE.)
* David Barksdale <david.barksdale@adcedosolutions.com>
* Manfred Manik Nerurkar <nerurkar*at*made-apps.biz> (copyright owned by MADE, GmbH)
* Joseph Gentle <me@josephg.com>
-* Douglas T. Crosher <dtc-moz@scieneer.com> (copyright owned by Mozilla Founcation)
+* Douglas T. Crosher <dtc-moz@scieneer.com> (copyright owned by Mozilla Foundation)
* Soeren Balko <soeren.balko@gmail.com>
* Ryan Kelly (ryan@rfk.id.au)
* Michael Lelli <toadking@toadking.com>
@@ -141,4 +141,11 @@ a license to everyone to use it as detailed in LICENSE.)
* Markus Henschel <markus.henschel@yager.de>
* Ophir Lojkine <ophir.lojkine@eleves.ec-nantes.fr>
* Ryan Sturgell <ryan.sturgell@gmail.com> (copyright owned by Google, Inc.)
+* Jason Green <jason@transgaming.com> (copyright owned by TransGaming, Inc.)
+* Ningxin Hu <ningxin.hu@intel.com> (copyright owned by Intel)
+* Nicolas Guillemot <nlguillemot@gmail.com>
+* Sathyanarayanan Gunasekaran <gsathya.ceg@gmail.com> (copyright owned by Mozilla Foundation)
+* Nikolay Vorobyov <nik.vorobyov@gmail.com>
+* Jonas Platte <mail@jonasplatte.de>
+* Sebastien Ronsse <sronsse@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index 18640add..e0781e5b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,9 +10,171 @@ 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
- - Emscripten: https://github.com/kripken/emscripten/compare/1.16.0...incoming
- - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.16.0...incoming
- - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.16.0...incoming
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.21.1...incoming
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.21.1...incoming
+ - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.21.1...incoming
+
+v1.21.1: 7/3/2014
+------------------
+ - Fixed an issue where wrong python interpreter could get invoked on Windows when both native and cygwin python were installed.
+ - Updated musl from version 0.9.13 to version 1.0.3.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.21.0...1.21.1
+ - Emscripten-LLVM: no changes.
+ - Emscripten-Clang: no changes.
+
+v1.21.0: 7/2/2014
+------------------
+ - Implemented new SDL 1.2 functions SDL_GetRGB, SDL_GetRGBA and SDL_putenv.
+ - Added support for /dev/random, /dev/urandom and C++11 std::random_device, which will use cryptographically secure random api if available. (#2447)
+ - Added support for CMake find_path() directive.
+ - Added support for std::unique_ptr in embind.
+ - Improved Windows support for ffdb.py.
+ - Implemented the clip_rect structure for created SDL surfaces.
+ - Fixed a regression with SDL touch events (#2466)
+ - Added support for C++11 std::thread::hardware_concurrency which backs to navigator.hardwareConcurrency. See http://wiki.whatwg.org/wiki/Navigator_HW_Concurrency (#2456)
+ - Optimized embind code generation with constexprs.
+ - Enabled the use of Runtime.add&removeFunction when closure minification is active (#2446)
+ - Implemented support for accessing WebGL when building via the proxy to worker architecture.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.20.0...1.21.0
+ - Emscripten-LLVM: no changes.
+ - Emscripten-Clang: no changes.
+
+v1.20.0: 6/13/2014
+------------------
+ - Optimize in-memory virtual filesystem performance when serialized to an IndexedDB.
+ - Fixed memcpy regression with ta0 and ta1 modes.
+ - Fixed an issue with line numbers being messed up when generating source maps (#2410)
+ - Fixed an ffdb logging bug that could cause it to drop messages if they were being received too fast. Added support getting memory and system descriptions with ffdb.
+ - Added a new extension to SDL "emscripten_SDL_SetEventHandler()" which enabled application to perform SDL event handling inside a JS event handler to overcome browser security restrictions. (#2417)
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.19.2...1.20.0
+ - Emscripten-LLVM: no changes.
+ - Emscripten-Clang: no changes.
+
+v1.19.2: 6/9/2014
+------------------
+ - Updated CMake support for response file handling.
+ - Fixed issues with glfwGetProcAddress and glfwSetWindowSizeCallback.
+ - Fixed an issue with regexes that caused issues on IE11 runtime (#2400)
+ - Added a new functions emscripten_get_preloaded_image_data() and emscripten_get_preloaded_image_data_from_FILE() to obtain pixel data of preloaded images.
+ - Greatly improved ffdb capabilities to operate a FFOS device.
+ - Fixed a Windows-specific bug where the user temp directory was littered with temporary .rsp files that did not get cleaned up.
+ - Improved SIMD support.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.19.1...1.19.2
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.19.1...1.19.2
+ - Emscripten-Clang: no changes.
+
+v1.19.1: 6/3/2014
+------------------
+ - Migrate to using musl sscanf and sprintf and the family that writes to memory, and not directly to the filesystem.
+ - Improve the error messages from -s SAFE_HEAP_ACCESS=1 runtime checks.
+ - Added new linker flag -s NO_DYNAMIC_EXECUTION=1 which removes the use of eval() and new Function() in the generated output. For more information, see "Eval and related functions are disabled" in https://developer.chrome.com/extensions/contentSecurityPolicy .
+ - Fixed a compiler issue when very large double constants are present. (#2392)
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.19.0...1.19.1
+ - Emscripten-LLVM: no changes.
+ - Emscripten-Clang: no changes.
+
+v1.19.0: 5/29/2014
+------------------
+ - Added an error message to signal that linkable modules are not supported in fastcomp.
+ - Fixed a miscompilation issue that resulted in an error "SyntaxError: invalid increment operand" and a statement +(+0) being generated (#2314)
+ - Make optimized compiler output smaller by running the shell code through uglify when not using closure.
+ - Fixed a crash in SDL audio loading code introduced in v1.18.3
+ - Fixed an issue where glTex(Sub)Image2D might throw an exception on error, instead of setting glGetError().
+ - Added new typedefs emscripten_align1_short, emscripten_align{1/2}_int, emscripten_align{1/2}_float and emscripten_align{1/2/4}_double to ease signaling the compiler that unaligned data is present. (#2378)
+ - Fixed an embind issue with refcount tracking on smart pointers.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.18.4...1.19.0
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.18.4...1.19.0
+ - Emscripten-Clang: no changes.
+
+v1.18.4: 5/27/2014
+------------------
+ - Fixed error message on unsupported linking options (#2365)
+ - Updated embind to latest version from IMVU upstream.
+ - Fixed an issue where source maps did not load properly in Firefox.
+ - Added a more descriptive error message to fastcomp when MAX_SETJMPS limit is violated. (#2379)
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.18.3...1.18.4
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.18.3...1.18.4
+ - Emscripten-Clang: no changes.
+
+v1.18.3: 5/21/2014
+------------------
+ - Added support to emcc command line for "archive groups": -Wl,--start-group and -Wl,--end-group
+ - Greatly optimized ccall and cwrap implementations.
+ - Added new support for SDL_Mix backend to use WebAudio to play back audio clips.
+ - Fixed a registerizeHarder issue with elimination of conditional expressions.
+ - Migrated single-character standard C functions (islower, tolower, and the family) to use musl implementations.
+ - Updated relooper to not optimize out breaks if it causes excessive nesting.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.18.2...1.18.3
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.18.2...1.18.3
+ - Emscripten-Clang: no changes.
+
+v1.18.2: 5/19/2014
+------------------
+ - Fixed a problem which blocked user applications from handling WebGL context loss events themselves.
+ - Added a new HTML5 api function emscripten_is_webgl_context_lost() which allows polling for context loss in addition to receiving events.
+ - Improved async wget progress events to work better across browsers.
+ - Improved WebIDL binder support.
+ - Added new typeof() function to emscripten::val.
+ - Added support for SDL window events SDL_WINDOWEVENT_FOCUS_GAINED, SDL_WINDOWEVENT_FOCUS_LOST, SDL_WINDOWEVENT_SHOWN, SDL_WINDOWEVENT_HIDDEN.
+ - Fixed a compiler miscompilation on unsigned i1 bitcasts (#2350)
+ - Fixed a compiler bug where doubles in varargs might not get 8-byte aligned (#2358)
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.18.1...1.18.2
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.18.1...1.18.2
+ - Emscripten-Clang: no changes.
+
+v1.18.1: 5/12/2014
+------------------
+ - Fixed an issue where the mouse wheel scroll did not work with SDL.
+ - Fixed an issue with emscripten_async_wget, which undesirably expected that the string pointer passed to it stayed alive for the duration of the operation (#2349)
+ - Emscripten now issues a warning message when the EXPORTED_FUNCTIONS list contains invalid symbol names (#2338)
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.18.0...1.18.1
+ - Emscripten-LLVM: no changes.
+ - Emscripten-Clang: no changes.
+
+v1.18.0: 5/10/2014
+------------------
+ - Enable support for low-level C<->JS interop to marshall 64 bit integers from C to JS.
+ - Fixed an issue that caused some programs to immediately run out of memory "(cannot enlarge memory arrays)" at startup. (#2334)
+ - Fixed a crash issue with generated touch events that didn't correspond to a real touch.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.17.0...1.18.0
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.17.0...1.18.0
+ - Emscripten-Clang: no changes.
+
+v1.17.0: 5/6/2014
+------------------
+ - Enabled asm.js compilation and -s PRECISE_F32 support when using embind.
+ - Improved relooper to emit switches in many-entried blocks.
+ - Fixed a GLFW bug where mouse wheel direction was reversed.
+ - Fixed glfwGetKey to work even when no callback is registered with glfwGetKeyCallback (#1320)
+ - Added a new tool 'webidl_binder' that generates C <-> JS interop code from WebIDL descriptions.
+ - Fix emscripten compilation to work on pages that don't contain a HTML canvas.
+ - Added a new error message to default shell when an uncaught exception is thrown.
+ - Improved error diagnostics reported by -s SAFE_HEAP=1.
+ - Added support for registering callbacks hook to VFS file open, write, move, close and delete.
+ - Added embind support to std::basic_string<unsigned char>
+ - By default, the C runtime will no longer exit after returning from main() when safeSetTimeout() or safeSetInterval() is used.
+ - Fixed an issue with sscanf formatting (#2322)
+ - Fixed an issue where precompiled headers were given a wrong output filename (#2320)
+ - Enabled registerizeHarder optimization pass to work when outlining is enabled.
+ - Fixed an issue with strptime month handling (#2324)
+ - Added an initial implementation of a new tool 'ffdb' which can be used to operate a Firefox OS phone from the command line.
+ - Fixed a compiler crash on assertion failure '!contains(BranchesOut, Target)' (emscripten-fastcomp #32)
+ - Added a new ABI to Clang that targets Emscripten specifically. Stop aligning member functions to save some space in the function table array.
+ - Full list of changes:
+ - Emscripten: https://github.com/kripken/emscripten/compare/1.16.0...1.17.0
+ - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.16.0...1.17.0
+ - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.16.0...1.17.0
v1.16.0: 4/16/2014
------------------
diff --git a/cmake/Modules/CMakeSystemSpecificInformation.cmake b/cmake/Modules/CMakeSystemSpecificInformation.cmake
new file mode 100644
index 00000000..cc223a63
--- /dev/null
+++ b/cmake/Modules/CMakeSystemSpecificInformation.cmake
@@ -0,0 +1,123 @@
+# XXX Emscripten:
+# This file is copied as-is from the CMake source tree. Due to how CMake
+# platform toolchain files work, we must have a copy of this file located
+# relative to Emscripten platform toolchain file, or file inclusion order
+# in cmGlobalGenerator::EnableLanguage will not find Emscripten.cmake
+# toolchain file, and as a result, it is not possible to set the default
+# compilation output suffix to .js, and as a consequence the script
+# check_function_exists() will not function properly (it will try to
+# build to wrong file suffix)
+
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2014 Kitware, Inc.
+# Copyright 2000-2011 Insight Software Consortium
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * 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.
+
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+# nor the names of their contributors may be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+# HOLDER 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.
+
+# ------------------------------------------------------------------------------
+
+# The above copyright and license notice applies to distributions of
+# CMake in source and binary form. Some source files contain additional
+# notices of original copyright by their contributors; see each source
+# for details. Third-party software packages supplied with CMake under
+# compatible licenses provide their own copyright notices documented in
+# corresponding subdirectories.
+
+# ------------------------------------------------------------------------------
+
+# CMake was initially developed by Kitware with the following sponsorship:
+
+# * National Library of Medicine at the National Institutes of Health
+# as part of the Insight Segmentation and Registration Toolkit (ITK).
+
+# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+# Visualization Initiative.
+
+# * National Alliance for Medical Image Computing (NAMIC) is funded by the
+# National Institutes of Health through the NIH Roadmap for Medical Research,
+# Grant U54 EB005149.
+
+# * Kitware, Inc.
+
+# This file is included by cmGlobalGenerator::EnableLanguage.
+# It is included after the compiler has been determined, so
+# we know things like the compiler name and if the compiler is gnu.
+
+# before cmake 2.6 these variables were set in cmMakefile.cxx. This is still
+# done to keep scripts and custom language and compiler modules working.
+# But they are reset here and set again in the platform files for the target
+# platform, so they can be used for testing the target platform instead
+# of testing the host platform.
+set(APPLE )
+set(UNIX )
+set(CYGWIN )
+set(WIN32 )
+
+
+# include Generic system information
+include(CMakeGenericSystem)
+
+# 2. now include SystemName.cmake file to set the system specific information
+set(CMAKE_SYSTEM_INFO_FILE Platform/${CMAKE_SYSTEM_NAME})
+
+include(${CMAKE_SYSTEM_INFO_FILE} OPTIONAL RESULT_VARIABLE _INCLUDED_SYSTEM_INFO_FILE)
+
+if(NOT _INCLUDED_SYSTEM_INFO_FILE)
+ message("System is unknown to cmake, create:\n${CMAKE_SYSTEM_INFO_FILE}"
+ " to use this system, please send your config file to "
+ "cmake@www.cmake.org so it can be added to cmake")
+ if(EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt)
+ configure_file(${CMAKE_BINARY_DIR}/CMakeCache.txt
+ ${CMAKE_BINARY_DIR}/CopyOfCMakeCache.txt COPYONLY)
+ message("Your CMakeCache.txt file was copied to CopyOfCMakeCache.txt. "
+ "Please send that file to cmake@www.cmake.org.")
+ endif()
+endif()
+
+
+# optionally include a file which can do extra-generator specific things, e.g.
+# CMakeFindEclipseCDT4.cmake asks gcc for the system include dirs for the Eclipse CDT4 generator
+if(CMAKE_EXTRA_GENERATOR)
+ string(REPLACE " " "" _CMAKE_EXTRA_GENERATOR_NO_SPACES ${CMAKE_EXTRA_GENERATOR} )
+ include("CMakeFind${_CMAKE_EXTRA_GENERATOR_NO_SPACES}" OPTIONAL)
+endif()
+
+
+# for most systems a module is the same as a shared library
+# so unless the variable CMAKE_MODULE_EXISTS is set just
+# copy the values from the LIBRARY variables
+# this has to be done after the system information has been loaded
+if(NOT CMAKE_MODULE_EXISTS)
+ set(CMAKE_SHARED_MODULE_PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}")
+ set(CMAKE_SHARED_MODULE_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}")
+endif()
+
+
+set(CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED 1)
diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake
index f9d8c773..acfa3183 100644
--- a/cmake/Platform/Emscripten.cmake
+++ b/cmake/Modules/Platform/Emscripten.cmake
@@ -3,7 +3,7 @@
# from CMakeLists.txt that invoke emcc.
# To use this toolchain file with CMake, invoke CMake with the following command line parameters
-# cmake -DCMAKE_TOOLCHAIN_FILE=<EmscriptenRoot>/cmake/Platform/Emscripten.cmake
+# cmake -DCMAKE_TOOLCHAIN_FILE=<EmscriptenRoot>/cmake/Modules/Platform/Emscripten.cmake
# -DCMAKE_BUILD_TYPE=<Debug|RelWithDebInfo|Release|MinSizeRel>
# -G "Unix Makefiles" (Linux and OSX)
# -G "MinGW Makefiles" (Windows)
@@ -12,20 +12,36 @@
# After that, build the generated Makefile with the command 'make'. On Windows, you may download and use 'mingw32-make' instead.
# The following variable describes the target OS we are building to.
-# Ideally, this could be 'Emscripten', but as Emscripten mimics the Linux platform, setting this to Linux will allow more of existing software to build.
-# Be sure to run Emscripten test_openjpeg if planning to change this.
-set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_NAME Emscripten)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_CROSSCOMPILING TRUE)
+# Tell CMake how it should instruct the compiler to generate multiple versions of an outputted .so library: e.g. "libfoo.so, libfoo.so.1, libfoo.so.1.4" etc.
+# This feature is activated if a shared library project has the property SOVERSION defined.
+set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
+
+# In CMake, CMAKE_HOST_WIN32 is set when we are cross-compiling from Win32 to Emscripten: http://www.cmake.org/cmake/help/v2.8.12/cmake.html#variable:CMAKE_HOST_WIN32
+# The variable WIN32 is set only when the target arch that will run the code will be WIN32, so unset WIN32 when cross-compiling.
+set(WIN32)
+
+# The same logic as above applies for APPLE and CMAKE_HOST_APPLE, so unset APPLE.
+set(APPLE)
+
+# And for UNIX and CMAKE_HOST_UNIX. However, Emscripten is often able to mimic being a Linux/Unix system, in which case a lot of existing CMakeLists.txt files can be configured for Emscripten while assuming UNIX build, so this is left enabled.
+set(UNIX 1)
+
# Do a no-op access on the CMAKE_TOOLCHAIN_FILE variable so that CMake will not issue a warning on it being unused.
if (CMAKE_TOOLCHAIN_FILE)
endif()
+# In order for check_function_exists() detection to work, we must signal it to pass an additional flag, which causes the compilation
+# to abort if linking results in any undefined symbols. The CMake detection mechanism depends on the undefined symbol error to be raised.
+set(CMAKE_REQUIRED_FLAGS "-s ERROR_ON_UNDEFINED_SYMBOLS=1")
+
# Locate where the Emscripten compiler resides in relative to this toolchain file.
if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
- get_filename_component(GUESS_EMSCRIPTEN_ROOT_PATH "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE)
+ get_filename_component(GUESS_EMSCRIPTEN_ROOT_PATH "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
if (EXISTS "${GUESS_EMSCRIPTEN_ROOT_PATH}/emranlib")
set(EMSCRIPTEN_ROOT_PATH "${GUESS_EMSCRIPTEN_ROOT_PATH}")
endif()
@@ -49,7 +65,7 @@ if (NOT CMAKE_MODULE_PATH)
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${EMSCRIPTEN_ROOT_PATH}/cmake/Modules")
-set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake")
+set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}/system")
if (CMAKE_HOST_WIN32)
set(EMCC_SUFFIX ".bat")
@@ -92,12 +108,12 @@ set(CMAKE_SYSTEM_INCLUDE_PATH "${EMSCRIPTEN_ROOT_PATH}/system/include")
#SET(CMAKE_STATIC_LIBRARY_SUFFIX ".bc")
#SET(CMAKE_SHARED_LIBRARY_PREFIX "")
#SET(CMAKE_SHARED_LIBRARY_SUFFIX ".bc")
-#IF (NOT CMAKE_EXECUTABLE_SUFFIX)
-# SET(CMAKE_EXECUTABLE_SUFFIX ".js")
-#endif()
+SET(CMAKE_EXECUTABLE_SUFFIX ".js")
#SET(CMAKE_FIND_LIBRARY_PREFIXES "")
#SET(CMAKE_FIND_LIBRARY_SUFFIXES ".bc")
+SET(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
@@ -107,21 +123,32 @@ set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@")
set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@")
# Specify the program to use when building static libraries. Force Emscripten-related command line options to clang.
-set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")
-set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_AR} rc <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")
-set(CMAKE_CXX_ARCHIVE_APPEND "${CMAKE_AR} r <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")
-set(CMAKE_C_ARCHIVE_APPEND "${CMAKE_AR} r <TARGET> ${CMAKE_START_TEMP_FILE} <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")
+set(CMAKE_C_CREATE_STATIC_LIBRARY "<CMAKE_AR> rc <TARGET> <LINK_FLAGS> <OBJECTS>")
+set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_AR> rc <TARGET> <LINK_FLAGS> <OBJECTS>")
# Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten.
set(EMSCRIPTEN 1 CACHE BOOL "If true, we are targeting Emscripten output.")
-# We are cross-compiling, so unset the common CMake variables that represent the target platform. Leave UNIX define enabled, since Emscripten
-# mimics a Linux environment.
-SET(WIN32)
-SET(APPLE)
-
+# Hardwire support for cmake-2.8/Modules/CMakeBackwardsCompatibilityC.cmake without having CMake to try complex things
+# to autodetect these:
+set(CMAKE_SKIP_COMPATIBILITY_TESTS 1)
+set(CMAKE_SIZEOF_CHAR 1)
+set(CMAKE_SIZEOF_UNSIGNED_SHORT 2)
+set(CMAKE_SIZEOF_SHORT 2)
+set(CMAKE_SIZEOF_INT 4)
+set(CMAKE_SIZEOF_UNSIGNED_LONG 4)
+set(CMAKE_SIZEOF_UNSIGNED_INT 4)
+set(CMAKE_SIZEOF_LONG 4)
+set(CMAKE_SIZEOF_VOID_P 4)
+set(CMAKE_SIZEOF_FLOAT 4)
+set(CMAKE_SIZEOF_DOUBLE 8)
set(CMAKE_C_SIZEOF_DATA_PTR 4)
set(CMAKE_CXX_SIZEOF_DATA_PTR 4)
+set(CMAKE_HAVE_LIMITS_H 1)
+set(CMAKE_HAVE_UNISTD_H 1)
+set(CMAKE_HAVE_PTHREAD_H 1)
+set(CMAKE_HAVE_SYS_PRCTL_H 1)
+set(CMAKE_WORDS_BIGENDIAN 0)
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE")
set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL")
diff --git a/emcc b/emcc
index a4bba2dd..d29704dd 100755
--- a/emcc
+++ b/emcc
@@ -60,7 +60,7 @@ OBJC_ENDINGS = ('.m',)
OBJCXX_ENDINGS = ('.mm',)
SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + OBJC_ENDINGS + OBJCXX_ENDINGS
BITCODE_ENDINGS = ('.bc', '.o', '.obj')
-DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll')
+DYNAMICLIB_ENDINGS = ('.dylib', '.so') # Windows .dll suffix is not included in this list, since those are never linked to directly on the command line.
STATICLIB_ENDINGS = ('.a',)
ASSEMBLY_ENDINGS = ('.ll',)
HEADER_ENDINGS = ('.h', '.hxx', '.hpp', '.hh', '.H', '.HXX', '.HPP', '.HH')
@@ -156,11 +156,11 @@ Options that are modified or new in %s include:
opt levels, see apply_opt_level() in
tools/shared.py and also src/settings.js.)
- -O2 As -O1, plus various js-level optimizations and
- LLVM -O3 optimizations. This is the recommended
- setting for a release build: slower compilation
- time in return for the smallest and fastest
- output.
+ -O2 As -O1, plus various js-level optimizations, LLVM
+ -O3 optimizations, and memory init file generation
+ (--memory-init-file 1). This is a good setting
+ for an optimized build: runs much faster than
+ -O1, and compiles much faster than -O3.
-Os Like -O2 with extra optimizations for size.
@@ -310,6 +310,14 @@ Options that are modified or new in %s include:
optimization, so it will be minified
properly if closure compiler is run.
+ Note that the post js will typically run after
+ main() completes (unless there is something
+ async). In that case, main() will exit and
+ the post js will not be reached (just as if
+ you call exit() in C code). If you want to
+ prevent that, you can build with
+ -s NO_EXIT_RUNTIME=1
+
--embed-file <file> A file to embed inside the generated
JavaScript. The compiled code will be able
to access the file in the current directory
@@ -482,7 +490,8 @@ Options that are modified or new in %s include:
--memory-init-file <on> 0: Do not emit a separate memory initialization
file, keep the static initialization inside
- the generated JavaScript as text (default)
+ the generated JavaScript as text (default
+ in -O0 and -O1)
1: Emit a separate memory initialization file
in binary format. This is more efficient than
storing it as text inside JavaScript, but does
@@ -495,7 +504,7 @@ Options that are modified or new in %s include:
stuff has happened and it is safe to call
library functions, as main() will only be
called at that time. You can also call
- addOnPreMain from a preRun.)
+ addOnPreMain from a preRun.) (default in -O2+)
-Wno-warn-absolute-paths If not specified, the compiler will warn about any
uses of absolute paths in -I and -L command line
@@ -503,8 +512,13 @@ Options that are modified or new in %s include:
to hide these warnings and acknowledge that the
explicit use of absolute paths is intentional.
- --proxy-to-worker Generates both html and js files. The main
- program is in js, and the html proxies to/from it.
+ --proxy-to-worker Runs the main application code in a worker, proxying
+ events to it and output from it.
+ If emitting htmlL, this emits an html and a js file,
+ with the js to be run in a worker. If emitting
+ js, the target filename contains the part to be run
+ on the main thread, while a second js file with
+ suffix ".worker.js" will contain the worker portion.
--emrun Enables the generated output to be aware of the
emrun command line tool. This allows stdout, stderr
@@ -818,7 +832,7 @@ try:
emrun = False
jcache = False
save_bc = False
- memory_init_file = False
+ memory_init_file = None
use_preload_cache = False
no_heap_copy = False
proxy_to_worker = False
@@ -1070,6 +1084,7 @@ try:
if js_opts is None: js_opts = opt_level >= 2
if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level]
if opt_level == 0: debug_level = 4
+ if memory_init_file is None: memory_init_file = opt_level >= 2
if llvm_lto is None and bind:
logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue
@@ -1249,6 +1264,8 @@ try:
if value[0] == '@':
value = '"@' + os.path.abspath(value[1:]) + '"'
value = value.replace('\\\\', '/').replace('\\', '/') # Convert backslash paths to forward slashes on Windows as well, since the JS compiler otherwise needs the backslashes escaped (alternative is to escape all input paths passing to JS, which feels clumsier to read)
+ else:
+ value = value.replace('\\', '\\\\')
exec('shared.Settings.' + key + ' = ' + value)
if key == 'EXPORTED_FUNCTIONS':
shared.Settings.ORIGINAL_EXPORTED_FUNCTIONS = shared.Settings.EXPORTED_FUNCTIONS[:] # used for warnings in emscripten.py
@@ -1269,10 +1286,10 @@ try:
assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten'
assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2'
assert not split_js_file, '--split-js is deprecated and not supported in fastcomp'
- assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet'
assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)'
assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp'
assert not shared.Settings.CORRUPTION_CHECK, 'CORRUPTION_CHECK is not supported in asm.js mode, which is what fastcomp can emit (you can use non-asm.js mode in non-fastcomp)'
+ assert not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE, 'Linking modules is not supported in fastcomp'
except Exception, e:
logging.error('Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend')
raise e
@@ -1289,8 +1306,8 @@ try:
fastcomp_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt']
if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1:
fastcomp_opts += ['-enable-emscripten-cxx-exceptions']
- if len(shared.Settings.EXCEPTION_CATCHING_WHITELIST) > 0:
- fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST)]
+ if shared.Settings.DISABLE_EXCEPTION_CATCHING == 2:
+ fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST or ['fake'])]
if shared.Settings.ASM_JS:
assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above'
@@ -1320,6 +1337,8 @@ try:
logging.warning('disabling closure because debug info was requested')
closure = False
+ assert not (shared.Settings.NO_DYNAMIC_EXECUTION and closure), 'cannot have both NO_DYNAMIC_EXECUTION and closure compiler enabled at the same time'
+
if closure:
shared.Settings.CLOSURE_COMPILER = 1
assert os.path.exists(shared.CLOSURE_COMPILER), logging.error('fatal: Closure compiler (%s) does not exist', shared.CLOSURE_COMPILER)
@@ -1345,11 +1364,12 @@ try:
if shared.Settings.MAIN_MODULE:
assert not shared.Settings.SIDE_MODULE
shared.Settings.INCLUDE_FULL_LIBRARY = 1
+ shared.Settings.EXPORT_ALL = 1
elif shared.Settings.SIDE_MODULE:
assert not shared.Settings.MAIN_MODULE
if shared.Settings.MAIN_MODULE or shared.Settings.SIDE_MODULE:
- assert not memory_init_file, 'memory init file is not supported with module linking'
+ memory_init_file = False # memory init file is not supported with module linking
assert shared.Settings.ASM_JS, 'module linking requires asm.js output (-s ASM_JS=1)'
shared.Settings.LINKABLE = 1 # TODO: add FORCE_DCE option for the brave people that do want to dce here and in side modules
debug_level = max(debug_level, 2)
@@ -1373,6 +1393,8 @@ try:
if shared.Settings.ASM_JS and shared.Settings.DLOPEN_SUPPORT:
assert shared.Settings.DISABLE_EXCEPTION_CATCHING, 'no exceptions support with dlopen in asm yet'
+ assert not (bind and shared.Settings.NO_DYNAMIC_EXECUTION), 'NO_DYNAMIC_EXECUTION disallows embind'
+
if proxy_to_worker:
shared.Settings.PROXY_TO_WORKER = 1
@@ -1689,7 +1711,7 @@ try:
logging.debug('wrote memory initialization to %s', memfile)
else:
logging.debug('did not see memory initialization')
- elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE:
+ elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE and debug_level < 4:
# not writing a binary init, but we can at least optimize them by splitting them up
src = open(final).read()
src = shared.JS.optimize_initializer(src)
@@ -1760,6 +1782,9 @@ try:
js_optimizer_queue += ['simplifyExpressions']
+ if shared.Settings.RELOOP and not shared.Settings.ASM_JS:
+ js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches
+
# simplify ifs if it is ok to make the code somewhat unreadable, and unless outlining (simplified ifs
# with commaified code breaks late aggressive variable elimination)
if shared.Settings.SIMPLIFY_IFS and (debug_level == 0 or profiling) and shared.Settings.OUTLINING_LIMIT == 0: js_optimizer_queue += ['simplifyIfs']
@@ -1794,8 +1819,11 @@ try:
if emit_symbol_map: js_optimizer_queue += ['symbolMap='+target+'.symbols']
if debug_level == 0: js_optimizer_queue += ['minifyWhitespace']
- if closure and shared.Settings.ASM_JS:
- js_optimizer_queue += ['closure']
+ if shared.Settings.ASM_JS:
+ if closure:
+ js_optimizer_queue += ['closure']
+ elif debug_level <= 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE:
+ js_optimizer_queue += ['cleanup']
if not shared.Settings.SIDE_MODULE: js_optimizer_queue += ['last'] # side modules are not finalized until after relocation
@@ -1824,7 +1852,7 @@ try:
js_target = unsuffixed(target) + '.js'
base_js_target = os.path.basename(js_target)
if proxy_to_worker:
- html.write(shell.replace('{{{ SCRIPT }}}', '<script>' + open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', target_basename) + '</script>'))
+ html.write(shell.replace('{{{ SCRIPT }}}', '<script>' + open(shared.path_from_root('src', 'webGLClient.js')).read() + '\n' + open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', shared.Settings.PROXY_TO_WORKER_FILENAME or target_basename) + '</script>'))
shutil.move(final, js_target)
elif not Compression.on:
# Normal code generation path
@@ -1969,8 +1997,13 @@ try {
split_javascript_file(final, unsuffixed(target), split_js_file)
else:
if debug_level >= 4: generate_source_map(target)
- # copy final JS to output
- shutil.move(final, target)
+ if proxy_to_worker:
+ worker_target_basename = target_basename + '.worker'
+ open(target, 'w').write(open(shared.path_from_root('src', 'webGLClient.js')).read() + '\n' + open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', shared.Settings.PROXY_TO_WORKER_FILENAME or worker_target_basename))
+ shutil.move(final, target[:-3] + '.worker.js')
+ else:
+ # copy final JS to output normally
+ shutil.move(final, target)
log_time('final emitting')
@@ -1985,6 +2018,3 @@ finally:
else:
logging.info('emcc saved files are in:' + temp_dir)
-#//eliminate a = a in js opt. will kill STACKTOP = STACKTOP in funcs that do not use the C stack! add test for no STACKTOP or sp in such a func
-#// minify if into ?: ?
-
diff --git a/emcmake b/emcmake
index 9617ace5..8a672eeb 100755
--- a/emcmake
+++ b/emcmake
@@ -4,5 +4,5 @@ import os, subprocess, sys
from tools import shared
configure_path = shared.path_from_root('emconfigure')
-exit(subprocess.call([configure_path] + sys.argv[1:]))
+exit(subprocess.call([shared.PYTHON, configure_path] + sys.argv[1:]))
diff --git a/emscripten-version.txt b/emscripten-version.txt
index 18abf253..6318f232 100644
--- a/emscripten-version.txt
+++ b/emscripten-version.txt
@@ -1,2 +1,2 @@
-1.18.3
+1.21.3
diff --git a/emscripten.py b/emscripten.py
index 9abaf60c..82187127 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -761,6 +761,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
if settings['ALIASING_FUNCTION_POINTERS'] == 0:
backend_args += ['-emscripten-no-aliasing-function-pointers']
backend_args += ['-O' + str(settings['OPT_LEVEL'])]
+ backend_args += ['-emscripten-max-setjmps=%d' % settings['MAX_SETJMPS']]
if DEBUG:
logging.debug('emscript: llvm backend: ' + ' '.join(backend_args))
t = time.time()
@@ -852,8 +853,9 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
# Call js compiler
if DEBUG: t = time.time()
- out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, [settings_file, ';', 'glue'] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
- cwd=path_from_root('src'))
+ out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine,
+ [settings_file, ';', 'glue'] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
+ cwd=path_from_root('src'), error_limit=300)
assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?'
glue, forwarded_data = out.split('//FORWARDED_DATA:')
@@ -929,7 +931,6 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
funcs_js += ['\n// EMSCRIPTEN_END_FUNCS\n']
- simple = os.environ.get('EMCC_SIMPLE_ASM')
class Counter:
i = 0
j = 0
@@ -1112,12 +1113,9 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
exported_implemented_functions = list(exported_implemented_functions) + metadata['initializers']
exported_implemented_functions.append('runPostSets')
exports = []
- if not simple:
- for export in exported_implemented_functions + asm_runtime_funcs + function_tables:
- exports.append("%s: %s" % (export, export))
- exports = '{ ' + ', '.join(exports) + ' }'
- else:
- exports = '_main'
+ for export in exported_implemented_functions + asm_runtime_funcs + function_tables:
+ exports.append("%s: %s" % (export, export))
+ exports = '{ ' + ', '.join(exports) + ' }'
# calculate globals
try:
del forwarded_json['Variables']['globals']['_llvm_global_ctors'] # not a true variable
@@ -1144,10 +1142,17 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
the_global = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in fundamentals]) + ' }'
sending = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in basic_funcs + global_funcs + basic_vars + basic_float_vars + global_vars]) + ' }'
# received
- if not simple:
- receiving = ';\n'.join(['var ' + s + ' = Module["' + s + '"] = asm["' + s + '"]' for s in exported_implemented_functions + function_tables])
- else:
- receiving = 'var _main = Module["_main"] = asm;'
+ receiving = ''
+ if settings['ASSERTIONS']:
+ # assert on the runtime being in a valid state when calling into compiled code. The only exceptions are
+ # some support code like malloc TODO: verify that malloc is actually safe to use that way
+ receiving = '\n'.join(['var real_' + s + ' = asm["' + s + '"]; asm["' + s + '''"] = function() {
+ assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
+ assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
+ return real_''' + s + '''.apply(null, arguments);
+};
+''' for s in exported_implemented_functions if s not in ['_malloc', '_free', '_memcpy', '_memset']])
+ receiving += ';\n'.join(['var ' + s + ' = Module["' + s + '"] = asm["' + s + '"]' for s in exported_implemented_functions + function_tables])
# finalize
@@ -1330,7 +1335,9 @@ def main(args, compiler_engine, cache, jcache, relooper, temp_files, DEBUG, DEBU
# Compile the assembly to Javascript.
if settings.get('RELOOP'):
if not relooper:
- relooper = cache.get_path('relooper.js')
+ relooper = settings.get('RELOOPER')
+ if not relooper:
+ relooper = cache.get_path('relooper.js')
settings.setdefault('RELOOPER', relooper)
if not os.path.exists(relooper):
shared.Building.ensure_relooper(relooper)
diff --git a/scons-tools/emscripten.py b/scons-tools/emscripten.py
index 94153adb..c82f43c8 100755
--- a/scons-tools/emscripten.py
+++ b/scons-tools/emscripten.py
@@ -20,7 +20,9 @@ def build_version_file(env):
EMSCRIPTEN_DEPENDENCIES = [
env.Glob('${EMSCRIPTEN_HOME}/src/*.js'),
env.Glob('${EMSCRIPTEN_HOME}/src/embind/*.js'),
+ env.Glob('${EMSCRIPTEN_HOME}/tools/*.js'),
env.Glob('${EMSCRIPTEN_HOME}/tools/*.py'),
+ '${EMSCRIPTEN_HOME}/emcc',
'${EMSCRIPTEN_HOME}/emscripten.py',
]
if env.subst('$EMSCRIPTEN_SHELL'):
@@ -40,7 +42,7 @@ def build_version_file(env):
env.AddPostAction(
emscripten_version_file,
- Delete(env.Dir('$EMSCRIPTEN_TEMP_DIR').abspath))
+ Delete(env.Dir('$EMSCRIPTEN_TEMP_DIR/cache/jcache').abspath))
return emscripten_version_file
@@ -148,21 +150,159 @@ LIBC_SOURCES = [
'system/lib/dlmalloc.c',
'system/lib/libc/musl/src/internal/floatscan.c',
'system/lib/libc/musl/src/internal/shgetc.c',
- 'system/lib/libc/musl/src/math/scalbn.c',
- 'system/lib/libc/musl/src/math/scalbnl.c',
+ 'system/lib/libc/musl/src/ctype/isalnum.c',
+ 'system/lib/libc/musl/src/ctype/isalpha.c',
+ 'system/lib/libc/musl/src/ctype/isascii.c',
+ 'system/lib/libc/musl/src/ctype/isblank.c',
+ 'system/lib/libc/musl/src/ctype/iscntrl.c',
+ 'system/lib/libc/musl/src/ctype/isdigit.c',
+ 'system/lib/libc/musl/src/ctype/isgraph.c',
+ 'system/lib/libc/musl/src/ctype/islower.c',
+ 'system/lib/libc/musl/src/ctype/isprint.c',
+ 'system/lib/libc/musl/src/ctype/ispunct.c',
+ 'system/lib/libc/musl/src/ctype/isspace.c',
+ 'system/lib/libc/musl/src/ctype/isupper.c',
+ 'system/lib/libc/musl/src/ctype/iswalnum.c',
+ 'system/lib/libc/musl/src/ctype/iswalpha.c',
+ 'system/lib/libc/musl/src/ctype/iswblank.c',
+ 'system/lib/libc/musl/src/ctype/iswcntrl.c',
+ 'system/lib/libc/musl/src/ctype/iswctype.c',
+ 'system/lib/libc/musl/src/ctype/iswdigit.c',
+ 'system/lib/libc/musl/src/ctype/iswgraph.c',
+ 'system/lib/libc/musl/src/ctype/iswlower.c',
+ 'system/lib/libc/musl/src/ctype/iswprint.c',
+ 'system/lib/libc/musl/src/ctype/iswpunct.c',
+ 'system/lib/libc/musl/src/ctype/iswspace.c',
+ 'system/lib/libc/musl/src/ctype/iswupper.c',
+ 'system/lib/libc/musl/src/ctype/iswxdigit.c',
+ 'system/lib/libc/musl/src/ctype/isxdigit.c',
+ 'system/lib/libc/musl/src/ctype/toascii.c',
+ 'system/lib/libc/musl/src/ctype/toupper.c',
+ 'system/lib/libc/musl/src/ctype/towctrans.c',
+ 'system/lib/libc/musl/src/ctype/wcswidth.c',
+ 'system/lib/libc/musl/src/ctype/wctrans.c',
+ 'system/lib/libc/musl/src/ctype/wcwidth.c',
+ 'system/lib/libc/musl/src/ctype/tolower.c',
+
'system/lib/libc/musl/src/stdio/__overflow.c',
+ 'system/lib/libc/musl/src/stdio/__string_read.c',
'system/lib/libc/musl/src/stdio/__toread.c',
'system/lib/libc/musl/src/stdio/__towrite.c',
'system/lib/libc/musl/src/stdio/__uflow.c',
+ 'system/lib/libc/musl/src/stdio/asprintf.c',
+ 'system/lib/libc/musl/src/stdio/fputwc.c',
+ 'system/lib/libc/musl/src/stdio/fputws.c',
+ 'system/lib/libc/musl/src/stdio/fwprintf.c',
+ 'system/lib/libc/musl/src/stdio/fwrite.c',
+ 'system/lib/libc/musl/src/stdio/snprintf.c',
+ 'system/lib/libc/musl/src/stdio/sprintf.c',
+ 'system/lib/libc/musl/src/stdio/sscanf.c',
+ 'system/lib/libc/musl/src/stdio/swprintf.c',
+ 'system/lib/libc/musl/src/stdio/vasprintf.c',
+ 'system/lib/libc/musl/src/stdio/vfprintf.c',
+ 'system/lib/libc/musl/src/stdio/vfscanf.c',
+ 'system/lib/libc/musl/src/stdio/vfwprintf.c',
+ 'system/lib/libc/musl/src/stdio/vsnprintf.c',
+ 'system/lib/libc/musl/src/stdio/vsprintf.c',
+ 'system/lib/libc/musl/src/stdio/vsscanf.c',
+ 'system/lib/libc/musl/src/stdio/vswprintf.c',
+ 'system/lib/libc/musl/src/stdio/vwprintf.c',
+ 'system/lib/libc/musl/src/stdio/wprintf.c',
+
'system/lib/libc/musl/src/stdlib/atof.c',
'system/lib/libc/musl/src/stdlib/strtod.c',
+
+ 'system/lib/libc/musl/src/string/bcmp.c',
+ 'system/lib/libc/musl/src/string/bcopy.c',
+ 'system/lib/libc/musl/src/string/bzero.c',
+ 'system/lib/libc/musl/src/string/index.c',
+ 'system/lib/libc/musl/src/string/memccpy.c',
+ 'system/lib/libc/musl/src/string/memchr.c',
'system/lib/libc/musl/src/string/memcmp.c',
+ 'system/lib/libc/musl/src/string/memmem.c',
+ 'system/lib/libc/musl/src/string/mempcpy.c',
+ 'system/lib/libc/musl/src/string/memrchr.c',
+ 'system/lib/libc/musl/src/string/rindex.c',
+ 'system/lib/libc/musl/src/string/stpcpy.c',
'system/lib/libc/musl/src/string/strcasecmp.c',
+ 'system/lib/libc/musl/src/string/strcasestr.c',
+ 'system/lib/libc/musl/src/string/strchr.c',
+ 'system/lib/libc/musl/src/string/strchrnul.c',
'system/lib/libc/musl/src/string/strcmp.c',
+ 'system/lib/libc/musl/src/string/strcspn.c',
+ 'system/lib/libc/musl/src/string/strdup.c',
+ 'system/lib/libc/musl/src/string/strlcat.c',
+ 'system/lib/libc/musl/src/string/strlcpy.c',
'system/lib/libc/musl/src/string/strncasecmp.c',
+ 'system/lib/libc/musl/src/string/strncat.c',
'system/lib/libc/musl/src/string/strncmp.c',
- 'system/lib/libc/musl/src/string/wmemset.c',
+ 'system/lib/libc/musl/src/string/strndup.c',
+ 'system/lib/libc/musl/src/string/strnlen.c',
+ 'system/lib/libc/musl/src/string/strpbrk.c',
+ 'system/lib/libc/musl/src/string/strrchr.c',
+ 'system/lib/libc/musl/src/string/strsep.c',
+ 'system/lib/libc/musl/src/string/strspn.c',
+ 'system/lib/libc/musl/src/string/strstr.c',
+ 'system/lib/libc/musl/src/string/strtok.c',
+ 'system/lib/libc/musl/src/string/strtok_r.c',
+ 'system/lib/libc/musl/src/string/strverscmp.c',
+ 'system/lib/libc/musl/src/string/wcpcpy.c',
+ 'system/lib/libc/musl/src/string/wcpncpy.c',
+ 'system/lib/libc/musl/src/string/wcscasecmp.c',
+ 'system/lib/libc/musl/src/string/wcscasecmp_l.c',
+ 'system/lib/libc/musl/src/string/wcscat.c',
+ 'system/lib/libc/musl/src/string/wcschr.c',
+ 'system/lib/libc/musl/src/string/wcscmp.c',
+ 'system/lib/libc/musl/src/string/wcscpy.c',
+ 'system/lib/libc/musl/src/string/wcscspn.c',
+ 'system/lib/libc/musl/src/string/wcsdup.c',
+ 'system/lib/libc/musl/src/string/wcslen.c',
+ 'system/lib/libc/musl/src/string/wcsncasecmp.c',
+ 'system/lib/libc/musl/src/string/wcsncasecmp_l.c',
+ 'system/lib/libc/musl/src/string/wcsncat.c',
+ 'system/lib/libc/musl/src/string/wcsncmp.c',
+ 'system/lib/libc/musl/src/string/wcsncpy.c',
+ 'system/lib/libc/musl/src/string/wcsnlen.c',
+ 'system/lib/libc/musl/src/string/wcspbrk.c',
+ 'system/lib/libc/musl/src/string/wcsrchr.c',
+ 'system/lib/libc/musl/src/string/wcsspn.c',
+ 'system/lib/libc/musl/src/string/wcsstr.c',
+ 'system/lib/libc/musl/src/string/wcstok.c',
+ 'system/lib/libc/musl/src/string/wcswcs.c',
+ 'system/lib/libc/musl/src/string/wmemchr.c',
+ 'system/lib/libc/musl/src/string/wmemcmp.c',
'system/lib/libc/musl/src/string/wmemcpy.c',
+ 'system/lib/libc/musl/src/string/wmemmove.c',
+ 'system/lib/libc/musl/src/string/wmemset.c',
+
+ 'system/lib/libc/musl/src/math/__cos.c',
+ 'system/lib/libc/musl/src/math/__cosdf.c',
+ 'system/lib/libc/musl/src/math/__sin.c',
+ 'system/lib/libc/musl/src/math/__sindf.c',
+ 'system/lib/libc/musl/src/math/frexp.c',
+ 'system/lib/libc/musl/src/math/frexpf.c',
+ 'system/lib/libc/musl/src/math/frexpl.c',
+ 'system/lib/libc/musl/src/math/ilogb.c',
+ 'system/lib/libc/musl/src/math/ilogbf.c',
+ 'system/lib/libc/musl/src/math/ilogbl.c',
+ 'system/lib/libc/musl/src/math/ldexp.c',
+ 'system/lib/libc/musl/src/math/ldexpf.c',
+ 'system/lib/libc/musl/src/math/ldexpl.c',
+ 'system/lib/libc/musl/src/math/lgamma.c',
+ 'system/lib/libc/musl/src/math/lgamma_r.c',
+ 'system/lib/libc/musl/src/math/lgammaf.c',
+ 'system/lib/libc/musl/src/math/lgammaf_r.c',
+ 'system/lib/libc/musl/src/math/lgammal.c',
+ 'system/lib/libc/musl/src/math/logb.c',
+ 'system/lib/libc/musl/src/math/logbf.c',
+ 'system/lib/libc/musl/src/math/logbl.c',
+ 'system/lib/libc/musl/src/math/scalbn.c',
+ 'system/lib/libc/musl/src/math/scalbnf.c',
+ 'system/lib/libc/musl/src/math/scalbnl.c',
+ 'system/lib/libc/musl/src/math/signgam.c',
+ 'system/lib/libc/musl/src/math/tgamma.c',
+ 'system/lib/libc/musl/src/math/tgammaf.c',
+ 'system/lib/libc/musl/src/math/tgammal.c',
]
LIBCXX_SOURCES = [os.path.join('system/lib/libcxx', x) for x in [
diff --git a/src/compiler.js b/src/compiler.js
index 17a8e83c..a86af011 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -319,7 +319,9 @@ try {
}
}
} catch(err) {
- printErr('aborting from js compiler due to exception: ' + err + ' | ' + err.stack);
+ printErr('Internal compiler error in src/compiler.js! Please raise a bug report at https://github.com/kripken/emscripten/issues/ with a log of the build and the input files used to run. Exception message: ' + err + ' | ' + err.stack);
+ if (ENVIRONMENT_IS_NODE) process.exit(1);
+ else throw err;
}
//var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] });
diff --git a/src/deps_info.json b/src/deps_info.json
index 029a20e1..e0983064 100644
--- a/src/deps_info.json
+++ b/src/deps_info.json
@@ -3,6 +3,7 @@
"SDL_Init": ["malloc", "free"],
"SDL_GL_GetProcAddress": ["emscripten_GetProcAddress"],
"eglGetProcAddress": ["emscripten_GetProcAddress"],
+ "glfwGetProcAddress": ["emscripten_GetProcAddress"],
"emscripten_GetProcAddress": ["strstr"]
}
diff --git a/src/determinstic.js b/src/deterministic.js
index 1ec0bbfe..4e9508f3 100644
--- a/src/determinstic.js
+++ b/src/deterministic.js
@@ -8,13 +8,14 @@ var TIME = 10000;
Date.now = function() {
return TIME++;
};
-performance.now = Date.now;
+if (typeof performance === 'object') performance.now = Date.now;
function hashMemory(id) {
var ret = 0;
- for (var i = 0; i < HEAPU8.length; i++) {
+ var len = Math.max(DYNAMICTOP, STATICTOP);
+ for (var i = 0; i < len; i++) {
ret = (ret*17 + HEAPU8[i])|0;
}
- print(id + ':' + ret);
+ printErr(id + ':' + ret);
}
diff --git a/src/embind/embind.js b/src/embind/embind.js
index 124ea569..8c8d73ad 100644
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -1216,9 +1216,18 @@ RegisteredPointer.prototype['fromWireType'] = function fromWireType(ptr) {
var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer);
if (undefined !== registeredInstance) {
- var rv = registeredInstance['clone']();
- this.destructor(ptr);
- return rv;
+ // JS object has been neutered, time to repopulate it
+ if (0 === registeredInstance.$$.count.value) {
+ registeredInstance.$$.ptr = rawPointer;
+ registeredInstance.$$.smartPtr = ptr;
+ return registeredInstance['clone']();
+ } else {
+ // else, just increment reference count on existing object
+ // it already has a reference to the smart pointer
+ var rv = registeredInstance['clone']();
+ this.destructor(ptr);
+ return rv;
+ }
}
function makeDefaultHandle() {
diff --git a/src/jsifier.js b/src/jsifier.js
index 065c66a8..1f6440dd 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -370,7 +370,7 @@ function JSify(data, functionsOnly) {
// name the function; overwrite if it's already named
snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '(');
- if (LIBRARY_DEBUG) {
+ if (LIBRARY_DEBUG && !LibraryManager.library[ident + '__asm']) {
snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); ');
snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}';
}
@@ -1321,10 +1321,10 @@ function JSify(data, functionsOnly) {
// vector load
var native = getVectorNativeType(item.valueType);
var base = getSIMDName(native);
- return base + '32x4(' + makeGetValue(value, 0, native, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 4, native, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 8, native, 0, item.unsigned, 0, item.align) + ',' +
- makeGetValue(value, 12, native, 0, item.unsigned, 0, item.align) + ');';
+ return 'SIMD.' + base + '32x4(' + makeGetValue(value, 0, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 4, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 8, native, 0, item.unsigned, 0, item.align) + ',' +
+ makeGetValue(value, 12, native, 0, item.unsigned, 0, item.align) + ');';
}
var impl = item.ident ? getVarImpl(item.funcData, item.ident) : VAR_EMULATED;
switch (impl) {
@@ -1395,7 +1395,7 @@ function JSify(data, functionsOnly) {
}
for (var i = 0; i < 4; i++) assert(mask[0] == 0 || mask == 1);
i = 0;
- return base + '32x4(' + mask.map(function(m) {
+ return 'SIMD.' + base + '32x4(' + mask.map(function(m) {
return (m == 1 ? second : first) + '.' + simdLane[i++];
}).join(',') + ')';
}
@@ -1899,8 +1899,12 @@ function JSify(data, functionsOnly) {
print('}');
}
if (PROXY_TO_WORKER) {
+ print(read('webGLWorker.js'));
print(read('proxyWorker.js'));
}
+ if (DETERMINISTIC) {
+ print(read('deterministic.js'));
+ }
if (RUNTIME_TYPE_INFO) {
Types.cleanForRuntime();
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
diff --git a/src/library.js b/src/library.js
index e71c10a5..3ec16c16 100644
--- a/src/library.js
+++ b/src/library.js
@@ -327,6 +327,7 @@ LibraryManager.library = {
path = Pointer_stringify(path);
// remove a trailing slash, if one - /a/b/ has basename of '', but
// we want to create b in the context of this function
+ path = PATH.normalize(path);
if (path[path.length-1] === '/') path = path.substr(0, path.length-1);
try {
FS.mkdir(path, mode, 0);
@@ -1562,7 +1563,10 @@ LibraryManager.library = {
case {{{ cDefine('_SC_STREAM_MAX') }}}: return 16;
case {{{ cDefine('_SC_TZNAME_MAX') }}}: return 6;
case {{{ cDefine('_SC_THREAD_DESTRUCTOR_ITERATIONS') }}}: return 4;
- case {{{ cDefine('_SC_NPROCESSORS_ONLN') }}}: return 1;
+ case {{{ cDefine('_SC_NPROCESSORS_ONLN') }}}: {
+ if (typeof navigator === 'object') return navigator['hardwareConcurrency'] || 1;
+ return 1;
+ }
}
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
@@ -2802,34 +2806,6 @@ LibraryManager.library = {
var stdin = {{{ makeGetValue(makeGlobalUse('_stdin'), '0', 'void*') }}};
return _fscanf(stdin, format, varargs);
},
- sscanf__deps: ['_scanString'],
- sscanf: function(s, format, varargs) {
- // int sscanf(const char *restrict s, const char *restrict format, ... );
- // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
- var index = 0;
- function get() { return {{{ makeGetValue('s', 'index++', 'i8') }}}; };
- function unget() { index--; };
- return __scanString(format, get, unget, varargs);
- },
- snprintf__deps: ['_formatString', 'malloc'],
- snprintf: function(s, n, format, varargs) {
- // int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
- // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
- var result = __formatString(format, varargs);
- var limit = (n === undefined) ? result.length
- : Math.min(result.length, Math.max(n - 1, 0));
- if (s < 0) {
- s = -s;
- var buf = _malloc(limit+1);
- {{{ makeSetValue('s', '0', 'buf', 'i8*') }}};
- s = buf;
- }
- for (var i = 0; i < limit; i++) {
- {{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}};
- }
- if (limit < n || (n === undefined)) {{{ makeSetValue('s', 'i', '0', 'i8') }}};
- return result.length;
- },
fprintf__deps: ['fwrite', '_formatString'],
fprintf: function(stream, format, varargs) {
// int fprintf(FILE *restrict stream, const char *restrict format, ...);
@@ -2847,16 +2823,6 @@ LibraryManager.library = {
var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
return _fprintf(stdout, format, varargs);
},
- sprintf__deps: ['snprintf'],
- sprintf: function(s, format, varargs) {
- // int sprintf(char *restrict s, const char *restrict format, ...);
- // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
- return _snprintf(s, undefined, format, varargs);
- },
- asprintf__deps: ['sprintf'],
- asprintf: function(s, format, varargs) {
- return _sprintf(-s, format, varargs);
- },
dprintf__deps: ['_formatString', 'write'],
dprintf: function(fd, format, varargs) {
var result = __formatString(format, varargs);
@@ -2868,14 +2834,10 @@ LibraryManager.library = {
#if TARGET_X86
// va_arg is just like our varargs
vfprintf: 'fprintf',
- vsnprintf: 'snprintf',
vprintf: 'printf',
- vsprintf: 'sprintf',
- vasprintf: 'asprintf',
vdprintf: 'dprintf',
vscanf: 'scanf',
vfscanf: 'fscanf',
- vsscanf: 'sscanf',
#endif
#if TARGET_ASMJS_UNKNOWN_EMSCRIPTEN
@@ -2884,22 +2846,10 @@ LibraryManager.library = {
vfprintf: function(s, f, va_arg) {
return _fprintf(s, f, {{{ makeGetValue('va_arg', 0, '*') }}});
},
- vsnprintf__deps: ['snprintf'],
- vsnprintf: function(s, n, format, va_arg) {
- return _snprintf(s, n, format, {{{ makeGetValue('va_arg', 0, '*') }}});
- },
vprintf__deps: ['printf'],
vprintf: function(format, va_arg) {
return _printf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
- vsprintf__deps: ['sprintf'],
- vsprintf: function(s, format, va_arg) {
- return _sprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
- },
- vasprintf__deps: ['asprintf'],
- vasprintf: function(s, format, va_arg) {
- return _asprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
- },
vdprintf__deps: ['dprintf'],
vdprintf: function (fd, format, va_arg) {
return _dprintf(fd, format, {{{ makeGetValue('va_arg', 0, '*') }}});
@@ -2912,10 +2862,6 @@ LibraryManager.library = {
vfscanf: function(s, format, va_arg) {
return _fscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
- vsscanf__deps: ['sscanf'],
- vsscanf: function(s, format, va_arg) {
- return _sscanf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
- },
#endif
// ==========================================================================
@@ -3224,7 +3170,7 @@ LibraryManager.library = {
#endif
environ: 'allocate(1, "i32*", ALLOC_STATIC)',
__environ__deps: ['environ'],
- __environ: '_environ',
+ __environ: 'environ',
__buildEnvironment__deps: ['__environ'],
__buildEnvironment: function(env) {
// WARNING: Arbitrary limit!
@@ -3411,6 +3357,7 @@ LibraryManager.library = {
return 0;
} else {
var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1.
+ if (resolved_name === 0) resolved_name = _malloc(size+1);
for (var i = 0; i < size; i++) {
{{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}};
}
@@ -3445,9 +3392,20 @@ LibraryManager.library = {
memcpy__sig: 'iiii',
memcpy__deps: ['emscripten_memcpy_big'],
memcpy: function(dest, src, num) {
+#if USE_TYPED_ARRAYS == 0
+ {{{ makeCopyValues('dest', 'src', 'num', 'null') }}};
+ return num;
+#endif
+#if USE_TYPED_ARRAYS == 1
+ {{{ makeCopyValues('dest', 'src', 'num', 'null') }}};
+ return num;
+#endif
+
dest = dest|0; src = src|0; num = num|0;
var ret = 0;
+#if USE_TYPED_ARRAYS
if ((num|0) >= 4096) return _emscripten_memcpy_big(dest|0, src|0, num|0)|0;
+#endif
ret = dest|0;
if ((dest&3) == (src&3)) {
while (dest & 3) {
@@ -4135,12 +4093,6 @@ LibraryManager.library = {
}
},
- // Destructors for std::exception since we don't have them implemented in libcxx as we aren't using libcxxabi.
- // These are also needed for the dlmalloc tests.
- _ZNSt9exceptionD0Ev: function() {},
- _ZNSt9exceptionD1Ev: function() {},
- _ZNSt9exceptionD2Ev: function() {},
-
_ZNKSt9exception4whatEv__deps: ['malloc'],
_ZNKSt9exception4whatEv: function() {
if (!__ZNKSt9exception4whatEv.buffer) {
@@ -4509,23 +4461,6 @@ LibraryManager.library = {
{{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}};
return x - {{{ makeGetValue('intpart', 0, 'float') }}};
},
- frexp: function(x, exp_addr) {
- var sig = 0, exp_ = 0;
- if (x !== 0) {
- var sign = 1;
- if (x < 0) {
- x = -x;
- sign = -1;
- }
- var raw_exp = Math.log(x)/Math.log(2);
- exp_ = Math.ceil(raw_exp);
- if (exp_ === raw_exp) exp_ += 1;
- sig = sign*x/Math.pow(2, exp_);
- }
- {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}};
- return sig;
- },
- frexpf: 'frexp',
finite: function(x) {
return isFinite(x);
},
@@ -4847,7 +4782,7 @@ LibraryManager.library = {
return 0;
} else {
FS.forceLoadFile(target);
- var lib_data = intArrayToString(target.contents);
+ var lib_data = FS.readFile(filename, { encoding: 'utf8' });
}
try {
diff --git a/src/library_browser.js b/src/library_browser.js
index 4ef7c577..34c3259a 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -41,6 +41,26 @@ mergeInto(LibraryManager.library, {
Module['setStatus']('');
}
}
+ },
+ runIter: function(func) {
+ if (ABORT) return;
+ if (Module['preMainLoop']) {
+ var preRet = Module['preMainLoop']();
+ if (preRet === false) {
+ return; // |return false| skips a frame
+ }
+ }
+ try {
+ func();
+ } catch (e) {
+ if (e instanceof ExitStatus) {
+ return;
+ } else {
+ if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+ throw e;
+ }
+ }
+ if (Module['postMainLoop']) Module['postMainLoop']();
}
},
isFullScreen: false,
@@ -51,7 +71,7 @@ mergeInto(LibraryManager.library, {
init: function() {
if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
- if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+ if (Browser.initted) return;
Browser.initted = true;
try {
@@ -196,6 +216,12 @@ mergeInto(LibraryManager.library, {
// Canvas event setup
var canvas = Module['canvas'];
+ function pointerLockChange() {
+ Browser.pointerLock = document['pointerLockElement'] === canvas ||
+ document['mozPointerLockElement'] === canvas ||
+ document['webkitPointerLockElement'] === canvas ||
+ document['msPointerLockElement'] === canvas;
+ }
if (canvas) {
// forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
// Module['forcedAspectRatio'] = 4 / 3;
@@ -212,12 +238,6 @@ mergeInto(LibraryManager.library, {
function(){}; // no-op if function does not exist
canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
- function pointerLockChange() {
- Browser.pointerLock = document['pointerLockElement'] === canvas ||
- document['mozPointerLockElement'] === canvas ||
- document['webkitPointerLockElement'] === canvas ||
- document['msPointerLockElement'] === canvas;
- }
document.addEventListener('pointerlockchange', pointerLockChange, false);
document.addEventListener('mozpointerlockchange', pointerLockChange, false);
@@ -242,6 +262,8 @@ mergeInto(LibraryManager.library, {
return null;
}
#endif
+ if (useWebGL && Module.ctx) return Module.ctx; // no need to recreate singleton GL context
+
var ctx;
var errorInfo = '?';
function onContextCreationError(event) {
@@ -282,49 +304,98 @@ mergeInto(LibraryManager.library, {
}
if (useWebGL) {
#if GL_DEBUG
- // Useful to debug native webgl apps: var Module = { printErr: function(x) { console.log(x) } };
- var tempCtx = ctx;
- var wrapper = {};
- for (var prop in tempCtx) {
- (function(prop) {
- switch (typeof tempCtx[prop]) {
- case 'function': {
- wrapper[prop] = function gl_wrapper() {
- if (GL.debug) {
- var printArgs = Array.prototype.slice.call(arguments).map(Runtime.prettyPrint);
- Module.printErr('[gl_f:' + prop + ':' + printArgs + ']');
- }
- var ret = tempCtx[prop].apply(tempCtx, arguments);
- if (GL.debug && typeof ret != 'undefined') {
- Module.printErr('[ gl:' + prop + ':return:' + Runtime.prettyPrint(ret) + ']');
- }
- return ret;
- }
- break;
+ function wrapDebugGL(ctx) {
+
+ var printObjectList = [];
+
+ function prettyPrint(arg) {
+ if (typeof arg == 'undefined') return '!UNDEFINED!';
+ if (typeof arg == 'boolean') arg = arg + 0;
+ if (!arg) return arg;
+ var index = printObjectList.indexOf(arg);
+ if (index >= 0) return '<' + arg + '|'; // + index + '>';
+ if (arg.toString() == '[object HTMLImageElement]') {
+ return arg + '\n\n';
+ }
+ if (arg.byteLength) {
+ return '{' + Array.prototype.slice.call(arg, 0, Math.min(arg.length, 400)) + '}'; // Useful for correct arrays, less so for compiled arrays, see the code below for that
+ var buf = new ArrayBuffer(32);
+ var i8buf = new Int8Array(buf);
+ var i16buf = new Int16Array(buf);
+ var f32buf = new Float32Array(buf);
+ switch(arg.toString()) {
+ case '[object Uint8Array]':
+ i8buf.set(arg.subarray(0, 32));
+ break;
+ case '[object Float32Array]':
+ f32buf.set(arg.subarray(0, 5));
+ break;
+ case '[object Uint16Array]':
+ i16buf.set(arg.subarray(0, 16));
+ break;
+ default:
+ alert('unknown array for debugging: ' + arg);
+ throw 'see alert';
}
- case 'number': case 'string': {
- wrapper.__defineGetter__(prop, function() {
- //Module.printErr('[gl_g:' + prop + ':' + tempCtx[prop] + ']');
- return tempCtx[prop];
- });
- wrapper.__defineSetter__(prop, function(value) {
- if (GL.debug) {
- Module.printErr('[gl_s:' + prop + ':' + value + ']');
+ var ret = '{' + arg.byteLength + ':\n';
+ var arr = Array.prototype.slice.call(i8buf);
+ ret += 'i8:' + arr.toString().replace(/,/g, ',') + '\n';
+ arr = Array.prototype.slice.call(f32buf, 0, 8);
+ ret += 'f32:' + arr.toString().replace(/,/g, ',') + '}';
+ return ret;
+ }
+ if (typeof arg == 'object') {
+ printObjectList.push(arg);
+ return '<' + arg + '|'; // + (printObjectList.length-1) + '>';
+ }
+ if (typeof arg == 'number') {
+ if (arg > 0) return '0x' + arg.toString(16) + ' (' + arg + ')';
+ }
+ return arg;
+ }
+
+ var wrapper = {};
+ for (var prop in ctx) {
+ (function(prop) {
+ switch (typeof ctx[prop]) {
+ case 'function': {
+ wrapper[prop] = function gl_wrapper() {
+ var printArgs = Array.prototype.slice.call(arguments).map(prettyPrint);
+ dump('[gl_f:' + prop + ':' + printArgs + ']\n');
+ var ret = ctx[prop].apply(ctx, arguments);
+ if (typeof ret != 'undefined') {
+ dump('[ gl:' + prop + ':return:' + prettyPrint(ret) + ']\n');
+ }
+ return ret;
}
- tempCtx[prop] = value;
- });
- break;
+ break;
+ }
+ case 'number': case 'string': {
+ wrapper.__defineGetter__(prop, function() {
+ //dump('[gl_g:' + prop + ':' + ctx[prop] + ']\n');
+ return ctx[prop];
+ });
+ wrapper.__defineSetter__(prop, function(value) {
+ dump('[gl_s:' + prop + ':' + value + ']\n');
+ ctx[prop] = value;
+ });
+ break;
+ }
}
- }
- })(prop);
+ })(prop);
+ }
+ return wrapper;
}
- ctx = wrapper;
#endif
+ // possible GL_DEBUG entry point: ctx = wrapDebugGL(ctx);
+
// Set the background of the WebGL canvas to black
canvas.style.backgroundColor = "black";
}
if (setInModule) {
- GLctx = Module.ctx = ctx;
+ if (!useWebGL) assert(typeof GLctx === 'undefined', 'cannot set in module if GLctx is used, but we are a non-GL context that would replace it');
+ Module.ctx = ctx;
+ if (useWebGL) GLctx = ctx;
Module.useWebGL = useWebGL;
Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
Browser.init();
@@ -395,9 +466,25 @@ mergeInto(LibraryManager.library, {
canvasContainer.requestFullScreen();
},
+ nextRAF: 0,
+
+ fakeRequestAnimationFrame: function(func) {
+ // try to keep 60fps between calls to here
+ var now = Date.now();
+ if (Browser.nextRAF === 0) {
+ Browser.nextRAF = now + 1000/60;
+ } else {
+ while (now + 2 >= Browser.nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0
+ Browser.nextRAF += 1000/60;
+ }
+ }
+ var delay = Math.max(Browser.nextRAF - now, 0);
+ setTimeout(func, delay);
+ },
+
requestAnimationFrame: function requestAnimationFrame(func) {
if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
- setTimeout(func, 1000/60);
+ Browser.fakeRequestAnimationFrame(func);
} else {
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = window['requestAnimationFrame'] ||
@@ -405,7 +492,7 @@ mergeInto(LibraryManager.library, {
window['webkitRequestAnimationFrame'] ||
window['msRequestAnimationFrame'] ||
window['oRequestAnimationFrame'] ||
- window['setTimeout'];
+ Browser.fakeRequestAnimationFrame;
}
window.requestAnimationFrame(func);
}
@@ -954,28 +1041,13 @@ mergeInto(LibraryManager.library, {
Browser.mainLoop.method = ''; // just warn once per call to set main loop
}
- if (Module['preMainLoop']) {
- Module['preMainLoop']();
- }
-
- try {
+ Browser.mainLoop.runIter(function() {
if (typeof arg !== 'undefined') {
Runtime.dynCall('vi', func, [arg]);
} else {
Runtime.dynCall('v', func);
}
- } catch (e) {
- if (e instanceof ExitStatus) {
- return;
- } else {
- if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
- throw e;
- }
- }
-
- if (Module['postMainLoop']) {
- Module['postMainLoop']();
- }
+ });
if (Browser.mainLoop.shouldPause) {
// catch pauses from the main loop itself
@@ -1175,6 +1247,39 @@ mergeInto(LibraryManager.library, {
var info = Browser.workers[id];
if (!info) return -1;
return info.awaited;
+ },
+
+ emscripten_get_preloaded_image_data: function(path, w, h) {
+ if (typeof path === "number") {
+ path = Pointer_stringify(path);
+ }
+
+ path = PATH.resolve(path);
+
+ var canvas = Module["preloadedImages"][path];
+ if (canvas) {
+ var ctx = canvas.getContext("2d");
+ var image = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ var buf = _malloc(canvas.width * canvas.height * 4);
+
+ HEAPU8.set(image.data, buf);
+
+ {{{ makeSetValue('w', '0', 'canvas.width', 'i32') }}};
+ {{{ makeSetValue('h', '0', 'canvas.height', 'i32') }}};
+ return buf;
+ }
+
+ return 0;
+ },
+
+ emscripten_get_preloaded_image_data_from_FILE__deps: ['emscripten_get_preloaded_image_data'],
+ emscripten_get_preloaded_image_data_from_FILE: function(file, w, h) {
+ var stream = FS.getStreamFromPtr(file);
+ if (stream) {
+ return _emscripten_get_preloaded_image_data(stream.path, w, h);
+ }
+
+ return 0;
}
});
diff --git a/src/library_fs.js b/src/library_fs.js
index 5f7f1dea..c9fe8b3b 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -607,6 +607,9 @@ mergeInto(LibraryManager.library, {
var lookup = FS.lookupPath(path, { parent: true });
var parent = lookup.node;
var name = PATH.basename(path);
+ if (!name || name === '.' || name === '..') {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
var err = FS.mayCreate(parent, name);
if (err) {
throw new FS.ErrnoError(err);
@@ -932,6 +935,9 @@ mergeInto(LibraryManager.library, {
});
},
open: function(path, flags, mode, fd_start, fd_end) {
+ if (path === "") {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+ }
flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
if ((flags & {{{ cDefine('O_CREAT') }}})) {
@@ -1077,6 +1083,10 @@ mergeInto(LibraryManager.library, {
if (!stream.stream_ops.write) {
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
}
+ if (stream.flags & {{{ cDefine('O_APPEND') }}}) {
+ // seek to the end before writing in append mode
+ FS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}});
+ }
var seeking = true;
if (typeof position === 'undefined') {
position = stream.position;
@@ -1084,10 +1094,6 @@ mergeInto(LibraryManager.library, {
} else if (!stream.seekable) {
throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
}
- if (stream.flags & {{{ cDefine('O_APPEND') }}}) {
- // seek to the end before writing in append mode
- FS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}});
- }
var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
if (!seeking) stream.position += bytesWritten;
try {
@@ -1207,6 +1213,21 @@ mergeInto(LibraryManager.library, {
TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
FS.mkdev('/dev/tty', FS.makedev(5, 0));
FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+ // setup /dev/[u]random
+ var random_device;
+ if (typeof crypto !== 'undefined') {
+ // for modern web browsers
+ var randomBuffer = new Uint8Array(1);
+ random_device = function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; };
+ } else if (ENVIRONMENT_IS_NODE) {
+ // for nodejs
+ random_device = function() { return require('crypto').randomBytes(1)[0]; };
+ } else {
+ // default for ES5 platforms
+ random_device = function() { return Math.floor(Math.random()*256); };
+ }
+ FS.createDevice('/dev', 'random', random_device);
+ FS.createDevice('/dev', 'urandom', random_device);
// we're not going to emulate the actual shm device,
// just create the tmp dirs that reside in it commonly
FS.mkdir('/dev/shm');
@@ -1480,6 +1501,7 @@ mergeInto(LibraryManager.library, {
// WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
// read() will try to parse UTF8.
obj.contents = intArrayFromString(Module['read'](obj.url), true);
+ obj.usedBytes = obj.contents.length;
} catch (e) {
success = false;
}
@@ -1601,6 +1623,10 @@ mergeInto(LibraryManager.library, {
node.contents = null;
node.url = properties.url;
}
+ // Add a function that defers querying the file size until it is asked the first time.
+ Object.defineProperty(node, "usedBytes", {
+ get: function() { return this.contents.length; }
+ });
// override each stream op with one that tries to force load the lazy file first
var stream_ops = {};
var keys = Object.keys(node.stream_ops);
diff --git a/src/library_gl.js b/src/library_gl.js
index 851b01b1..ffcbef62 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -431,21 +431,42 @@ var LibraryGL = {
sizePerPixel = 2;
break;
default:
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
break;
case 0x1403 /* GL_UNSIGNED_SHORT */:
if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
sizePerPixel = 2;
} else {
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
break;
case 0x1405 /* GL_UNSIGNED_INT */:
if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
sizePerPixel = 4;
} else {
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
break;
case 0x84FA /* UNSIGNED_INT_24_8_WEBGL */:
@@ -457,8 +478,8 @@ var LibraryGL = {
sizePerPixel = 2;
break;
case 0x1406 /* GL_FLOAT */:
-#if ASSERTIONS
- assert(GL.floatExt, 'Must have OES_texture_float to use float textures');
+#if GL_ASSERTIONS
+ if (!GL.floatExt) Module.printErr('Must have OES_texture_float to use float textures');
#endif
switch (format) {
case 0x1907 /* GL_RGB */:
@@ -468,12 +489,51 @@ var LibraryGL = {
sizePerPixel = 4*4;
break;
default:
- throw 'Invalid format (' + format + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
internalFormat = GLctx.RGBA;
break;
+ case 0x8D61 /* GL_HALF_FLOAT_OES */:
+ switch (format) {
+ case 0x1903 /* GL_RED */:
+ sizePerPixel = 2;
+ break;
+ case 0x8277 /* GL_RG */:
+ sizePerPixel = 2*2;
+ break;
+ case 0x1907 /* GL_RGB */:
+ sizePerPixel = 3*2;
+ break;
+ case 0x1908 /* GL_RGBA */:
+ sizePerPixel = 4*2;
+ break;
+ default:
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
+ }
+ break;
default:
- throw 'Invalid type (' + type + ')';
+ GL.recordError(0x0500); // GL_INVALID_ENUM
+#if GL_ASSERTIONS
+ Module.printErr('GL_INVALID_ENUM in glTex[Sub]Image, type: ' + type + ', format: ' + format);
+#endif
+ return {
+ pixels: null,
+ internalFormat: 0x0
+ };
}
var bytes = GL.computeImageSize(width, height, sizePerPixel, GL.unpackAlignment);
if (type == 0x1401 /* GL_UNSIGNED_BYTE */) {
@@ -488,7 +548,7 @@ var LibraryGL = {
return {
pixels: pixels,
internalFormat: internalFormat
- }
+ };
},
#if GL_FFP_ONLY
@@ -652,22 +712,22 @@ var LibraryGL = {
"EXT_shader_texture_lod" ];
function shouldEnableAutomatically(extension) {
- for(var i in automaticallyEnabledExtensions) {
- var include = automaticallyEnabledExtensions[i];
+ var ret = false;
+ automaticallyEnabledExtensions.forEach(function(include) {
if (ext.indexOf(include) != -1) {
- return true;
+ ret = true;
}
- }
- return false;
+ });
+ return ret;
}
- var extensions = GLctx.getSupportedExtensions();
- for(var e in extensions) {
- var ext = extensions[e].replace('MOZ_', '').replace('WEBKIT_', '');
+
+ GLctx.getSupportedExtensions().forEach(function(ext) {
+ ext = ext.replace('MOZ_', '').replace('WEBKIT_', '');
if (automaticallyEnabledExtensions.indexOf(ext) != -1) {
GLctx.getExtension(ext); // Calling .getExtension enables that extension permanently, no need to store the return value to be enabled.
}
- }
+ });
},
// In WebGL, uniforms in a shader program are accessed through an opaque object type 'WebGLUniformLocation'.
@@ -798,6 +858,7 @@ var LibraryGL = {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}};
var texture = GL.textures[id];
+ if (!texture) continue;
GLctx.deleteTexture(texture);
texture.name = 0;
GL.textures[id] = null;
@@ -1281,7 +1342,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[0];
view[0] = {{{ makeGetValue('value', '0', 'float') }}};
@@ -1298,7 +1359,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[1];
view[0] = {{{ makeGetValue('value', '0', 'float') }}};
@@ -1316,7 +1377,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[2];
view[0] = {{{ makeGetValue('value', '0', 'float') }}};
@@ -1335,7 +1396,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform
view = GL.miniTempBufferViews[3];
view[0] = {{{ makeGetValue('value', '0', 'float') }}};
@@ -1355,7 +1416,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform matrix
view = GL.miniTempBufferViews[3];
for (var i = 0; i < 4; i++) {
@@ -1374,7 +1435,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform matrix
view = GL.miniTempBufferViews[8];
for (var i = 0; i < 9; i++) {
@@ -1393,7 +1454,7 @@ var LibraryGL = {
#endif
location = GL.uniforms[location];
var view;
- if (count == 1) {
+ if (count === 1) {
// avoid allocation for the common case of uploading one uniform matrix
view = GL.miniTempBufferViews[15];
for (var i = 0; i < 16; i++) {
diff --git a/src/library_glfw.js b/src/library_glfw.js
index 6d539326..6dfea101 100644
--- a/src/library_glfw.js
+++ b/src/library_glfw.js
@@ -417,6 +417,9 @@ var LibraryGLFW = {
glfwSetWindowSizeCallback: function(cbfun) {
GLFW.resizeFunc = cbfun;
+ if (GLFW.resizeFunc) {
+ Runtime.dynCall('vii', GLFW.resizeFunc, [Module['canvas'].width, Module['canvas'].height]);
+ }
},
glfwSetWindowCloseCallback: function(cbfun) {
@@ -507,9 +510,9 @@ var LibraryGLFW = {
return Module.ctx.getSupportedExtensions().indexOf(Pointer_stringify(extension)) > -1;
},
- glfwGetProcAddress__deps: ['glfwGetProcAddress'],
+ glfwGetProcAddress__deps: ['emscripten_GetProcAddress'],
glfwGetProcAddress: function(procname) {
- return _getProcAddress(procname);
+ return _emscripten_GetProcAddress(procname);
},
glfwGetGLVersion: function(major, minor, rev) {
diff --git a/src/library_glut.js b/src/library_glut.js
index 445e08a4..d6293d85 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -383,7 +383,7 @@ var LibraryGLUT = {
function callback() {
if (GLUT.idleFunc) {
Runtime.dynCall('v', GLUT.idleFunc);
- Browser.safeSetTimeout(callback, 0);
+ Browser.safeSetTimeout(callback, 4); // HTML spec specifies a 4ms minimum delay on the main thread; workers might get more, but we standardize here
}
}
if (!GLUT.idleFunc) {
@@ -489,8 +489,9 @@ var LibraryGLUT = {
GLUT.requestedAnimationFrame = true;
Browser.requestAnimationFrame(function() {
GLUT.requestedAnimationFrame = false;
- if (ABORT) return;
- Runtime.dynCall('v', GLUT.displayFunc);
+ Browser.mainLoop.runIter(function() {
+ Runtime.dynCall('v', GLUT.displayFunc);
+ });
});
}
},
diff --git a/src/library_html5.js b/src/library_html5.js
index d5d0cd66..238575de 100644
--- a/src/library_html5.js
+++ b/src/library_html5.js
@@ -198,7 +198,6 @@ var LibraryJSEvents = {
},
fillMouseEventData: function(eventStruct, e) {
- var rect = Module['canvas'].getBoundingClientRect();
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.timestamp, 'JSEvents.tick()', 'double') }}};
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenX, 'e.screenX', 'i32') }}};
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenY, 'e.screenY', 'i32') }}};
@@ -212,8 +211,15 @@ var LibraryJSEvents = {
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.buttons, 'e.buttons', 'i16') }}};
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementX, 'e["movementX"] || e["mozMovementX"] || e["webkitMovementX"] || (e.screenX-JSEvents.previousScreenX)', 'i32') }}};
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementY, 'e["movementY"] || e["mozMovementY"] || e["webkitMovementY"] || (e.screenY-JSEvents.previousScreenY)', 'i32') }}};
- {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}};
- {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}};
+
+ if (Module['canvas']) {
+ var rect = Module['canvas'].getBoundingClientRect();
+ {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}};
+ {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}};
+ } else { // Canvas is not initialized, return 0.
+ {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, '0', 'i32') }}};
+ {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, '0', 'i32') }}};
+ }
JSEvents.previousScreenX = e.screenX;
JSEvents.previousScreenY = e.screenY;
},
diff --git a/src/library_idbfs.js b/src/library_idbfs.js
index 91015e77..8082c196 100644
--- a/src/library_idbfs.js
+++ b/src/library_idbfs.js
@@ -135,6 +135,9 @@ mergeInto(LibraryManager.library, {
if (FS.isDir(stat.mode)) {
return callback(null, { timestamp: stat.mtime, mode: stat.mode });
} else if (FS.isFile(stat.mode)) {
+ // Performance consideration: storing a normal JavaScript array to a IndexedDB is much slower than storing a typed array.
+ // Therefore always convert the file contents to a typed array first before writing the data to IndexedDB.
+ node.contents = MEMFS.getFileDataAsTypedArray(node);
return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
} else {
return callback(new Error('node type not supported'));
diff --git a/src/library_memfs.js b/src/library_memfs.js
index 95c3ae65..72ecdcfe 100644
--- a/src/library_memfs.js
+++ b/src/library_memfs.js
@@ -2,11 +2,6 @@ mergeInto(LibraryManager.library, {
$MEMFS__deps: ['$FS'],
$MEMFS: {
ops_table: null,
-
- // content modes
- CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it, without copying (note: someone else needs to free() it, if that is necessary)
- CONTENT_FLEXIBLE: 2, // has been modified or never set to anything, and is a flexible js array that can grow/shrink
- CONTENT_FIXED: 3, // contains some fixed-size content written into it, in a typed array
mount: function(mount) {
return MEMFS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, 0);
},
@@ -71,8 +66,11 @@ mergeInto(LibraryManager.library, {
} else if (FS.isFile(node.mode)) {
node.node_ops = MEMFS.ops_table.file.node;
node.stream_ops = MEMFS.ops_table.file.stream;
- node.contents = [];
- node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+ node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.buffer.byteLength which gives the whole capacity.
+ // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred
+ // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size
+ // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme.
+ node.contents = null;
} else if (FS.isLink(node.mode)) {
node.node_ops = MEMFS.ops_table.link.node;
node.stream_ops = MEMFS.ops_table.link.stream;
@@ -87,13 +85,88 @@ mergeInto(LibraryManager.library, {
}
return node;
},
- ensureFlexible: function(node) {
- if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
- var contents = node.contents;
- node.contents = Array.prototype.slice.call(contents);
- node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+
+ // Given a file node, returns its file data converted to a regular JS array. You should treat this as read-only.
+ getFileDataAsRegularArray: function(node) {
+#if USE_TYPED_ARRAYS == 2
+ if (node.contents && node.contents.subarray) {
+ var arr = [];
+ for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]);
+ return arr; // Returns a copy of the original data.
+ }
+#endif
+ return node.contents; // No-op, the file contents are already in a JS array. Return as-is.
+ },
+
+#if USE_TYPED_ARRAYS == 2
+ // Given a file node, returns its file data converted to a typed array.
+ getFileDataAsTypedArray: function(node) {
+ if (node.contents && node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes.
+ return new Uint8Array(node.contents);
+ },
+#endif
+
+ // Allocates a new backing store for the given node so that it can fit at least newSize amount of bytes.
+ // May allocate more, to provide automatic geometric increase and amortized linear performance appending writes.
+ // Never shrinks the storage.
+ expandFileStorage: function(node, newCapacity) {
+#if USE_TYPED_ARRAYS == 2
+
+#if !MEMFS_APPEND_TO_TYPED_ARRAYS
+ // If we are asked to expand the size of a file that already exists, revert to using a standard JS array to store the file
+ // instead of a typed array. This makes resizing the array more flexible because we can just .push() elements at the back to
+ // increase the size.
+ if (node.contents && node.contents.subarray && newCapacity > node.contents.length) {
+ node.contents = MEMFS.getFileDataAsRegularArray(node);
+ node.usedBytes = node.contents.length; // We might be writing to a lazy-loaded file which had overridden this property, so force-reset it.
+ }
+#endif
+
+ if (!node.contents || node.contents.subarray) { // Keep using a typed array if creating a new storage, or if old one was a typed array as well.
+ var prevCapacity = node.contents ? node.contents.buffer.byteLength : 0;
+ if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough.
+ // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity.
+ // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to
+ // avoid overshooting the allocation cap by a very large margin.
+ var CAPACITY_DOUBLING_MAX = 1024 * 1024;
+ newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) | 0);
+ if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding.
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(newCapacity); // Allocate new storage.
+ if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage.
+ return;
+ }
+#endif
+ // Not using a typed array to back the file storage. Use a standard JS array instead.
+ if (!node.contents && newCapacity > 0) node.contents = [];
+ while (node.contents.length < newCapacity) node.contents.push(0);
+ },
+
+ // Performs an exact resize of the backing file storage to the given size, if the size is not exactly this, the storage is fully reallocated.
+ resizeFileStorage: function(node, newSize) {
+ if (node.usedBytes == newSize) return;
+ if (newSize == 0) {
+ node.contents = null; // Fully decommit when requesting a resize to zero.
+ node.usedBytes = 0;
+ return;
}
+
+#if USE_TYPED_ARRAYS == 2
+ if (!node.contents || node.contents.subarray) { // Resize a typed array if that is being used as the backing store.
+ var oldContents = node.contents;
+ node.contents = new Uint8Array(new ArrayBuffer(newSize)); // Allocate new storage.
+ node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage.
+ node.usedBytes = newSize;
+ return;
+ }
+#endif
+ // Backing with a JS array.
+ if (!node.contents) node.contents = [];
+ if (node.contents.length > newSize) node.contents.length = newSize;
+ else while (node.contents.length < newSize) node.contents.push(0);
+ node.usedBytes = newSize;
},
+
node_ops: {
getattr: function(node) {
var attr = {};
@@ -108,7 +181,7 @@ mergeInto(LibraryManager.library, {
if (FS.isDir(node.mode)) {
attr.size = 4096;
} else if (FS.isFile(node.mode)) {
- attr.size = node.contents.length;
+ attr.size = node.usedBytes;
} else if (FS.isLink(node.mode)) {
attr.size = node.link.length;
} else {
@@ -131,10 +204,7 @@ mergeInto(LibraryManager.library, {
node.timestamp = attr.timestamp;
}
if (attr.size !== undefined) {
- MEMFS.ensureFlexible(node);
- var contents = node.contents;
- if (attr.size < contents.length) contents.length = attr.size;
- else while (attr.size > contents.length) contents.push(0);
+ MEMFS.resizeFileStorage(node, attr.size);
}
},
lookup: function(parent, name) {
@@ -198,9 +268,8 @@ mergeInto(LibraryManager.library, {
stream_ops: {
read: function(stream, buffer, offset, length, position) {
var contents = stream.node.contents;
- if (position >= contents.length)
- return 0;
- var size = Math.min(contents.length - position, length);
+ if (position >= stream.node.usedBytes) return 0;
+ var size = Math.min(stream.node.usedBytes - position, length);
assert(size >= 0);
#if USE_TYPED_ARRAYS == 2
if (size > 8 && contents.subarray) { // non-trivial, and typed array
@@ -208,47 +277,56 @@ mergeInto(LibraryManager.library, {
} else
#endif
{
- for (var i = 0; i < size; i++) {
- buffer[offset + i] = contents[position + i];
- }
+ for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
}
return size;
},
+
+ // Writes the byte range (buffer[offset], buffer[offset+length]) to offset 'position' into the file pointed by 'stream'
write: function(stream, buffer, offset, length, position, canOwn) {
+ if (!length) return 0;
var node = stream.node;
node.timestamp = Date.now();
- var contents = node.contents;
+
#if USE_TYPED_ARRAYS == 2
- if (length && contents.length === 0 && position === 0 && buffer.subarray) {
- // just replace it with the new data
+ if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array?
+ if (canOwn) { // Can we just reuse the buffer we are given?
#if ASSERTIONS
- assert(buffer.length);
+ assert(position === 0, 'canOwn must imply no weird position inside the file');
#endif
- if (canOwn && offset === 0) {
- node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
- node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
- } else {
- node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
- node.contentMode = MEMFS.CONTENT_FIXED;
+ node.contents = buffer.subarray(offset, offset + length);
+ node.usedBytes = length;
+ return length;
+ } else if (node.usedBytes === 0 && position === 0) { // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data.
+ node.contents = new Uint8Array(buffer.subarray(offset, offset + length));
+ node.usedBytes = length;
+ return length;
+ } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file?
+ node.contents.set(buffer.subarray(offset, offset + length), position);
+ return length;
}
- return length;
}
#endif
- MEMFS.ensureFlexible(node);
- var contents = node.contents;
- while (contents.length < position) contents.push(0);
- for (var i = 0; i < length; i++) {
- contents[position + i] = buffer[offset + i];
- }
+ // Appending to an existing file and we need to reallocate, or source data did not come as a typed array.
+ MEMFS.expandFileStorage(node, position+length);
+#if USE_TYPED_ARRAYS == 2
+ if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position); // Use typed array write if available.
+ else
+#endif
+ for (var i = 0; i < length; i++) {
+ node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not.
+ }
+ node.usedBytes = Math.max(node.usedBytes, position+length);
return length;
},
+
llseek: function(stream, offset, whence) {
var position = offset;
if (whence === 1) { // SEEK_CUR.
position += stream.position;
} else if (whence === 2) { // SEEK_END.
if (FS.isFile(stream.node.mode)) {
- position += stream.node.contents.length;
+ position += stream.node.usedBytes;
}
}
if (position < 0) {
@@ -259,10 +337,8 @@ mergeInto(LibraryManager.library, {
return position;
},
allocate: function(stream, offset, length) {
- MEMFS.ensureFlexible(stream.node);
- var contents = stream.node.contents;
- var limit = offset + length;
- while (limit > contents.length) contents.push(0);
+ MEMFS.expandFileStorage(stream.node, offset + length);
+ stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);
},
mmap: function(stream, buffer, offset, length, position, prot, flags) {
if (!FS.isFile(stream.node.mode)) {
@@ -280,7 +356,7 @@ mergeInto(LibraryManager.library, {
ptr = contents.byteOffset;
} else {
// Try to avoid unnecessary slices.
- if (position > 0 || position + length < contents.length) {
+ if (position > 0 || position + length < stream.node.usedBytes) {
if (contents.subarray) {
contents = contents.subarray(position, position + length);
} else {
diff --git a/src/library_sdl.js b/src/library_sdl.js
index fd8c6860..c00c0d6c 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -84,6 +84,9 @@ var LibrarySDL = {
TOUCH_DEFAULT_ID: 0, // Our default deviceID for touch events (we get nothing from the browser)
+ eventHandler: null,
+ eventHandlerContext: null,
+
keyCodes: { // DOM code ==> SDL code. See https://developer.mozilla.org/en/Document_Object_Model_%28DOM%29/KeyboardEvent and SDL_keycode.h
// For keys that don't have unicode value, we map DOM codes with the corresponding scan codes + 1024 (using "| 1 << 10")
16: 225 | 1<<10, // shift
@@ -257,6 +260,16 @@ var LibrarySDL = {
};
},
+ checkPixelFormat: function(fmt) {
+#if ASSERTIONS
+ // Canvas screens are always RGBA.
+ var format = {{{ makeGetValue('fmt', C_STRUCTS.SDL_PixelFormat.format, 'i32') }}};
+ if (format != {{{ cDefine('SDL_PIXELFORMAT_RGBA8888') }}}) {
+ Runtime.warnOnce('Unsupported pixel format!');
+ }
+#endif
+ },
+
// Load SDL color into a CSS-style color specification
loadColorToCSSRGB: function(color) {
var rgba = {{{ makeGetValue('color', '0', 'i32') }}};
@@ -304,7 +317,12 @@ var LibrarySDL = {
{{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}}; // assuming RGBA or indexed for now,
// since that is what ImageData gives us in browsers
{{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}};
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}};
+
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect+C_STRUCTS.SDL_Rect.x, '0', 'i32') }}};
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect+C_STRUCTS.SDL_Rect.y, '0', 'i32') }}};
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect+C_STRUCTS.SDL_Rect.w, 'Module["canvas"].width', 'i32') }}};
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect+C_STRUCTS.SDL_Rect.h, 'Module["canvas"].height', 'i32') }}};
+
{{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}};
{{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}};
@@ -699,6 +717,9 @@ var LibrarySDL = {
Module.printErr('SDL event queue full, dropping events');
SDL.events = SDL.events.slice(0, 10000);
}
+ // If we have a handler installed, this will push the events to the app
+ // instead of the app polling for them.
+ SDL.flushEventsToHandler();
return;
},
@@ -750,10 +771,40 @@ var LibrarySDL = {
}
},
+ flushEventsToHandler: function() {
+ if (!SDL.eventHandler) return;
+
+ // All SDLEvents take the same amount of memory
+ var sdlEventPtr = allocate({{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}, "i8", ALLOC_STACK);
+
+ while (SDL.pollEvent(sdlEventPtr)) {
+ Runtime.dynCall('iii', SDL.eventHandler, [SDL.eventHandlerContext, sdlEventPtr]);
+ }
+ },
+
+ pollEvent: function(ptr) {
+ if (SDL.initFlags & 0x200 && SDL.joystickEventState) {
+ // If SDL_INIT_JOYSTICK was supplied AND the joystick system is configured
+ // to automatically query for events, query for joystick events.
+ SDL.queryJoysticks();
+ }
+ if (ptr) {
+ while (SDL.events.length > 0) {
+ if (SDL.makeCEvent(SDL.events.shift(), ptr) !== false) return 1;
+ }
+ return 0;
+ } else {
+ // XXX: somewhat risky in that we do not check if the event is real or not (makeCEvent returns false) if no pointer supplied
+ return SDL.events.length > 0;
+ }
+ },
+
+ // returns false if the event was determined to be irrelevant
makeCEvent: function(event, ptr) {
if (typeof event === 'number') {
- // This is a pointer to a native C event that was SDL_PushEvent'ed
- _memcpy(ptr, event, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); // XXX
+ // This is a pointer to a copy of a native C event that was SDL_PushEvent'ed
+ _memcpy(ptr, event, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}});
+ _free(event); // the copy is no longer needed
return;
}
@@ -838,7 +889,7 @@ var LibrarySDL = {
var dx = x - lx;
var dy = y - ly;
if (touch['deviceID'] === undefined) touch.deviceID = SDL.TOUCH_DEFAULT_ID;
- if (dx === 0 && dy === 0 && event.type === 'touchmove') return; // don't send these if nothing happened
+ if (dx === 0 && dy === 0 && event.type === 'touchmove') return false; // don't send these if nothing happened
{{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.timestamp, '_SDL_GetTicks()', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_TouchFingerEvent.touchId, 'touch.deviceID', 'i64') }}};
@@ -1279,30 +1330,43 @@ var LibrarySDL = {
Module['canvas'].addEventListener(event, SDL.receiveEvent, true);
});
+ var canvas = Module['canvas'];
+
// (0,0) means 'use fullscreen' in native; in Emscripten, use the current canvas size.
if (width == 0 && height == 0) {
- var canvas = Module['canvas'];
width = canvas.width;
height = canvas.height;
}
- Browser.setCanvasSize(width, height, true);
- // Free the old surface first.
- if (SDL.screen) {
- SDL.freeSurface(SDL.screen);
- assert(!SDL.screen);
- }
- SDL.screen = SDL.makeSurface(width, height, flags, true, 'screen');
if (!SDL.addedResizeListener) {
SDL.addedResizeListener = true;
Browser.resizeListeners.push(function(w, h) {
- SDL.receiveEvent({
- type: 'resize',
- w: w,
- h: h
- });
+ if (!SDL.settingVideoMode) {
+ SDL.receiveEvent({
+ type: 'resize',
+ w: w,
+ h: h
+ });
+ }
});
}
+
+ if (width !== canvas.width || height !== canvas.height) {
+ SDL.settingVideoMode = true; // SetVideoMode itself should not trigger resize events
+ Browser.setCanvasSize(width, height);
+ SDL.settingVideoMode = false;
+ }
+
+ // Free the old surface first if there is one
+ if (SDL.screen) {
+ SDL.freeSurface(SDL.screen);
+ assert(!SDL.screen);
+ }
+
+ if (SDL.GL) flags = flags | 0x04000000; // SDL_OPENGL - if we are using GL, then later calls to SetVideoMode may not mention GL, but we do need it. Once in GL mode, we never leave it.
+
+ SDL.screen = SDL.makeSurface(width, height, flags, true, 'screen');
+
return SDL.screen;
},
@@ -1310,11 +1374,7 @@ var LibrarySDL = {
return SDL.screen;
},
- SDL_QuitSubSystem: function(flags) {
- Module.print('SDL_QuitSubSystem called (and ignored)');
- },
-
- SDL_Quit: function() {
+ SDL_AudioQuit: function() {
for (var i = 0; i < SDL.numChannels; ++i) {
if (SDL.channels[i].audio) {
SDL.channels[i].audio.pause();
@@ -1323,6 +1383,19 @@ var LibrarySDL = {
}
if (SDL.music.audio) SDL.music.audio.pause();
SDL.music.audio = undefined;
+ },
+
+ SDL_VideoQuit: function() {
+ Module.print('SDL_VideoQuit called (and ignored)');
+ },
+
+ SDL_QuitSubSystem: function(flags) {
+ Module.print('SDL_QuitSubSystem called (and ignored)');
+ },
+
+ SDL_Quit__deps: ['SDL_AudioQuit'],
+ SDL_Quit: function() {
+ _SDL_AudioQuit();
Module.print('SDL_Quit called (and ignored)');
},
@@ -1709,20 +1782,13 @@ var LibrarySDL = {
},
SDL_PollEvent: function(ptr) {
- if (SDL.initFlags & 0x200 && SDL.joystickEventState) {
- // If SDL_INIT_JOYSTICK was supplied AND the joystick system is configured
- // to automatically query for events, query for joystick events.
- SDL.queryJoysticks();
- }
- if (SDL.events.length === 0) return 0;
- if (ptr) {
- SDL.makeCEvent(SDL.events.shift(), ptr);
- }
- return 1;
+ return SDL.pollEvent(ptr);
},
SDL_PushEvent: function(ptr) {
- SDL.events.push(ptr); // XXX Should we copy it? Not clear from API
+ var copy = _malloc({{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}});
+ _memcpy(copy, ptr, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}});
+ SDL.events.push(copy);
return 0;
},
@@ -1740,9 +1806,12 @@ var LibrarySDL = {
var event = SDL.events[index];
var type = SDL.DOMEventToSDLEvent[event.type];
if (from <= type && type <= to) {
- SDL.makeCEvent(event, events);
- SDL.events.splice(index, 1);
- retrievedEventCount++;
+ if (SDL.makeCEvent(event, events) === false) {
+ index++;
+ } else {
+ SDL.events.splice(index, 1);
+ retrievedEventCount++;
+ }
} else {
index++;
}
@@ -1758,6 +1827,13 @@ var LibrarySDL = {
SDL.handleEvent(event);
});
},
+
+ // An Emscripten-specific extension to SDL: Some browser APIs require that they are called from within an event handler function.
+ // Allow recording a callback that will be called for each received event.
+ emscripten_SDL_SetEventHandler: function(handler, userdata) {
+ SDL.eventHandler = handler;
+ SDL.eventHandlerContext = userdata;
+ },
SDL_SetColors: function(surf, colors, firstColor, nColors) {
var surfData = SDL.surfaces[surf];
@@ -1786,15 +1862,48 @@ var LibrarySDL = {
},
SDL_MapRGB: function(fmt, r, g, b) {
- // Canvas screens are always RGBA. We assume the machine is little-endian.
+ SDL.checkPixelFormat(fmt);
+ // We assume the machine is little-endian.
return r&0xff|(g&0xff)<<8|(b&0xff)<<16|0xff000000;
},
SDL_MapRGBA: function(fmt, r, g, b, a) {
- // Canvas screens are always RGBA. We assume the machine is little-endian.
+ SDL.checkPixelFormat(fmt);
+ // We assume the machine is little-endian.
return r&0xff|(g&0xff)<<8|(b&0xff)<<16|(a&0xff)<<24;
},
+ SDL_GetRGB: function(pixel, fmt, r, g, b) {
+ SDL.checkPixelFormat(fmt);
+ // We assume the machine is little-endian.
+ if (r) {
+ {{{ makeSetValue('r', '0', 'pixel&0xff', 'i8') }}};
+ }
+ if (g) {
+ {{{ makeSetValue('g', '0', '(pixel>>8)&0xff', 'i8') }}};
+ }
+ if (b) {
+ {{{ makeSetValue('b', '0', '(pixel>>16)&0xff', 'i8') }}};
+ }
+ },
+
+ SDL_GetRGBA: function(pixel, fmt, r, g, b, a) {
+ SDL.checkPixelFormat(fmt);
+ // We assume the machine is little-endian.
+ if (r) {
+ {{{ makeSetValue('r', '0', 'pixel&0xff', 'i8') }}};
+ }
+ if (g) {
+ {{{ makeSetValue('g', '0', '(pixel>>8)&0xff', 'i8') }}};
+ }
+ if (b) {
+ {{{ makeSetValue('b', '0', '(pixel>>16)&0xff', 'i8') }}};
+ }
+ if (a) {
+ {{{ makeSetValue('a', '0', '(pixel>>24)&0xff', 'i8') }}};
+ }
+ },
+
SDL_GetAppState: function() {
var state = 0;
@@ -1913,8 +2022,10 @@ var LibrarySDL = {
} else {
var imageData = surfData.ctx.getImageData(0, 0, surfData.width, surfData.height);
if (raw.bpp == 4) {
+ // rgba
imageData.data.set({{{ makeHEAPView('U8', 'raw.data', 'raw.data+raw.size') }}});
} else if (raw.bpp == 3) {
+ // rgb
var pixels = raw.size/3;
var data = imageData.data;
var sourcePtr = raw.data;
@@ -1925,6 +2036,19 @@ var LibrarySDL = {
data[destPtr++] = {{{ makeGetValue('sourcePtr++', 0, 'i8', null, 1) }}};
data[destPtr++] = 255;
}
+ } else if (raw.bpp == 1) {
+ // grayscale
+ var pixels = raw.size;
+ var data = imageData.data;
+ var sourcePtr = raw.data;
+ var destPtr = 0;
+ for (var i = 0; i < pixels; i++) {
+ var value = {{{ makeGetValue('sourcePtr++', 0, 'i8', null, 1) }}};
+ data[destPtr++] = value;
+ data[destPtr++] = value;
+ data[destPtr++] = value;
+ data[destPtr++] = 255;
+ }
} else {
Module.printErr('cannot handle bpp ' + raw.bpp);
return 0;
@@ -2332,7 +2456,7 @@ var LibrarySDL = {
return 0;
}
- var arrayBuffer = bytes.buffer || bytes;
+ var arrayBuffer = bytes ? bytes.buffer || bytes : bytes;
// To allow user code to work around browser bugs with audio playback on <audio> elements an Web Audio, enable
// the user code to hook in a callback to decide on a file basis whether each file should use Web Audio or <audio> for decoding and playback.
@@ -2601,7 +2725,7 @@ var LibrarySDL = {
if (info && info.audio) {
info.audio.pause();
} else {
- Module.printErr('Mix_Pause: no sound found for channel: ' + channel);
+ //Module.printErr('Mix_Pause: no sound found for channel: ' + channel);
}
},
@@ -2850,7 +2974,9 @@ var LibrarySDL = {
return _emscripten_GetProcAddress(name_);
},
- SDL_GL_SwapBuffers: function() {},
+ SDL_GL_SwapBuffers: function() {
+ if (Browser.doSwapBuffers) Browser.doSwapBuffers(); // in workers, this is used to send out a buffered frame
+ },
// SDL 2
@@ -2906,6 +3032,8 @@ var LibrarySDL = {
SDL_getenv: 'getenv',
+ SDL_putenv: 'putenv',
+
// TODO
SDL_SetGamma: function(r, g, b) {
diff --git a/src/modules.js b/src/modules.js
index fd5c23cd..0c1d24bc 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -443,6 +443,28 @@ var LibraryManager = {
}
}
+ // apply synonyms. these are typically not speed-sensitive, and doing it this way makes it possible to not include hacks in the compiler
+ // (and makes it simpler to switch between SDL versions, fastcomp and non-fastcomp, etc.).
+ var lib = LibraryManager.library;
+ libloop: for (var x in lib) {
+ if (x.lastIndexOf('__') > 0) continue; // ignore __deps, __*
+ if (lib[x + '__asm']) continue; // ignore asm library functions, those need to be fully optimized
+ if (typeof lib[x] === 'string') {
+ var target = x;
+ while (typeof lib[target] === 'string') {
+ if (lib[target].indexOf('(') >= 0) continue libloop;
+ if (lib[target].indexOf('Math_') == 0) continue libloop;
+ target = lib[target];
+ }
+ if (lib[target + '__asm']) continue; // This is an alias of an asm library function. Also needs to be fully optimized.
+ if (typeof lib[target] === 'undefined' || typeof lib[target] === 'function') {
+ lib[x] = new Function('return _' + target + '.apply(null, arguments)');
+ if (!lib[x + '__deps']) lib[x + '__deps'] = [];
+ lib[x + '__deps'].push(target);
+ }
+ }
+ }
+
/*
// export code for CallHandlers.h
printErr('============================');
diff --git a/src/parseTools.js b/src/parseTools.js
index 0c413afa..ececf477 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -2035,7 +2035,7 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) {
} else if (param.intertype == 'mathop') {
return processMathop(param);
} else if (param.intertype === 'vector') {
- return getVectorBaseType(param.type) + '32x4(' + param.idents.join(',') + ')';
+ return 'SIMD.' + getVectorBaseType(param.type) + '32x4(' + param.idents.join(',') + ')';
} else {
throw 'invalid llvm parameter: ' + param.intertype;
}
@@ -2700,7 +2700,7 @@ var simdLane = ['x', 'y', 'z', 'w'];
function ensureVector(ident, base) {
Types.usesSIMD = true;
- return ident == 0 ? base + '32x4.splat(0)' : ident;
+ return ident == 0 ? 'SIMD.' + base + '32x4.splat(0)' : ident;
}
function ensureValidFFIType(type) {
diff --git a/src/postamble.js b/src/postamble.js
index b90049bc..085dee69 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -13,6 +13,11 @@ if (memoryInitializer) {
addRunDependency('memory initializer');
Browser.asyncLoad(memoryInitializer, function(data) {
#if USE_TYPED_ARRAYS == 2
+#if ASSERTIONS
+ for (var i = 0; i < data.length; i++) {
+ assert(HEAPU8[STATIC_BASE + i] === 0, "area for memory initializer should not have been touched before it's loaded");
+ }
+#endif
HEAPU8.set(data, STATIC_BASE);
#else
allocate(data, 'i8', ALLOC_NONE, STATIC_BASE);
@@ -56,7 +61,7 @@ Module['callMain'] = Module.callMain = function callMain(args) {
argv.push(0);
}
}
- var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+ var argv = [allocate(intArrayFromString(Module['thisProgram'] || '/bin/this.program'), 'i8', ALLOC_NORMAL) ];
pad();
for (var i = 0; i < argc-1; i = i + 1) {
argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
@@ -79,9 +84,7 @@ Module['callMain'] = Module.callMain = function callMain(args) {
#endif
// if we're not running an evented main loop, it's time to exit
- if (!Module['noExitRuntime']) {
- exit(ret);
- }
+ exit(ret);
}
catch(e) {
if (e instanceof ExitStatus) {
@@ -122,6 +125,8 @@ function run(args) {
if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
Module['calledRun'] = true;
+ if (ABORT) return;
+
ensureInitRuntime();
preMain();
@@ -143,7 +148,7 @@ function run(args) {
setTimeout(function() {
Module['setStatus']('');
}, 1);
- if (!ABORT) doRun();
+ doRun();
}, 1);
} else {
doRun();
@@ -152,6 +157,13 @@ function run(args) {
Module['run'] = Module.run = run;
function exit(status) {
+ if (Module['noExitRuntime']) {
+#if ASSERTIONS
+ Module.printErr('exit(' + status + ') called, but noExitRuntime, so not exiting');
+#endif
+ return;
+ }
+
ABORT = true;
EXITSTATUS = status;
STACKTOP = initialStackTop;
@@ -159,16 +171,14 @@ function exit(status) {
// exit the runtime
exitRuntime();
- // TODO We should handle this differently based on environment.
- // In the browser, the best we can do is throw an exception
- // to halt execution, but in node we could process.exit and
- // I'd imagine SM shell would have something equivalent.
- // This would let us set a proper exit status (which
- // would be great for checking test exit statuses).
- // https://github.com/kripken/emscripten/issues/1371
-
- // throw an exception to halt the current execution
- throw new ExitStatus(status);
+ if (ENVIRONMENT_IS_NODE) {
+ process['exit'](status);
+ } else if (ENVIRONMENT_IS_SHELL && typeof quit === 'function') {
+ quit(status);
+ } else {
+ // no proper way to exit with a return code, throw an exception to halt the current execution
+ throw new ExitStatus(status);
+ }
}
Module['exit'] = Module.exit = exit;
diff --git a/src/preamble.js b/src/preamble.js
index fbce6b6b..e6d3f552 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -7,6 +7,10 @@
{{RUNTIME}}
Module['Runtime'] = Runtime;
+#if CLOSURE_COMPILER
+Runtime['addFunction'] = Runtime.addFunction;
+Runtime['removeFunction'] = Runtime.removeFunction;
+#endif
#if ASM_JS
#if RESERVED_FUNCTION_POINTERS
@@ -41,13 +45,13 @@ var ACCEPTABLE_SAFE_HEAP_ERRORS = 0;
function SAFE_HEAP_ACCESS(dest, type, store, ignore, storeValue) {
//if (dest === A_NUMBER) Module.print ([dest, type, store, ignore, storeValue] + ' ' + stackTrace()); // Something like this may be useful, in debugging
- assert(dest > 0, 'segmentation fault');
+ if (dest <= 0) abort('segmentation fault ' + (store ? ('storing value ' + storeValue) : 'loading') + ' type ' + type + ' at address ' + dest);
#if USE_TYPED_ARRAYS
// When using typed arrays, reads over the top of TOTAL_MEMORY will fail silently, so we must
// correct that by growing TOTAL_MEMORY as needed. Without typed arrays, memory is a normal
// JS array so it will work (potentially slowly, depending on the engine).
- assert(ignore || dest < Math.max(DYNAMICTOP, STATICTOP));
+ if (!ignore && dest >= Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault ' + (store ? ('storing value ' + storeValue) : 'loading') + ' type ' + type + ' at address ' + dest + '. Heap ends at address ' + Math.max(DYNAMICTOP, STATICTOP));
assert(ignore || DYNAMICTOP <= TOTAL_MEMORY);
#endif
@@ -312,10 +316,15 @@ var globalScope = this;
// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
function getCFunc(ident) {
- try {
- var func = Module['_' + ident]; // closure exported function
- if (!func) func = eval('_' + ident); // explicit lookup
- } catch(e) {
+ var func = Module['_' + ident]; // closure exported function
+ if (!func) {
+#if NO_DYNAMIC_EXECUTION == 0
+ try {
+ func = eval('_' + ident); // explicit lookup
+ } catch(e) {}
+#else
+ abort('NO_DYNAMIC_EXECUTION was set, cannot eval - ccall/cwrap are not functional');
+#endif
}
assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
return func;
@@ -396,7 +405,7 @@ var cwrap, ccall;
return ret;
}
- var sourceRegex = /^function\s\((.*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;
+ var sourceRegex = /^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;
function parseJSFunc(jsfunc) {
// Match the body and the return value of a javascript function source
var parsed = jsfunc.toString().match(sourceRegex).slice(1);
@@ -418,6 +427,7 @@ var cwrap, ccall;
// alert(my_function(99, 12));
//
cwrap = function cwrap(ident, returnType, argTypes) {
+ argTypes = argTypes || [];
var cfunc = getCFunc(ident);
// When the function takes numbers and returns a number, we can just return
// the original function
@@ -458,7 +468,11 @@ var cwrap, ccall;
funcstr += JSsource['stackRestore'].body + ';';
}
funcstr += 'return ret})';
+#if NO_DYNAMIC_EXECUTION == 0
return eval(funcstr);
+#else
+ abort('NO_DYNAMIC_EXECUTION was set, cannot eval - ccall is not functional');
+#endif
};
})();
Module["cwrap"] = cwrap;
@@ -1083,6 +1097,7 @@ var __ATEXIT__ = []; // functions called during shutdown
var __ATPOSTRUN__ = []; // functions called after the runtime has exited
var runtimeInitialized = false;
+var runtimeExited = false;
function preRun() {
// compatibility - merge in anything from Module['preRun'] at this time
@@ -1112,6 +1127,7 @@ function exitRuntime() {
}
#endif
callRuntimeCallbacks(__ATEXIT__);
+ runtimeExited = true;
}
function postRun() {
@@ -1287,6 +1303,11 @@ function addRunDependency(id) {
if (runDependencyWatcher === null && typeof setInterval !== 'undefined') {
// Check for missing dependencies every few seconds
runDependencyWatcher = setInterval(function() {
+ if (ABORT) {
+ clearInterval(runDependencyWatcher);
+ runDependencyWatcher = null;
+ return;
+ }
var shown = false;
for (var dep in runDependencyTracking) {
if (!shown) {
diff --git a/src/proxyClient.js b/src/proxyClient.js
index 2d1c76fe..3fc8313f 100644
--- a/src/proxyClient.js
+++ b/src/proxyClient.js
@@ -1,7 +1,39 @@
// proxy to/from worker
-Module.ctx = Module.canvas.getContext('2d');
+// utils
+
+function FPSTracker(text) {
+ var last = 0;
+ var mean = 0;
+ var counter = 0;
+ this.tick = function() {
+ var now = Date.now();
+ if (last > 0) {
+ var diff = now - last;
+ mean = 0.99*mean + 0.01*diff;
+ if (counter++ === 60) {
+ counter = 0;
+ dump(text + ' fps: ' + (1000/mean).toFixed(2) + '\n');
+ }
+ }
+ last = now;
+ };
+}
+
+/*
+function GenericTracker(text) {
+ var mean = 0;
+ var counter = 0;
+ this.tick = function(value) {
+ mean = 0.99*mean + 0.01*value;
+ if (counter++ === 60) {
+ counter = 0;
+ dump(text + ': ' + (mean).toFixed(2) + '\n');
+ }
+ };
+}
+*/
// render
@@ -24,13 +56,39 @@ window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequest
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
renderFrame;
+/*
+(function() {
+ var trueRAF = window.requestAnimationFrame;
+ var tracker = new FPSTracker('client');
+ window.requestAnimationFrame = function(func) {
+ trueRAF(function() {
+ tracker.tick();
+ func();
+ });
+ }
+})();
+*/
+
// end render
+// Frame throttling
+
+var frameId = 0;
+
+// Worker
+
var worker = new Worker('{{{ filename }}}.js');
+WebGLClient.prefetch();
+
+setTimeout(function() {
+ worker.postMessage({ target: 'worker-init', width: Module.canvas.width, height: Module.canvas.height, preMain: true });
+}, 0); // delay til next frame, to make sure html is ready
+
var workerResponded = false;
worker.onmessage = function worker_onmessage(event) {
+ //dump('\nclient got ' + JSON.stringify(event.data).substr(0, 150) + '\n');
if (!workerResponded) {
workerResponded = true;
if (Module.setStatus) Module.setStatus('');
@@ -52,10 +110,18 @@ worker.onmessage = function worker_onmessage(event) {
}
case 'canvas': {
switch (data.op) {
+ case 'getContext': {
+ Module.ctx = Module.canvas.getContext(data.type, data.attributes);
+ if (data.type !== '2d') {
+ // possible GL_DEBUG entry point: Module.ctx = wrapDebugGL(Module.ctx);
+ Module.glClient = new WebGLClient();
+ }
+ break;
+ }
case 'resize': {
Module.canvas.width = data.width;
Module.canvas.height = data.height;
- Module.canvasData = Module.ctx.getImageData(0, 0, data.width, data.height);
+ if (Module.ctx && Module.ctx.getImageData) Module.canvasData = Module.ctx.getImageData(0, 0, data.width, data.height);
worker.postMessage({ target: 'canvas', boundingClientRect: cloneObject(Module.canvas.getBoundingClientRect()) });
break;
}
@@ -74,6 +140,34 @@ worker.onmessage = function worker_onmessage(event) {
}
break;
}
+ case 'gl': {
+ Module.glClient.onmessage(data);
+ break;
+ }
+ case 'tick': {
+ frameId = data.id;
+ worker.postMessage({ target: 'tock', id: frameId });
+ break;
+ }
+ case 'Image': {
+ assert(data.method === 'src');
+ var img = new Image();
+ img.onload = function() {
+ assert(img.complete);
+ var canvas = document.createElement('canvas');
+ canvas.width = img.width;
+ canvas.height = img.height;
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0);
+ var imageData = ctx.getImageData(0, 0, img.width, img.height);
+ worker.postMessage({ target: 'Image', method: 'onload', id: data.id, width: img.width, height: img.height, data: imageData.data, preMain: true });
+ };
+ img.onerror = function() {
+ worker.postMessage({ target: 'Image', method: 'onerror', id: data.id, preMain: true });
+ };
+ img.src = data.src;
+ break;
+ }
default: throw 'what?';
}
};
diff --git a/src/proxyWorker.js b/src/proxyWorker.js
index cfe0c26e..7647b5da 100644
--- a/src/proxyWorker.js
+++ b/src/proxyWorker.js
@@ -1,4 +1,73 @@
+if (typeof console === 'undefined') {
+ // we can't call Module.printErr because that might be circular
+ var console = {
+ log: function(x) {
+ if (typeof dump === 'function') dump('log: ' + x + '\n');
+ },
+ debug: function(x) {
+ if (typeof dump === 'function') dump('debug: ' + x + '\n');
+ },
+ info: function(x) {
+ if (typeof dump === 'function') dump('info: ' + x + '\n');
+ },
+ warn: function(x) {
+ if (typeof dump === 'function') dump('warn: ' + x + '\n');
+ },
+ error: function(x) {
+ if (typeof dump === 'function') dump('error: ' + x + '\n');
+ },
+ };
+}
+
+/*
+function proxify(object, nick) {
+ return new Proxy(object, {
+ get: function(target, name) {
+ var ret = target[name];
+ if (ret === undefined) console.log('PROXY ' + [nick, target, name, ret, typeof ret]);
+ return ret;
+ }
+ });
+}
+*/
+
+function FPSTracker(text) {
+ var last = 0;
+ var mean = 0;
+ var counter = 0;
+ this.tick = function() {
+ var now = Date.now();
+ if (last > 0) {
+ var diff = now - last;
+ mean = 0.99*mean + 0.01*diff;
+ if (counter++ === 60) {
+ counter = 0;
+ dump(text + ' fps: ' + (1000/mean).toFixed(2) + '\n');
+ }
+ }
+ last = now;
+ }
+}
+
+function Element() { throw 'TODO: Element' }
+function HTMLCanvasElement() { throw 'TODO: HTMLCanvasElement' }
+function HTMLVideoElement() { throw 'TODO: HTMLVideoElement' }
+
+function PropertyBag() {
+ this.addProperty = function(){};
+ this.removeProperty = function(){};
+};
+
+var IndexedObjects = {
+ nextId: 1,
+ cache: {},
+ add: function(object) {
+ object.id = this.nextId++;
+ this.cache[object.id] = object;
+ }
+};
+
function EventListener() {
this.listeners = {};
@@ -7,6 +76,14 @@ function EventListener() {
this.listeners[event].push(func);
};
+ this.removeEventListener = function(event, func) {
+ var list = this.listeners[event];
+ if (!list) return;
+ var me = list.indexOf(func);
+ if (me < 0) return;
+ list.splice(me, 1);
+ };
+
this.fireEvent = function fireEvent(event) {
event.preventDefault = function(){};
@@ -16,7 +93,27 @@ function EventListener() {
});
}
};
-};
+}
+
+function Image() {
+ IndexedObjects.add(this);
+ EventListener.call(this);
+ var src = '';
+ Object.defineProperty(this, 'src', {
+ set: function(value) {
+ src = value;
+ assert(this.id);
+ postMessage({ target: 'Image', method: 'src', src: src, id: this.id });
+ },
+ get: function() {
+ return src;
+ }
+ });
+}
+Image.prototype.onload = function(){};
+Image.prototype.onerror = function(){};
+
+var HTMLImageElement = Image;
var window = this;
var windowExtra = new EventListener();
@@ -26,6 +123,35 @@ window.close = function window_close() {
postMessage({ target: 'window', method: 'close' });
};
+window.alert = function(text) {
+ Module.printErr('alert forever: ' + text);
+ while (1){};
+};
+
+window.scrollX = window.scrollY = 0; // TODO: proxy these
+
+window.WebGLRenderingContext = WebGLWorker;
+
+window.requestAnimationFrame = (function() {
+ // similar to Browser.requestAnimationFrame
+ var nextRAF = 0;
+ return function(func) {
+ // try to keep 60fps between calls to here
+ var now = Date.now();
+ if (nextRAF === 0) {
+ nextRAF = now + 1000/60;
+ } else {
+ while (now + 2 >= nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0
+ nextRAF += 1000/60;
+ }
+ }
+ var delay = Math.max(nextRAF - now, 0);
+ setTimeout(func, delay);
+ };
+})();
+
+var webGLWorker = new WebGLWorker();
+
var document = new EventListener();
document.createElement = function document_createElement(what) {
@@ -39,28 +165,50 @@ document.createElement = function document_createElement(what) {
height: canvas.height,
data: new Uint8Array(canvas.width*canvas.height*4)
};
- postMessage({ target: 'canvas', op: 'resize', width: canvas.width, height: canvas.height });
+ if (canvas === Module['canvas']) {
+ postMessage({ target: 'canvas', op: 'resize', width: canvas.width, height: canvas.height });
+ }
}
};
- canvas.getContext = function canvas_getContext(type) {
- assert(type == '2d');
- return {
- getImageData: function(x, y, w, h) {
- assert(x == 0 && y == 0 && w == canvas.width && h == canvas.height);
- canvas.ensureData();
- return {
- width: canvas.data.width,
- height: canvas.data.height,
- data: new Uint8Array(canvas.data.data) // TODO: can we avoid this copy?
- };
- },
- putImageData: function(image, x, y) {
- canvas.ensureData();
- assert(x == 0 && y == 0 && image.width == canvas.width && image.height == canvas.height);
- canvas.data.data.set(image.data); // TODO: can we avoid this copy?
- postMessage({ target: 'canvas', op: 'render', image: canvas.data });
- }
- };
+ canvas.getContext = function canvas_getContext(type, attributes) {
+ if (canvas === Module['canvas']) {
+ postMessage({ target: 'canvas', op: 'getContext', type: type, attributes: attributes });
+ }
+ if (type === '2d') {
+ return {
+ getImageData: function(x, y, w, h) {
+ assert(x == 0 && y == 0 && w == canvas.width && h == canvas.height);
+ canvas.ensureData();
+ return {
+ width: canvas.data.width,
+ height: canvas.data.height,
+ data: new Uint8Array(canvas.data.data) // TODO: can we avoid this copy?
+ };
+ },
+ putImageData: function(image, x, y) {
+ canvas.ensureData();
+ assert(x == 0 && y == 0 && image.width == canvas.width && image.height == canvas.height);
+ canvas.data.data.set(image.data); // TODO: can we avoid this copy?
+ if (canvas === Module['canvas']) {
+ postMessage({ target: 'canvas', op: 'render', image: canvas.data });
+ }
+ },
+ drawImage: function(image, x, y, w, h, ox, oy, ow, oh) {
+ assert (!x && !y && !ox && !oy);
+ assert(w === ow && h === oh);
+ assert(canvas.width === w || w === undefined);
+ assert(canvas.height === h || h === undefined);
+ assert(image.width === canvas.width && image.height === canvas.height);
+ canvas.ensureData();
+ canvas.data.data.set(image.data.data); // TODO: can we avoid this copy?
+ if (canvas === Module['canvas']) {
+ postMessage({ target: 'canvas', op: 'render', image: canvas.data });
+ }
+ }
+ };
+ } else {
+ return webGLWorker;
+ }
};
canvas.boundingClientRect = {};
canvas.getBoundingClientRect = function canvas_getBoundingClientRect() {
@@ -73,18 +221,72 @@ document.createElement = function document_createElement(what) {
right: canvas.boundingClientRect.right
};
};
+ canvas.style = new PropertyBag();
+ canvas.exitPointerLock = function(){};
+
+ canvas.width_ = canvas.width_ || 0;
+ canvas.height_ = canvas.height_ || 0;
+ Object.defineProperty(canvas, 'width', {
+ set: function(value) {
+ canvas.width_ = value;
+ if (canvas === Module['canvas']) {
+ postMessage({ target: 'canvas', op: 'resize', width: canvas.width_, height: canvas.height_ });
+ }
+ },
+ get: function() {
+ return canvas.width_;
+ }
+ });
+ Object.defineProperty(canvas, 'height', {
+ set: function(value) {
+ canvas.height_ = value;
+ if (canvas === Module['canvas']) {
+ postMessage({ target: 'canvas', op: 'resize', width: canvas.width_, height: canvas.height_ });
+ }
+ },
+ get: function() {
+ return canvas.height_;
+ }
+ });
+
return canvas;
}
default: throw 'document.createElement ' + what;
}
};
-if (typeof console === 'undefined') {
- var console = {
- log: function(x) {
- Module.printErr(x);
- }
- };
+document.getElementById = function(id) {
+ if (id === 'canvas' || id === 'application-canvas') {
+ return Module.canvas;
+ }
+ throw 'document.getElementById failed on ' + id;
+};
+
+document.documentElement = {};
+
+document.styleSheets = [{
+ cssRules: [], // TODO: forward to client
+ insertRule: function(rule, i) {
+ this.cssRules.splice(i, 0, rule);
+ }
+}];
+
+function Audio() {
+ Runtime.warnOnce('faking Audio elements, no actual sound will play');
+}
+Audio.prototype = new EventListener();
+Object.defineProperty(Audio.prototype, 'src', {
+ set: function(value) {
+ if (value[0] === 'd') return; // ignore data urls
+ this.onerror();
+ },
+});
+
+Audio.prototype.play = function(){};
+Audio.prototype.pause = function(){};
+
+Audio.prototype.cloneNode = function() {
+ return new Audio;
}
Module.canvas = document.createElement('canvas');
@@ -92,12 +294,32 @@ Module.canvas = document.createElement('canvas');
Module.setStatus = function(){};
Module.print = function Module_print(x) {
+ //dump('OUT: ' + x + '\n');
postMessage({ target: 'stdout', content: x });
};
Module.printErr = function Module_printErr(x) {
+ //dump('ERR: ' + x + '\n');
postMessage({ target: 'stderr', content: x });
};
+// Frame throttling
+
+var frameId = 0;
+var clientFrameId = 0;
+
+var postMainLoop = Module['postMainLoop'];
+Module['postMainLoop'] = function() {
+ if (postMainLoop) postMainLoop();
+ // frame complete, send a frame id
+ postMessage({ target: 'tick', id: frameId++ });
+ commandBuffer = [];
+};
+
+// Wait to start running until we receive some info from the client
+
+addRunDependency('gl-prefetch');
+addRunDependency('worker-init');
+
// buffer messages until the program starts to run
var messageBuffer = null;
@@ -115,13 +337,15 @@ function messageResender() {
}
onmessage = function onmessage(message) {
- if (!calledMain) {
+ if (!calledMain && !message.data.preMain) {
if (!messageBuffer) {
messageBuffer = [];
setTimeout(messageResender, 100);
}
messageBuffer.push(message);
+ return;
}
+ //dump('worker got ' + JSON.stringify(message.data) + '\n');
switch (message.data.target) {
case 'document': {
document.fireEvent(message.data.event);
@@ -139,6 +363,39 @@ onmessage = function onmessage(message) {
} else throw 'ey?';
break;
}
+ case 'gl': {
+ webGLWorker.onmessage(message.data);
+ break;
+ }
+ case 'tock': {
+ clientFrameId = message.data.id;
+ break;
+ }
+ case 'Image': {
+ var img = IndexedObjects.cache[message.data.id];
+ switch (message.data.method) {
+ case 'onload': {
+ img.width = message.data.width;
+ img.height = message.data.height;
+ img.data = { width: img.width, height: img.height, data: message.data.data };
+ img.complete = true;
+ img.onload();
+ break;
+ }
+ case 'onerror': {
+ img.onerror({ srcElement: img });
+ break;
+ }
+ }
+ break;
+ }
+ case 'worker-init': {
+ Module.canvas = document.createElement('canvas');
+ Module.canvas.width_ = message.data.width;
+ Module.canvas.height_ = message.data.height;
+ removeRunDependency('worker-init');
+ break;
+ }
default: throw 'wha? ' + message.data.target;
}
};
diff --git a/src/runtime.js b/src/runtime.js
index 4466a308..96b12294 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -418,12 +418,16 @@ var Runtime = {
abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
}
}
+#if NO_DYNAMIC_EXECUTION == 0
try {
var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
} catch(e) {
Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
throw e;
}
+#else
+ abort('NO_DYNAMIC_EXECUTION was set, cannot eval, so EM_ASM is not functional');
+#endif
return Runtime.asmConstCache[code] = evalled;
},
diff --git a/src/settings.js b/src/settings.js
index 3289eace..14077efd 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -323,6 +323,10 @@ var FS_LOG = 0; // Log all FS operations. This is especially helpful when you'r
// so that you can create a virtual file system with all of the required files.
var CASE_INSENSITIVE_FS = 0; // If set to nonzero, the provided virtual filesystem if treated case-insensitive, like
// Windows and OSX do. If set to 0, the VFS is case-sensitive, like on Linux.
+var MEMFS_APPEND_TO_TYPED_ARRAYS = 0; // If set to nonzero, MEMFS will always utilize typed arrays as the backing store
+ // for appending data to files. The default behavior is to use typed arrays for files
+ // when the file size doesn't change after initial creation, and for files that do
+ // change size, use normal JS arrays instead.
var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss
// When enabled, 0-initialized globals are sorted to the end of the globals list,
@@ -418,9 +422,14 @@ var RUNTIME_LINKED_LIBS = []; // If this is a main file (BUILD_AS_SHARED_LIB ==
// linked libraries can break things.
var BUILD_AS_WORKER = 0; // If set to 1, this is a worker library, a special kind of library
// that is run in a worker. See emscripten.h
+
var PROXY_TO_WORKER = 0; // If set to 1, we build the project into a js file that will run
// in a worker, and generate an html file that proxies input and
// output to/from it.
+var PROXY_TO_WORKER_FILENAME = ''; // If set, the script file name the main thread loads.
+ // Useful if your project doesn't run the main emscripten-
+ // generated script immediately but does some setup before
+
var LINKABLE = 0; // If set to 1, this file can be linked with others, either as a shared
// library or as the main file that calls a shared library. To enable that,
// we will not internalize all symbols and cull the unused ones, in other
@@ -474,6 +483,9 @@ var HEADLESS = 0; // If 1, will include shim code that tries to 'fake' a browser
// very partial - it is hard to fake a whole browser! - so
// keep your expectations low for this to work.
+var DETERMINISTIC = 0; // If 1, we force Date.now(), Math.random, etc. to return deterministic
+ // results. Good for comparing builds for debugging purposes (and nothing else)
+
var BENCHMARK = 0; // If 1, will just time how long main() takes to execute, and not
// print out anything at all whatsoever. This is useful for benchmarking.
@@ -502,6 +514,11 @@ var JS_CHUNK_SIZE = 10240; // Used as a maximum size before breaking up expressi
var EXPORT_NAME = 'Module'; // Global variable to export the module as for environments without a standardized module
// loading system (e.g. the browser and SM shell).
+var NO_DYNAMIC_EXECUTION = 0; // When enabled, we do not emit eval() and new Function(), which disables some functionality
+ // (causing runtime errors if attempted to be used), but allows the emitted code to be
+ // acceptable in places that disallow dynamic code execution (chrome packaged app, non-
+ // privileged firefox app, etc.)
+
var RUNNING_JS_OPTS = 0; // whether js opts will be run, after the main compiler
var COMPILER_ASSERTIONS = 0; // costly (slow) compile-time assertions
diff --git a/src/shell.js b/src/shell.js
index e1c0eb54..85b13337 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -70,6 +70,7 @@ if (ENVIRONMENT_IS_NODE) {
globalEval(read(f));
};
+ Module['thisProgram'] = process['argv'][1];
Module['arguments'] = process['argv'].slice(2);
module['exports'] = Module;
@@ -96,7 +97,9 @@ else if (ENVIRONMENT_IS_SHELL) {
this['{{{ EXPORT_NAME }}}'] = Module;
+#if CLOSURE_COMPILER
eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+#endif
}
else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
Module['read'] = function read(url) {
@@ -139,7 +142,11 @@ else {
}
function globalEval(x) {
+#if NO_DYNAMIC_EXECUTION == 0
eval.call(null, x);
+#else
+ throw 'NO_DYNAMIC_EXECUTION was set, cannot eval';
+#endif
}
if (!Module['load'] == 'undefined' && Module['read']) {
Module['load'] = function load(f) {
diff --git a/src/simd.js b/src/simd.js
index 6e3e3675..d5ff8b15 100644
--- a/src/simd.js
+++ b/src/simd.js
@@ -22,6 +22,9 @@
"use strict";
+// SIMD module.
+var SIMD = {};
+
/**
* Construct a new instance of float32x4 number.
* @param {double} value used for x lane.
@@ -30,9 +33,9 @@
* @param {double} value used for w lane.
* @constructor
*/
-function float32x4(x, y, z, w) {
- if (!(this instanceof float32x4)) {
- return new float32x4(x, y, z, w);
+SIMD.float32x4 = function(x, y, z, w) {
+ if (!(this instanceof SIMD.float32x4)) {
+ return new SIMD.float32x4(x, y, z, w);
}
this.storage_ = new Float32Array(4);
this.storage_[0] = x;
@@ -45,8 +48,8 @@ function float32x4(x, y, z, w) {
* Construct a new instance of float32x4 number with 0.0 in all lanes.
* @constructor
*/
-float32x4.zero = function() {
- return float32x4(0.0, 0.0, 0.0, 0.0);
+SIMD.float32x4.zero = function() {
+ return SIMD.float32x4(0.0, 0.0, 0.0, 0.0);
}
/**
@@ -55,38 +58,10 @@ float32x4.zero = function() {
* @param {double} value used for all lanes.
* @constructor
*/
-float32x4.splat = function(s) {
- return float32x4(s, s, s, s);
+SIMD.float32x4.splat = function(s) {
+ return SIMD.float32x4(s, s, s, s);
}
-Object.defineProperty(float32x4.prototype, 'x', {
- get: function() { return this.storage_[0]; }
-});
-
-Object.defineProperty(float32x4.prototype, 'y', {
- get: function() { return this.storage_[1]; }
-});
-
-Object.defineProperty(float32x4.prototype, 'z', {
- get: function() { return this.storage_[2]; }
-});
-
-Object.defineProperty(float32x4.prototype, 'w',
- { get: function() { return this.storage_[3]; }
-});
-
-/**
- * Extract the sign bit from each lane return them in the first 4 bits.
- */
-Object.defineProperty(float32x4.prototype, 'signMask', {
- get: function() {
- var mx = this.x < 0.0 ? 1 : 0;
- var my = this.y < 0.0 ? 1 : 0;
- var mz = this.z < 0.0 ? 1 : 0;
- var mw = this.w < 0.0 ? 1 : 0;
- return mx | my << 1 | mz << 2 | mw << 3;
- }
-});
/**
* Construct a new instance of int32x4 number.
@@ -96,9 +71,9 @@ Object.defineProperty(float32x4.prototype, 'signMask', {
* @param {integer} 32-bit unsigned value used for w lane.
* @constructor
*/
-function int32x4(x, y, z, w) {
- if (!(this instanceof int32x4)) {
- return new int32x4(x, y, z, w);
+SIMD.int32x4 = function(x, y, z, w) {
+ if (!(this instanceof SIMD.int32x4)) {
+ return new SIMD.int32x4(x, y, z, w);
}
this.storage_ = new Int32Array(4);
this.storage_[0] = x;
@@ -108,6 +83,14 @@ function int32x4(x, y, z, w) {
}
/**
+ * Construct a new instance of int32x4 number with 0 in all lanes.
+ * @constructor
+ */
+SIMD.int32x4.zero = function() {
+ return SIMD.int32x4(0, 0, 0, 0);
+}
+
+/**
* Construct a new instance of int32x4 number with 0xFFFFFFFF or 0x0 in each
* lane, depending on the truth value in x, y, z, and w.
* @param {boolean} flag used for x lane.
@@ -116,11 +99,11 @@ function int32x4(x, y, z, w) {
* @param {boolean} flag used for w lane.
* @constructor
*/
-int32x4.bool = function(x, y, z, w) {
- return int32x4(x ? -1 : 0x0,
- y ? -1 : 0x0,
- z ? -1 : 0x0,
- w ? -1 : 0x0);
+SIMD.int32x4.bool = function(x, y, z, w) {
+ return SIMD.int32x4(x ? -1 : 0x0,
+ y ? -1 : 0x0,
+ z ? -1 : 0x0,
+ w ? -1 : 0x0);
}
/**
@@ -129,746 +112,637 @@ int32x4.bool = function(x, y, z, w) {
* @param {integer} value used for all lanes.
* @constructor
*/
-int32x4.splat = function(s) {
- return int32x4(s, s, s, s);
+SIMD.int32x4.splat = function(s) {
+ return SIMD.int32x4(s, s, s, s);
}
-Object.defineProperty(int32x4.prototype, 'x', {
- get: function() { return this.storage_[0]; }
-});
+/**
+* @return {float32x4} New instance of float32x4 with absolute values of
+* t.
+*/
+SIMD.float32x4.abs = function(t) {
+ return SIMD.float32x4(Math.abs(t.x), Math.abs(t.y), Math.abs(t.z),
+ Math.abs(t.w));
+}
-Object.defineProperty(int32x4.prototype, 'y', {
- get: function() { return this.storage_[1]; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with negated values of
+ * t.
+ */
+SIMD.float32x4.neg = function(t) {
+ return SIMD.float32x4(-t.x, -t.y, -t.z, -t.w);
+}
-Object.defineProperty(int32x4.prototype, 'z', {
- get: function() { return this.storage_[2]; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with a + b.
+ */
+SIMD.float32x4.add = function(a, b) {
+ return SIMD.float32x4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+}
-Object.defineProperty(int32x4.prototype, 'w',
- { get: function() { return this.storage_[3]; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with a - b.
+ */
+SIMD.float32x4.sub = function(a, b) {
+ return SIMD.float32x4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+}
-Object.defineProperty(int32x4.prototype, 'flagX', {
- get: function() { return this.storage_[0] != 0x0; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with a * b.
+ */
+SIMD.float32x4.mul = function(a, b) {
+ return SIMD.float32x4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
+}
-Object.defineProperty(int32x4.prototype, 'flagY', {
- get: function() { return this.storage_[1] != 0x0; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with a / b.
+ */
+SIMD.float32x4.div = function(a, b) {
+ return SIMD.float32x4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
+}
-Object.defineProperty(int32x4.prototype, 'flagZ', {
- get: function() { return this.storage_[2] != 0x0; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with t's values clamped
+ * between lowerLimit and upperLimit.
+ */
+SIMD.float32x4.clamp = function(t, lowerLimit, upperLimit) {
+ var cx = t.x < lowerLimit.x ? lowerLimit.x : t.x;
+ var cy = t.y < lowerLimit.y ? lowerLimit.y : t.y;
+ var cz = t.z < lowerLimit.z ? lowerLimit.z : t.z;
+ var cw = t.w < lowerLimit.w ? lowerLimit.w : t.w;
+ cx = cx > upperLimit.x ? upperLimit.x : cx;
+ cy = cy > upperLimit.y ? upperLimit.y : cy;
+ cz = cz > upperLimit.z ? upperLimit.z : cz;
+ cw = cw > upperLimit.w ? upperLimit.w : cw;
+ return SIMD.float32x4(cx, cy, cz, cw);
+}
-Object.defineProperty(int32x4.prototype, 'flagW',
- { get: function() { return this.storage_[3] != 0x0; }
-});
+/**
+ * @return {float32x4} New instance of float32x4 with the minimum value of
+ * t and other.
+ */
+SIMD.float32x4.min = function(t, other) {
+ var cx = t.x > other.x ? other.x : t.x;
+ var cy = t.y > other.y ? other.y : t.y;
+ var cz = t.z > other.z ? other.z : t.z;
+ var cw = t.w > other.w ? other.w : t.w;
+ return SIMD.float32x4(cx, cy, cz, cw);
+}
/**
- * Extract the sign bit from each lane return them in the first 4 bits.
+ * @return {float32x4} New instance of float32x4 with the maximum value of
+ * t and other.
*/
-Object.defineProperty(int32x4.prototype, 'signMask', {
- get: function() {
- var mx = (this.storage_[0] & 0x80000000) >>> 31;
- var my = (this.storage_[1] & 0x80000000) >>> 31;
- var mz = (this.storage_[2] & 0x80000000) >>> 31;
- var mw = (this.storage_[3] & 0x80000000) >>> 31;
- return mx | my << 1 | mz << 2 | mw << 3;
- }
-});
+SIMD.float32x4.max = function(t, other) {
+ var cx = t.x < other.x ? other.x : t.x;
+ var cy = t.y < other.y ? other.y : t.y;
+ var cz = t.z < other.z ? other.z : t.z;
+ var cw = t.w < other.w ? other.w : t.w;
+ return SIMD.float32x4(cx, cy, cz, cw);
+}
-function isNumber(o) {
- return typeof o == "number" || (typeof o == "object" && o.constructor === Number);
+/**
+ * @return {float32x4} New instance of float32x4 with reciprocal value of
+ * t.
+ */
+SIMD.float32x4.reciprocal = function(t) {
+ return SIMD.float32x4(1.0 / t.x, 1.0 / t.y, 1.0 / t.z, 1.0 / t.w);
}
-function isTypedArray(o) {
- return (o instanceof Int8Array) ||
- (o instanceof Uint8Array) ||
- (o instanceof Uint8ClampedArray) ||
- (o instanceof Int16Array) ||
- (o instanceof Uint16Array) ||
- (o instanceof Int32Array) ||
- (o instanceof Uint32Array) ||
- (o instanceof Float32Array) ||
- (o instanceof Float64Array) ||
- (o instanceof Float32x4Array);
+/**
+ * @return {float32x4} New instance of float32x4 with square root of the
+ * reciprocal value of t.
+ */
+SIMD.float32x4.reciprocalSqrt = function(t) {
+ return SIMD.float32x4(Math.sqrt(1.0 / t.x), Math.sqrt(1.0 / t.y),
+ Math.sqrt(1.0 / t.z), Math.sqrt(1.0 / t.w));
+}
+/**
+ * @return {float32x4} New instance of float32x4 with values of t
+ * scaled by s.
+ */
+SIMD.float32x4.scale = function(t, s) {
+ return SIMD.float32x4(s * t.x, s * t.y, s * t.z, s * t.w);
}
-function isArrayBuffer(o) {
- return (o instanceof ArrayBuffer);
+/**
+ * @return {float32x4} New instance of float32x4 with square root of
+ * values of t.
+ */
+SIMD.float32x4.sqrt = function(t) {
+ return SIMD.float32x4(Math.sqrt(t.x), Math.sqrt(t.y),
+ Math.sqrt(t.z), Math.sqrt(t.w));
}
-function Float32x4Array(a, b, c) {
- if (isNumber(a)) {
- this.storage_ = new Float32Array(a*4);
- this.length_ = a;
- this.byteOffset_ = 0;
- return;
- } else if (isTypedArray(a)) {
- if (!(a instanceof Float32x4Array)) {
- throw "Copying typed array of non-Float32x4Array is unimplemented.";
- }
- this.storage_ = new Float32Array(a.length * 4);
- this.length_ = a.length;
- this.byteOffset_ = 0;
- // Copy floats.
- for (var i = 0; i < a.length*4; i++) {
- this.storage_[i] = a.storage_[i];
- }
- } else if (isArrayBuffer(a)) {
- if ((b != undefined) && (b % Float32x4Array.BYTES_PER_ELEMENT) != 0) {
- throw "byteOffset must be a multiple of 16.";
- }
- if (c != undefined) {
- c *= 4;
- this.storage_ = new Float32Array(a, b, c);
- }
- else {
- // Note: new Float32Array(a, b) is NOT equivalent to new Float32Array(a, b, undefined)
- this.storage_ = new Float32Array(a, b);
- }
- this.length_ = this.storage_.length / 4;
- this.byteOffset_ = b != undefined ? b : 0;
- } else {
- throw "Unknown type of first argument.";
- }
+/**
+ * @param {float32x4} t An instance of float32x4 to be shuffled.
+ * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
+ * @return {float32x4} New instance of float32x4 with lanes shuffled.
+ */
+SIMD.float32x4.shuffle = function(t, mask) {
+ var _x = (mask) & 0x3;
+ var _y = (mask >> 2) & 0x3;
+ var _z = (mask >> 4) & 0x3;
+ var _w = (mask >> 6) & 0x3;
+ return SIMD.float32x4(t.storage_[_x], t.storage_[_y], t.storage_[_z],
+ t.storage_[_w]);
}
-Object.defineProperty(Float32x4Array.prototype, 'length',
- { get: function() { return this.length_; }
-});
+/**
+ * @param {float32x4} t1 An instance of float32x4 to be shuffled. XY lanes in result
+ * @param {float32x4} t2 An instance of float32x4 to be shuffled. ZW lanes in result
+ * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
+ * @return {float32x4} New instance of float32x4 with lanes shuffled.
+ */
+SIMD.float32x4.shuffleMix = function(t1, t2, mask) {
+ var _x = (mask) & 0x3;
+ var _y = (mask >> 2) & 0x3;
+ var _z = (mask >> 4) & 0x3;
+ var _w = (mask >> 6) & 0x3;
+ return SIMD.float32x4(t1.storage_[_x], t1.storage_[_y], t2.storage_[_z],
+ t2.storage_[_w]);
+}
-Object.defineProperty(Float32x4Array.prototype, 'byteLength',
- { get: function() { return this.length_ * Float32x4Array.BYTES_PER_ELEMENT; }
-});
+/**
+ * @param {double} value used for x lane.
+ * @return {float32x4} New instance of float32x4 with the values in t and
+ * x replaced with {x}.
+ */
+SIMD.float32x4.withX = function(t, x) {
+ return SIMD.float32x4(x, t.y, t.z, t.w);
+}
-Object.defineProperty(Float32x4Array, 'BYTES_PER_ELEMENT',
- { get: function() { return 16; }
-});
+/**
+ * @param {double} value used for y lane.
+ * @return {float32x4} New instance of float32x4 with the values in t and
+ * y replaced with {y}.
+ */
+SIMD.float32x4.withY = function(t, y) {
+ return SIMD.float32x4(t.x, y, t.z, t.w);
+}
-Object.defineProperty(Float32x4Array.prototype, 'BYTES_PER_ELEMENT',
- { get: function() { return 16; }
-});
+/**
+ * @param {double} value used for z lane.
+ * @return {float32x4} New instance of float32x4 with the values in t and
+ * z replaced with {z}.
+ */
+SIMD.float32x4.withZ = function(t, z) {
+ return SIMD.float32x4(t.x, t.y, z, t.w);
+}
-Object.defineProperty(Float32x4Array.prototype, 'byteOffset',
- { get: function() { return this.byteOffset_; }
-});
+/**
+ * @param {double} value used for w lane.
+ * @return {float32x4} New instance of float32x4 with the values in t and
+ * w replaced with {w}.
+ */
+SIMD.float32x4.withW = function(t, w) {
+ return SIMD.float32x4(t.x, t.y, t.z, w);
+}
-Object.defineProperty(Float32x4Array.prototype, 'buffer',
- { get: function() { return this.storage_.buffer; }
-});
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @param {float32x4} other An instance of float32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t < other.
+ */
+SIMD.float32x4.lessThan = function(t, other) {
+ var cx = t.x < other.x;
+ var cy = t.y < other.y;
+ var cz = t.z < other.z;
+ var cw = t.w < other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
-Float32x4Array.prototype.getAt = function(i) {
- if (i < 0) {
- throw "Index must be >= 0.";
- }
- if (i >= this.length) {
- throw "Index out of bounds.";
- }
- var x = this.storage_[i*4+0];
- var y = this.storage_[i*4+1];
- var z = this.storage_[i*4+2];
- var w = this.storage_[i*4+3];
- return float32x4(x, y, z, w);
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @param {float32x4} other An instance of float32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t <= other.
+ */
+SIMD.float32x4.lessThanOrEqual = function(t, other) {
+ var cx = t.x <= other.x;
+ var cy = t.y <= other.y;
+ var cz = t.z <= other.z;
+ var cw = t.w <= other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
}
-Float32x4Array.prototype.setAt = function(i, v) {
- if (i < 0) {
- throw "Index must be >= 0.";
- }
- if (i >= this.length) {
- throw "Index out of bounds.";
- }
- if (!(v instanceof float32x4)) {
- throw "Value is not a float32x4.";
- }
- this.storage_[i*4+0] = v.x;
- this.storage_[i*4+1] = v.y;
- this.storage_[i*4+2] = v.z;
- this.storage_[i*4+3] = v.w;
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @param {float32x4} other An instance of float32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t == other.
+ */
+SIMD.float32x4.equal = function(t, other) {
+ var cx = t.x == other.x;
+ var cy = t.y == other.y;
+ var cz = t.z == other.z;
+ var cw = t.w == other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
}
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @param {float32x4} other An instance of float32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t != other.
+ */
+SIMD.float32x4.notEqual = function(t, other) {
+ var cx = t.x != other.x;
+ var cy = t.y != other.y;
+ var cz = t.z != other.z;
+ var cw = t.w != other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
-function Int32x4Array(a, b, c) {
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @param {float32x4} other An instance of float32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t >= other.
+ */
+SIMD.float32x4.greaterThanOrEqual = function(t, other) {
+ var cx = t.x >= other.x;
+ var cy = t.y >= other.y;
+ var cz = t.z >= other.z;
+ var cw = t.w >= other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
- function isNumber(o) {
- return typeof o == "number" || (typeof o == "object" && o.constructor === Number);
- }
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @param {float32x4} other An instance of float32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t > other.
+ */
+SIMD.float32x4.greaterThan = function(t, other) {
+ var cx = t.x > other.x;
+ var cy = t.y > other.y;
+ var cz = t.z > other.z;
+ var cw = t.w > other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
- function isTypedArray(o) {
- return (o instanceof Int8Array) ||
- (o instanceof Uint8Array) ||
- (o instanceof Uint8ClampedArray) ||
- (o instanceof Int16Array) ||
- (o instanceof Uint16Array) ||
- (o instanceof Int32Array) ||
- (o instanceof Uint32Array) ||
- (o instanceof Float32Array) ||
- (o instanceof Float64Array) ||
- (o instanceof Int32x4Array) ||
- (o instanceof Float32x4Array);
- }
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @return {int32x4} a bit-wise copy of t as a int32x4.
+ */
+SIMD.float32x4.bitsToInt32x4 = function(t) {
+ var alias = new Int32Array(t.storage_.buffer);
+ return SIMD.int32x4(alias[0], alias[1], alias[2], alias[3]);
+}
- function isArrayBuffer(o) {
- return (o instanceof ArrayBuffer);
- }
+/**
+ * @param {float32x4} t An instance of float32x4.
+ * @return {int32x4} with a integer to float conversion of t.
+ */
+SIMD.float32x4.toInt32x4 = function(t) {
+ var a = SIMD.int32x4(t.storage_[0], t.storage_[1], t.storage_[2],
+ t.storage_[3]);
+ return a;
+}
- if (isNumber(a)) {
- this.storage_ = new Int32Array(a*4);
- this.length_ = a;
- this.byteOffset_ = 0;
- return;
- } else if (isTypedArray(a)) {
- if (!(a instanceof Int32x4Array)) {
- throw "Copying typed array of non-Int32x4Array is unimplemented.";
- }
- this.storage_ = new Int32Array(a.length * 4);
- this.length_ = a.length;
- this.byteOffset_ = 0;
- // Copy floats.
- for (var i = 0; i < a.length*4; i++) {
- this.storage_[i] = a.storage_[i];
- }
- } else if (isArrayBuffer(a)) {
- if ((b != undefined) && (b % Int32x4Array.BYTES_PER_ELEMENT) != 0) {
- throw "byteOffset must be a multiple of 16.";
- }
- if (c != undefined) {
- c *= 4;
- this.storage_ = new Int32Array(a, b, c);
- }
- else {
- // Note: new Int32Array(a, b) is NOT equivalent to new Float32Array(a, b, undefined)
- this.storage_ = new Int32Array(a, b);
- }
- this.length_ = this.storage_.length / 4;
- this.byteOffset_ = b != undefined ? b : 0;
- } else {
- throw "Unknown type of first argument.";
- }
+/**
+ * @param {float32x4} a An instance of float32x4.
+ * @param {float32x4} b An instance of float32x4.
+ * @return {float32x4} New instance of float32x4 with values of a & b.
+ */
+SIMD.float32x4.and = function(a, b) {
+ var aInt = SIMD.float32x4.bitsToInt32x4(a);
+ var bInt = SIMD.float32x4.bitsToInt32x4(b);
+ return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.and(aInt, bInt));
}
-Object.defineProperty(Int32x4Array.prototype, 'length',
- { get: function() { return this.length_; }
-});
+/**
+ * @param {float32x4} a An instance of float32x4.
+ * @param {float32x4} b An instance of float32x4.
+ * @return {float32x4} New instance of float32x4 with values of a | b.
+ */
+SIMD.float32x4.or = function(a, b) {
+ var aInt = SIMD.float32x4.bitsToInt32x4(a);
+ var bInt = SIMD.float32x4.bitsToInt32x4(b);
+ return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(aInt, bInt));
+}
-Object.defineProperty(Int32x4Array.prototype, 'byteLength',
- { get: function() { return this.length_ * Int32x4Array.BYTES_PER_ELEMENT; }
-});
+/**
+ * @param {float32x4} a An instance of float32x4.
+ * @param {float32x4} b An instance of float32x4.
+ * @return {float32x4} New instance of float32x4 with values of a ^ b.
+ */
+SIMD.float32x4.xor = function(a, b) {
+ var aInt = SIMD.float32x4.bitsToInt32x4(a);
+ var bInt = SIMD.float32x4.bitsToInt32x4(b);
+ return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.xor(aInt, bInt));
+}
-Object.defineProperty(Int32x4Array, 'BYTES_PER_ELEMENT',
- { get: function() { return 16; }
-});
+/**
+ * @param {float32x4} a An instance of float32x4.
+ * @return {float32x4} New instance of float32x4 with values of ~a.
+ */
+SIMD.float32x4.not = function(a) {
+ var aInt = SIMD.float32x4.bitsToInt32x4(a);
+ return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.not(aInt));
+}
-Object.defineProperty(Int32x4Array.prototype, 'BYTES_PER_ELEMENT',
- { get: function() { return 16; }
-});
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int32x4} b An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of a & b.
+ */
+SIMD.int32x4.and = function(a, b) {
+ return SIMD.int32x4(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
+}
-Object.defineProperty(Int32x4Array.prototype, 'byteOffset',
- { get: function() { return this.byteOffset_; }
-});
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int32x4} b An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of a | b.
+ */
+SIMD.int32x4.or = function(a, b) {
+ return SIMD.int32x4(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
+}
-Object.defineProperty(Int32x4Array.prototype, 'buffer',
- { get: function() { return this.storage_.buffer; }
-});
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int32x4} b An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of a ^ b.
+ */
+SIMD.int32x4.xor = function(a, b) {
+ return SIMD.int32x4(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
+}
-Int32x4Array.prototype.getAt = function(i) {
- if (i < 0) {
- throw "Index must be >= 0.";
- }
- if (i >= this.length) {
- throw "Index out of bounds.";
- }
- var x = this.storage_[i*4+0];
- var y = this.storage_[i*4+1];
- var z = this.storage_[i*4+2];
- var w = this.storage_[i*4+3];
- return float32x4(x, y, z, w);
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of ~t
+ */
+SIMD.int32x4.not = function(t) {
+ return SIMD.int32x4(~t.x, ~t.y, ~t.z, ~t.w);
}
-Int32x4Array.prototype.setAt = function(i, v) {
- if (i < 0) {
- throw "Index must be >= 0.";
- }
- if (i >= this.length) {
- throw "Index out of bounds.";
- }
- if (!(v instanceof int32x4)) {
- throw "Value is not a int32x4.";
- }
- this.storage_[i*4+0] = v.x;
- this.storage_[i*4+1] = v.y;
- this.storage_[i*4+2] = v.z;
- this.storage_[i*4+3] = v.w;
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of -t
+ */
+SIMD.int32x4.neg = function(t) {
+ return SIMD.int32x4(-t.x, -t.y, -t.z, -t.w);
}
-var SIMD = (function () {
- return {
- float32x4: {
- /**
- * @return {float32x4} New instance of float32x4 with absolute values of
- * t.
- */
- abs: function(t) {
- return new float32x4(Math.abs(t.x), Math.abs(t.y), Math.abs(t.z),
- Math.abs(t.w));
- },
- /**
- * @return {float32x4} New instance of float32x4 with negated values of
- * t.
- */
- neg: function(t) {
- return new float32x4(-t.x, -t.y, -t.z, -t.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with a + b.
- */
- add: function(a, b) {
- return new float32x4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with a - b.
- */
- sub: function(a, b) {
- return new float32x4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with a * b.
- */
- mul: function(a, b) {
- return new float32x4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with a / b.
- */
- div: function(a, b) {
- return new float32x4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with t's values clamped
- * between lowerLimit and upperLimit.
- */
- clamp: function(t, lowerLimit, upperLimit) {
- var cx = t.x < lowerLimit.x ? lowerLimit.x : t.x;
- var cy = t.y < lowerLimit.y ? lowerLimit.y : t.y;
- var cz = t.z < lowerLimit.z ? lowerLimit.z : t.z;
- var cw = t.w < lowerLimit.w ? lowerLimit.w : t.w;
- cx = cx > upperLimit.x ? upperLimit.x : cx;
- cy = cy > upperLimit.y ? upperLimit.y : cy;
- cz = cz > upperLimit.z ? upperLimit.z : cz;
- cw = cw > upperLimit.w ? upperLimit.w : cw;
- return new float32x4(cx, cy, cz, cw);
- },
- /**
- * @return {float32x4} New instance of float32x4 with the minimum value of
- * t and other.
- */
- min: function(t, other) {
- var cx = t.x > other.x ? other.x : t.x;
- var cy = t.y > other.y ? other.y : t.y;
- var cz = t.z > other.z ? other.z : t.z;
- var cw = t.w > other.w ? other.w : t.w;
- return new float32x4(cx, cy, cz, cw);
- },
- /**
- * @return {float32x4} New instance of float32x4 with the maximum value of
- * t and other.
- */
- max: function(t, other) {
- var cx = t.x < other.x ? other.x : t.x;
- var cy = t.y < other.y ? other.y : t.y;
- var cz = t.z < other.z ? other.z : t.z;
- var cw = t.w < other.w ? other.w : t.w;
- return new float32x4(cx, cy, cz, cw);
- },
- /**
- * @return {float32x4} New instance of float32x4 with reciprocal value of
- * t.
- */
- reciprocal: function(t) {
- return new float32x4(1.0 / t.x, 1.0 / t.y, 1.0 / t.z, 1.0 / t.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with square root of the
- * reciprocal value of t.
- */
- reciprocalSqrt: function(t) {
- return new float32x4(Math.sqrt(1.0 / t.x), Math.sqrt(1.0 / t.y),
- Math.sqrt(1.0 / t.z), Math.sqrt(1.0 / t.w));
- },
- /**
- * @return {float32x4} New instance of float32x4 with values of t
- * scaled by s.
- */
- scale: function(t, s) {
- return new float32x4(s * t.x, s * t.y, s * t.z, s * t.w);
- },
- /**
- * @return {float32x4} New instance of float32x4 with square root of
- * values of t.
- */
- sqrt: function(t) {
- return new float32x4(Math.sqrt(t.x), Math.sqrt(t.y),
- Math.sqrt(t.z), Math.sqrt(t.w));
- },
- /**
- * @param {float32x4} t An instance of float32x4 to be shuffled.
- * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
- * @return {float32x4} New instance of float32x4 with lanes shuffled.
- */
- shuffle: function(t, mask) {
- var _x = (mask) & 0x3;
- var _y = (mask >> 2) & 0x3;
- var _z = (mask >> 4) & 0x3;
- var _w = (mask >> 6) & 0x3;
- return new float32x4(t.storage_[_x], t.storage_[_y], t.storage_[_z],
- t.storage_[_w]);
- },
- /**
- * @param {float32x4} t1 An instance of float32x4 to be shuffled. XY lanes in result
- * @param {float32x4} t2 An instance of float32x4 to be shuffled. ZW lanes in result
- * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
- * @return {float32x4} New instance of float32x4 with lanes shuffled.
- */
- shuffleMix: function(t1, t2, mask) {
- var _x = (mask) & 0x3;
- var _y = (mask >> 2) & 0x3;
- var _z = (mask >> 4) & 0x3;
- var _w = (mask >> 6) & 0x3;
- return new float32x4(t1.storage_[_x], t1.storage_[_y], t2.storage_[_z],
- t2.storage_[_w]);
- },
- /**
- * @param {double} value used for x lane.
- * @return {float32x4} New instance of float32x4 with the values in t and
- * x replaced with {x}.
- */
- withX: function(t, x) {
- return new float32x4(x, t.y, t.z, t.w);
- },
- /**
- * @param {double} value used for y lane.
- * @return {float32x4} New instance of float32x4 with the values in t and
- * y replaced with {y}.
- */
- withY: function(t, y) {
- return new float32x4(t.x, y, t.z, t.w);
- },
- /**
- * @param {double} value used for z lane.
- * @return {float32x4} New instance of float32x4 with the values in t and
- * z replaced with {z}.
- */
- withZ: function(t, z) {
- return new float32x4(t.x, t.y, z, t.w);
- },
- /**
- * @param {double} value used for w lane.
- * @return {float32x4} New instance of float32x4 with the values in t and
- * w replaced with {w}.
- */
- withW: function(t, w) {
- return new float32x4(t.x, t.y, t.z, w);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @param {float32x4} other An instance of float32x4.
- * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
- * the result of t < other.
- */
- lessThan: function(t, other) {
- var cx = t.x < other.x;
- var cy = t.y < other.y;
- var cz = t.z < other.z;
- var cw = t.w < other.w;
- return int32x4.bool(cx, cy, cz, cw);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @param {float32x4} other An instance of float32x4.
- * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
- * the result of t <= other.
- */
- lessThanOrEqual: function(t, other) {
- var cx = t.x <= other.x;
- var cy = t.y <= other.y;
- var cz = t.z <= other.z;
- var cw = t.w <= other.w;
- return int32x4.bool(cx, cy, cz, cw);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @param {float32x4} other An instance of float32x4.
- * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
- * the result of t == other.
- */
- equal: function(t, other) {
- var cx = t.x == other.x;
- var cy = t.y == other.y;
- var cz = t.z == other.z;
- var cw = t.w == other.w;
- return int32x4.bool(cx, cy, cz, cw);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @param {float32x4} other An instance of float32x4.
- * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
- * the result of t != other.
- */
- notEqual: function(t, other) {
- var cx = t.x != other.x;
- var cy = t.y != other.y;
- var cz = t.z != other.z;
- var cw = t.w != other.w;
- return int32x4.bool(cx, cy, cz, cw);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @param {float32x4} other An instance of float32x4.
- * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
- * the result of t >= other.
- */
- greaterThanOrEqual: function(t, other) {
- var cx = t.x >= other.x;
- var cy = t.y >= other.y;
- var cz = t.z >= other.z;
- var cw = t.w >= other.w;
- return int32x4.bool(cx, cy, cz, cw);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @param {float32x4} other An instance of float32x4.
- * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
- * the result of t > other.
- */
- greaterThan: function(t, other) {
- var cx = t.x > other.x;
- var cy = t.y > other.y;
- var cz = t.z > other.z;
- var cw = t.w > other.w;
- return int32x4.bool(cx, cy, cz, cw);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @return {int32x4} a bit-wise copy of t as a int32x4.
- */
- bitsToInt32x4: function(t) {
- var alias = new Int32Array(t.storage_.buffer);
- return new int32x4(alias[0], alias[1], alias[2], alias[3]);
- },
- /**
- * @param {float32x4} t An instance of float32x4.
- * @return {int32x4} with a integer to float conversion of t.
- */
- toInt32x4: function(t) {
- var a = new int32x4(t.storage_[0], t.storage_[1], t.storage_[2],
- t.storage_[3]);
- return a;
- }
- },
- int32x4: {
- /**
- * @param {int32x4} a An instance of int32x4.
- * @param {int32x4} b An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of a & b.
- */
- and: function(a, b) {
- return new int32x4(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
- },
- /**
- * @param {int32x4} a An instance of int32x4.
- * @param {int32x4} b An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of a | b.
- */
- or: function(a, b) {
- return new int32x4(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
- },
- /**
- * @param {int32x4} a An instance of int32x4.
- * @param {int32x4} b An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of a ^ b.
- */
- xor: function(a, b) {
- return new int32x4(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of ~t
- */
- not: function(t) {
- return new int32x4(~t.x, ~t.y, ~t.z, ~t.w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of -t
- */
- neg: function(t) {
- return new int32x4(-t.x, -t.y, -t.z, -t.w);
- },
- /**
- * @param {int32x4} a An instance of int32x4.
- * @param {int32x4} b An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of a + b.
- */
- add: function(a, b) {
- return new int32x4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
- },
- /**
- * @param {int32x4} a An instance of int32x4.
- * @param {int32x4} b An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of a - b.
- */
- sub: function(a, b) {
- return new int32x4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
- },
- /**
- * @param {int32x4} a An instance of int32x4.
- * @param {int32x4} b An instance of int32x4.
- * @return {int32x4} New instance of int32x4 with values of a * b.
- */
- mul: function(a, b) {
- return new int32x4(Math.imul(a.x, b.x), Math.imul(a.y, b.y),
- Math.imul(a.z, b.z), Math.imul(a.w, b.w));
- },
- /**
- * @param {int32x4} t An instance of float32x4 to be shuffled.
- * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
- * @return {int32x4} New instance of float32x4 with lanes shuffled.
- */
- shuffle: function(t, mask) {
- var _x = (mask) & 0x3;
- var _y = (mask >> 2) & 0x3;
- var _z = (mask >> 4) & 0x3;
- var _w = (mask >> 6) & 0x3;
- return new int32x4(t.storage_[_x], t.storage_[_y], t.storage_[_z],
- t.storage_[_w]);
- },
- /**
- * @param {int32x4} t1 An instance of float32x4 to be shuffled. XY lanes in result
- * @param {int32x4} t2 An instance of float32x4 to be shuffled. ZW lanes in result
- * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
- * @return {int32x4} New instance of float32x4 with lanes shuffled.
- */
- shuffleMix: function(t1, t2, mask) {
- var _x = (mask) & 0x3;
- var _y = (mask >> 2) & 0x3;
- var _z = (mask >> 4) & 0x3;
- var _w = (mask >> 6) & 0x3;
- return new int32x4(t1.storage_[_x], t1.storage_[_y], t2.storage_[_z],
- t2.storage_[_w]);
- },
- /**
- * @param {float32x4}
- */
- select: function(t, trueValue, falseValue) {
- var tv = SIMD.float32x4.bitsToInt32x4(trueValue);
- var fv = SIMD.float32x4.bitsToInt32x4(falseValue);
- var tr = SIMD.int32x4.and(t, tv);
- var fr = SIMD.int32x4.and(SIMD.int32x4.not(t), fv);
- return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(tr, fr));
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @param {integer} 32-bit value used for x lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * x lane replaced with {x}.
- */
- withX: function(t, x) {
- return new int32x4(x, t.y, t.z, t.w);
- },
- /**
- * param {int32x4} t An instance of int32x4.
- * @param {integer} 32-bit value used for y lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * y lane replaced with {y}.
- */
- withY: function(t, y) {
- return new int32x4(t.x, y, t.z, t.w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @param {integer} 32-bit value used for z lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * z lane replaced with {z}.
- */
- withZ: function(t, z) {
- return new int32x4(t.x, t.y, z, t.w);
- },
- /**
- * @param {integer} 32-bit value used for w lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * w lane replaced with {w}.
- */
- withW: function(t, w) {
- return new int32x4(t.x, t.y, t.z, w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @param {boolean} x flag used for x lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * x lane replaced with {x}.
- */
- withFlagX: function(t, flagX) {
- var x = flagX ? 0xFFFFFFFF : 0x0;
- return new int32x4(x, t.y, t.z, t.w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @param {boolean} y flag used for y lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * y lane replaced with {y}.
- */
- withFlagY: function(t, flagY) {
- var y = flagY ? 0xFFFFFFFF : 0x0;
- return new int32x4(t.x, y, t.z, t.w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @param {boolean} z flag used for z lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * z lane replaced with {z}.
- */
- withFlagZ: function(t, flagZ) {
- var z = flagZ ? 0xFFFFFFFF : 0x0;
- return new int32x4(t.x, t.y, z, t.w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @param {boolean} w flag used for w lane.
- * @return {int32x4} New instance of int32x4 with the values in t and
- * w lane replaced with {w}.
- */
- withFlagW: function(t, flagW) {
- var w = flagW ? 0xFFFFFFFF : 0x0;
- return new int32x4(t.x, t.y, t.z, w);
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @return {float32x4} a bit-wise copy of t as a float32x4.
- */
- bitsToFloat32x4: function(t) {
- var temp_storage = new Int32Array([t.storage_[0], t.storage_[1], t.storage_[2], t.storage_[3]]);
- var alias = new Float32Array(temp_storage.buffer);
- var fx4 = float32x4.zero();
- fx4.storage_ = alias;
- return fx4;
- },
- /**
- * @param {int32x4} t An instance of int32x4.
- * @return {float32x4} with a float to integer conversion copy of t.
- */
- toFloat32x4: function(t) {
- var a = float32x4.zero();
- a.storage_[0] = t.storage_[0];
- a.storage_[1] = t.storage_[1];
- a.storage_[2] = t.storage_[2];
- a.storage_[3] = t.storage_[3];
- return a;
- }
- }
- }
-})();
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int32x4} b An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of a + b.
+ */
+SIMD.int32x4.add = function(a, b) {
+ return SIMD.int32x4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+}
+
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int32x4} b An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of a - b.
+ */
+SIMD.int32x4.sub = function(a, b) {
+ return SIMD.int32x4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+}
+
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int32x4} b An instance of int32x4.
+ * @return {int32x4} New instance of int32x4 with values of a * b.
+ */
+SIMD.int32x4.mul = function(a, b) {
+ return SIMD.int32x4(Math.imul(a.x, b.x), Math.imul(a.y, b.y),
+ Math.imul(a.z, b.z), Math.imul(a.w, b.w));
+}
+
+/**
+ * @param {int32x4} t An instance of float32x4 to be shuffled.
+ * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
+ * @return {int32x4} New instance of float32x4 with lanes shuffled.
+ */
+SIMD.int32x4.shuffle = function(t, mask) {
+ var _x = (mask) & 0x3;
+ var _y = (mask >> 2) & 0x3;
+ var _z = (mask >> 4) & 0x3;
+ var _w = (mask >> 6) & 0x3;
+ return SIMD.int32x4(t.storage_[_x], t.storage_[_y], t.storage_[_z],
+ t.storage_[_w]);
+}
+
+/**
+ * @param {int32x4} t1 An instance of float32x4 to be shuffled. XY lanes in result
+ * @param {int32x4} t2 An instance of float32x4 to be shuffled. ZW lanes in result
+ * @param {integer} mask One of the 256 shuffle masks, for example, SIMD.XXXX.
+ * @return {int32x4} New instance of float32x4 with lanes shuffled.
+ */
+SIMD.int32x4.shuffleMix = function(t1, t2, mask) {
+ var _x = (mask) & 0x3;
+ var _y = (mask >> 2) & 0x3;
+ var _z = (mask >> 4) & 0x3;
+ var _w = (mask >> 6) & 0x3;
+ return SIMD.int32x4(t1.storage_[_x], t1.storage_[_y], t2.storage_[_z],
+ t2.storage_[_w]);
+}
+
+/**
+ * @param {float32x4}
+ */
+SIMD.int32x4.select = function(t, trueValue, falseValue) {
+ var tv = SIMD.float32x4.bitsToInt32x4(trueValue);
+ var fv = SIMD.float32x4.bitsToInt32x4(falseValue);
+ var tr = SIMD.int32x4.and(t, tv);
+ var fr = SIMD.int32x4.and(SIMD.int32x4.not(t), fv);
+ return SIMD.int32x4.bitsToFloat32x4(SIMD.int32x4.or(tr, fr));
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {integer} 32-bit value used for x lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * x lane replaced with {x}.
+ */
+SIMD.int32x4.withX = function(t, x) {
+ return SIMD.int32x4(x, t.y, t.z, t.w);
+}
+
+/**
+ * param {int32x4} t An instance of int32x4.
+ * @param {integer} 32-bit value used for y lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * y lane replaced with {y}.
+ */
+SIMD.int32x4.withY = function(t, y) {
+ return SIMD.int32x4(t.x, y, t.z, t.w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {integer} 32-bit value used for z lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * z lane replaced with {z}.
+ */
+SIMD.int32x4.withZ = function(t, z) {
+ return SIMD.int32x4(t.x, t.y, z, t.w);
+}
+
+/**
+ * @param {integer} 32-bit value used for w lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * w lane replaced with {w}.
+ */
+SIMD.int32x4.withW = function(t, w) {
+ return SIMD.int32x4(t.x, t.y, t.z, w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {boolean} x flag used for x lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * x lane replaced with {x}.
+ */
+SIMD.int32x4.withFlagX = function(t, flagX) {
+ var x = flagX ? 0xFFFFFFFF : 0x0;
+ return SIMD.int32x4(x, t.y, t.z, t.w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {boolean} y flag used for y lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * y lane replaced with {y}.
+ */
+SIMD.int32x4.withFlagY = function(t, flagY) {
+ var y = flagY ? 0xFFFFFFFF : 0x0;
+ return SIMD.int32x4(t.x, y, t.z, t.w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {boolean} z flag used for z lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * z lane replaced with {z}.
+ */
+SIMD.int32x4.withFlagZ = function(t, flagZ) {
+ var z = flagZ ? 0xFFFFFFFF : 0x0;
+ return SIMD.int32x4(t.x, t.y, z, t.w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {boolean} w flag used for w lane.
+ * @return {int32x4} New instance of int32x4 with the values in t and
+ * w lane replaced with {w}.
+ */
+SIMD.int32x4.withFlagW = function(t, flagW) {
+ var w = flagW ? 0xFFFFFFFF : 0x0;
+ return SIMD.int32x4(t.x, t.y, t.z, w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {int32x4} other An instance of int32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t == other.
+ */
+SIMD.int32x4.equal = function(t, other) {
+ var cx = t.x == other.x;
+ var cy = t.y == other.y;
+ var cz = t.z == other.z;
+ var cw = t.w == other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {int32x4} other An instance of int32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t > other.
+ */
+SIMD.int32x4.greaterThan = function(t, other) {
+ var cx = t.x > other.x;
+ var cy = t.y > other.y;
+ var cz = t.z > other.z;
+ var cw = t.w > other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @param {int32x4} other An instance of int32x4.
+ * @return {int32x4} 0xFFFFFFFF or 0x0 in each lane depending on
+ * the result of t < other.
+ */
+SIMD.int32x4.lessThan = function(t, other) {
+ var cx = t.x < other.x;
+ var cy = t.y < other.y;
+ var cz = t.z < other.z;
+ var cw = t.w < other.w;
+ return SIMD.int32x4.bool(cx, cy, cz, cw);
+}
+
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int} bits Bit count to shift by.
+ * @return {int32x4} lanes in a shifted by bits.
+ */
+SIMD.int32x4.shiftLeft = function(a, bits) {
+ var x = a.x << bits;
+ var y = a.y << bits;
+ var z = a.z << bits;
+ var w = a.w << bits;
+ return SIMD.int32x4(x, y, z, w);
+}
+
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int} bits Bit count to shift by.
+ * @return {int32x4} lanes in a shifted by bits.
+ */
+SIMD.int32x4.shiftRightLogical = function(a, bits) {
+ var x = a.x >>> bits;
+ var y = a.y >>> bits;
+ var z = a.z >>> bits;
+ var w = a.w >>> bits;
+ return SIMD.int32x4(x, y, z, w);
+}
+
+/**
+ * @param {int32x4} a An instance of int32x4.
+ * @param {int} bits Bit count to shift by.
+ * @return {int32x4} lanes in a shifted by bits.
+ */
+SIMD.int32x4.shiftRightArithmetic = function(a, bits) {
+ var x = a.x >> bits;
+ var y = a.y >> bits;
+ var z = a.z >> bits;
+ var w = a.w >> bits;
+ return SIMD.int32x4(x, y, z, w);
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @return {float32x4} a bit-wise copy of t as a float32x4.
+ */
+SIMD.int32x4.bitsToFloat32x4 = function(t) {
+ var temp_storage = new Int32Array([t.storage_[0], t.storage_[1], t.storage_[2], t.storage_[3]]);
+ var alias = new Float32Array(temp_storage.buffer);
+ var fx4 = SIMD.float32x4.zero();
+ fx4.storage_ = alias;
+ return fx4;
+}
+
+/**
+ * @param {int32x4} t An instance of int32x4.
+ * @return {float32x4} with a float to integer conversion copy of t.
+ */
+SIMD.int32x4.toFloat32x4 = function(t) {
+ var a = float32x4.zero();
+ a.storage_[0] = t.storage_[0];
+ a.storage_[1] = t.storage_[1];
+ a.storage_[2] = t.storage_[2];
+ a.storage_[3] = t.storage_[3];
+ return a;
+}
Object.defineProperty(SIMD, 'XXXX', { get: function() { return 0x0; } });
Object.defineProperty(SIMD, 'XXXY', { get: function() { return 0x40; } });
@@ -1126,3 +1000,302 @@ Object.defineProperty(SIMD, 'WWWX', { get: function() { return 0x3F; } });
Object.defineProperty(SIMD, 'WWWY', { get: function() { return 0x7F; } });
Object.defineProperty(SIMD, 'WWWZ', { get: function() { return 0xBF; } });
Object.defineProperty(SIMD, 'WWWW', { get: function() { return 0xFF; } });
+
+Object.defineProperty(SIMD.float32x4.prototype, 'x', {
+ get: function() { return this.storage_[0]; }
+});
+
+Object.defineProperty(SIMD.float32x4.prototype, 'y', {
+ get: function() { return this.storage_[1]; }
+});
+
+Object.defineProperty(SIMD.float32x4.prototype, 'z', {
+ get: function() { return this.storage_[2]; }
+});
+
+Object.defineProperty(SIMD.float32x4.prototype, 'w',
+ { get: function() { return this.storage_[3]; }
+});
+
+/**
+ * Extract the sign bit from each lane return them in the first 4 bits.
+ */
+Object.defineProperty(SIMD.float32x4.prototype, 'signMask', {
+ get: function() {
+ var mx = this.x < 0.0 ? 1 : 0;
+ var my = this.y < 0.0 ? 1 : 0;
+ var mz = this.z < 0.0 ? 1 : 0;
+ var mw = this.w < 0.0 ? 1 : 0;
+ return mx | my << 1 | mz << 2 | mw << 3;
+ }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'x', {
+ get: function() { return this.storage_[0]; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'y', {
+ get: function() { return this.storage_[1]; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'z', {
+ get: function() { return this.storage_[2]; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'w',
+ { get: function() { return this.storage_[3]; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'flagX', {
+ get: function() { return this.storage_[0] != 0x0; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'flagY', {
+ get: function() { return this.storage_[1] != 0x0; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'flagZ', {
+ get: function() { return this.storage_[2] != 0x0; }
+});
+
+Object.defineProperty(SIMD.int32x4.prototype, 'flagW',
+ { get: function() { return this.storage_[3] != 0x0; }
+});
+
+/**
+ * Extract the sign bit from each lane return them in the first 4 bits.
+ */
+Object.defineProperty(SIMD.int32x4.prototype, 'signMask', {
+ get: function() {
+ var mx = (this.storage_[0] & 0x80000000) >>> 31;
+ var my = (this.storage_[1] & 0x80000000) >>> 31;
+ var mz = (this.storage_[2] & 0x80000000) >>> 31;
+ var mw = (this.storage_[3] & 0x80000000) >>> 31;
+ return mx | my << 1 | mz << 2 | mw << 3;
+ }
+});
+
+function isNumber(o) {
+ return typeof o == "number" || (typeof o == "object" && o.constructor === Number);
+}
+
+function isTypedArray(o) {
+ return (o instanceof Int8Array) ||
+ (o instanceof Uint8Array) ||
+ (o instanceof Uint8ClampedArray) ||
+ (o instanceof Int16Array) ||
+ (o instanceof Uint16Array) ||
+ (o instanceof Int32Array) ||
+ (o instanceof Uint32Array) ||
+ (o instanceof Float32Array) ||
+ (o instanceof Float64Array) ||
+ (o instanceof Float32x4Array);
+}
+
+function isArrayBuffer(o) {
+ return (o instanceof ArrayBuffer);
+}
+
+function Float32x4Array(a, b, c) {
+ if (isNumber(a)) {
+ this.storage_ = new Float32Array(a*4);
+ this.length_ = a;
+ this.byteOffset_ = 0;
+ return;
+ } else if (isTypedArray(a)) {
+ if (!(a instanceof Float32x4Array)) {
+ throw "Copying typed array of non-Float32x4Array is unimplemented.";
+ }
+ this.storage_ = new Float32Array(a.length * 4);
+ this.length_ = a.length;
+ this.byteOffset_ = 0;
+ // Copy floats.
+ for (var i = 0; i < a.length*4; i++) {
+ this.storage_[i] = a.storage_[i];
+ }
+ } else if (isArrayBuffer(a)) {
+ if ((b != undefined) && (b % Float32x4Array.BYTES_PER_ELEMENT) != 0) {
+ throw "byteOffset must be a multiple of 16.";
+ }
+ if (c != undefined) {
+ c *= 4;
+ this.storage_ = new Float32Array(a, b, c);
+ }
+ else {
+ // Note = new Float32Array(a, b) is NOT equivalent to new Float32Array(a, b, undefined)
+ this.storage_ = new Float32Array(a, b);
+ }
+ this.length_ = this.storage_.length / 4;
+ this.byteOffset_ = b != undefined ? b : 0;
+ } else {
+ throw "Unknown type of first argument.";
+ }
+}
+
+Object.defineProperty(Float32x4Array.prototype, 'length',
+ { get: function() { return this.length_; }
+});
+
+Object.defineProperty(Float32x4Array.prototype, 'byteLength',
+ { get: function() { return this.length_ * Float32x4Array.BYTES_PER_ELEMENT; }
+});
+
+Object.defineProperty(Float32x4Array, 'BYTES_PER_ELEMENT',
+ { get: function() { return 16; }
+});
+
+Object.defineProperty(Float32x4Array.prototype, 'BYTES_PER_ELEMENT',
+ { get: function() { return 16; }
+});
+
+Object.defineProperty(Float32x4Array.prototype, 'byteOffset',
+ { get: function() { return this.byteOffset_; }
+});
+
+Object.defineProperty(Float32x4Array.prototype, 'buffer',
+ { get: function() { return this.storage_.buffer; }
+});
+
+Float32x4Array.prototype.getAt = function(i) {
+ if (i < 0) {
+ throw "Index must be >= 0.";
+ }
+ if (i >= this.length) {
+ throw "Index out of bounds.";
+ }
+ var x = this.storage_[i*4+0];
+ var y = this.storage_[i*4+1];
+ var z = this.storage_[i*4+2];
+ var w = this.storage_[i*4+3];
+ return SIMD.float32x4(x, y, z, w);
+}
+
+Float32x4Array.prototype.setAt = function(i, v) {
+ if (i < 0) {
+ throw "Index must be >= 0.";
+ }
+ if (i >= this.length) {
+ throw "Index out of bounds.";
+ }
+ if (!(v instanceof SIMD.float32x4)) {
+ throw "Value is not a float32x4.";
+ }
+ this.storage_[i*4+0] = v.x;
+ this.storage_[i*4+1] = v.y;
+ this.storage_[i*4+2] = v.z;
+ this.storage_[i*4+3] = v.w;
+}
+
+
+function Int32x4Array(a, b, c) {
+
+ function isNumber(o) {
+ return typeof o == "number" || (typeof o == "object" && o.constructor === Number);
+ }
+
+ function isTypedArray(o) {
+ return (o instanceof Int8Array) ||
+ (o instanceof Uint8Array) ||
+ (o instanceof Uint8ClampedArray) ||
+ (o instanceof Int16Array) ||
+ (o instanceof Uint16Array) ||
+ (o instanceof Int32Array) ||
+ (o instanceof Uint32Array) ||
+ (o instanceof Float32Array) ||
+ (o instanceof Float64Array) ||
+ (o instanceof Int32x4Array) ||
+ (o instanceof Float32x4Array);
+ }
+
+ function isArrayBuffer(o) {
+ return (o instanceof ArrayBuffer);
+ }
+
+ if (isNumber(a)) {
+ this.storage_ = new Int32Array(a*4);
+ this.length_ = a;
+ this.byteOffset_ = 0;
+ return;
+ } else if (isTypedArray(a)) {
+ if (!(a instanceof Int32x4Array)) {
+ throw "Copying typed array of non-Int32x4Array is unimplemented.";
+ }
+ this.storage_ = new Int32Array(a.length * 4);
+ this.length_ = a.length;
+ this.byteOffset_ = 0;
+ // Copy ints.
+ for (var i = 0; i < a.length*4; i++) {
+ this.storage_[i] = a.storage_[i];
+ }
+ } else if (isArrayBuffer(a)) {
+ if ((b != undefined) && (b % Int32x4Array.BYTES_PER_ELEMENT) != 0) {
+ throw "byteOffset must be a multiple of 16.";
+ }
+ if (c != undefined) {
+ c *= 4;
+ this.storage_ = new Int32Array(a, b, c);
+ }
+ else {
+ // Note = new Int32Array(a, b) is NOT equivalent to new Float32Array(a, b, undefined)
+ this.storage_ = new Int32Array(a, b);
+ }
+ this.length_ = this.storage_.length / 4;
+ this.byteOffset_ = b != undefined ? b : 0;
+ } else {
+ throw "Unknown type of first argument.";
+ }
+}
+
+Object.defineProperty(Int32x4Array.prototype, 'length',
+ { get: function() { return this.length_; }
+});
+
+Object.defineProperty(Int32x4Array.prototype, 'byteLength',
+ { get: function() { return this.length_ * Int32x4Array.BYTES_PER_ELEMENT; }
+});
+
+Object.defineProperty(Int32x4Array, 'BYTES_PER_ELEMENT',
+ { get: function() { return 16; }
+});
+
+Object.defineProperty(Int32x4Array.prototype, 'BYTES_PER_ELEMENT',
+ { get: function() { return 16; }
+});
+
+Object.defineProperty(Int32x4Array.prototype, 'byteOffset',
+ { get: function() { return this.byteOffset_; }
+});
+
+Object.defineProperty(Int32x4Array.prototype, 'buffer',
+ { get: function() { return this.storage_.buffer; }
+});
+
+Int32x4Array.prototype.getAt = function(i) {
+ if (i < 0) {
+ throw "Index must be >= 0.";
+ }
+ if (i >= this.length) {
+ throw "Index out of bounds.";
+ }
+ var x = this.storage_[i*4+0];
+ var y = this.storage_[i*4+1];
+ var z = this.storage_[i*4+2];
+ var w = this.storage_[i*4+3];
+ return SIMD.int32x4(x, y, z, w);
+}
+
+Int32x4Array.prototype.setAt = function(i, v) {
+ if (i < 0) {
+ throw "Index must be >= 0.";
+ }
+ if (i >= this.length) {
+ throw "Index out of bounds.";
+ }
+ if (!(v instanceof SIMD.int32x4)) {
+ throw "Value is not a int32x4.";
+ }
+ this.storage_[i*4+0] = v.x;
+ this.storage_[i*4+1] = v.y;
+ this.storage_[i*4+2] = v.z;
+ this.storage_[i*4+3] = v.w;
+} \ No newline at end of file
diff --git a/src/struct_info.json b/src/struct_info.json
index 2fb9962d..94a64845 100644
--- a/src/struct_info.json
+++ b/src/struct_info.json
@@ -873,7 +873,7 @@
},
{
"file": "SDL/SDL_pixels.h",
- "defines": [],
+ "defines": ["SDL_PIXELFORMAT_RGBA8888"],
"structs": {
"SDL_Palette": [
"ncolors",
diff --git a/src/webGLClient.js b/src/webGLClient.js
new file mode 100644
index 00000000..491eb4c0
--- /dev/null
+++ b/src/webGLClient.js
@@ -0,0 +1,319 @@
+// WebGLWorker client code
+
+function assert(x) {
+ if (!x) throw 'failed assert';
+}
+
+function WebGLClient() {
+ var objects = {};
+
+ var ctx = null;
+ var buffer = null;
+ var i = 0;
+ var skippable = false;
+ var currFrameBuffer = null;
+
+ function func0(name) {
+ ctx[name]();
+ }
+ function func1(name) {
+ ctx[name](buffer[i]);
+ i++;
+ }
+ function func2(name) {
+ ctx[name](buffer[i], buffer[i+1]);
+ i += 2;
+ }
+ function func3(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2]);
+ i += 3;
+ }
+ function func4(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]);
+ i += 4;
+ }
+ function func5(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4]);
+ i += 5;
+ }
+ function func6(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5]);
+ i += 6;
+ }
+ function func7(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5], buffer[i+6]);
+ i += 7;
+ }
+ function func9(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7], buffer[i+8]);
+ i += 9;
+ }
+
+ // lookuppers, convert integer ids to cached objects for some args
+ function func1L0(name) {
+ ctx[name](objects[buffer[i]]);
+ i++;
+ }
+ function func2L0(name) {
+ ctx[name](objects[buffer[i]], buffer[i+1]);
+ i += 2;
+ }
+ function func2L0L1(name) {
+ ctx[name](objects[buffer[i]], objects[buffer[i+1]]);
+ i += 2;
+ }
+ function func2L1_(name) {
+ ctx[name](buffer[i], buffer[i+1] ? objects[buffer[i+1]] : null);
+ i += 2;
+ }
+ function func3L0(name) {
+ ctx[name](objects[buffer[i]], buffer[i+1], buffer[i+2]);
+ i += 3;
+ }
+ function func4L3_(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3] ? objects[buffer[i+3]] : null);
+ i += 4;
+ }
+ function func5L3_(name) {
+ ctx[name](buffer[i], buffer[i+1], buffer[i+2], buffer[i+3] ? objects[buffer[i+3]] : null, buffer[i+4]);
+ i += 5;
+ }
+
+ // constructors, last argument is the id to save as
+ function funcC0(name) {
+ var object = ctx[name]();
+ var id = buffer[i++];
+ objects[id] = object;
+ }
+ function funcC1(name) {
+ var object = ctx[name](buffer[i++]);
+ var id = buffer[i++];
+ objects[id] = object;
+ }
+ function funcC2(name) {
+ var object = ctx[name](buffer[i++], buffer[i++]);
+ var id = buffer[i++];
+ objects[id] = object;
+ }
+ function funcC2L0(name) {
+ var object = ctx[name](objects[buffer[i++]], buffer[i++]);
+ var id = buffer[i++];
+ objects[id] = object;
+ }
+
+ // destructors, stop holding on to the object in the cache
+ function funcD0(name) {
+ var id = buffer[i++];
+ var object = objects[id];
+ objects[id] = null;
+ ctx[name](object);
+ }
+
+ // special cases/optimizations
+ function bindFramebuffer() {
+ currFrameBuffer = buffer[i+1] ? objects[buffer[i+1]] : null;
+ ctx.bindFramebuffer(buffer[i], currFrameBuffer);
+ i += 2;
+ }
+ function drawArrays(name) {
+ if (!skippable || currFrameBuffer !== null) {
+ ctx.drawArrays(buffer[i], buffer[i+1], buffer[i+2]);
+ }
+ i += 3;
+ }
+ function drawElements(name) {
+ if (!skippable || currFrameBuffer !== null) {
+ ctx.drawElements(buffer[i], buffer[i+1], buffer[i+2], buffer[i+3]);
+ }
+ i += 4;
+ }
+ function enable() {
+ ctx.enable(buffer[i++]);
+ }
+ function disable() {
+ ctx.disable(buffer[i++]);
+ }
+ function enableVertexAttribArray() {
+ ctx.enableVertexAttribArray(buffer[i++]);
+ }
+ function disableVertexAttribArray() {
+ ctx.disableVertexAttribArray(buffer[i++]);
+ }
+ function activeTexture() {
+ ctx.activeTexture(buffer[i++]);
+ }
+ function uniform1i() {
+ ctx.uniform1i(objects[buffer[i]], buffer[i+1]);
+ i += 2;
+ }
+ function uniform1f() {
+ ctx.uniform1f(objects[buffer[i]], buffer[i+1]);
+ i += 2;
+ }
+ function uniform3fv() {
+ ctx.uniform3fv(objects[buffer[i]], buffer[i+1]);
+ i += 2;
+ }
+ function uniform4fv() {
+ ctx.uniform4fv(objects[buffer[i]], buffer[i+1]);
+ i += 2;
+ }
+ function vertexAttribPointer() {
+ ctx.vertexAttribPointer(buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], buffer[i+5]);
+ i += 6;
+ }
+
+ var calls = {
+ 0: { name: 'NULL', func: func0 },
+ 1: { name: 'getExtension', func: func1 },
+ 2: { name: 'enable', func: enable },
+ 3: { name: 'disable', func: disable },
+ 4: { name: 'clear', func: func1 },
+ 5: { name: 'clearColor', func: func4 },
+ 6: { name: 'createShader', func: funcC1 },
+ 7: { name: 'deleteShader', func: funcD0 },
+ 8: { name: 'shaderSource', func: func2L0 },
+ 9: { name: 'compileShader', func: func1L0 },
+ 10: { name: 'createProgram', func: funcC0 },
+ 11: { name: 'deleteProgram', func: funcD0 },
+ 12: { name: 'attachShader', func: func2L0L1 },
+ 13: { name: 'bindAttribLocation', func: func3L0 },
+ 14: { name: 'linkProgram', func: func1L0 },
+ 15: { name: 'getProgramParameter', func: function() { assert(ctx.getProgramParameter(objects[buffer[i++]], buffer[i++]), 'we cannot handle errors, we are async proxied WebGL'); } },
+ 16: { name: 'getUniformLocation', func: funcC2L0 },
+ 17: { name: 'useProgram', func: func1L0 },
+ 18: { name: 'uniform1i', func: uniform1i },
+ 19: { name: 'uniform1f', func: uniform1f },
+ 20: { name: 'uniform3fv', func: uniform3fv },
+ 21: { name: 'uniform4fv', func: uniform4fv },
+ 22: { name: 'uniformMatrix4fv', func: func3L0 },
+ 23: { name: 'vertexAttrib4fv', func: func2 },
+ 24: { name: 'createBuffer', func: funcC0 },
+ 25: { name: 'deleteBuffer', func: funcD0 },
+ 26: { name: 'bindBuffer', func: func2L1_ },
+ 27: { name: 'bufferData', func: func3 },
+ 28: { name: 'bufferSubData', func: func3 },
+ 29: { name: 'viewport', func: func4 },
+ 30: { name: 'vertexAttribPointer', func: vertexAttribPointer },
+ 31: { name: 'enableVertexAttribArray', func: enableVertexAttribArray },
+ 32: { name: 'disableVertexAttribArray', func: disableVertexAttribArray },
+ 33: { name: 'drawArrays', func: drawArrays },
+ 34: { name: 'drawElements', func: drawElements },
+ 35: { name: 'getError', func: function() { assert(ctx.getError() === ctx.NO_ERROR, 'we cannot handle errors, we are async proxied WebGL') } },
+ 36: { name: 'createTexture', func: funcC0 },
+ 37: { name: 'deleteTexture', func: funcD0 },
+ 38: { name: 'bindTexture', func: func2L1_ },
+ 39: { name: 'texParameteri', func: func3 },
+ 40: { name: 'texImage2D', func: func9 },
+ 41: { name: 'compressedTexImage2D', func: func7 },
+ 42: { name: 'activeTexture', func: activeTexture },
+ 43: { name: 'getShaderParameter', func: function() { assert(ctx.getShaderParameter(objects[buffer[i++]], buffer[i++]), 'we cannot handle errors, we are async proxied WebGL'); } },
+ 44: { name: 'clearDepth', func: func1 },
+ 45: { name: 'depthFunc', func: func1 },
+ 46: { name: 'frontFace', func: func1 },
+ 47: { name: 'cullFace', func: func1 },
+ 48: { name: 'pixelStorei', func: func2 },
+ 49: { name: 'depthMask', func: func1 },
+ 50: { name: 'depthRange', func: func2 },
+ 51: { name: 'blendFunc', func: func2 },
+ 52: { name: 'scissor', func: func4 },
+ 53: { name: 'colorMask', func: func4 },
+ 54: { name: 'lineWidth', func: func1 },
+ 55: { name: 'createFramebuffer', func: funcC0 },
+ 56: { name: 'deleteFramebuffer', func: funcD0 },
+ 57: { name: 'bindFramebuffer', func: bindFramebuffer },
+ 58: { name: 'framebufferTexture2D', func: func5L3_ },
+ 59: { name: 'createRenderbuffer', func: funcC0 },
+ 60: { name: 'deleteRenderbuffer', func: funcD0 },
+ 61: { name: 'bindRenderbuffer', func: func2L1_ },
+ 62: { name: 'renderbufferStorage', func: func4 },
+ 63: { name: 'framebufferRenderbuffer', func: func4L3_ },
+ 64: { name: 'debugPrint', func: func1 },
+ 65: { name: 'hint', func: func2 },
+ 66: { name: 'blendEquation', func: func1 },
+ 67: { name: 'generateMipmap', func: func1 },
+ 68: { name: 'uniformMatrix3fv', func: func3L0 },
+ };
+
+ function renderCommands(buf) {
+ ctx = Module.ctx;
+ i = 0;
+ buffer = buf;
+ var len = buffer.length;
+ //dump('issuing commands, buffer len: ' + len + '\n');
+ while (i < len) {
+ var info = calls[buffer[i++]];
+ var name = info.name;
+ info.func(name);
+ //var err;
+ //while ((err = ctx.getError()) !== ctx.NO_ERROR) {
+ // dump('warning: GL error ' + err + ', after ' + [command, numArgs] + '\n');
+ //}
+ assert(i <= len);
+ }
+ }
+
+ var commandBuffers = [];
+
+ function renderAllCommands() {
+ // we can skip parts of the frames before the last, as we just need their side effects
+ skippable = true;
+ for (var i = 0; i < commandBuffers.length-1; i++) {
+ renderCommands(commandBuffers[i]);
+ }
+ skippable = false;
+ renderCommands(commandBuffers[commandBuffers.length-1]);
+ commandBuffers.length = 0;
+ }
+
+ this.onmessage = function(msg) {
+ //dump('client GL got ' + JSON.stringify(msg) + '\n');
+ switch(msg.op) {
+ case 'render': {
+ if (commandBuffers.length === 0) {
+ // requestion a new frame, we will clear the buffers after rendering them
+ window.requestAnimationFrame(renderAllCommands);
+ }
+ commandBuffers.push(msg.commandBuffer);
+ break;
+ }
+ default: throw 'weird gl onmessage ' + JSON.stringify(msg);
+ }
+ };
+}
+
+WebGLClient.prefetch = function() {
+ // Create a fake temporary GL context
+ var canvas = document.createElement('canvas');
+ var ctx = canvas.getContext('webgl-experimental') || canvas.getContext('webgl');
+ if (!ctx) return;
+
+ // Fetch the parameters and proxy them
+ var parameters = {};
+ ['MAX_VERTEX_ATTRIBS', 'MAX_TEXTURE_IMAGE_UNITS', 'MAX_TEXTURE_SIZE', 'MAX_CUBE_MAP_TEXTURE_SIZE', 'MAX_VERTEX_UNIFORM_VECTORS', 'MAX_FRAGMENT_UNIFORM_VECTORS', 'MAX_VARYING_VECTORS', 'MAX_COMBINED_TEXTURE_IMAGE_UNITS', 'MAX_VERTEX_TEXTURE_IMAGE_UNITS', 'VENDOR', 'RENDERER', 'VERSION', 'SHADING_LANGUAGE_VERSION', 'COMPRESSED_TEXTURE_FORMATS'].forEach(function(name) {
+ var id = ctx[name];
+ parameters[id] = ctx.getParameter(id);
+ });
+ // Try to enable some extensions, so we can access their parameters
+ [{ extName: 'EXT_texture_filter_anisotropic', paramName: 'MAX_TEXTURE_MAX_ANISOTROPY_EXT' }].forEach(function(pair) {
+ var ext = ctx.getExtension(pair.extName) || ctx.getExtension('MOZ_' + pair.extName) || 'WEBKIT_' + ctx.getExtension(pair.extName);
+ if (ext) {
+ var id = ext[pair.paramName];
+ parameters[id] = ctx.getParameter(id);
+ }
+ });
+ // Fetch shader precisions
+ var precisions = {};
+ ['FRAGMENT_SHADER', 'VERTEX_SHADER'].forEach(function(shaderType) {
+ shaderType = ctx[shaderType];
+ precisions[shaderType] = {};
+ ['LOW_FLOAT', 'MEDIUM_FLOAT', 'HIGH_FLOAT', 'LOW_INT', 'MEDIUM_INT', 'HIGH_INT'].forEach(function(precisionType) {
+ precisionType = ctx[precisionType];
+ var info = ctx.getShaderPrecisionFormat(shaderType, precisionType);
+ precisions[shaderType][precisionType] = info ? { rangeMin: info.rangeMin, rangeMax: info.rangeMax, precision: info.precision } : info;
+ });
+ });
+
+ worker.postMessage({ target: 'gl', op: 'setPrefetched', parameters: parameters, extensions: ctx.getSupportedExtensions(), precisions: precisions, preMain: true });
+};
+
diff --git a/src/webGLWorker.js b/src/webGLWorker.js
new file mode 100644
index 00000000..98fb0089
--- /dev/null
+++ b/src/webGLWorker.js
@@ -0,0 +1,983 @@
+// WebGLWorker worker code
+
+function WebGLBuffer(id) {
+ this.what = 'buffer';
+ this.id = id;
+}
+function WebGLProgram(id) {
+ this.what = 'program';
+ this.id = id;
+ this.shaders = [];
+ this.attributes = {};
+ this.attributeVec = [];
+}
+function WebGLFramebuffer(id) {
+ this.what = 'frameBuffer';
+ this.id = id;
+}
+function WebGLRenderbuffer(id) {
+ this.what = 'renderBuffer';
+ this.id = id;
+}
+function WebGLTexture(id) {
+ this.what = 'texture';
+ this.id = id;
+ this.binding = 0;
+}
+
+function WebGLWorker() {
+ //=======
+ // State
+ //=======
+
+ var commandBuffer = [];
+
+ var nextId = 1; // valid ids are > 0
+
+ var bindings = {
+ texture2D: null,
+ arrayBuffer: null,
+ elementArrayBuffer: null,
+ program: null
+ };
+
+ //===========
+ // Constants
+ //===========
+
+ /* ClearBufferMask */
+ this.DEPTH_BUFFER_BIT = 0x00000100;
+ this.STENCIL_BUFFER_BIT = 0x00000400;
+ this.COLOR_BUFFER_BIT = 0x00004000;
+
+ /* BeginMode */
+ this.POINTS = 0x0000;
+ this.LINES = 0x0001;
+ this.LINE_LOOP = 0x0002;
+ this.LINE_STRIP = 0x0003;
+ this.TRIANGLES = 0x0004;
+ this.TRIANGLE_STRIP = 0x0005;
+ this.TRIANGLE_FAN = 0x0006;
+
+ /* AlphaFunction (not supported in ES20) */
+ /* NEVER */
+ /* LESS */
+ /* EQUAL */
+ /* LEQUAL */
+ /* GREATER */
+ /* NOTEQUAL */
+ /* GEQUAL */
+ /* ALWAYS */
+
+ /* BlendingFactorDest */
+ this.ZERO = 0;
+ this.ONE = 1;
+ this.SRC_COLOR = 0x0300;
+ this.ONE_MINUS_SRC_COLOR = 0x0301;
+ this.SRC_ALPHA = 0x0302;
+ this.ONE_MINUS_SRC_ALPHA = 0x0303;
+ this.DST_ALPHA = 0x0304;
+ this.ONE_MINUS_DST_ALPHA = 0x0305;
+
+ /* BlendingFactorSrc */
+ /* ZERO */
+ /* ONE */
+ this.DST_COLOR = 0x0306;
+ this.ONE_MINUS_DST_COLOR = 0x0307;
+ this.SRC_ALPHA_SATURATE = 0x0308;
+ /* SRC_ALPHA */
+ /* ONE_MINUS_SRC_ALPHA */
+ /* DST_ALPHA */
+ /* ONE_MINUS_DST_ALPHA */
+
+ /* BlendEquationSeparate */
+ this.FUNC_ADD = 0x8006;
+ this.BLEND_EQUATION = 0x8009;
+ this.BLEND_EQUATION_RGB = 0x8009; /* same as BLEND_EQUATION */
+ this.BLEND_EQUATION_ALPHA = 0x883D;
+
+ /* BlendSubtract */
+ this.FUNC_SUBTRACT = 0x800A;
+ this.FUNC_REVERSE_SUBTRACT = 0x800B;
+
+ /* Separate Blend Functions */
+ this.BLEND_DST_RGB = 0x80C8;
+ this.BLEND_SRC_RGB = 0x80C9;
+ this.BLEND_DST_ALPHA = 0x80CA;
+ this.BLEND_SRC_ALPHA = 0x80CB;
+ this.CONSTANT_COLOR = 0x8001;
+ this.ONE_MINUS_CONSTANT_COLOR = 0x8002;
+ this.CONSTANT_ALPHA = 0x8003;
+ this.ONE_MINUS_CONSTANT_ALPHA = 0x8004;
+ this.BLEND_COLOR = 0x8005;
+
+ /* Buffer Objects */
+ this.ARRAY_BUFFER = 0x8892;
+ this.ELEMENT_ARRAY_BUFFER = 0x8893;
+ this.ARRAY_BUFFER_BINDING = 0x8894;
+ this.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895;
+
+ this.STREAM_DRAW = 0x88E0;
+ this.STATIC_DRAW = 0x88E4;
+ this.DYNAMIC_DRAW = 0x88E8;
+
+ this.BUFFER_SIZE = 0x8764;
+ this.BUFFER_USAGE = 0x8765;
+
+ this.CURRENT_VERTEX_ATTRIB = 0x8626;
+
+ /* CullFaceMode */
+ this.FRONT = 0x0404;
+ this.BACK = 0x0405;
+ this.FRONT_AND_BACK = 0x0408;
+
+ /* DepthFunction */
+ /* NEVER */
+ /* LESS */
+ /* EQUAL */
+ /* LEQUAL */
+ /* GREATER */
+ /* NOTEQUAL */
+ /* GEQUAL */
+ /* ALWAYS */
+
+ /* EnableCap */
+ /* TEXTURE_2D */
+ this.CULL_FACE = 0x0B44;
+ this.BLEND = 0x0BE2;
+ this.DITHER = 0x0BD0;
+ this.STENCIL_TEST = 0x0B90;
+ this.DEPTH_TEST = 0x0B71;
+ this.SCISSOR_TEST = 0x0C11;
+ this.POLYGON_OFFSET_FILL = 0x8037;
+ this.SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
+ this.SAMPLE_COVERAGE = 0x80A0;
+
+ /* ErrorCode */
+ this.NO_ERROR = 0;
+ this.INVALID_ENUM = 0x0500;
+ this.INVALID_VALUE = 0x0501;
+ this.INVALID_OPERATION = 0x0502;
+ this.OUT_OF_MEMORY = 0x0505;
+
+ /* FrontFaceDirection */
+ this.CW = 0x0900;
+ this.CCW = 0x0901;
+
+ /* GetPName */
+ this.LINE_WIDTH = 0x0B21;
+ this.ALIASED_POINT_SIZE_RANGE = 0x846D;
+ this.ALIASED_LINE_WIDTH_RANGE = 0x846E;
+ this.CULL_FACE_MODE = 0x0B45;
+ this.FRONT_FACE = 0x0B46;
+ this.DEPTH_RANGE = 0x0B70;
+ this.DEPTH_WRITEMASK = 0x0B72;
+ this.DEPTH_CLEAR_VALUE = 0x0B73;
+ this.DEPTH_FUNC = 0x0B74;
+ this.STENCIL_CLEAR_VALUE = 0x0B91;
+ this.STENCIL_FUNC = 0x0B92;
+ this.STENCIL_FAIL = 0x0B94;
+ this.STENCIL_PASS_DEPTH_FAIL = 0x0B95;
+ this.STENCIL_PASS_DEPTH_PASS = 0x0B96;
+ this.STENCIL_REF = 0x0B97;
+ this.STENCIL_VALUE_MASK = 0x0B93;
+ this.STENCIL_WRITEMASK = 0x0B98;
+ this.STENCIL_BACK_FUNC = 0x8800;
+ this.STENCIL_BACK_FAIL = 0x8801;
+ this.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802;
+ this.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803;
+ this.STENCIL_BACK_REF = 0x8CA3;
+ this.STENCIL_BACK_VALUE_MASK = 0x8CA4;
+ this.STENCIL_BACK_WRITEMASK = 0x8CA5;
+ this.VIEWPORT = 0x0BA2;
+ this.SCISSOR_BOX = 0x0C10;
+ /* SCISSOR_TEST */
+ this.COLOR_CLEAR_VALUE = 0x0C22;
+ this.COLOR_WRITEMASK = 0x0C23;
+ this.UNPACK_ALIGNMENT = 0x0CF5;
+ this.PACK_ALIGNMENT = 0x0D05;
+ this.MAX_TEXTURE_SIZE = 0x0D33;
+ this.MAX_VIEWPORT_DIMS = 0x0D3A;
+ this.SUBPIXEL_BITS = 0x0D50;
+ this.RED_BITS = 0x0D52;
+ this.GREEN_BITS = 0x0D53;
+ this.BLUE_BITS = 0x0D54;
+ this.ALPHA_BITS = 0x0D55;
+ this.DEPTH_BITS = 0x0D56;
+ this.STENCIL_BITS = 0x0D57;
+ this.POLYGON_OFFSET_UNITS = 0x2A00;
+ /* POLYGON_OFFSET_FILL */
+ this.POLYGON_OFFSET_FACTOR = 0x8038;
+ this.TEXTURE_BINDING_2D = 0x8069;
+ this.SAMPLE_BUFFERS = 0x80A8;
+ this.SAMPLES = 0x80A9;
+ this.SAMPLE_COVERAGE_VALUE = 0x80AA;
+ this.SAMPLE_COVERAGE_INVERT = 0x80AB;
+
+ /* GetTextureParameter */
+ /* TEXTURE_MAG_FILTER */
+ /* TEXTURE_MIN_FILTER */
+ /* TEXTURE_WRAP_S */
+ /* TEXTURE_WRAP_T */
+
+ this.COMPRESSED_TEXTURE_FORMATS = 0x86A3;
+
+ /* HintMode */
+ this.DONT_CARE = 0x1100;
+ this.FASTEST = 0x1101;
+ this.NICEST = 0x1102;
+
+ /* HintTarget */
+ this.GENERATE_MIPMAP_HINT = 0x8192;
+
+ /* DataType */
+ this.BYTE = 0x1400;
+ this.UNSIGNED_BYTE = 0x1401;
+ this.SHORT = 0x1402;
+ this.UNSIGNED_SHORT = 0x1403;
+ this.INT = 0x1404;
+ this.UNSIGNED_INT = 0x1405;
+ this.FLOAT = 0x1406;
+
+ /* PixelFormat */
+ this.DEPTH_COMPONENT = 0x1902;
+ this.ALPHA = 0x1906;
+ this.RGB = 0x1907;
+ this.RGBA = 0x1908;
+ this.LUMINANCE = 0x1909;
+ this.LUMINANCE_ALPHA = 0x190A;
+
+ /* PixelType */
+ /* UNSIGNED_BYTE */
+ this.UNSIGNED_SHORT_4_4_4_4 = 0x8033;
+ this.UNSIGNED_SHORT_5_5_5_1 = 0x8034;
+ this.UNSIGNED_SHORT_5_6_5 = 0x8363;
+
+ /* Shaders */
+ this.FRAGMENT_SHADER = 0x8B30;
+ this.VERTEX_SHADER = 0x8B31;
+ this.MAX_VERTEX_ATTRIBS = 0x8869;
+ this.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
+ this.MAX_VARYING_VECTORS = 0x8DFC;
+ this.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
+ this.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
+ this.MAX_TEXTURE_IMAGE_UNITS = 0x8872;
+ this.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
+ this.SHADER_TYPE = 0x8B4F;
+ this.DELETE_STATUS = 0x8B80;
+ this.LINK_STATUS = 0x8B82;
+ this.VALIDATE_STATUS = 0x8B83;
+ this.ATTACHED_SHADERS = 0x8B85;
+ this.ACTIVE_UNIFORMS = 0x8B86;
+ this.ACTIVE_ATTRIBUTES = 0x8B89;
+ this.SHADING_LANGUAGE_VERSION = 0x8B8C;
+ this.CURRENT_PROGRAM = 0x8B8D;
+
+ /* StencilFunction */
+ this.NEVER = 0x0200;
+ this.LESS = 0x0201;
+ this.EQUAL = 0x0202;
+ this.LEQUAL = 0x0203;
+ this.GREATER = 0x0204;
+ this.NOTEQUAL = 0x0205;
+ this.GEQUAL = 0x0206;
+ this.ALWAYS = 0x0207;
+
+ /* StencilOp */
+ /* ZERO */
+ this.KEEP = 0x1E00;
+ this.REPLACE = 0x1E01;
+ this.INCR = 0x1E02;
+ this.DECR = 0x1E03;
+ this.INVERT = 0x150A;
+ this.INCR_WRAP = 0x8507;
+ this.DECR_WRAP = 0x8508;
+
+ /* StringName */
+ this.VENDOR = 0x1F00;
+ this.RENDERER = 0x1F01;
+ this.VERSION = 0x1F02;
+
+ /* TextureMagFilter */
+ this.NEAREST = 0x2600;
+ this.LINEAR = 0x2601;
+
+ /* TextureMinFilter */
+ /* NEAREST */
+ /* LINEAR */
+ this.NEAREST_MIPMAP_NEAREST = 0x2700;
+ this.LINEAR_MIPMAP_NEAREST = 0x2701;
+ this.NEAREST_MIPMAP_LINEAR = 0x2702;
+ this.LINEAR_MIPMAP_LINEAR = 0x2703;
+
+ /* TextureParameterName */
+ this.TEXTURE_MAG_FILTER = 0x2800;
+ this.TEXTURE_MIN_FILTER = 0x2801;
+ this.TEXTURE_WRAP_S = 0x2802;
+ this.TEXTURE_WRAP_T = 0x2803;
+
+ /* TextureTarget */
+ this.TEXTURE_2D = 0x0DE1;
+ this.TEXTURE = 0x1702;
+
+ this.TEXTURE_CUBE_MAP = 0x8513;
+ this.TEXTURE_BINDING_CUBE_MAP = 0x8514;
+ this.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
+ this.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
+ this.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
+ this.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
+ this.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
+ this.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
+ this.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
+
+ /* TextureUnit */
+ this.TEXTURE0 = 0x84C0;
+ this.TEXTURE1 = 0x84C1;
+ this.TEXTURE2 = 0x84C2;
+ this.TEXTURE3 = 0x84C3;
+ this.TEXTURE4 = 0x84C4;
+ this.TEXTURE5 = 0x84C5;
+ this.TEXTURE6 = 0x84C6;
+ this.TEXTURE7 = 0x84C7;
+ this.TEXTURE8 = 0x84C8;
+ this.TEXTURE9 = 0x84C9;
+ this.TEXTURE10 = 0x84CA;
+ this.TEXTURE11 = 0x84CB;
+ this.TEXTURE12 = 0x84CC;
+ this.TEXTURE13 = 0x84CD;
+ this.TEXTURE14 = 0x84CE;
+ this.TEXTURE15 = 0x84CF;
+ this.TEXTURE16 = 0x84D0;
+ this.TEXTURE17 = 0x84D1;
+ this.TEXTURE18 = 0x84D2;
+ this.TEXTURE19 = 0x84D3;
+ this.TEXTURE20 = 0x84D4;
+ this.TEXTURE21 = 0x84D5;
+ this.TEXTURE22 = 0x84D6;
+ this.TEXTURE23 = 0x84D7;
+ this.TEXTURE24 = 0x84D8;
+ this.TEXTURE25 = 0x84D9;
+ this.TEXTURE26 = 0x84DA;
+ this.TEXTURE27 = 0x84DB;
+ this.TEXTURE28 = 0x84DC;
+ this.TEXTURE29 = 0x84DD;
+ this.TEXTURE30 = 0x84DE;
+ this.TEXTURE31 = 0x84DF;
+ this.ACTIVE_TEXTURE = 0x84E0;
+
+ /* TextureWrapMode */
+ this.REPEAT = 0x2901;
+ this.CLAMP_TO_EDGE = 0x812F;
+ this.MIRRORED_REPEAT = 0x8370;
+
+ /* Uniform Types */
+ this.FLOAT_VEC2 = 0x8B50;
+ this.FLOAT_VEC3 = 0x8B51;
+ this.FLOAT_VEC4 = 0x8B52;
+ this.INT_VEC2 = 0x8B53;
+ this.INT_VEC3 = 0x8B54;
+ this.INT_VEC4 = 0x8B55;
+ this.BOOL = 0x8B56;
+ this.BOOL_VEC2 = 0x8B57;
+ this.BOOL_VEC3 = 0x8B58;
+ this.BOOL_VEC4 = 0x8B59;
+ this.FLOAT_MAT2 = 0x8B5A;
+ this.FLOAT_MAT3 = 0x8B5B;
+ this.FLOAT_MAT4 = 0x8B5C;
+ this.SAMPLER_2D = 0x8B5E;
+ this.SAMPLER_CUBE = 0x8B60;
+
+ /* Vertex Arrays */
+ this.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622;
+ this.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623;
+ this.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624;
+ this.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625;
+ this.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A;
+ this.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645;
+ this.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
+
+ /* Read Format */
+ this.IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A;
+ this.IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B;
+
+ /* Shader Source */
+ this.COMPILE_STATUS = 0x8B81;
+
+ /* Shader Precision-Specified Types */
+ this.LOW_FLOAT = 0x8DF0;
+ this.MEDIUM_FLOAT = 0x8DF1;
+ this.HIGH_FLOAT = 0x8DF2;
+ this.LOW_INT = 0x8DF3;
+ this.MEDIUM_INT = 0x8DF4;
+ this.HIGH_INT = 0x8DF5;
+
+ /* Framebuffer Object. */
+ this.FRAMEBUFFER = 0x8D40;
+ this.RENDERBUFFER = 0x8D41;
+
+ this.RGBA4 = 0x8056;
+ this.RGB5_A1 = 0x8057;
+ this.RGB565 = 0x8D62;
+ this.DEPTH_COMPONENT16 = 0x81A5;
+ this.STENCIL_INDEX = 0x1901;
+ this.STENCIL_INDEX8 = 0x8D48;
+ this.DEPTH_STENCIL = 0x84F9;
+
+ this.RENDERBUFFER_WIDTH = 0x8D42;
+ this.RENDERBUFFER_HEIGHT = 0x8D43;
+ this.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44;
+ this.RENDERBUFFER_RED_SIZE = 0x8D50;
+ this.RENDERBUFFER_GREEN_SIZE = 0x8D51;
+ this.RENDERBUFFER_BLUE_SIZE = 0x8D52;
+ this.RENDERBUFFER_ALPHA_SIZE = 0x8D53;
+ this.RENDERBUFFER_DEPTH_SIZE = 0x8D54;
+ this.RENDERBUFFER_STENCIL_SIZE = 0x8D55;
+
+ this.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0;
+ this.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1;
+ this.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2;
+ this.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+
+ this.COLOR_ATTACHMENT0 = 0x8CE0;
+ this.DEPTH_ATTACHMENT = 0x8D00;
+ this.STENCIL_ATTACHMENT = 0x8D20;
+ this.DEPTH_STENCIL_ATTACHMENT = 0x821A;
+
+ this.NONE = 0;
+
+ this.FRAMEBUFFER_COMPLETE = 0x8CD5;
+ this.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
+ this.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+ this.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
+ this.FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
+
+ this.FRAMEBUFFER_BINDING = 0x8CA6;
+ this.RENDERBUFFER_BINDING = 0x8CA7;
+ this.MAX_RENDERBUFFER_SIZE = 0x84E8;
+
+ this.INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+
+ /* WebGL-specific enums */
+ this.UNPACK_FLIP_Y_WEBGL = 0x9240;
+ this.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
+ this.CONTEXT_LOST_WEBGL = 0x9242;
+ this.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+ this.BROWSER_DEFAULT_WEBGL = 0x9244;
+
+ //==========
+ // Functions
+ //==========
+
+ var that = this;
+
+ // Helpers
+
+ this.onmessage = function(msg) {
+ //dump('worker GL got ' + JSON.stringify(msg) + '\n');
+ switch(msg.op) {
+ case 'setPrefetched': {
+ WebGLWorker.prototype.prefetchedParameters = msg.parameters;
+ WebGLWorker.prototype.prefetchedExtensions = msg.extensions;
+ WebGLWorker.prototype.prefetchedPrecisions = msg.precisions;
+ removeRunDependency('gl-prefetch');
+ break;
+ }
+ default: throw 'weird gl onmessage ' + JSON.stringify(msg);
+ }
+ };
+
+ function revname(name) {
+ for (var x in that) if (that[x] === name) return x;
+ return null;
+ }
+
+ // GL
+
+ this.getParameter = function(name) {
+ assert(name);
+ if (name in this.prefetchedParameters) return this.prefetchedParameters[name];
+ switch (name) {
+ case this.TEXTURE_BINDING_2D: {
+ return bindings.texture2D;
+ }
+ case this.ARRAY_BUFFER_BINDING: {
+ return bindings.arrayBuffer;
+ }
+ case this.ELEMENT_ARRAY_BUFFER_BINDING: {
+ return bindings.elementArrayBuffer;
+ }
+ case this.CURRENT_PROGRAM: {
+ return bindings.program;
+ }
+ default: throw 'TODO: get parameter ' + name + ' : ' + revname(name);
+ }
+ };
+ this.getExtension = function(name) {
+ var i = this.prefetchedExtensions.indexOf(name);
+ if (i < 0) return null;
+ commandBuffer.push(1, name);
+ switch (name) {
+ case 'EXT_texture_filter_anisotropic':
+ case 'MOZ_EXT_texture_filter_anisotropic':
+ case 'WEBKIT_EXT_texture_filter_anisotropic': {
+ return {
+ TEXTURE_MAX_ANISOTROPY_EXT: 0x84FE,
+ MAX_TEXTURE_MAX_ANISOTROPY_EXT: 0x84FF
+ };
+ }
+ case 'OES_standard_derivatives':
+ case 'MOZ_OES_standard_derivatives':
+ case 'WEBKIT_OES_standard_derivatives': {
+ return { FRAGMENT_SHADER_DERIVATIVE_HINT_OES: 0x8B8B };
+ }
+ };
+ return true; // TODO: return an object here
+ };
+ this.getSupportedExtensions = function() {
+ return this.prefetchedExtensions;
+ };
+ this.getShaderPrecisionFormat = function(shaderType, precisionType) {
+ return this.prefetchedPrecisions[shaderType][precisionType];
+ };
+ this.enable = function(cap) {
+ commandBuffer.push(2, cap);
+ };
+ this.disable = function(cap) {
+ commandBuffer.push(3, cap);
+ };
+ this.clear = function(mask) {
+ commandBuffer.push(4, mask);
+ };
+ this.clearColor = function(r, g, b, a) {
+ commandBuffer.push(5, r, g, b, a);
+ };
+ this.createShader = function(type) {
+ var id = nextId++;
+ commandBuffer.push(6, type, id);
+ return { id: id, what: 'shader', type: type };
+ };
+ this.deleteShader = function(shader) {
+ if (!shader) return;
+ commandBuffer.push(7, shader.id);
+ };
+ this.shaderSource = function(shader, source) {
+ shader.source = source;
+ commandBuffer.push(8, shader.id, source);
+ };
+ this.compileShader = function(shader) {
+ commandBuffer.push(9, shader.id);
+ };
+ this.getShaderInfoLog = function(shader) {
+ return ''; // optimistic assumption of success; no proxying
+ };
+ this.createProgram = function() {
+ var id = nextId++;
+ commandBuffer.push(10, id);
+ return new WebGLProgram(id);
+ };
+ this.deleteProgram = function(program) {
+ if (!program) return;
+ commandBuffer.push(11, program.id);
+ };
+ this.attachShader = function(program, shader) {
+ program.shaders.push(shader);
+ commandBuffer.push(12, program.id, shader.id);
+ };
+ this.bindAttribLocation = function(program, index, name) {
+ program.attributes[name] = { what: 'attribute', name: name, size: -1, location: index, type: '?' }; // fill in size, type later
+ program.attributeVec[index] = name;
+ commandBuffer.push(13, program.id, index, name);
+ };
+ this.getAttribLocation = function(program, name) {
+ // all existing attribs are cached locally
+ if (name in program.attributes) return program.attributes[name].location;
+ return -1;
+ };
+ this.linkProgram = function(program) {
+ // parse shader sources
+ function getTypeId(text) {
+ switch (text) {
+ case 'bool': return that.BOOL;
+ case 'int': return that.INT;
+ case 'uint': return that.UNSIGNED_INT;
+ case 'float': return that.FLOAT;
+ case 'vec2': return that.FLOAT_VEC2;
+ case 'vec3': return that.FLOAT_VEC3;
+ case 'vec4': return that.FLOAT_VEC4;
+ case 'ivec2': return that.INT_VEC2;
+ case 'ivec3': return that.INT_VEC3;
+ case 'ivec4': return that.INT_VEC4;
+ case 'bvec2': return that.BOOL_VEC2;
+ case 'bvec3': return that.BOOL_VEC3;
+ case 'bvec4': return that.BOOL_VEC4;
+ case 'mat2': return that.FLOAT_MAT2;
+ case 'mat3': return that.FLOAT_MAT3;
+ case 'mat4': return that.FLOAT_MAT4;
+ case 'sampler2D': return that.SAMPLER_2D;
+ case 'samplerCube': return that.SAMPLER_CUBE;
+ default: throw 'not yet recognized type text: ' + text;
+ }
+ }
+ function parseElementType(shader, type, obj, vec) {
+ var source = shader.source;
+ source = source.replace(/\n/g, '|\n'); // barrier between lines, to make regexing easier
+ var newItems = source.match(new RegExp(type + '\\s+\\w+\\s+[\\w,\\s\[\\]]+;', 'g'));
+ if (!newItems) return;
+ newItems.forEach(function(item) {
+ var m = new RegExp(type + '\\s+(\\w+)\\s+([\\w,\\s\[\\]]+);').exec(item);
+ assert(m);
+ m[2].split(',').map(function(name) { name = name.trim(); return name.search(/\s/) >= 0 ? '' : name }).filter(function(name) { return !!name }).forEach(function(name) {
+ var size = 1;
+ var open = name.indexOf('[');
+ var fullname = name;
+ if (open >= 0) {
+ var close = name.indexOf(']');
+ size = parseInt(name.substring(open+1, close));
+ name = name.substr(0, open);
+ fullname = name + '[0]';
+ }
+ if (!obj[name]) {
+ obj[name] = { what: type, name: fullname, size: size, location: -1, type: getTypeId(m[1]) };
+ if (vec) vec.push(name);
+ }
+ });
+ });
+ }
+
+ program.uniforms = {};
+ program.uniformVec = [];
+
+ var existingAttributes = {};
+
+ program.shaders.forEach(function(shader) {
+ parseElementType(shader, 'uniform', program.uniforms, program.uniformVec);
+ parseElementType(shader, 'attribute', existingAttributes, null);
+ });
+
+ // bind not-yet bound attributes
+ for (var attr in existingAttributes) {
+ if (!(attr in program.attributes)) {
+ var index = program.attributeVec.length;
+ this.bindAttribLocation(program, index, attr);
+ }
+ program.attributes[attr].size = existingAttributes[attr].size;
+ program.attributes[attr].type = existingAttributes[attr].type;
+ }
+
+ commandBuffer.push(14, program.id);
+ };
+ this.getProgramParameter = function(program, name) {
+ switch (name) {
+ case this.ACTIVE_UNIFORMS: return program.uniformVec.length;
+ case this.ACTIVE_ATTRIBUTES: return program.attributeVec.length;
+ case this.LINK_STATUS: {
+ // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow
+ commandBuffer.push(15, program.id, name);
+ return true;
+ }
+ default: throw 'bad getProgramParameter ' + revname(name);
+ }
+ };
+ this.getActiveAttrib = function(program, index) {
+ var name = program.attributeVec[index];
+ if (!name) return null;
+ return program.attributes[name];
+ };
+ this.getActiveUniform = function(program, index) {
+ var name = program.uniformVec[index];
+ if (!name) return null;
+ return program.uniforms[name];
+ };
+ this.getUniformLocation = function(program, name) {
+ var fullname = name;
+ var index = -1;
+ var open = name.indexOf('[');
+ if (open >= 0) {
+ var close = name.indexOf(']');
+ index = parseInt(name.substring(open+1, close));
+ name = name.substr(0, open);
+ }
+ if (!(name in program.uniforms)) return null;
+ var id = nextId++;
+ commandBuffer.push(16, program.id, fullname, id);
+ return { what: 'location', uniform: program.uniforms[name], id: id, index: index };
+ };
+ this.getProgramInfoLog = function(shader) {
+ return ''; // optimistic assumption of success; no proxying
+ };
+ this.useProgram = function(program) {
+ commandBuffer.push(17, program ? program.id : 0);
+ bindings.program = program;
+ };
+ this.uniform1i = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(18, location.id, data);
+ };
+ this.uniform1f = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(19, location.id, data);
+ };
+ this.uniform3fv = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(20, location.id, new Float32Array(data));
+ };
+ this.uniform4fv = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(21, location.id, new Float32Array(data));
+ };
+ this.uniformMatrix4fv = function(location, transpose, data) {
+ if (!location) return;
+ commandBuffer.push(22, location.id, transpose, new Float32Array(data));
+ };
+ this.vertexAttrib4fv = function(index, values) {
+ commandBuffer.push(23, index, new Float32Array(values));
+ };
+ this.createBuffer = function() {
+ var id = nextId++;
+ commandBuffer.push(24, id);
+ return new WebGLBuffer(id);
+ };
+ this.deleteBuffer = function(buffer) {
+ if (!buffer) return;
+ commandBuffer.push(25, buffer.id);
+ };
+ this.bindBuffer = function(target, buffer) {
+ commandBuffer.push(26, target, buffer ? buffer.id : 0);
+ switch (target) {
+ case this.ARRAY_BUFFER_BINDING: {
+ bindings.arrayBuffer = buffer;
+ break;
+ }
+ case this.ELEMENT_ARRAY_BUFFER_BINDING: {
+ bindings.elementArrayBuffer = buffer;
+ break;
+ }
+ }
+ };
+ function duplicate(something) {
+ // clone data properly: handles numbers, null, typed arrays, js arrays and array buffers
+ if (!something || typeof something === 'number') return something;
+ if (something.slice) return something.slice(0); // ArrayBuffer or js array
+ return new something.constructor(something); // typed array
+ }
+ this.bufferData = function(target, something, usage) {
+ commandBuffer.push(27, target, duplicate(something), usage);
+ };
+ this.bufferSubData = function(target, offset, something) {
+ commandBuffer.push(28, target, offset, duplicate(something));
+ };
+ this.viewport = function(x, y, w, h) {
+ commandBuffer.push(29, x, y, w, h);
+ };
+ this.vertexAttribPointer = function(index, size, type, normalized, stride, offset) {
+ commandBuffer.push(30, index, size, type, normalized, stride, offset);
+ };
+ this.enableVertexAttribArray = function(index) {
+ commandBuffer.push(31, index);
+ };
+ this.disableVertexAttribArray = function(index) {
+ commandBuffer.push(32, index);
+ };
+ this.drawArrays = function(mode, first, count) {
+ commandBuffer.push(33, mode, first, count);
+ };
+ this.drawElements = function(mode, count, type, offset) {
+ commandBuffer.push(34, mode, count, type, offset);
+ };
+ this.getError = function() {
+ // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow
+ commandBuffer.push(35);
+ return this.NO_ERROR;
+ };
+ this.createTexture = function() {
+ var id = nextId++;
+ commandBuffer.push(36, id);
+ return new WebGLTexture(id);
+ };
+ this.deleteTexture = function(texture) {
+ if (!texture) return;
+ commandBuffer.push(37, texture.id);
+ texture.id = 0;
+ };
+ this.isTexture = function(texture) {
+ return texture && texture.what === 'texture' && texture.id > 0 && texture.binding;
+ };
+ this.bindTexture = function(target, texture) {
+ switch (target) {
+ case that.TEXTURE_2D: {
+ bindings.texture2D = texture;
+ break;
+ }
+ }
+ texture.binding = target;
+ commandBuffer.push(38, target, texture ? texture.id : 0);
+ };
+ this.texParameteri = function(target, pname, param) {
+ commandBuffer.push(39, target, pname, param);
+ };
+ this.texImage2D = function(target, level, internalformat, width, height, border, format, type, pixels) {
+ if (pixels === undefined) {
+ format = width; // width, height, border do not exist in the shorter overload
+ type = height;
+ pixels = border;
+ assert(pixels instanceof Image);
+ assert(internalformat === format && format === this.RGBA); // HTML Images are RGBA, 8-bit
+ assert(type === this.UNSIGNED_BYTE);
+ var data = pixels.data;
+ width = data.width;
+ height = data.height;
+ border = 0;
+ pixels = new Uint8Array(data.data); // XXX transform from clamped to normal, could have been done in duplicate
+ }
+ commandBuffer.push(40, target, level, internalformat, width, height, border, format, type, duplicate(pixels));
+ };
+ this.compressedTexImage2D = function(target, level, internalformat, width, height, border, pixels) {
+ commandBuffer.push(41, target, level, internalformat, width, height, border, duplicate(pixels));
+ };
+ this.activeTexture = function(texture) {
+ commandBuffer.push(42, texture);
+ };
+ this.getShaderParameter = function(shader, pname) {
+ switch (pname) {
+ case this.SHADER_TYPE: return shader.type;
+ case this.COMPILE_STATUS: {
+ // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow
+ commandBuffer.push(43, shader.id, pname);
+ return true;
+ }
+ default: throw 'unsupported getShaderParameter ' + pname;
+ }
+ };
+ this.clearDepth = function(depth) {
+ commandBuffer.push(44, depth);
+ };
+ this.depthFunc = function(depth) {
+ commandBuffer.push(45, depth);
+ };
+ this.frontFace = function(depth) {
+ commandBuffer.push(46, depth);
+ };
+ this.cullFace = function(depth) {
+ commandBuffer.push(47, depth);
+ };
+ this.readPixels = function(depth) {
+ abort('readPixels is impossible, we are async GL');
+ };
+ this.pixelStorei = function(pname, param) {
+ commandBuffer.push(48, pname, param);
+ };
+ this.depthMask = function(flag) {
+ commandBuffer.push(49, flag);
+ };
+ this.depthRange = function(near, far) {
+ commandBuffer.push(50, near, far);
+ };
+ this.blendFunc = function(sfactor, dfactor) {
+ commandBuffer.push(51, sfactor, dfactor);
+ };
+ this.scissor = function(x, y, width, height) {
+ commandBuffer.push(52, x, y, width, height);
+ };
+ this.colorMask = function(red, green, blue, alpha) {
+ commandBuffer.push(53, red, green, blue, alpha);
+ };
+ this.lineWidth = function(width) {
+ commandBuffer.push(54, width);
+ };
+ this.createFramebuffer = function() {
+ var id = nextId++;
+ commandBuffer.push(55, id);
+ return new WebGLFramebuffer(id);
+ };
+ this.deleteFramebuffer = function(framebuffer) {
+ if (!framebuffer) return;
+ commandBuffer.push(56, framebuffer.id);
+ };
+ this.bindFramebuffer = function(target, framebuffer) {
+ commandBuffer.push(57, target, framebuffer ? framebuffer.id : 0);
+ };
+ this.framebufferTexture2D = function(target, attachment, textarget, texture, level) {
+ commandBuffer.push(58, target, attachment, textarget, texture ? texture.id : 0, level);
+ };
+ this.checkFramebufferStatus = function(target) {
+ return this.FRAMEBUFFER_COMPLETE; // XXX totally wrong
+ };
+ this.createRenderbuffer = function() {
+ var id = nextId++;
+ commandBuffer.push(59, id);
+ return new WebGLRenderbuffer(id);
+ };
+ this.deleteRenderbuffer = function(renderbuffer) {
+ if (!renderbuffer) return;
+ commandBuffer.push(60, renderbuffer.id);
+ };
+ this.bindRenderbuffer = function(target, renderbuffer) {
+ commandBuffer.push(61, target, renderbuffer ? renderbuffer.id : 0);
+ };
+ this.renderbufferStorage = function(target, internalformat, width, height) {
+ commandBuffer.push(62, target, internalformat, width, height);
+ };
+ this.framebufferRenderbuffer = function(target, attachment, renderbuffertarget, renderbuffer) {
+ commandBuffer.push(63, target, attachment, renderbuffertarget, renderbuffer ? renderbuffer.id : 0);
+ };
+ this.debugPrint = function(text) { // useful to interleave debug output properly with client GL commands
+ commandBuffer.push(64, text);
+ };
+ this.hint = function(target, mode) {
+ commandBuffer.push(65, target, mode);
+ };
+ this.blendEquation = function(mode) {
+ commandBuffer.push(66, mode);
+ };
+ this.generateMipmap = function(target) {
+ commandBuffer.push(67, target);
+ };
+ this.uniformMatrix3fv = function(location, transpose, data) {
+ if (!location) return;
+ commandBuffer.push(68, location.id, transpose, new Float32Array(data));
+ };
+
+ // Setup
+
+ var theoreticalTracker = new FPSTracker('server (theoretical)');
+ var throttledTracker = new FPSTracker('server (client-throttled)');
+
+ function preRAF() {
+ //theoreticalTracker.tick();
+ // if too many frames in queue, skip a main loop iter
+ if (Math.abs(frameId - clientFrameId) >= 4) {
+ return false;
+ }
+ //throttledTracker.tick();
+ }
+
+ function postRAF() {
+ if (commandBuffer.length > 0) {
+ postMessage({ target: 'gl', op: 'render', commandBuffer: commandBuffer });
+ commandBuffer = [];
+ }
+ }
+
+ assert(!Browser.doSwapBuffers);
+ Browser.doSwapBuffers = postRAF;
+
+ var trueRAF = window.requestAnimationFrame;
+ window.requestAnimationFrame = function(func) {
+ trueRAF(function() {
+ if (preRAF() === false) {
+ window.requestAnimationFrame(func); // skip this frame, do it later
+ return;
+ }
+ func();
+ postRAF();
+ });
+ }
+
+}
+
+// share prefetched data among all instances
+
+WebGLWorker.prototype.prefetchedParameters = {};
+WebGLWorker.prototype.prefetchedExtensions = {};
+WebGLWorker.prototype.prefetchedPrecisions = {};
+
diff --git a/system/include/SDL/SDL_events.h b/system/include/SDL/SDL_events.h
index 183ea4b2..66f5c82f 100644
--- a/system/include/SDL/SDL_events.h
+++ b/system/include/SDL/SDL_events.h
@@ -615,6 +615,14 @@ extern DECLSPEC void SDLCALL SDL_DelEventWatch(SDL_EventFilter filter,
extern DECLSPEC void SDLCALL SDL_FilterEvents(SDL_EventFilter filter,
void *userdata);
+/**
+ * An Emscripten-specific extension to SDL: Some browser APIs require that they are called from within an event handler function.
+ * Allow recording a callback that will be called for each received event. This is used in place of SDL_PollEvent.
+ * Your application will be called whenever there are events available.
+ */
+extern DECLSPEC void SDLCALL emscripten_SDL_SetEventHandler(SDL_EventFilter handler,
+ void *userdata);
+
/*@{*/
#define SDL_QUERY -1
#define SDL_IGNORE 0
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index 7bc28ff6..32bf546a 100644
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -71,7 +71,7 @@ namespace emscripten {
void _embind_register_function(
const char* name,
unsigned argCount,
- TYPEID argTypes[],
+ const TYPEID argTypes[],
const char* signature,
GenericFunction invoker,
GenericFunction function);
@@ -137,7 +137,7 @@ namespace emscripten {
void _embind_register_class_constructor(
TYPEID classType,
unsigned argCount,
- TYPEID argTypes[],
+ const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
GenericFunction constructor);
@@ -146,7 +146,7 @@ namespace emscripten {
TYPEID classType,
const char* methodName,
unsigned argCount,
- TYPEID argTypes[],
+ const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
void* context,
@@ -168,7 +168,7 @@ namespace emscripten {
TYPEID classType,
const char* methodName,
unsigned argCount,
- TYPEID argTypes[],
+ const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
GenericFunction method);
@@ -413,8 +413,8 @@ namespace emscripten {
auto invoker = &Invoker<ReturnType, Args...>::invoke;
_embind_register_function(
name,
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoker),
reinterpret_cast<GenericFunction>(invoker),
reinterpret_cast<GenericFunction>(fn));
@@ -422,8 +422,8 @@ namespace emscripten {
namespace internal {
template<typename ClassType, typename... Args>
- ClassType* operator_new(Args... args) {
- return new ClassType(args...);
+ ClassType* operator_new(Args&&... args) {
+ return new ClassType(std::forward<Args>(args)...);
}
template<typename WrapperType, typename ClassType, typename... Args>
@@ -534,9 +534,7 @@ namespace emscripten {
template<typename T>
inline T* getContext(const T& t) {
// not a leak because this is called once per binding
- T* p = reinterpret_cast<T*>(malloc(sizeof(T)));
- new(p) T(t);
- return p;
+ return new T(t);
}
template<typename T>
@@ -760,6 +758,7 @@ namespace emscripten {
}
~value_object() {
+ using namespace internal;
_embind_finalize_value_object(internal::TypeID<ClassType>::get());
}
@@ -1084,7 +1083,7 @@ namespace emscripten {
class_() = delete;
- explicit class_(const char* name) {
+ EMSCRIPTEN_ALWAYS_INLINE explicit class_(const char* name) {
using namespace internal;
BaseSpecifier::template verify<ClassType>();
@@ -1111,7 +1110,7 @@ namespace emscripten {
}
template<typename PointerType>
- const class_& smart_ptr(const char* name) const {
+ EMSCRIPTEN_ALWAYS_INLINE const class_& smart_ptr(const char* name) const {
using namespace internal;
typedef smart_ptr_trait<PointerType> PointerTrait;
@@ -1141,14 +1140,14 @@ namespace emscripten {
};
template<typename... ConstructorArgs, typename... Policies>
- const class_& constructor(Policies... policies) const {
+ EMSCRIPTEN_ALWAYS_INLINE const class_& constructor(Policies... policies) const {
return constructor(
&internal::operator_new<ClassType, ConstructorArgs...>,
policies...);
}
template<typename... Args, typename ReturnType, typename... Policies>
- const class_& constructor(ReturnType (*factory)(Args...), Policies...) const {
+ EMSCRIPTEN_ALWAYS_INLINE const class_& constructor(ReturnType (*factory)(Args...), Policies...) const {
using namespace internal;
// TODO: allows all raw pointers... policies need a rethink
@@ -1156,8 +1155,8 @@ namespace emscripten {
auto invoke = &Invoker<ReturnType, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(factory));
@@ -1165,7 +1164,7 @@ namespace emscripten {
}
template<typename SmartPtr, typename... Args, typename... Policies>
- const class_& smart_ptr_constructor(const char* smartPtrName, SmartPtr (*factory)(Args...), Policies...) const {
+ EMSCRIPTEN_ALWAYS_INLINE const class_& smart_ptr_constructor(const char* smartPtrName, SmartPtr (*factory)(Args...), Policies...) const {
using namespace internal;
smart_ptr<SmartPtr>(smartPtrName);
@@ -1174,8 +1173,8 @@ namespace emscripten {
auto invoke = &Invoker<SmartPtr, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(factory));
@@ -1183,7 +1182,7 @@ namespace emscripten {
}
template<typename WrapperType, typename PointerType = WrapperType*, typename... ConstructorArgs>
- const class_& allow_subclass(
+ EMSCRIPTEN_ALWAYS_INLINE const class_& allow_subclass(
const char* wrapperClassName,
const char* pointerName = "<UnknownPointerName>",
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<ConstructorArgs...>()
@@ -1209,7 +1208,7 @@ namespace emscripten {
}
template<typename WrapperType, typename... ConstructorArgs>
- const class_& allow_subclass(
+ EMSCRIPTEN_ALWAYS_INLINE const class_& allow_subclass(
const char* wrapperClassName,
::emscripten::constructor<ConstructorArgs...> constructor
) const {
@@ -1226,8 +1225,8 @@ namespace emscripten {
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoker),
reinterpret_cast<GenericFunction>(invoker),
getContext(memberFunction),
@@ -1245,8 +1244,8 @@ namespace emscripten {
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoker),
reinterpret_cast<GenericFunction>(invoker),
getContext(memberFunction),
@@ -1263,8 +1262,8 @@ namespace emscripten {
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
getContext(function),
@@ -1362,8 +1361,8 @@ namespace emscripten {
_embind_register_class_class_function(
TypeID<ClassType>::get(),
methodName,
- args.count,
- args.types,
+ args.getCount(),
+ args.getTypes(),
getSignature(invoke),
reinterpret_cast<internal::GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(classMethod));
@@ -1466,6 +1465,7 @@ namespace emscripten {
typedef EnumType enum_type;
enum_(const char* name) {
+ using namespace internal;
_embind_register_enum(
internal::TypeID<EnumType>::get(),
name,
@@ -1474,6 +1474,7 @@ namespace emscripten {
}
enum_& value(const char* name, EnumType value) {
+ using namespace internal;
// TODO: there's still an issue here.
// if EnumType is an unsigned long, then JS may receive it as a signed long
static_assert(sizeof(value) <= sizeof(internal::GenericEnumValue), "enum type must fit in a GenericEnumValue");
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index d669938d..7533be8c 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -14,10 +14,45 @@
extern "C" {
#endif
+#include <stdio.h>
+
#if !__EMSCRIPTEN__
#include <SDL/SDL.h> /* for SDL_Delay in async_call */
#endif
+
+/* Typedefs */
+
+/*
+ * Unaligned types, helpful to force LLVM to emit unaligned
+ * loads/stores in places in your code where SAFE_HEAP found
+ * an unaligned operation. (It's better to avoid unaligned
+ * operations, but if you are reading from a packed stream of
+ * bytes or such, these types may be useful.)
+ */
+
+typedef short __attribute__((aligned(1))) emscripten_align1_short;
+
+typedef int __attribute__((aligned(2))) emscripten_align2_int;
+typedef int __attribute__((aligned(1))) emscripten_align1_int;
+
+typedef float __attribute__((aligned(2))) emscripten_align2_float;
+typedef float __attribute__((aligned(1))) emscripten_align1_float;
+
+typedef double __attribute__((aligned(4))) emscripten_align4_double;
+typedef double __attribute__((aligned(2))) emscripten_align2_double;
+typedef double __attribute__((aligned(1))) emscripten_align1_double;
+
+/*
+ * Function pointer types
+ */
+
+typedef void (*em_callback_func)(void);
+typedef void (*em_arg_callback_func)(void*);
+typedef void (*em_str_callback_func)(const char *);
+
+/* Functions */
+
/*
* Convenient syntax for inline assembly/js. Allows stuff like
*
@@ -27,8 +62,8 @@ extern "C" {
* does a function call to reach it). It supports newlines,
*
* EM_ASM(
- * window.alert('hai'));
- * window.alert('bai'));
+ * window.alert('hai');
+ * window.alert('bai');
* )
*
* Notes: Double-quotes (") are not supported, but you can use
@@ -97,7 +132,7 @@ extern void emscripten_async_run_script(const char *script, int millis);
* for this is to load an asset module, that is, the output of the
* file packager.
*/
-extern void emscripten_async_load_script(const char *script, void (*onload)(void), void (*onerror)(void));
+extern void emscripten_async_load_script(const char *script, em_callback_func onload, em_callback_func onerror);
/*
* Set a C function as the main event loop. The JS environment
@@ -143,8 +178,8 @@ extern void emscripten_async_load_script(const char *script, void (*onload)(void
* before the main loop will be called the first time.
*/
#if __EMSCRIPTEN__
-extern void emscripten_set_main_loop(void (*func)(void), int fps, int simulate_infinite_loop);
-extern void emscripten_set_main_loop_arg(void (*func)(void*), void *arg, int fps, int simulate_infinite_loop);
+extern void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop);
+extern void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop);
extern void emscripten_pause_main_loop(void);
extern void emscripten_resume_main_loop(void);
extern void emscripten_cancel_main_loop(void);
@@ -228,13 +263,13 @@ extern void emscripten_set_socket_close_callback(void *userData, void (*func)(in
* at specific time in the future.
*/
#if __EMSCRIPTEN__
-extern void _emscripten_push_main_loop_blocker(void (*func)(void *), void *arg, const char *name);
-extern void _emscripten_push_uncounted_main_loop_blocker(void (*func)(void *), void *arg, const char *name);
+extern void _emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name);
+extern void _emscripten_push_uncounted_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name);
#else
-inline void _emscripten_push_main_loop_blocker(void (*func)(void *), void *arg, const char *name) {
+inline void _emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name) {
func(arg);
}
-inline void _emscripten_push_uncounted_main_loop_blocker(void (*func)(void *), void *arg, const char *name) {
+inline void _emscripten_push_uncounted_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name) {
func(arg);
}
#endif
@@ -265,9 +300,9 @@ inline void emscripten_set_main_loop_expected_blockers(int num) {}
* mechanism is used.
*/
#if __EMSCRIPTEN__
-extern void emscripten_async_call(void (*func)(void *), void *arg, int millis);
+extern void emscripten_async_call(em_arg_callback_func func, void *arg, int millis);
#else
-inline void emscripten_async_call(void (*func)(void *), void *arg, int millis) {
+inline void emscripten_async_call(em_arg_callback_func func, void *arg, int millis) {
if (millis) SDL_Delay(millis);
func(arg);
}
@@ -344,7 +379,7 @@ float emscripten_random(void);
* If any error occurred 'onerror' will called.
* The callbacks are called with the file as their argument.
*/
-void emscripten_async_wget(const char* url, const char* file, void (*onload)(const char*), void (*onerror)(const char*));
+void emscripten_async_wget(const char* url, const char* file, em_str_callback_func onload, em_str_callback_func onerror);
/*
* Data version of emscripten_async_wget. Instead of writing
@@ -368,7 +403,9 @@ void emscripten_async_wget(const char* url, const char* file, void (*onload)(con
* @arg that was provided to this function.
*
*/
-void emscripten_async_wget_data(const char* url, void *arg, void (*onload)(void*, void*, int), void (*onerror)(void*));
+typedef void (*em_async_wget_onload_func)(void*, void*, int);
+
+void emscripten_async_wget_data(const char* url, void *arg, em_async_wget_onload_func onload, em_arg_callback_func onerror);
/*
* More feature-complete version of emscripten_async_wget. Note:
@@ -385,7 +422,10 @@ void emscripten_async_wget_data(const char* url, void *arg, void (*onload)(void*
* and file if is a success, the progress value during progress
* and http status code if is an error.
*/
-void emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, void (*onload)(void*, const char*), void (*onerror)(void*, int), void (*onprogress)(void*, int));
+typedef void (*em_async_wget2_onload_func)(void*, const char*);
+typedef void (*em_async_wget2_onstatus_func)(void*, int);
+
+void emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, em_async_wget2_onload_func onload, em_async_wget2_onstatus_func onerror, em_async_wget2_onstatus_func onprogress);
/*
* More feature-complete version of emscripten_async_wget_data. Note:
@@ -407,7 +447,11 @@ void emscripten_async_wget2(const char* url, const char* file, const char* requ
* If any error occurred 'onerror' will called with the HTTP status code
and a string with the status description.
*/
-void emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, void (*onload)(void*, void*, unsigned), void (*onerror)(void*, int, const char*), void (*onprogress)(void*, int, int));
+typedef void (*em_async_wget2_data_onload_func)(void*, void *, unsigned*);
+typedef void (*em_async_wget2_data_onerror_func)(void*, int, const char*);
+typedef void (*em_async_wget2_data_onprogress_func)(void*, int, int);
+
+void emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress);
/*
* Prepare a file in asynchronous way. This does just the
@@ -419,7 +463,7 @@ void emscripten_async_wget2_data(const char* url, const char* requesttype, const
* The callbacks are called with the file as their argument.
* @return 0 if successful, -1 if the file does not exist
*/
-int emscripten_async_prepare(const char* file, void (*onload)(const char*), void (*onerror)(const char*));
+int emscripten_async_prepare(const char* file, em_str_callback_func onload, em_str_callback_func onerror);
/*
* Data version of emscripten_async_prepare, which receives
@@ -435,7 +479,9 @@ int emscripten_async_prepare(const char* file, void (*onload)(const char*), void
* the fake filename.
* @suffix The file suffix, e.g. 'png' or 'jpg'.
*/
-void emscripten_async_prepare_data(char* data, int size, const char *suffix, void *arg, void (*onload)(void*, const char*), void (*onerror)(void*));
+typedef void (*em_async_prepare_data_onload_func)(void*, const char*);
+
+void emscripten_async_prepare_data(char* data, int size, const char *suffix, void *arg, em_async_prepare_data_onload_func onload, em_arg_callback_func onerror);
/*
* Worker API. Basically a wrapper around web workers, lets
@@ -484,7 +530,9 @@ void emscripten_destroy_worker(worker_handle worker);
* @callback the callback with the response (can be null)
* @arg an argument to be passed to the callback
*/
-void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, void (*callback)(char *, int, void*), void *arg);
+typedef void (*em_worker_callback_func)(char*, int, void*);
+
+void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, em_worker_callback_func callback, void *arg);
/*
* Sends a response when in a worker call. Both functions post a message
@@ -549,52 +597,25 @@ int emscripten_get_compiler_setting(const char *name);
*/
void emscripten_debugger();
-
-/* ===================================== */
-/* Internal APIs. Be careful with these. */
-/* ===================================== */
-
/*
- * Profiling tools.
- * INIT must be called first, with the maximum identifier that
- * will be used. BEGIN will add some code that marks
- * the beginning of a section of code whose run time you
- * want to measure. END will finish such a section. Note: If you
- * call begin but not end, you will get invalid data!
- * The profiling data will be written out if you call Profile.dump().
+ * Get preloaded image data and the size of the image.
+ *
+ * Returns pointer to loaded image or NULL.
+ * width/height of image are written to w/h if data is valid.
+ * Pointer should be free()'d
*/
-extern void EMSCRIPTEN_PROFILE_INIT(int max);
-extern void EMSCRIPTEN_PROFILE_BEGIN(int id);
-extern void EMSCRIPTEN_PROFILE_END(int id);
+char *emscripten_get_preloaded_image_data(const char *path, int *w, int *h);
/*
- * jcache-friendly printf. printf in general will receive a string
- * literal, which becomes a global constant, which invalidates all
- * jcache entries. emscripten_jcache_printf is parsed before
- * clang into something without any string literals, so you can
- * add such printouts to your code and only the (chunk containing
- * the) function you modify will be invalided and recompiled.
+ * Get preloaded image data from a c FILE *.
*
- * Note in particular that you need to already have a call to this
- * function in your code *before* you add one and do an incremental
- * build, so that adding an external reference does not invalidate
- * everything.
- *
- * This function assumes the first argument is a string literal
- * (otherwise you don't need it), and the other arguments, if any,
- * are neither strings nor complex expressions (but just simple
- * variables). (You can create a variable to store a complex
- * expression on the previous line, if necessary.)
+ * Returns pointer to loaded image or NULL.
+ * width/height of image are written to w/h if data is valid.
+ * Pointer should be free()'d
*/
-#ifdef __cplusplus
-void emscripten_jcache_printf(const char *format, ...);
-void emscripten_jcache_printf_(...); /* internal use */
-#endif
+char *emscripten_get_preloaded_image_data_from_FILE(FILE *file, int *w, int *h);
-/* Helper API for EM_ASM - do not call this yourself */
-void emscripten_asm_const(const char *code);
-int emscripten_asm_const_int(const char *code, ...);
-double emscripten_asm_const_double(const char *code, ...);
+/* Logging utilities */
/* If specified, logs directly to the browser console/inspector
* window. If not specified, logs via the application Module. */
@@ -660,6 +681,40 @@ void emscripten_log(int flags, ...);
*/
int emscripten_get_callstack(int flags, char *out, int maxbytes);
+
+/* ===================================== */
+/* Internal APIs. Be careful with these. */
+/* ===================================== */
+
+/*
+ * jcache-friendly printf. printf in general will receive a string
+ * literal, which becomes a global constant, which invalidates all
+ * jcache entries. emscripten_jcache_printf is parsed before
+ * clang into something without any string literals, so you can
+ * add such printouts to your code and only the (chunk containing
+ * the) function you modify will be invalided and recompiled.
+ *
+ * Note in particular that you need to already have a call to this
+ * function in your code *before* you add one and do an incremental
+ * build, so that adding an external reference does not invalidate
+ * everything.
+ *
+ * This function assumes the first argument is a string literal
+ * (otherwise you don't need it), and the other arguments, if any,
+ * are neither strings nor complex expressions (but just simple
+ * variables). (You can create a variable to store a complex
+ * expression on the previous line, if necessary.)
+ */
+#ifdef __cplusplus
+void emscripten_jcache_printf(const char *format, ...);
+void emscripten_jcache_printf_(...); /* internal use */
+#endif
+
+/* Helper API for EM_ASM - do not call this yourself */
+void emscripten_asm_const(const char *code);
+int emscripten_asm_const_int(const char *code, ...);
+double emscripten_asm_const_double(const char *code, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h
index 74c32a99..a8faee6c 100644
--- a/system/include/emscripten/html5.h
+++ b/system/include/emscripten/html5.h
@@ -12,7 +12,7 @@ extern "C" {
* - Fullscreen Events for browser canvas fullscreen modes transitioning. See https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html
* - Pointer Lock Events for relative-mode mouse motion control. See http://www.w3.org/TR/pointerlock/
* - Vibration API for mobile device haptic vibration feedback control. See http://dev.w3.org/2009/dap/vibration/
- * - Page Visibility Events for power management control. See http://www.w3c-test.org/webperf/specs/PageVisibility/
+ * - Page Visibility Events for power management control. See http://www.w3.org/TR/page-visibility/
* - Touch Events. See http://www.w3.org/TR/touch-events/
* - Gamepad API. See http://www.w3.org/TR/gamepad/
* - Beforeunload event. See http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#beforeunloadevent
@@ -198,6 +198,7 @@ typedef struct EmscriptenMouseEvent {
long movementX;
long movementY;
// Emscripten-specific extension: These fields give the mouse coordinates mapped to the Emscripten canvas client area.
+ // If the Emscripten canvas does not exist (Module.canvas element is null), then these fields will contain a value (0, 0).
long canvasX;
long canvasY;
// Pad this struct to multiple of 8 bytes to make WheelEvent unambiguously align to 8 bytes.
@@ -268,6 +269,9 @@ typedef struct EmscriptenUiEvent {
/*
* Registers a callback function for receiving DOM element resize and scroll events.
* See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-resize
+ * Note: For the resize callback, pass in target = 0 to get resize events from the Window object. The DOM3 Events spec only
+ * requires that the Window object sends resize events. It is valid to register a resize callback to other DOM elements,
+ * but the browser is not required to fire resize events on them.
*/
extern EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData));
extern EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData));
@@ -473,7 +477,7 @@ extern EMSCRIPTEN_RESULT emscripten_exit_pointerlock(void);
/*
* The event structure passed in the visibilitychange event.
- * http://www.w3c-test.org/webperf/specs/PageVisibility/
+ * http://www.w3.org/TR/page-visibility/
*/
typedef struct EmscriptenVisibilityChangeEvent {
// If true, the current browser page is now hidden.
@@ -484,7 +488,7 @@ typedef struct EmscriptenVisibilityChangeEvent {
/*
* Registers a callback function for receiving the visibilitychange event.
- * http://www.w3c-test.org/webperf/specs/PageVisibility/
+ * http://www.w3.org/TR/page-visibility/
*/
extern EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData));
/*
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
index 31f5923e..78c4b60c 100644
--- a/system/include/emscripten/val.h
+++ b/system/include/emscripten/val.h
@@ -33,7 +33,7 @@ namespace emscripten {
EM_VAL _emval_new(
EM_VAL value,
unsigned argCount,
- internal::TYPEID argTypes[],
+ const TYPEID argTypes[],
EM_VAR_ARGS argv);
EM_VAL _emval_get_global(const char* name);
@@ -45,14 +45,14 @@ namespace emscripten {
EM_VAL _emval_call(
EM_VAL value,
unsigned argCount,
- internal::TYPEID argTypes[],
+ const TYPEID argTypes[],
EM_VAR_ARGS argv);
// DO NOT call this more than once per signature. It will
// leak generated function objects!
EM_METHOD_CALLER _emval_get_method_caller(
unsigned argCount, // including return value
- internal::TYPEID argTypes[]);
+ const TYPEID argTypes[]);
EM_GENERIC_WIRE_TYPE _emval_call_method(
EM_METHOD_CALLER caller,
EM_VAL handle,
@@ -62,7 +62,7 @@ namespace emscripten {
bool _emval_has_function(
EM_VAL value,
const char* methodName,
- internal::TYPEID filter);
+ const TYPEID filter);
EM_VAL _emval_typeof(EM_VAL value);
}
@@ -91,7 +91,7 @@ namespace emscripten {
private:
static EM_METHOD_CALLER init_method_caller() {
WithPolicies<>::ArgTypeList<ReturnType, Args...> args;
- return _emval_get_method_caller(args.count, args.types);
+ return _emval_get_method_caller(args.getCount(), args.getTypes());
}
};
@@ -357,8 +357,8 @@ namespace emscripten {
return val(
_emval_new(
handle,
- argList.count,
- argList.types,
+ argList.getCount(),
+ argList.getTypes(),
argv));
}
@@ -381,8 +381,8 @@ namespace emscripten {
return val(
_emval_call(
handle,
- argList.count,
- argList.types,
+ argList.getCount(),
+ argList.getTypes(),
argv));
}
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index c20e2f55..d61b0bc7 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -27,10 +27,7 @@ namespace emscripten {
#endif
namespace internal {
- typedef void (*GenericFunction)();
-
- typedef const struct _TYPEID {}* TYPEID;
-
+ typedef const void* TYPEID;
// We don't need the full std::type_info implementation. We
// just need a unique identifier per type and polymorphic type
@@ -38,49 +35,48 @@ namespace emscripten {
template<typename T>
struct CanonicalizedID {
- static TYPEID get() {
- static _TYPEID c;
+ static char c;
+ static constexpr TYPEID get() {
return &c;
}
};
template<typename T>
+ char CanonicalizedID<T>::c;
+
+ template<typename T>
struct Canonicalized {
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
};
template<typename T>
struct LightTypeID {
- static TYPEID get() {
+ static constexpr TYPEID get() {
typedef typename Canonicalized<T>::type C;
- if (has_unbound_type_names || std::is_polymorphic<C>::value) {
- return reinterpret_cast<TYPEID>(&typeid(C));
- } else {
- return CanonicalizedID<C>::get();
- }
+ return (has_unbound_type_names || std::is_polymorphic<C>::value)
+ ? &typeid(C)
+ : CanonicalizedID<C>::get();
}
};
template<typename T>
- const TYPEID getLightTypeID(const T& value) {
+ constexpr TYPEID getLightTypeID(const T& value) {
typedef typename Canonicalized<T>::type C;
- if (has_unbound_type_names || std::is_polymorphic<C>::value) {
- return reinterpret_cast<TYPEID>(&typeid(value));
- } else {
- return LightTypeID<T>::get();
- }
+ return (has_unbound_type_names || std::is_polymorphic<C>::value)
+ ? &typeid(value)
+ : LightTypeID<T>::get();
}
template<typename T>
struct TypeID {
- static TYPEID get() {
+ static constexpr TYPEID get() {
return LightTypeID<T>::get();
}
};
template<typename T>
struct TypeID<std::unique_ptr<T>> {
- static TYPEID get() {
+ static constexpr TYPEID get() {
return TypeID<T>::get();
}
};
@@ -96,7 +92,7 @@ namespace emscripten {
template<typename T>
struct TypeID<AllowedRawPointer<T>> {
- static TYPEID get() {
+ static constexpr TYPEID get() {
return LightTypeID<T*>::get();
}
};
@@ -125,40 +121,89 @@ namespace emscripten {
};
};
- // ArgTypes<>
+ // TypeList<>
- template<int Index, typename... Args>
- struct ArgTypes;
+ template<typename...>
+ struct TypeList {};
- template<int Index>
- struct ArgTypes<Index> {
- template<typename... Policies>
- static void fill(TYPEID* argTypes) {
- }
+ // Cons :: T, TypeList<types...> -> Cons<T, types...>
+
+ template<typename First, typename TypeList>
+ struct Cons;
+
+ template<typename First, typename... Rest>
+ struct Cons<First, TypeList<Rest...>> {
+ typedef TypeList<First, Rest...> type;
+ };
+
+ // Apply :: T, TypeList<types...> -> T<types...>
+
+ template<template<typename...> class Output, typename TypeList>
+ struct Apply;
+
+ template<template<typename...> class Output, typename... Types>
+ struct Apply<Output, TypeList<Types...>> {
+ typedef Output<Types...> type;
};
- template<int Index, typename T, typename... Remaining>
- struct ArgTypes<Index, T, Remaining...> {
- template<typename... Policies>
- static void fill(TYPEID* argTypes) {
- typedef typename ExecutePolicies<Policies...>::template With<T, Index>::type TransformT;
- *argTypes = TypeID<TransformT>::get();
- return ArgTypes<Index + 1, Remaining...>::template fill<Policies...>(argTypes + 1);
+ // MapWithIndex_
+
+ template<template<size_t, typename> class Mapper, size_t CurrentIndex, typename... Args>
+ struct MapWithIndex_;
+
+ template<template<size_t, typename> class Mapper, size_t CurrentIndex, typename First, typename... Rest>
+ struct MapWithIndex_<Mapper, CurrentIndex, First, Rest...> {
+ typedef typename Cons<
+ typename Mapper<CurrentIndex, First>::type,
+ typename MapWithIndex_<Mapper, CurrentIndex + 1, Rest...>::type
+ >::type type;
+ };
+
+ template<template<size_t, typename> class Mapper, size_t CurrentIndex>
+ struct MapWithIndex_<Mapper, CurrentIndex> {
+ typedef TypeList<> type;
+ };
+
+ template<template<typename...> class Output, template<size_t, typename> class Mapper, typename... Args>
+ struct MapWithIndex {
+ typedef typename internal::Apply<
+ Output,
+ typename MapWithIndex_<Mapper, 0, Args...>::type
+ >::type type;
+ };
+
+
+ template<typename ArgList>
+ struct ArgArrayGetter;
+
+ template<typename... Args>
+ struct ArgArrayGetter<TypeList<Args...>> {
+ static const TYPEID* get() {
+ static constexpr TYPEID types[] = { TypeID<Args>::get()... };
+ return types;
}
};
// WithPolicies<...>::ArgTypeList<...>
+
template<typename... Policies>
struct WithPolicies {
+ template<size_t Index, typename T>
+ struct MapWithPolicies {
+ typedef typename ExecutePolicies<Policies...>::template With<T, Index>::type type;
+ };
+
template<typename... Args>
struct ArgTypeList {
- ArgTypeList() {
- count = sizeof...(Args);
- ArgTypes<0, Args...>::template fill<Policies...>(types);
+ unsigned getCount() const {
+ return sizeof...(Args);
}
- unsigned count;
- TYPEID types[sizeof...(Args)];
+ const TYPEID* getTypes() const {
+ return ArgArrayGetter<
+ typename MapWithIndex<TypeList, MapWithPolicies, Args...>::type
+ >::get();
+ }
};
};
@@ -293,7 +338,6 @@ namespace emscripten {
}
};
- // Is this necessary?
template<typename T>
struct GenericBindingType<std::unique_ptr<T>> {
typedef typename BindingType<T>::WireType WireType;
@@ -301,6 +345,10 @@ namespace emscripten {
static WireType toWireType(std::unique_ptr<T> p) {
return BindingType<T>::toWireType(*p);
}
+
+ static std::unique_ptr<T> fromWireType(WireType wt) {
+ return std::unique_ptr<T>(new T(std::move(BindingType<T>::fromWireType(wt))));
+ }
};
template<typename Enum>
diff --git a/system/include/libc/arpa/ftp.h b/system/include/libc/arpa/ftp.h
index 4041aeba..fb0a46f2 100644
--- a/system/include/libc/arpa/ftp.h
+++ b/system/include/libc/arpa/ftp.h
@@ -1,5 +1,5 @@
-#ifndef _ARPA_FTP_H_
-#define _ARPA_FTP_H_
+#ifndef _ARPA_FTP_H
+#define _ARPA_FTP_H
#define PRELIM 1
#define COMPLETE 2
#define CONTINUE 3
diff --git a/system/include/libc/arpa/inet.h b/system/include/libc/arpa/inet.h
index 5dcadaae..37f8c11e 100644
--- a/system/include/libc/arpa/inet.h
+++ b/system/include/libc/arpa/inet.h
@@ -20,7 +20,7 @@ int inet_pton (int, const char *__restrict, void *__restrict);
const char *inet_ntop (int, const void *__restrict, char *__restrict, socklen_t);
int inet_aton (const char *, struct in_addr *);
-struct in_addr inet_makeaddr(int, int);
+struct in_addr inet_makeaddr(in_addr_t, in_addr_t);
in_addr_t inet_lnaof(struct in_addr);
in_addr_t inet_netof(struct in_addr);
diff --git a/system/include/libc/assert.h b/system/include/libc/assert.h
index c64d3e52..fae53fc4 100644
--- a/system/include/libc/assert.h
+++ b/system/include/libc/assert.h
@@ -12,7 +12,10 @@
extern "C" {
#endif
-_Noreturn void __assert_fail (const char *, const char *, int, const char *);
+#if __EMSCRIPTEN__
+_Noreturn
+#endif
+void __assert_fail (const char *, const char *, int, const char *);
#ifdef __cplusplus
}
diff --git a/system/include/libc/bits/resource.h b/system/include/libc/bits/resource.h
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/system/include/libc/bits/resource.h
@@ -0,0 +1,2 @@
+
+
diff --git a/system/include/libc/dlfcn.h b/system/include/libc/dlfcn.h
index db26194b..78fb0733 100644
--- a/system/include/libc/dlfcn.h
+++ b/system/include/libc/dlfcn.h
@@ -31,7 +31,7 @@ typedef struct {
const char *dli_sname;
void *dli_saddr;
} Dl_info;
-int dladdr(void *, Dl_info *);
+int dladdr(const void *, Dl_info *);
int dlinfo(void *, int, void *);
#endif
diff --git a/system/include/libc/elf.h b/system/include/libc/elf.h
index 0075f9fc..4d8c0c8e 100644
--- a/system/include/libc/elf.h
+++ b/system/include/libc/elf.h
@@ -105,6 +105,7 @@ typedef struct {
#define ELFOSABI_HPUX 1
#define ELFOSABI_NETBSD 2
#define ELFOSABI_LINUX 3
+#define ELFOSABI_GNU 3
#define ELFOSABI_SOLARIS 6
#define ELFOSABI_AIX 7
#define ELFOSABI_IRIX 8
@@ -211,7 +212,11 @@ typedef struct {
#define EM_OPENRISC 92
#define EM_ARC_A5 93
#define EM_XTENSA 94
-#define EM_NUM 95
+#define EM_AARCH64 183
+#define EM_TILEPRO 188
+#define EM_MICROBLAZE 189
+#define EM_TILEGX 191
+#define EM_NUM 192
#define EM_ALPHA 0x9026
#define EV_NONE 0
@@ -487,6 +492,8 @@ typedef struct {
#define PT_HIPROC 0x7fffffff
+#define PN_XNUM 0xffff
+
#define PF_X (1 << 0)
#define PF_W (1 << 1)
@@ -512,12 +519,31 @@ typedef struct {
#define NT_LWPSTATUS 16
#define NT_LWPSINFO 17
#define NT_PRFPXREG 20
+#define NT_SIGINFO 0x53494749
+#define NT_FILE 0x46494c45
#define NT_PRXFPREG 0x46e62b7f
#define NT_PPC_VMX 0x100
#define NT_PPC_SPE 0x101
#define NT_PPC_VSX 0x102
#define NT_386_TLS 0x200
#define NT_386_IOPERM 0x201
+#define NT_X86_XSTATE 0x202
+#define NT_S390_HIGH_GPRS 0x300
+#define NT_S390_TIMER 0x301
+#define NT_S390_TODCMP 0x302
+#define NT_S390_TODPREG 0x303
+#define NT_S390_CTRS 0x304
+#define NT_S390_PREFIX 0x305
+#define NT_S390_LAST_BREAK 0x306
+#define NT_S390_SYSTEM_CALL 0x307
+#define NT_S390_TDB 0x308
+#define NT_ARM_VFP 0x400
+#define NT_ARM_TLS 0x401
+#define NT_ARM_HW_BREAK 0x402
+#define NT_ARM_HW_WATCH 0x403
+#define NT_METAG_CBUF 0x500
+#define NT_METAG_RPIPE 0x501
+#define NT_METAG_TLS 0x502
#define NT_VERSION 1
@@ -666,7 +692,15 @@ typedef struct {
#define DF_1_ENDFILTEE 0x00004000
#define DF_1_DISPRELDNE 0x00008000
#define DF_1_DISPRELPND 0x00010000
-
+#define DF_1_NODIRECT 0x00020000
+#define DF_1_IGNMULDEF 0x00040000
+#define DF_1_NOKSYMS 0x00080000
+#define DF_1_NOHDR 0x00100000
+#define DF_1_EDITED 0x00200000
+#define DF_1_NORELOC 0x00400000
+#define DF_1_SYMINTPOSE 0x00800000
+#define DF_1_GLOBAUDIT 0x01000000
+#define DF_1_SINGLETON 0x02000000
#define DTF_1_PARINIT 0x00000001
#define DTF_1_CONFEXP 0x00000002
@@ -832,6 +866,8 @@ typedef struct {
#define AT_RANDOM 25
+#define AT_HWCAP2 26
+
#define AT_EXECFN 31
@@ -979,6 +1015,7 @@ typedef struct {
#define R_386_TLS_DTPMOD32 35
#define R_386_TLS_DTPOFF32 36
#define R_386_TLS_TPOFF32 37
+#define R_386_SIZE32 38
#define R_386_TLS_GOTDESC 39
#define R_386_TLS_DESC_CALL 40
#define R_386_TLS_DESC 41
@@ -1109,20 +1146,6 @@ typedef struct {
#define DT_SPARC_NUM 2
-
-#define HWCAP_SPARC_FLUSH 1
-#define HWCAP_SPARC_STBAR 2
-#define HWCAP_SPARC_SWAP 4
-#define HWCAP_SPARC_MULDIV 8
-#define HWCAP_SPARC_V9 16
-#define HWCAP_SPARC_ULTRA3 32
-#define HWCAP_SPARC_BLKINIT 64
-#define HWCAP_SPARC_N2 128
-
-
-
-
-
#define EF_MIPS_NOREORDER 1
#define EF_MIPS_PIC 2
#define EF_MIPS_CPIC 4
@@ -1130,6 +1153,7 @@ typedef struct {
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_NAN2008 1024
#define EF_MIPS_ARCH 0xf0000000
@@ -1139,9 +1163,10 @@ typedef struct {
#define EF_MIPS_ARCH_3 0x20000000
#define EF_MIPS_ARCH_4 0x30000000
#define EF_MIPS_ARCH_5 0x40000000
-#define EF_MIPS_ARCH_32 0x60000000
-#define EF_MIPS_ARCH_64 0x70000000
-
+#define EF_MIPS_ARCH_32 0x50000000
+#define EF_MIPS_ARCH_64 0x60000000
+#define EF_MIPS_ARCH_32R2 0x70000000
+#define EF_MIPS_ARCH_64R2 0x80000000
#define E_MIPS_ARCH_1 0x00000000
@@ -1149,8 +1174,8 @@ typedef struct {
#define E_MIPS_ARCH_3 0x20000000
#define E_MIPS_ARCH_4 0x30000000
#define E_MIPS_ARCH_5 0x40000000
-#define E_MIPS_ARCH_32 0x60000000
-#define E_MIPS_ARCH_64 0x70000000
+#define E_MIPS_ARCH_32 0x50000000
+#define E_MIPS_ARCH_64 0x60000000
@@ -2020,7 +2045,8 @@ typedef Elf32_Addr Elf32_Conflict;
#define EF_ARM_VFP_FLOAT 0x400
#define EF_ARM_MAVERICK_FLOAT 0x800
-
+#define EF_ARM_ABI_FLOAT_SOFT 0x200
+#define EF_ARM_ABI_FLOAT_HARD 0x400
#define EF_ARM_SYMSARESORTED 0x04
@@ -2064,6 +2090,128 @@ typedef Elf32_Addr Elf32_Conflict;
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3)
+#define R_AARCH64_NONE 0
+#define R_AARCH64_ABS64 257
+#define R_AARCH64_ABS32 258
+#define R_AARCH64_ABS16 259
+#define R_AARCH64_PREL64 260
+#define R_AARCH64_PREL32 261
+#define R_AARCH64_PREL16 262
+#define R_AARCH64_MOVW_UABS_G0 263
+#define R_AARCH64_MOVW_UABS_G0_NC 264
+#define R_AARCH64_MOVW_UABS_G1 265
+#define R_AARCH64_MOVW_UABS_G1_NC 266
+#define R_AARCH64_MOVW_UABS_G2 267
+#define R_AARCH64_MOVW_UABS_G2_NC 268
+#define R_AARCH64_MOVW_UABS_G3 269
+#define R_AARCH64_MOVW_SABS_G0 270
+#define R_AARCH64_MOVW_SABS_G1 271
+#define R_AARCH64_MOVW_SABS_G2 272
+#define R_AARCH64_LD_PREL_LO19 273
+#define R_AARCH64_ADR_PREL_LO21 274
+#define R_AARCH64_ADR_PREL_PG_HI21 275
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276
+#define R_AARCH64_ADD_ABS_LO12_NC 277
+#define R_AARCH64_LDST8_ABS_LO12_NC 278
+#define R_AARCH64_TSTBR14 279
+#define R_AARCH64_CONDBR19 280
+#define R_AARCH64_JUMP26 282
+#define R_AARCH64_CALL26 283
+#define R_AARCH64_LDST16_ABS_LO12_NC 284
+#define R_AARCH64_LDST32_ABS_LO12_NC 285
+#define R_AARCH64_LDST64_ABS_LO12_NC 286
+#define R_AARCH64_MOVW_PREL_G0 287
+#define R_AARCH64_MOVW_PREL_G0_NC 288
+#define R_AARCH64_MOVW_PREL_G1 289
+#define R_AARCH64_MOVW_PREL_G1_NC 290
+#define R_AARCH64_MOVW_PREL_G2 291
+#define R_AARCH64_MOVW_PREL_G2_NC 292
+#define R_AARCH64_MOVW_PREL_G3 293
+#define R_AARCH64_LDST128_ABS_LO12_NC 299
+#define R_AARCH64_MOVW_GOTOFF_G0 300
+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301
+#define R_AARCH64_MOVW_GOTOFF_G1 302
+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303
+#define R_AARCH64_MOVW_GOTOFF_G2 304
+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305
+#define R_AARCH64_MOVW_GOTOFF_G3 306
+#define R_AARCH64_GOTREL64 307
+#define R_AARCH64_GOTREL32 308
+#define R_AARCH64_GOT_LD_PREL19 309
+#define R_AARCH64_LD64_GOTOFF_LO15 310
+#define R_AARCH64_ADR_GOT_PAGE 311
+#define R_AARCH64_LD64_GOT_LO12_NC 312
+#define R_AARCH64_LD64_GOTPAGE_LO15 313
+#define R_AARCH64_TLSGD_ADR_PREL21 512
+#define R_AARCH64_TLSGD_ADR_PAGE21 513
+#define R_AARCH64_TLSGD_ADD_LO12_NC 514
+#define R_AARCH64_TLSGD_MOVW_G1 515
+#define R_AARCH64_TLSGD_MOVW_G0_NC 516
+#define R_AARCH64_TLSLD_ADR_PREL21 517
+#define R_AARCH64_TLSLD_ADR_PAGE21 518
+#define R_AARCH64_TLSLD_ADD_LO12_NC 519
+#define R_AARCH64_TLSLD_MOVW_G1 520
+#define R_AARCH64_TLSLD_MOVW_G0_NC 521
+#define R_AARCH64_TLSLD_LD_PREL19 522
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527
+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540
+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541
+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542
+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543
+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548
+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559
+#define R_AARCH64_TLSDESC_LD_PREL19 560
+#define R_AARCH64_TLSDESC_ADR_PREL21 561
+#define R_AARCH64_TLSDESC_ADR_PAGE21 562
+#define R_AARCH64_TLSDESC_LD64_LO12 563
+#define R_AARCH64_TLSDESC_ADD_LO12 564
+#define R_AARCH64_TLSDESC_OFF_G1 565
+#define R_AARCH64_TLSDESC_OFF_G0_NC 566
+#define R_AARCH64_TLSDESC_LDR 567
+#define R_AARCH64_TLSDESC_ADD 568
+#define R_AARCH64_TLSDESC_CALL 569
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573
+#define R_AARCH64_COPY 1024
+#define R_AARCH64_GLOB_DAT 1025
+#define R_AARCH64_JUMP_SLOT 1026
+#define R_AARCH64_RELATIVE 1027
+#define R_AARCH64_TLS_DTPMOD64 1028
+#define R_AARCH64_TLS_DTPREL64 1029
+#define R_AARCH64_TLS_TPREL64 1030
+#define R_AARCH64_TLSDESC 1031
#define R_ARM_NONE 0
@@ -2079,7 +2227,7 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_ARM_THM_PC22 10
#define R_ARM_THM_PC8 11
#define R_ARM_AMP_VCALL9 12
-#define R_ARM_SWI24 13
+#define R_ARM_TLS_DESC 13
#define R_ARM_THM_SWI8 14
#define R_ARM_XPC25 15
#define R_ARM_THM_XPC22 16
@@ -2094,12 +2242,78 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_ARM_GOTPC 25
#define R_ARM_GOT32 26
#define R_ARM_PLT32 27
+#define R_ARM_CALL 28
+#define R_ARM_JUMP24 29
+#define R_ARM_THM_JUMP24 30
+#define R_ARM_BASE_ABS 31
#define R_ARM_ALU_PCREL_7_0 32
#define R_ARM_ALU_PCREL_15_8 33
#define R_ARM_ALU_PCREL_23_15 34
#define R_ARM_LDR_SBREL_11_0 35
#define R_ARM_ALU_SBREL_19_12 36
#define R_ARM_ALU_SBREL_27_20 37
+#define R_ARM_TARGET1 38
+#define R_ARM_SBREL31 39
+#define R_ARM_V4BX 40
+#define R_ARM_TARGET2 41
+#define R_ARM_PREL31 42
+#define R_ARM_MOVW_ABS_NC 43
+#define R_ARM_MOVT_ABS 44
+#define R_ARM_MOVW_PREL_NC 45
+#define R_ARM_MOVT_PREL 46
+#define R_ARM_THM_MOVW_ABS_NC 47
+#define R_ARM_THM_MOVT_ABS 48
+#define R_ARM_THM_MOVW_PREL_NC 49
+#define R_ARM_THM_MOVT_PREL 50
+#define R_ARM_THM_JUMP19 51
+#define R_ARM_THM_JUMP6 52
+#define R_ARM_THM_ALU_PREL_11_0 53
+#define R_ARM_THM_PC12 54
+#define R_ARM_ABS32_NOI 55
+#define R_ARM_REL32_NOI 56
+#define R_ARM_ALU_PC_G0_NC 57
+#define R_ARM_ALU_PC_G0 58
+#define R_ARM_ALU_PC_G1_NC 59
+#define R_ARM_ALU_PC_G1 60
+#define R_ARM_ALU_PC_G2 61
+#define R_ARM_LDR_PC_G1 62
+#define R_ARM_LDR_PC_G2 63
+#define R_ARM_LDRS_PC_G0 64
+#define R_ARM_LDRS_PC_G1 65
+#define R_ARM_LDRS_PC_G2 66
+#define R_ARM_LDC_PC_G0 67
+#define R_ARM_LDC_PC_G1 68
+#define R_ARM_LDC_PC_G2 69
+#define R_ARM_ALU_SB_G0_NC 70
+#define R_ARM_ALU_SB_G0 71
+#define R_ARM_ALU_SB_G1_NC 72
+#define R_ARM_ALU_SB_G1 73
+#define R_ARM_ALU_SB_G2 74
+#define R_ARM_LDR_SB_G0 75
+#define R_ARM_LDR_SB_G1 76
+#define R_ARM_LDR_SB_G2 77
+#define R_ARM_LDRS_SB_G0 78
+#define R_ARM_LDRS_SB_G1 79
+#define R_ARM_LDRS_SB_G2 80
+#define R_ARM_LDC_SB_G0 81
+#define R_ARM_LDC_SB_G1 82
+#define R_ARM_LDC_SB_G2 83
+#define R_ARM_MOVW_BREL_NC 84
+#define R_ARM_MOVT_BREL 85
+#define R_ARM_MOVW_BREL 86
+#define R_ARM_THM_MOVW_BREL_NC 87
+#define R_ARM_THM_MOVT_BREL 88
+#define R_ARM_THM_MOVW_BREL 89
+#define R_ARM_TLS_GOTDESC 90
+#define R_ARM_TLS_CALL 91
+#define R_ARM_TLS_DESCSEQ 92
+#define R_ARM_THM_TLS_CALL 93
+#define R_ARM_PLT32_ABS 94
+#define R_ARM_GOT_ABS 95
+#define R_ARM_GOT_PREL 96
+#define R_ARM_GOT_BREL12 97
+#define R_ARM_GOTOFF12 98
+#define R_ARM_GOTRELAX 99
#define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101
#define R_ARM_THM_PC11 102
@@ -2113,7 +2327,15 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_ARM_TLS_IE32 107
#define R_ARM_TLS_LE32 108
-
+#define R_ARM_TLS_LDO12 109
+#define R_ARM_TLS_LE12 110
+#define R_ARM_TLS_IE12GP 111
+#define R_ARM_ME_TOO 128
+#define R_ARM_THM_TLS_DESCSEQ 129
+#define R_ARM_THM_TLS_DESCSEQ16 129
+#define R_ARM_THM_TLS_DESCSEQ32 130
+#define R_ARM_THM_GOT_BREL12 131
+#define R_ARM_IRELATIVE 160
#define R_ARM_RXPC25 249
#define R_ARM_RSBREL32 250
#define R_ARM_THM_RPC22 251
@@ -2421,15 +2643,21 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_X86_64_PC64 24
#define R_X86_64_GOTOFF64 25
#define R_X86_64_GOTPC32 26
-
+#define R_X86_64_GOT64 27
+#define R_X86_64_GOTPCREL64 28
+#define R_X86_64_GOTPC64 29
+#define R_X86_64_GOTPLT64 30
+#define R_X86_64_PLTOFF64 31
+#define R_X86_64_SIZE32 32
+#define R_X86_64_SIZE64 33
#define R_X86_64_GOTPC32_TLSDESC 34
#define R_X86_64_TLSDESC_CALL 35
#define R_X86_64_TLSDESC 36
#define R_X86_64_IRELATIVE 37
-
-#define R_X86_64_NUM 38
+#define R_X86_64_RELATIVE64 38
+#define R_X86_64_NUM 39
diff --git a/system/include/libc/fcntl.h b/system/include/libc/fcntl.h
index b9bc2695..2d8fa6e4 100644
--- a/system/include/libc/fcntl.h
+++ b/system/include/libc/fcntl.h
@@ -59,8 +59,6 @@ int posix_fallocate(int, off_t, off_t);
#define AT_REMOVEDIR 0x200
#define AT_SYMLINK_FOLLOW 0x400
#define AT_EACCESS 0x200
-#define AT_NO_AUTOMOUNT 0x800
-#define AT_EMPTY_PATH 0x1000
#define POSIX_FADV_NORMAL 0
#define POSIX_FADV_RANDOM 1
@@ -95,6 +93,9 @@ int posix_fallocate(int, off_t, off_t);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+#define AT_NO_AUTOMOUNT 0x800
+#define AT_EMPTY_PATH 0x1000
+
#define FAPPEND O_APPEND
#define FFSYNC O_FSYNC
#define FASYNC O_ASYNC
@@ -147,6 +148,7 @@ struct f_owner_ex {
#define SPLICE_F_MORE 4
#define SPLICE_F_GIFT 8
int fallocate(int, int, off_t, off_t);
+#define fallocate64 fallocate
ssize_t readahead(int, off_t, size_t);
int sync_file_range(int, off_t, off_t, unsigned);
ssize_t vmsplice(int, const struct iovec *, size_t, unsigned);
@@ -159,6 +161,7 @@ ssize_t tee(int, int, size_t, unsigned);
#define F_GETLK64 F_GETLK
#define F_SETLK64 F_SETLK
#define F_SETLKW64 F_SETLKW
+#define flock64 flock
#define open64 open
#define openat64 openat
#define creat64 creat
diff --git a/system/include/libc/float.h b/system/include/libc/float.h
index c7b208af..2b2ad399 100644
--- a/system/include/libc/float.h
+++ b/system/include/libc/float.h
@@ -3,10 +3,10 @@
#define FLT_RADIX 2
-#define FLT_TRUE_MIN 1.40129846e-45F
-#define FLT_MIN 1.17549435e-38F
-#define FLT_MAX 3.40282347e+38F
-#define FLT_EPSILON 1.19209290e-07F
+#define FLT_TRUE_MIN 1.40129846432481707092e-45F
+#define FLT_MIN 1.17549435082228750797e-38F
+#define FLT_MAX 3.40282346638528859812e+38F
+#define FLT_EPSILON 1.1920928955078125e-07F
#define FLT_MANT_DIG 24
#define FLT_MIN_EXP (-125)
@@ -16,10 +16,10 @@
#define FLT_MIN_10_EXP (-37)
#define FLT_MAX_10_EXP 38
-#define DBL_TRUE_MIN 4.9406564584124654e-324
-#define DBL_MIN 2.2250738585072014e-308
-#define DBL_MAX 1.7976931348623157e+308
-#define DBL_EPSILON 2.2204460492503131e-16
+#define DBL_TRUE_MIN 4.94065645841246544177e-324
+#define DBL_MIN 2.22507385850720138309e-308
+#define DBL_MAX 1.79769313486231570815e+308
+#define DBL_EPSILON 2.22044604925031308085e-16
#define DBL_MANT_DIG 53
#define DBL_MIN_EXP (-1021)
diff --git a/system/include/libc/fnmatch.h b/system/include/libc/fnmatch.h
index 72345b8b..f9593217 100644
--- a/system/include/libc/fnmatch.h
+++ b/system/include/libc/fnmatch.h
@@ -5,17 +5,12 @@
extern "C" {
#endif
-#include <features.h>
-
#define FNM_PATHNAME 0x1
#define FNM_NOESCAPE 0x2
#define FNM_PERIOD 0x4
-
-#ifdef _GNU_SOURCE
#define FNM_LEADING_DIR 0x8
#define FNM_CASEFOLD 0x10
#define FNM_FILE_NAME FNM_PATHNAME
-#endif
#define FNM_NOMATCH 1
#define FNM_NOSYS (-1)
diff --git a/system/include/libc/inttypes.h b/system/include/libc/inttypes.h
index c51769fa..61dcb727 100644
--- a/system/include/libc/inttypes.h
+++ b/system/include/libc/inttypes.h
@@ -24,8 +24,10 @@ uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
#if UINTPTR_MAX == UINT64_MAX
#define __PRI64 "l"
+#define __PRIPTR "l"
#else
#define __PRI64 "ll"
+#define __PRIPTR ""
#endif
#define PRId8 "d"
@@ -125,12 +127,12 @@ uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
#define PRIxMAX __PRI64 "x"
#define PRIXMAX __PRI64 "X"
-#define PRIdPTR "ld"
-#define PRIiPTR "li"
-#define PRIoPTR "lo"
-#define PRIuPTR "lu"
-#define PRIxPTR "lx"
-#define PRIXPTR "lX"
+#define PRIdPTR __PRIPTR "d"
+#define PRIiPTR __PRIPTR "i"
+#define PRIoPTR __PRIPTR "o"
+#define PRIuPTR __PRIPTR "u"
+#define PRIxPTR __PRIPTR "x"
+#define PRIXPTR __PRIPTR "X"
#define SCNd8 "hhd"
#define SCNd16 "hd"
@@ -213,11 +215,11 @@ uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);
#define SCNuMAX __PRI64 "u"
#define SCNxMAX __PRI64 "x"
-#define SCNdPTR "ld"
-#define SCNiPTR "li"
-#define SCNoPTR "lo"
-#define SCNuPTR "lu"
-#define SCNxPTR "lx"
+#define SCNdPTR __PRIPTR "d"
+#define SCNiPTR __PRIPTR "i"
+#define SCNoPTR __PRIPTR "o"
+#define SCNuPTR __PRIPTR "u"
+#define SCNxPTR __PRIPTR "x"
#ifdef __cplusplus
}
diff --git a/system/include/libc/langinfo.h b/system/include/libc/langinfo.h
index c6349ad1..2153c42e 100644
--- a/system/include/libc/langinfo.h
+++ b/system/include/libc/langinfo.h
@@ -5,6 +5,7 @@
extern "C" {
#endif
+#include <features.h>
#include <nl_types.h>
#define __NEED_locale_t
@@ -75,8 +76,11 @@ extern "C" {
#define THOUSEP 0x10001
#define YESEXPR 0x50000
#define NOEXPR 0x50001
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define YESSTR 0x50002
#define NOSTR 0x50003
+#endif
char *nl_langinfo(nl_item);
char *nl_langinfo_l(nl_item, locale_t);
diff --git a/system/include/libc/limits.h b/system/include/libc/limits.h
index 54d1940b..f9805a1e 100644
--- a/system/include/libc/limits.h
+++ b/system/include/libc/limits.h
@@ -40,7 +40,9 @@
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define PIPE_BUF 4096
+#ifdef PAGE_SIZE
#define PAGESIZE PAGE_SIZE
+#endif
#define FILESIZEBITS 64
#define NAME_MAX 255
#define SYMLINK_MAX 255
@@ -53,7 +55,7 @@
#define WORD_BIT 32
#define SSIZE_MAX LONG_MAX
#define TZNAME_MAX 6
-#define TTY_NAME_MAX 20
+#define TTY_NAME_MAX 32
#define HOST_NAME_MAX 255
/* Implementation choices... */
@@ -82,12 +84,18 @@
#define NL_ARGMAX 9
#define NL_LANGMAX 32
#define NL_MSGMAX 32767
-#define NL_NMAX (MB_LEN_MAX*4)
#define NL_SETMAX 255
#define NL_TEXTMAX 2048
#endif
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) \
+ || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE+0 < 700)
+
+#define NL_NMAX 16
+
+#endif
+
/* POSIX/SUS requirements follow. These numbers come directly
* from SUS and have nothing to do with the host system. */
diff --git a/system/include/libc/locale.h b/system/include/libc/locale.h
index 7e80fd93..ce384381 100644
--- a/system/include/libc/locale.h
+++ b/system/include/libc/locale.h
@@ -7,7 +7,11 @@ extern "C" {
#include <features.h>
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#define LC_CTYPE 0
#define LC_NUMERIC 1
diff --git a/system/include/libc/math.h b/system/include/libc/math.h
index c029156a..6ac91da2 100644
--- a/system/include/libc/math.h
+++ b/system/include/libc/math.h
@@ -16,7 +16,7 @@ extern "C" {
#define INFINITY __builtin_inff()
#else
#define NAN (0.0f/0.0f)
-#define INFINITY 1e40f
+#define INFINITY 1e5000f
#endif
#define HUGE_VALF INFINITY
@@ -42,12 +42,14 @@ int __fpclassifyl(long double);
static __inline unsigned __FLOAT_BITS(float __f)
{
- union {float __f; unsigned __i;} __u = {__f};
+ union {float __f; unsigned __i;} __u;
+ __u.__f = __f;
return __u.__i;
}
static __inline unsigned long long __DOUBLE_BITS(double __f)
{
- union {double __f; unsigned long long __i;} __u = {__f};
+ union {double __f; unsigned long long __i;} __u;
+ __u.__f = __f;
return __u.__i;
}
@@ -91,20 +93,20 @@ int __signbitl(long double);
static __inline int __is##rel(type __x, type __y) \
{ return !isunordered(__x,__y) && __x op __y; }
-__ISREL_DEF(lessf, <, float)
-__ISREL_DEF(less, <, double)
+__ISREL_DEF(lessf, <, float_t)
+__ISREL_DEF(less, <, double_t)
__ISREL_DEF(lessl, <, long double)
-__ISREL_DEF(lessequalf, <=, float)
-__ISREL_DEF(lessequal, <=, double)
+__ISREL_DEF(lessequalf, <=, float_t)
+__ISREL_DEF(lessequal, <=, double_t)
__ISREL_DEF(lessequall, <=, long double)
-__ISREL_DEF(lessgreaterf, !=, float)
-__ISREL_DEF(lessgreater, !=, double)
+__ISREL_DEF(lessgreaterf, !=, float_t)
+__ISREL_DEF(lessgreater, !=, double_t)
__ISREL_DEF(lessgreaterl, !=, long double)
-__ISREL_DEF(greaterf, >, float)
-__ISREL_DEF(greater, >, double)
+__ISREL_DEF(greaterf, >, float_t)
+__ISREL_DEF(greater, >, double_t)
__ISREL_DEF(greaterl, >, long double)
-__ISREL_DEF(greaterequalf, >=, float)
-__ISREL_DEF(greaterequal, >=, double)
+__ISREL_DEF(greaterequalf, >=, float_t)
+__ISREL_DEF(greaterequal, >=, double_t)
__ISREL_DEF(greaterequall, >=, long double)
#define __tg_pred_2(x, y, p) ( \
@@ -349,7 +351,7 @@ long double truncl(long double);
#if defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE)
#undef MAXFLOAT
-#define MAXFLOAT 3.40282347e+38F
+#define MAXFLOAT 3.40282346638528859812e+38F
#endif
#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
@@ -379,7 +381,13 @@ double yn(int, double);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define HUGE 3.40282347e+38F
+#define HUGE 3.40282346638528859812e+38F
+
+double drem(double, double);
+float dremf(float, float);
+
+int finite(double);
+int finitef(float);
double scalb(double, double);
float scalbf(float, float);
diff --git a/system/include/libc/net/if_arp.h b/system/include/libc/net/if_arp.h
index 371ab104..18d5dcf9 100644
--- a/system/include/libc/net/if_arp.h
+++ b/system/include/libc/net/if_arp.h
@@ -52,6 +52,7 @@ struct arphdr {
#define ARPHRD_ROSE 270
#define ARPHRD_X25 271
#define ARPHRD_HWX25 272
+#define ARPHRD_CAN 280
#define ARPHRD_PPP 512
#define ARPHRD_CISCO 513
#define ARPHRD_HDLC ARPHRD_CISCO
@@ -84,7 +85,12 @@ struct arphdr {
#define ARPHRD_IEEE80211_PRISM 802
#define ARPHRD_IEEE80211_RADIOTAP 803
#define ARPHRD_IEEE802154 804
-#define ARPHRD_IEEE802154_PHY 805
+#define ARPHRD_IEEE802154_MONITOR 805
+#define ARPHRD_PHONET 820
+#define ARPHRD_PHONET_PIPE 821
+#define ARPHRD_CAIF 822
+#define ARPHRD_IP6GRE 823
+#define ARPHRD_NETLINK 824
#define ARPHRD_VOID 0xFFFF
#define ARPHRD_NONE 0xFFFE
diff --git a/system/include/libc/netdb.h b/system/include/libc/netdb.h
index 8a7013ad..dfc70e2b 100644
--- a/system/include/libc/netdb.h
+++ b/system/include/libc/netdb.h
@@ -131,9 +131,11 @@ int *__h_errno_location(void);
#define TRY_AGAIN 2
#define NO_RECOVERY 3
#define NO_DATA 4
+#define NO_ADDRESS NO_DATA
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+void herror(const char *);
const char *hstrerror(int);
int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *);
int gethostbyname2_r(const char *, int, struct hostent *, char *, size_t, struct hostent **, int *);
diff --git a/system/include/libc/netinet/if_ether.h b/system/include/libc/netinet/if_ether.h
index 17d5dabd..34f9be55 100644
--- a/system/include/libc/netinet/if_ether.h
+++ b/system/include/libc/netinet/if_ether.h
@@ -54,6 +54,7 @@
#define ETH_P_8021AH 0x88E7
#define ETH_P_MVRP 0x88F5
#define ETH_P_1588 0x88F7
+#define ETH_P_PRP 0x88FB
#define ETH_P_FCOE 0x8906
#define ETH_P_TDLS 0x890D
#define ETH_P_FIP 0x8914
diff --git a/system/include/libc/netinet/in.h b/system/include/libc/netinet/in.h
index d886fc28..ee6e19fb 100644
--- a/system/include/libc/netinet/in.h
+++ b/system/include/libc/netinet/in.h
@@ -53,6 +53,11 @@ struct ipv6_mreq
#define INADDR_NONE ((in_addr_t) 0xffffffff)
#define INADDR_LOOPBACK ((in_addr_t) 0x7f000001)
+#define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000)
+#define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001)
+#define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002)
+#define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff)
+
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
@@ -91,10 +96,12 @@ uint16_t ntohs(uint16_t);
#define IPPROTO_NONE 59
#define IPPROTO_DSTOPTS 60
#define IPPROTO_MTP 92
+#define IPPROTO_BEETPH 94
#define IPPROTO_ENCAP 98
#define IPPROTO_PIM 103
#define IPPROTO_COMP 108
#define IPPROTO_SCTP 132
+#define IPPROTO_MH 135
#define IPPROTO_UDPLITE 136
#define IPPROTO_RAW 255
#define IPPROTO_MAX 256
@@ -142,7 +149,7 @@ uint16_t ntohs(uint16_t);
(IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0xe))
#define __ARE_4_EQUAL(a,b) \
- (!( 0[a]-0[b] | 1[a]-1[b] | 2[a]-2[b] | 3[a]-3[b] ))
+ (!( (0[a]-0[b]) | (1[a]-1[b]) | (2[a]-2[b]) | (3[a]-3[b]) ))
#define IN6_ARE_ADDR_EQUAL(a,b) \
__ARE_4_EQUAL((const uint32_t *)(a), (const uint32_t *)(b))
@@ -204,27 +211,13 @@ uint16_t ntohs(uint16_t);
#define IP_MULTICAST_ALL 49
#define IP_UNICAST_IF 50
-#ifdef _GNU_SOURCE
-#define MCAST_JOIN_GROUP 42
-#define MCAST_BLOCK_SOURCE 43
-#define MCAST_UNBLOCK_SOURCE 44
-#define MCAST_LEAVE_GROUP 45
-#define MCAST_JOIN_SOURCE_GROUP 46
-#define MCAST_LEAVE_SOURCE_GROUP 47
-#define MCAST_MSFILTER 48
-
-#define MCAST_EXCLUDE 0
-#define MCAST_INCLUDE 1
-#endif
-
#define IP_RECVRETOPTS IP_RETOPTS
#define IP_PMTUDISC_DONT 0
#define IP_PMTUDISC_WANT 1
#define IP_PMTUDISC_DO 2
#define IP_PMTUDISC_PROBE 3
-
-#define SOL_IP 0
+#define IP_PMTUDISC_INTERFACE 4
#define IP_DEFAULT_MULTICAST_TTL 1
#define IP_DEFAULT_MULTICAST_LOOP 1
@@ -236,6 +229,19 @@ struct ip_opts
char ip_opts[40];
};
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+
+#define MCAST_JOIN_GROUP 42
+#define MCAST_BLOCK_SOURCE 43
+#define MCAST_UNBLOCK_SOURCE 44
+#define MCAST_LEAVE_GROUP 45
+#define MCAST_JOIN_SOURCE_GROUP 46
+#define MCAST_LEAVE_SOURCE_GROUP 47
+#define MCAST_MSFILTER 48
+
+#define MCAST_EXCLUDE 0
+#define MCAST_INCLUDE 1
+
struct ip_mreq
{
struct in_addr imr_multiaddr;
@@ -249,6 +255,45 @@ struct ip_mreqn
int imr_ifindex;
};
+struct ip_mreq_source {
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_interface;
+ struct in_addr imr_sourceaddr;
+};
+
+struct ip_msfilter {
+ struct in_addr imsf_multiaddr;
+ struct in_addr imsf_interface;
+ uint32_t imsf_fmode;
+ uint32_t imsf_numsrc;
+ struct in_addr imsf_slist[1];
+};
+#define IP_MSFILTER_SIZE(numsrc) \
+ (sizeof(struct ip_msfilter) - sizeof(struct in_addr) \
+ + (numsrc) * sizeof(struct in_addr))
+
+struct group_req {
+ uint32_t gr_interface;
+ struct sockaddr_storage gr_group;
+};
+
+struct group_source_req {
+ uint32_t gsr_interface;
+ struct sockaddr_storage gsr_group;
+ struct sockaddr_storage gsr_source;
+};
+
+struct group_filter {
+ uint32_t gf_interface;
+ struct sockaddr_storage gf_group;
+ uint32_t gf_fmode;
+ uint32_t gf_numsrc;
+ struct sockaddr_storage gf_slist[1];
+};
+#define GROUP_FILTER_SIZE(numsrc) \
+ (sizeof(struct group_filter) - sizeof(struct sockaddr_storage) \
+ + (numsrc) * sizeof(struct sockaddr_storage))
+
struct in_pktinfo
{
int ipi_ifindex;
@@ -267,6 +312,7 @@ struct ip6_mtuinfo
struct sockaddr_in6 ip6m_addr;
uint32_t ip6m_mtu;
};
+#endif
#define IPV6_ADDRFORM 1
#define IPV6_2292PKTINFO 2
@@ -276,7 +322,6 @@ struct ip6_mtuinfo
#define IPV6_2292PKTOPTIONS 6
#define IPV6_CHECKSUM 7
#define IPV6_2292HOPLIMIT 8
-#define SCM_SRCRT IPV6_RXSRCRT
#define IPV6_NEXTHOP 9
#define IPV6_AUTHHDR 10
#define IPV6_UNICAST_HOPS 16
@@ -315,15 +360,11 @@ struct ip6_mtuinfo
#define IPV6_RXHOPOPTS IPV6_HOPOPTS
#define IPV6_RXDSTOPTS IPV6_DSTOPTS
-
#define IPV6_PMTUDISC_DONT 0
#define IPV6_PMTUDISC_WANT 1
#define IPV6_PMTUDISC_DO 2
#define IPV6_PMTUDISC_PROBE 3
-#define SOL_IPV6 41
-#define SOL_ICMPV6 58
-
#define IPV6_RTHDR_LOOSE 0
#define IPV6_RTHDR_STRICT 1
diff --git a/system/include/libc/netinet/tcp.h b/system/include/libc/netinet/tcp.h
index 8266f21d..d3db0421 100644
--- a/system/include/libc/netinet/tcp.h
+++ b/system/include/libc/netinet/tcp.h
@@ -26,46 +26,155 @@
#define TCP_REPAIR_OPTIONS 22
#define TCP_FASTOPEN 23
#define TCP_TIMESTAMP 24
+#define TCP_NOTSENT_LOWAT 25
+
+#define TCP_ESTABLISHED 1
+#define TCP_SYN_SENT 2
+#define TCP_SYN_RECV 3
+#define TCP_FIN_WAIT1 4
+#define TCP_FIN_WAIT2 5
+#define TCP_TIME_WAIT 6
+#define TCP_CLOSE 7
+#define TCP_CLOSE_WAIT 8
+#define TCP_LAST_ACK 9
+#define TCP_LISTEN 10
+#define TCP_CLOSING 11
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define SOL_TCP 6
#include <sys/types.h>
#include <sys/socket.h>
-#endif
+#include <stdint.h>
+#include <endian.h>
+
+typedef uint32_t tcp_seq;
+#define TH_FIN 0x01
+#define TH_SYN 0x02
+#define TH_RST 0x04
+#define TH_PUSH 0x08
+#define TH_ACK 0x10
+#define TH_URG 0x20
+
+struct tcphdr {
#ifdef _GNU_SOURCE
-#include <endian.h>
-struct tcphdr
-{
- u_int16_t source;
- u_int16_t dest;
- u_int32_t seq;
- u_int32_t ack_seq;
+#ifdef __GNUC__
+ __extension__
+#endif
+ union { struct {
+
+ uint16_t source;
+ uint16_t dest;
+ uint32_t seq;
+ uint32_t ack_seq;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint16_t res1:4;
+ uint16_t doff:4;
+ uint16_t fin:1;
+ uint16_t syn:1;
+ uint16_t rst:1;
+ uint16_t psh:1;
+ uint16_t ack:1;
+ uint16_t urg:1;
+ uint16_t res2:2;
+#else
+ uint16_t doff:4;
+ uint16_t res1:4;
+ uint16_t res2:2;
+ uint16_t urg:1;
+ uint16_t ack:1;
+ uint16_t psh:1;
+ uint16_t rst:1;
+ uint16_t syn:1;
+ uint16_t fin:1;
+#endif
+ uint16_t window;
+ uint16_t check;
+ uint16_t urg_ptr;
+
+ }; struct {
+#endif
+
+ uint16_t th_sport;
+ uint16_t th_dport;
+ uint32_t th_seq;
+ uint32_t th_ack;
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u_int16_t res1:4;
- u_int16_t doff:4;
- u_int16_t fin:1;
- u_int16_t syn:1;
- u_int16_t rst:1;
- u_int16_t psh:1;
- u_int16_t ack:1;
- u_int16_t urg:1;
- u_int16_t res2:2;
+ uint8_t th_x2:4;
+ uint8_t th_off:4;
#else
- u_int16_t doff:4;
- u_int16_t res1:4;
- u_int16_t res2:2;
- u_int16_t urg:1;
- u_int16_t ack:1;
- u_int16_t psh:1;
- u_int16_t rst:1;
- u_int16_t syn:1;
- u_int16_t fin:1;
+ uint8_t th_off:4;
+ uint8_t th_x2:4;
+#endif
+ uint8_t th_flags;
+ uint16_t th_win;
+ uint16_t th_sum;
+ uint16_t th_urp;
+
+#ifdef _GNU_SOURCE
+ }; };
#endif
- u_int16_t window;
- u_int16_t check;
- u_int16_t urg_ptr;
};
#endif
+#ifdef _GNU_SOURCE
+#define TCPI_OPT_TIMESTAMPS 1
+#define TCPI_OPT_SACK 2
+#define TCPI_OPT_WSCALE 4
+#define TCPI_OPT_ECN 8
+
+#define TCP_CA_Open 0
+#define TCP_CA_Disorder 1
+#define TCP_CA_CWR 2
+#define TCP_CA_Recovery 3
+#define TCP_CA_Loss 4
+
+struct tcp_info
+{
+ uint8_t tcpi_state;
+ uint8_t tcpi_ca_state;
+ uint8_t tcpi_retransmits;
+ uint8_t tcpi_probes;
+ uint8_t tcpi_backoff;
+ uint8_t tcpi_options;
+ uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+ uint32_t tcpi_rto;
+ uint32_t tcpi_ato;
+ uint32_t tcpi_snd_mss;
+ uint32_t tcpi_rcv_mss;
+ uint32_t tcpi_unacked;
+ uint32_t tcpi_sacked;
+ uint32_t tcpi_lost;
+ uint32_t tcpi_retrans;
+ uint32_t tcpi_fackets;
+ uint32_t tcpi_last_data_sent;
+ uint32_t tcpi_last_ack_sent;
+ uint32_t tcpi_last_data_recv;
+ uint32_t tcpi_last_ack_recv;
+ uint32_t tcpi_pmtu;
+ uint32_t tcpi_rcv_ssthresh;
+ uint32_t tcpi_rtt;
+ uint32_t tcpi_rttvar;
+ uint32_t tcpi_snd_ssthresh;
+ uint32_t tcpi_snd_cwnd;
+ uint32_t tcpi_advmss;
+ uint32_t tcpi_reordering;
+ uint32_t tcpi_rcv_rtt;
+ uint32_t tcpi_rcv_space;
+ uint32_t tcpi_total_retrans;
+};
+
+#define TCP_MD5SIG_MAXKEYLEN 80
+
+struct tcp_md5sig
+{
+ struct sockaddr_storage tcpm_addr;
+ uint16_t __tcpm_pad1;
+ uint16_t tcpm_keylen;
+ uint32_t __tcpm_pad2;
+ uint8_t tcpm_key[TCP_MD5SIG_MAXKEYLEN];
+};
+
+#endif
+
#endif
diff --git a/system/include/libc/netinet/udp.h b/system/include/libc/netinet/udp.h
index 15b91454..b1b0eb81 100644
--- a/system/include/libc/netinet/udp.h
+++ b/system/include/libc/netinet/udp.h
@@ -5,19 +5,22 @@
extern "C" {
#endif
+#include <features.h>
#include <stdint.h>
-struct udphdr {
- uint16_t source;
- uint16_t dest;
- uint16_t len;
- uint16_t check;
-};
-
+#ifdef _GNU_SOURCE
#define uh_sport source
#define uh_dport dest
#define uh_ulen len
#define uh_sum check
+#endif
+
+struct udphdr {
+ uint16_t uh_sport;
+ uint16_t uh_dport;
+ uint16_t uh_ulen;
+ uint16_t uh_sum;
+};
#define UDP_CORK 1
#define UDP_ENCAP 100
diff --git a/system/include/libc/paths.h b/system/include/libc/paths.h
index 22848704..67de6b3c 100644
--- a/system/include/libc/paths.h
+++ b/system/include/libc/paths.h
@@ -21,7 +21,6 @@
#define _PATH_UTMP "/dev/null/utmp"
#define _PATH_VI "/usr/bin/vi"
#define _PATH_WTMP "/dev/null/wtmp"
-#define _PATH_LASTLOG "/var/log/lastlog"
#define _PATH_DEV "/dev/"
#define _PATH_TMP "/tmp/"
diff --git a/system/include/libc/resolv.h b/system/include/libc/resolv.h
index 259e4bc1..e12cb3c7 100644
--- a/system/include/libc/resolv.h
+++ b/system/include/libc/resolv.h
@@ -125,15 +125,13 @@ struct res_sym {
struct __res_state *__res_state(void);
#define _res (*__res_state())
-struct rrec;
-
int res_init(void);
int res_query(const char *, int, int, unsigned char *, int);
int res_querydomain(const char *, const char *, int, int, unsigned char *, int);
int res_search(const char *, int, int, unsigned char *, int);
-int res_mkquery(int, const char *, int, int, char *, int, struct rrec *, char *, int);
-int res_send(const char *, int, char *, int);
-int dn_comp(unsigned char *, unsigned char *, int, unsigned char **, unsigned char *, unsigned char **);
+int res_mkquery(int, const char *, int, int, const unsigned char *, int, const unsigned char*, unsigned char *, int);
+int res_send(const unsigned char *, int, unsigned char *, int);
+int dn_comp(const char *, unsigned char *, int, unsigned char **, unsigned char **);
int dn_expand(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
int dn_skipname(const unsigned char *, const unsigned char *);
diff --git a/system/include/libc/sched.h b/system/include/libc/sched.h
index 6a6b2fcb..105dac95 100644
--- a/system/include/libc/sched.h
+++ b/system/include/libc/sched.h
@@ -78,7 +78,7 @@ int __sched_cpucount(size_t, const cpu_set_t *);
int sched_getaffinity(pid_t, size_t, cpu_set_t *);
int sched_setaffinity(pid_t, size_t, const cpu_set_t *);
-#define __CPU_op_S(i, size, set, op) ( (i)/8 >= (size) ? 0 : \
+#define __CPU_op_S(i, size, set, op) ( (i)/8U >= (size) ? 0 : \
((set)->__bits[(i)/8/sizeof(long)] op (1UL<<((i)%(8*sizeof(long))))) )
#define CPU_SET_S(i, size, set) __CPU_op_S(i, size, set, |=)
diff --git a/system/include/libc/search.h b/system/include/libc/search.h
index ebfe08a2..27f61072 100644
--- a/system/include/libc/search.h
+++ b/system/include/libc/search.h
@@ -13,7 +13,7 @@ extern "C" {
typedef enum { FIND, ENTER } ACTION;
typedef enum { preorder, postorder, endorder, leaf } VISIT;
-typedef struct {
+typedef struct entry {
char *key;
void *data;
} ENTRY;
diff --git a/system/include/libc/signal.h b/system/include/libc/signal.h
index e65a8065..3fb21b2a 100644
--- a/system/include/libc/signal.h
+++ b/system/include/libc/signal.h
@@ -77,11 +77,7 @@ extern "C" {
#define CLD_STOPPED 5
#define CLD_CONTINUED 6
-typedef struct sigaltstack {
- void *ss_sp;
- int ss_flags;
- size_t ss_size;
-} stack_t;
+typedef struct sigaltstack stack_t;
union sigval {
int sival_int;
@@ -218,11 +214,8 @@ void (*sigset(int, void (*)(int)))(int);
#define SIGSTKSZ 8192
#endif
-#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE)
-#define NSIG _NSIG
-#endif
-
#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
+#define NSIG _NSIG
typedef void (*sig_t)(int);
#endif
@@ -230,8 +223,8 @@ typedef void (*sig_t)(int);
typedef void (*sighandler_t)(int);
void (*bsd_signal(int, void (*)(int)))(int);
int sigisemptyset(const sigset_t *);
-int sigorset (sigset_t *, sigset_t *, sigset_t *);
-int sigandset(sigset_t *, sigset_t *, sigset_t *);
+int sigorset (sigset_t *, const sigset_t *, const sigset_t *);
+int sigandset(sigset_t *, const sigset_t *, const sigset_t *);
#define SA_NOMASK SA_NODEFER
#define SA_ONESHOT SA_RESETHAND
diff --git a/system/include/libc/stddef.h b/system/include/libc/stddef.h
index 9d522486..0a329190 100644
--- a/system/include/libc/stddef.h
+++ b/system/include/libc/stddef.h
@@ -1,7 +1,11 @@
#ifndef _STDDEF_H
#define _STDDEF_H
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#define __NEED_ptrdiff_t
#define __NEED_size_t
diff --git a/system/include/libc/stdio.h b/system/include/libc/stdio.h
index cd60bb55..884d2e6a 100644
--- a/system/include/libc/stdio.h
+++ b/system/include/libc/stdio.h
@@ -21,7 +21,11 @@ extern "C" {
#include <bits/alltypes.h>
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#undef EOF
#define EOF (-1)
diff --git a/system/include/libc/stdlib.h b/system/include/libc/stdlib.h
index bca1fb41..f034c6e5 100644
--- a/system/include/libc/stdlib.h
+++ b/system/include/libc/stdlib.h
@@ -7,7 +7,11 @@ extern "C" {
#include <features.h>
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#define __NEED_size_t
#define __NEED_wchar_t
@@ -89,7 +93,7 @@ size_t wcstombs (char *__restrict, const wchar_t *__restrict, size_t);
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WIFEXITED(s) (!WTERMSIG(s))
#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
-#define WIFSIGNALED(s) (((s)&0xffff)-1 < 0xffu)
+#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
int posix_memalign (void **, size_t, size_t);
int setenv (const char *, const char *, int);
@@ -139,6 +143,7 @@ int mkstemps (char *, int);
int mkostemps (char *, int, int);
void *valloc (size_t);
void *memalign(size_t, size_t);
+int getloadavg(double *, int);
#define WCOREDUMP(s) ((s) & 0x80)
#define WIFCONTINUED(s) ((s) == 0xffff)
#endif
diff --git a/system/include/libc/string.h b/system/include/libc/string.h
index d4412333..ff9badb9 100644
--- a/system/include/libc/string.h
+++ b/system/include/libc/string.h
@@ -7,7 +7,11 @@ extern "C" {
#include <features.h>
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#define __NEED_size_t
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
diff --git a/system/include/libc/sys/inotify.h b/system/include/libc/sys/inotify.h
index a5bf96a6..46638cac 100644
--- a/system/include/libc/sys/inotify.h
+++ b/system/include/libc/sys/inotify.h
@@ -48,7 +48,7 @@ struct inotify_event {
int inotify_init(void);
int inotify_init1(int);
int inotify_add_watch(int, const char *, uint32_t);
-int inotify_rm_watch(int, uint32_t);
+int inotify_rm_watch(int, int);
#ifdef __cplusplus
}
diff --git a/system/include/libc/sys/mman.h b/system/include/libc/sys/mman.h
index 9a1e60ff..a34448a6 100644
--- a/system/include/libc/sys/mman.h
+++ b/system/include/libc/sys/mman.h
@@ -33,7 +33,7 @@ int munlockall (void);
#ifdef _GNU_SOURCE
void *mremap (void *, size_t, size_t, int, ...);
-int remap_file_pages (void *, size_t, int, ssize_t, int);
+int remap_file_pages (void *, size_t, int, size_t, int);
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
diff --git a/system/include/libc/sys/mtio.h b/system/include/libc/sys/mtio.h
index dc8e5f52..f16a529b 100644
--- a/system/include/libc/sys/mtio.h
+++ b/system/include/libc/sys/mtio.h
@@ -102,7 +102,7 @@ struct mt_tape_info {
{MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
{MT_ISSCSI1, "Generic SCSI-1 tape"}, \
{MT_ISSCSI2, "Generic SCSI-2 tape"}, \
- {0, NULL} \
+ {0, 0} \
}
struct mtpos {
diff --git a/system/include/libc/sys/procfs.h b/system/include/libc/sys/procfs.h
index 6a346053..f7936c43 100644
--- a/system/include/libc/sys/procfs.h
+++ b/system/include/libc/sys/procfs.h
@@ -40,7 +40,7 @@ struct elf_prpsinfo
char pr_zomb;
char pr_nice;
unsigned long int pr_flag;
-#if __WORDSIZE == 32
+#if UINTPTR_MAX == 0xffffffff
unsigned short int pr_uid;
unsigned short int pr_gid;
#else
diff --git a/system/include/libc/sys/ptrace.h b/system/include/libc/sys/ptrace.h
index 6cd3afdd..a133e66a 100644
--- a/system/include/libc/sys/ptrace.h
+++ b/system/include/libc/sys/ptrace.h
@@ -37,6 +37,8 @@ extern "C" {
#define PTRACE_INTERRUPT 0x4207
#define PTRACE_LISTEN 0x4208
#define PTRACE_PEEKSIGINFO 0x4209
+#define PTRACE_GETSIGMASK 0x420a
+#define PTRACE_SETSIGMASK 0x420b
#define PT_READ_I PTRACE_PEEKTEXT
#define PT_READ_D PTRACE_PEEKDATA
diff --git a/system/include/libc/sys/resource.h b/system/include/libc/sys/resource.h
index 22ff2f3b..58392d64 100644
--- a/system/include/libc/sys/resource.h
+++ b/system/include/libc/sys/resource.h
@@ -15,8 +15,9 @@ extern "C" {
#endif
#include <bits/alltypes.h>
+#include <bits/resource.h>
-typedef unsigned long rlim_t;
+typedef unsigned long long rlim_t;
struct rlimit
{
@@ -59,6 +60,9 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
#define prlimit64 prlimit
#endif
+#define PRIO_MIN (-20)
+#define PRIO_MAX 20
+
#define PRIO_PROCESS 0
#define PRIO_PGRP 1
#define PRIO_USER 2
@@ -75,11 +79,13 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
#define RLIMIT_DATA 2
#define RLIMIT_STACK 3
#define RLIMIT_CORE 4
+#ifndef RLIMIT_RSS
#define RLIMIT_RSS 5
-#define RLIMIT_NOFILE 7
-#define RLIMIT_AS 9
#define RLIMIT_NPROC 6
+#define RLIMIT_NOFILE 7
#define RLIMIT_MEMLOCK 8
+#define RLIMIT_AS 9
+#endif
#define RLIMIT_LOCKS 10
#define RLIMIT_SIGPENDING 11
#define RLIMIT_MSGQUEUE 12
diff --git a/system/include/libc/sys/sem.h b/system/include/libc/sys/sem.h
index e74ea208..e7c36980 100644
--- a/system/include/libc/sys/sem.h
+++ b/system/include/libc/sys/sem.h
@@ -27,22 +27,7 @@ extern "C" {
#include <endian.h>
-struct semid_ds {
- struct ipc_perm sem_perm;
- long sem_otime;
- unsigned long __unused1;
- long sem_ctime;
- unsigned long __unused2;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- unsigned short sem_nsems;
- char __sem_nsems_pad[sizeof(long)-sizeof(short)];
-#else
- char __sem_nsems_pad[sizeof(long)-sizeof(short)];
- unsigned short sem_nsems;
-#endif
- unsigned long __unused3;
- unsigned long __unused4;
-};
+#include <bits/sem.h>
#define _SEM_SEMUN_UNDEFINED 1
diff --git a/system/include/libc/sys/shm.h b/system/include/libc/sys/shm.h
index c20f0334..67be822b 100644
--- a/system/include/libc/sys/shm.h
+++ b/system/include/libc/sys/shm.h
@@ -14,6 +14,13 @@ extern "C" {
#include <bits/alltypes.h>
#include <sys/ipc.h>
+
+#ifdef _GNU_SOURCE
+#define __used_ids used_ids
+#define __swap_attempts swap_attempts
+#define __swap_successes swap_successes
+#endif
+
#include <bits/shm.h>
#define SHM_R 0400
@@ -33,20 +40,6 @@ extern "C" {
#define SHM_HUGETLB 04000
#define SHM_NORESERVE 010000
-struct shminfo {
- unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4];
-};
-
-struct shm_info {
- int used_ids;
- unsigned long shm_tot, shm_rss, shm_swp;
-#ifdef _GNU_SOURCE
- unsigned long swap_attempts, swap_successes;
-#else
- unsigned long __reserved[2];
-#endif
-};
-
typedef unsigned long shmatt_t;
void *shmat(int, const void *, int);
diff --git a/system/include/libc/sys/signalfd.h b/system/include/libc/sys/signalfd.h
index 4f3d3999..55431b91 100644
--- a/system/include/libc/sys/signalfd.h
+++ b/system/include/libc/sys/signalfd.h
@@ -30,11 +30,12 @@ struct signalfd_siginfo {
uint32_t ssi_trapno;
int32_t ssi_status;
int32_t ssi_int;
- uintptr_t ssi_ptr;
+ uint64_t ssi_ptr;
uint64_t ssi_utime;
uint64_t ssi_stime;
uint64_t ssi_addr;
- uint8_t pad[128-12*4-sizeof(void *)-3*8];
+ uint16_t ssi_addr_lsb;
+ uint8_t pad[128-12*4-4*8-2];
};
#ifdef __cplusplus
diff --git a/system/include/libc/sys/socket.h b/system/include/libc/sys/socket.h
index 08488c8b..8e8c9e92 100644
--- a/system/include/libc/sys/socket.h
+++ b/system/include/libc/sys/socket.h
@@ -19,12 +19,14 @@ extern "C" {
#include <bits/socket.h>
+#ifdef _GNU_SOURCE
struct ucred
{
pid_t pid;
uid_t uid;
gid_t gid;
};
+#endif
struct linger
{
@@ -33,7 +35,7 @@ struct linger
};
#define SHUT_RD 0
-#define SHUT_WD 1
+#define SHUT_WR 1
#define SHUT_RDWR 2
#ifndef SOCK_STREAM
@@ -199,11 +201,17 @@ struct linger
#define SO_NOFCS 43
#define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
+#define SO_BUSY_POLL 46
+#define SO_MAX_PACING_RATE 47
#ifndef SOL_SOCKET
#define SOL_SOCKET 1
#endif
+#define SOL_IP 0
+#define SOL_IPV6 41
+#define SOL_ICMPV6 58
+
#define SOL_RAW 255
#define SOL_DECNET 261
#define SOL_X25 262
@@ -224,7 +232,7 @@ struct linger
#define MSG_EOR 0x0080
#define MSG_WAITALL 0x0100
#define MSG_FIN 0x0200
-#define MSD_SYN 0x0400
+#define MSG_SYN 0x0400
#define MSG_CONFIRM 0x0800
#define MSG_RST 0x1000
#define MSG_ERRQUEUE 0x2000
@@ -289,10 +297,6 @@ int setsockopt (int, int, int, const void *, socklen_t);
int sockatmark (int);
-#define SHUT_RD 0
-#define SHUT_WR 1
-#define SHUT_RDWR 2
-
#ifdef __cplusplus
}
#endif
diff --git a/system/include/libc/sys/time.h b/system/include/libc/sys/time.h
index 3ce824e6..bfe1414e 100644
--- a/system/include/libc/sys/time.h
+++ b/system/include/libc/sys/time.h
@@ -43,14 +43,25 @@ int adjtime (const struct timeval *, struct timeval *);
#define timerclear(t) ((t)->tv_sec = (t)->tv_usec = 0)
#define timercmp(s,t,op) ((s)->tv_sec == (t)->tv_sec ? \
(s)->tv_usec op (t)->tv_usec : (s)->tv_sec op (t)->tv_sec)
-#define timeradd(s,t,a) ( (a)->tv_sec = (s)->tv_sec + (t)->tv_sec, \
+#define timeradd(s,t,a) (void) ( (a)->tv_sec = (s)->tv_sec + (t)->tv_sec, \
((a)->tv_usec = (s)->tv_usec + (t)->tv_usec) >= 1000000 && \
((a)->tv_usec -= 1000000, (a)->tv_sec++) )
-#define timersub(s,t,a) ( (a)->tv_sec = (s)->tv_sec - (t)->tv_sec, \
+#define timersub(s,t,a) (void) ( (a)->tv_sec = (s)->tv_sec - (t)->tv_sec, \
((a)->tv_usec = (s)->tv_usec - (t)->tv_usec) < 0 && \
((a)->tv_usec += 1000000, (a)->tv_sec--) )
#endif
+#if defined(_GNU_SOURCE)
+#define TIMEVAL_TO_TIMESPEC(tv, ts) ( \
+ (ts)->tv_sec = (tv)->tv_sec, \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000, \
+ (void)0 )
+#define TIMESPEC_TO_TIMEVAL(tv, ts) ( \
+ (tv)->tv_sec = (ts)->tv_sec, \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000, \
+ (void)0 )
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/system/include/libc/sys/wait.h b/system/include/libc/sys/wait.h
index a7ad7cd1..50c5c709 100644
--- a/system/include/libc/sys/wait.h
+++ b/system/include/libc/sys/wait.h
@@ -6,8 +6,6 @@ extern "C" {
#include <features.h>
-#include <signal.h>
-
#define __NEED_pid_t
#define __NEED_id_t
#include <bits/alltypes.h>
@@ -19,9 +17,15 @@ typedef enum {
} idtype_t;
pid_t wait (int *);
-int waitid (idtype_t, id_t, siginfo_t *, int);
pid_t waitpid (pid_t, int *, int );
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+#include <signal.h>
+int waitid (idtype_t, id_t, siginfo_t *, int);
+#endif
+
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#include <sys/resource.h>
pid_t wait3 (int *, int, struct rusage *);
@@ -46,7 +50,7 @@ pid_t wait4 (pid_t, int *, int, struct rusage *);
#define WCOREDUMP(s) ((s) & 0x80)
#define WIFEXITED(s) (!WTERMSIG(s))
#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00)
-#define WIFSIGNALED(s) (((s)&0xffff)-1 < 0xffu)
+#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
#define WIFCONTINUED(s) ((s) == 0xffff)
#ifdef __cplusplus
diff --git a/system/include/libc/syslog.h b/system/include/libc/syslog.h
index a9468d4d..71dbd99b 100644
--- a/system/include/libc/syslog.h
+++ b/system/include/libc/syslog.h
@@ -21,7 +21,7 @@ extern "C" {
#define LOG_MAKEPRI(f, p) (((f)<<3)|(p))
#define LOG_MASK(p) (1<<(p))
-#define LOG_UPTO(p) ((1<<(p)+1)-1)
+#define LOG_UPTO(p) ((1<<((p)+1))-1)
#define LOG_KERN (0<<3)
#define LOG_USER (1<<3)
@@ -82,7 +82,7 @@ typedef struct {
{ "emerg", LOG_EMERG }, { "err", LOG_ERR }, { "error", LOG_ERR }, \
{ "info", LOG_INFO }, { "none", INTERNAL_NOPRI }, \
{ "notice", LOG_NOTICE }, { "panic", LOG_EMERG }, \
- { "warn", LOG_WARNING }, { "warning", LOG_WARNING }, { NULL, -1 } })
+ { "warn", LOG_WARNING }, { "warning", LOG_WARNING }, { 0, -1 } })
#define facilitynames ((CODE *)(const struct __CODE []){ \
{ "auth", LOG_AUTH }, { "authpriv", LOG_AUTHPRIV }, \
{ "cron", LOG_CRON }, { "daemon", LOG_DAEMON }, { "ftp", LOG_FTP }, \
@@ -93,7 +93,7 @@ typedef struct {
{ "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, \
{ "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, \
{ "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, \
- { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { NULL, -1 } })
+ { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { 0, -1 } })
#endif
#endif
diff --git a/system/include/libc/time.h b/system/include/libc/time.h
index 6b2a0693..dc880706 100644
--- a/system/include/libc/time.h
+++ b/system/include/libc/time.h
@@ -7,7 +7,12 @@ extern "C" {
#include <features.h>
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
+
#define __NEED_size_t
#define __NEED_time_t
@@ -82,8 +87,8 @@ struct itimerspec
#define CLOCK_PROCESS_CPUTIME_ID 2
#define CLOCK_THREAD_CPUTIME_ID 3
#define CLOCK_MONOTONIC_RAW 4
-#define CLOCK_REALTIME_COURSE 5
-#define CLOCK_MONOTONIC_COURSE 6
+#define CLOCK_REALTIME_COARSE 5
+#define CLOCK_MONOTONIC_COARSE 6
#define CLOCK_BOOTTIME 7
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9
@@ -120,7 +125,7 @@ struct tm *getdate (const char *);
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-int stime(time_t *);
+int stime(const time_t *);
time_t timegm(struct tm *);
#endif
diff --git a/system/include/libc/unistd.h b/system/include/libc/unistd.h
index 995a84ea..e33e28bf 100644
--- a/system/include/libc/unistd.h
+++ b/system/include/libc/unistd.h
@@ -15,7 +15,11 @@ extern "C" {
#define SEEK_CUR 1
#define SEEK_END 2
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#define __NEED_size_t
#define __NEED_ssize_t
@@ -31,6 +35,7 @@ extern "C" {
int pipe(int [2]);
int pipe2(int [2], int);
int close(int);
+int posix_close(int, int);
int dup(int);
int dup2(int, int);
int dup3(int, int, int);
@@ -196,6 +201,8 @@ int eaccess(const char *, int);
#define off64_t off_t
#endif
+#define POSIX_CLOSE_RESTART 0
+
#define _XOPEN_VERSION 700
#define _XOPEN_UNIX 1
#define _XOPEN_ENH_I18N 1
@@ -239,7 +246,9 @@ int eaccess(const char *, int);
#define _POSIX_READER_WRITER_LOCKS _POSIX_VERSION
#define _POSIX_ASYNCHRONOUS_IO _POSIX_VERSION
#define _POSIX_SEMAPHORES _POSIX_VERSION
-#undef _POSIX_SHARED_MEMORY_OBJECTS
+#ifndef __EMSCRIPTEN__
+#define _POSIX_SHARED_MEMORY_OBJECTS _POSIX_VERSION
+#endif
#define _POSIX2_C_BIND _POSIX_VERSION
diff --git a/system/include/libc/utmp.h b/system/include/libc/utmp.h
index b357ac8c..e9ba23e2 100644
--- a/system/include/libc/utmp.h
+++ b/system/include/libc/utmp.h
@@ -10,6 +10,7 @@ extern "C" {
#define ACCOUNTING 9
#define UT_NAMESIZE 32
#define UT_HOSTSIZE 256
+#define UT_LINESIZE 32
struct lastlog {
time_t ll_time;
@@ -22,6 +23,8 @@ struct lastlog {
#define ut_addr ut_addr_v6[0]
#define utmp utmpx
#define utmpname(x) (-1)
+#define e_exit __e_exit
+#define e_termination __e_termination
void endutent(void);
struct utmp *getutent(void);
diff --git a/system/include/libc/utmpx.h b/system/include/libc/utmpx.h
index fd5f515a..f0c3b013 100644
--- a/system/include/libc/utmpx.h
+++ b/system/include/libc/utmpx.h
@@ -5,6 +5,8 @@
extern "C" {
#endif
+#include <features.h>
+
#define __NEED_pid_t
#define __NEED_time_t
#define __NEED_suseconds_t
@@ -12,19 +14,17 @@ extern "C" {
#include <bits/alltypes.h>
-#define UT_LINESIZE 32
-
struct utmpx
{
short ut_type;
pid_t ut_pid;
- char ut_line[UT_LINESIZE];
+ char ut_line[32];
char ut_id[4];
char ut_user[32];
char ut_host[256];
struct {
- short e_termination;
- short e_exit;
+ short __e_termination;
+ short __e_exit;
} ut_exit;
long ut_session;
struct timeval ut_tv;
@@ -39,7 +39,11 @@ struct utmpx *getutxline(const struct utmpx *);
struct utmpx *pututxline(const struct utmpx *);
void setutxent(void);
+#if defined(_BSD_SOURCE) | defined(_GNU_SOURCE)
+#define e_exit __e_exit
+#define e_termination __e_termination
void updwtmpx(const char *, const struct utmpx *);
+#endif
#define EMPTY 0
#define RUN_LVL 1
diff --git a/system/include/libc/wchar.h b/system/include/libc/wchar.h
index fd5aac5f..9fd967cc 100644
--- a/system/include/libc/wchar.h
+++ b/system/include/libc/wchar.h
@@ -33,7 +33,11 @@ extern "C" {
#define WCHAR_MIN (-1-0x7fffffff+L'\0')
#endif
+#ifdef __cplusplus
#define NULL 0L
+#else
+#define NULL ((void*)0)
+#endif
#undef WEOF
#define WEOF 0xffffffffU
diff --git a/system/lib/build_cxx_natively.sh b/system/lib/build_cxx_natively.sh
new file mode 100755
index 00000000..1cf2749c
--- /dev/null
+++ b/system/lib/build_cxx_natively.sh
@@ -0,0 +1,3 @@
+# useful for testing purposes, compare native build to js build
+~/Dev/fastcomp/hybridbuild/Release+Asserts/bin/clang -std=c++0x -nostdinc++ test.cpp libcxxabi/src/*.cpp libcxx/*.cpp -Ilibcxxabi/include -I../include/libcxx -lpthread -g
+
diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols
index d889d509..90783d8d 100644
--- a/system/lib/libc.symbols
+++ b/system/lib/libc.symbols
@@ -55,7 +55,11 @@
T atol
W bulk_free
W calloc
+ T ffs
W free
+ T frexp
+ T frexpf
+ T frexpl
W independent_calloc
W independent_comalloc
T isdigit
@@ -72,14 +76,18 @@
W malloc_usable_size
W mallopt
W memalign
+ T MUSL_vfprintf
W posix_memalign
W pvalloc
W realloc
W realloc_in_place
T scalbn
T scalbnl
+ T memchr
T memcmp
T memcpy
+ T snprintf
+ T sprintf
T strtod
T strtoull
T strtoll
@@ -101,3 +109,7 @@
T strtold_l
T tolower
W valloc
+ T vsnprintf
+ T vsprintf
+ T wcrtomb
+ T wctomb
diff --git a/system/include/libc/bits/signal.h b/system/lib/libc/musl/arch/js/bits/signal.h
index 75844e5b..03c6dbf9 100644
--- a/system/include/libc/bits/signal.h
+++ b/system/lib/libc/musl/arch/js/bits/signal.h
@@ -23,6 +23,12 @@
#define REG_SS 18
#endif
+typedef struct sigaltstack {
+ void *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
typedef int greg_t, gregset_t[19];
typedef struct _fpstate {
diff --git a/system/lib/libc/musl/arch/js/syscall_arch.h b/system/lib/libc/musl/arch/js/syscall_arch.h
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/system/lib/libc/musl/arch/js/syscall_arch.h
@@ -0,0 +1,2 @@
+
+
diff --git a/system/lib/libc/musl/readme.txt b/system/lib/libc/musl/readme.txt
index 9b9b6ad2..0e2777c0 100644
--- a/system/lib/libc/musl/readme.txt
+++ b/system/lib/libc/musl/readme.txt
@@ -1,4 +1,4 @@
-These sources were downloaded from the musl-0.9.13 release on August 30, 2013.
+These sources were downloaded from the musl-1.0.3 release on Jul 2, 2014.
Differences from upstream musl include:
diff --git a/system/lib/libc/musl/src/ctype/iswspace.c b/system/lib/libc/musl/src/ctype/iswspace.c
index 99d517e6..b0c0ae18 100644
--- a/system/lib/libc/musl/src/ctype/iswspace.c
+++ b/system/lib/libc/musl/src/ctype/iswspace.c
@@ -14,6 +14,5 @@ int iswspace(wint_t wc)
0x2006, 0x2008, 0x2009, 0x200a,
0x2028, 0x2029, 0x205f, 0x3000, 0
};
- if (wcschr(spaces, wc)) return 1;
- return 0;
+ return wc && wcschr(spaces, wc);
}
diff --git a/system/lib/libc/musl/src/internal/libc.h b/system/lib/libc/musl/src/internal/libc.h
index c9416f07..d625b56a 100644
--- a/system/lib/libc/musl/src/internal/libc.h
+++ b/system/lib/libc/musl/src/internal/libc.h
@@ -3,24 +3,27 @@
#include <stdlib.h>
#include <stdio.h>
+#include <limits.h>
struct __libc {
void *main_thread;
int threaded;
int secure;
size_t *auxv;
- int (*atexit)(void (*)(void));
- void (*fini)(void);
- void (*ldso_fini)(void);
volatile int threads_minus_1;
int canceldisable;
FILE *ofl_head;
int ofl_lock[2];
size_t tls_size;
+ size_t page_size;
};
extern size_t __hwcap;
+#ifndef PAGE_SIZE
+#define PAGE_SIZE libc.page_size
+#endif
+
#if !defined(__PIC__) || (100*__GNUC__+__GNUC_MINOR__ >= 303 && !defined(__PCC__))
#ifdef __PIC__
@@ -50,8 +53,8 @@ void __lock(volatile int *) ATTR_LIBC_VISIBILITY;
void __unlock(volatile int *) ATTR_LIBC_VISIBILITY;
int __lockfile(FILE *) ATTR_LIBC_VISIBILITY;
void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY;
-#define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1))
-#define UNLOCK(x) (libc.threads_minus_1 ? (__unlock(x),1) : ((void)(x),1))
+#define LOCK(x) __lock(x)
+#define UNLOCK(x) __unlock(x)
void __synccall(void (*)(void *), void *);
int __setxid(int, int, int, int);
diff --git a/system/lib/libc/musl/src/internal/libm.h b/system/lib/libc/musl/src/internal/libm.h
index 9f0d3bc8..ebcd7849 100644
--- a/system/lib/libc/musl/src/internal/libm.h
+++ b/system/lib/libc/musl/src/internal/libm.h
@@ -155,15 +155,4 @@ long double __tanl(long double, long double, int);
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/locale_impl.h b/system/lib/libc/musl/src/internal/locale_impl.h
index c268124f..f41c6f24 100644
--- a/system/lib/libc/musl/src/internal/locale_impl.h
+++ b/system/lib/libc/musl/src/internal/locale_impl.h
@@ -1,5 +1,5 @@
#include <locale.h>
-struct __locale {
+struct __locale_struct {
int dummy;
};
diff --git a/system/lib/libc/musl/src/internal/stdio_impl.h b/system/lib/libc/musl/src/internal/stdio_impl.h
index 6bcd44dc..1f40ca0f 100644
--- a/system/lib/libc/musl/src/internal/stdio_impl.h
+++ b/system/lib/libc/musl/src/internal/stdio_impl.h
@@ -7,7 +7,7 @@
#define UNGET 8
-#if 1 // XXX EMSCRIPTEN
+#if __EMSCRIPTEN__
#define FFINALLOCK(f) 0
#define FLOCK(f) 0
#define FUNLOCK(f) 0
@@ -23,6 +23,7 @@
#define F_EOF 16
#define F_ERR 32
#define F_SVB 64
+#define F_APP 128
struct _IO_FILE {
unsigned flags;
@@ -95,4 +96,9 @@ int __fmodeflags(const char *);
FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t);
int __fclose_ca(FILE *);
+#if __EMSCRIPTEN__ // musl-specific vfscanf and vfprintf live parallel to JS handwritten vfscanf and vfprintf, so musl ones are prefixed.
+int MUSL_vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap);
+int MUSL_vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap);
+#endif
+
#endif
diff --git a/system/lib/libc/musl/src/locale/strcasecmp_l.c b/system/lib/libc/musl/src/locale/strcasecmp_l.c
index eea2f80b..ca805430 100644
--- a/system/lib/libc/musl/src/locale/strcasecmp_l.c
+++ b/system/lib/libc/musl/src/locale/strcasecmp_l.c
@@ -1,5 +1,4 @@
#include <strings.h>
-#include <ctype.h>
int strcasecmp_l(const char *l, const char *r, locale_t loc)
{
diff --git a/system/lib/libc/musl/src/locale/strfmon.c b/system/lib/libc/musl/src/locale/strfmon.c
index f510d9a4..e25db972 100644
--- a/system/lib/libc/musl/src/locale/strfmon.c
+++ b/system/lib/libc/musl/src/locale/strfmon.c
@@ -3,7 +3,6 @@
#include <stdarg.h>
#include <monetary.h>
#include <errno.h>
-#include <stdarg.h>
static ssize_t vstrfmon_l(char *s, size_t n, locale_t loc, const char *fmt, va_list ap)
{
diff --git a/system/lib/libc/musl/src/locale/wcsxfrm.c b/system/lib/libc/musl/src/locale/wcsxfrm.c
index cb79c97e..5d89e7dd 100644
--- a/system/lib/libc/musl/src/locale/wcsxfrm.c
+++ b/system/lib/libc/musl/src/locale/wcsxfrm.c
@@ -6,10 +6,12 @@
size_t __wcsxfrm_l(wchar_t *restrict dest, const wchar_t *restrict src, size_t n, locale_t loc)
{
size_t l = wcslen(src);
- if (l >= n) {
+ if (l < n) {
+ wmemcpy(dest, src, l+1);
+ } else if (n) {
wmemcpy(dest, src, n-1);
dest[n-1] = 0;
- } else wcscpy(dest, src);
+ }
return l;
}
diff --git a/system/lib/libc/musl/src/math/frexp.c b/system/lib/libc/musl/src/math/frexp.c
new file mode 100644
index 00000000..27b6266e
--- /dev/null
+++ b/system/lib/libc/musl/src/math/frexp.c
@@ -0,0 +1,23 @@
+#include <math.h>
+#include <stdint.h>
+
+double frexp(double x, int *e)
+{
+ union { double d; uint64_t i; } y = { x };
+ int ee = y.i>>52 & 0x7ff;
+
+ if (!ee) {
+ if (x) {
+ x = frexp(x*0x1p64, e);
+ *e -= 64;
+ } else *e = 0;
+ return x;
+ } else if (ee == 0x7ff) {
+ return x;
+ }
+
+ *e = ee - 0x3fe;
+ y.i &= 0x800fffffffffffffull;
+ y.i |= 0x3fe0000000000000ull;
+ return y.d;
+}
diff --git a/system/lib/libc/musl/src/math/frexpf.c b/system/lib/libc/musl/src/math/frexpf.c
new file mode 100644
index 00000000..07870975
--- /dev/null
+++ b/system/lib/libc/musl/src/math/frexpf.c
@@ -0,0 +1,23 @@
+#include <math.h>
+#include <stdint.h>
+
+float frexpf(float x, int *e)
+{
+ union { float f; uint32_t i; } y = { x };
+ int ee = y.i>>23 & 0xff;
+
+ if (!ee) {
+ if (x) {
+ x = frexpf(x*0x1p64, e);
+ *e -= 64;
+ } else *e = 0;
+ return x;
+ } else if (ee == 0xff) {
+ return x;
+ }
+
+ *e = ee - 0x7e;
+ y.i &= 0x807ffffful;
+ y.i |= 0x3f000000ul;
+ return y.f;
+}
diff --git a/system/lib/libc/musl/src/math/frexpl.c b/system/lib/libc/musl/src/math/frexpl.c
new file mode 100644
index 00000000..3c1b5537
--- /dev/null
+++ b/system/lib/libc/musl/src/math/frexpl.c
@@ -0,0 +1,29 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double frexpl(long double x, int *e)
+{
+ return frexp(x, e);
+}
+#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
+long double frexpl(long double x, int *e)
+{
+ union ldshape u = {x};
+ int ee = u.i.se & 0x7fff;
+
+ if (!ee) {
+ if (x) {
+ x = frexpl(x*0x1p120, e);
+ *e -= 120;
+ } else *e = 0;
+ return x;
+ } else if (ee == 0x7fff) {
+ return x;
+ }
+
+ *e = ee - 0x3ffe;
+ u.i.se &= 0x8000;
+ u.i.se |= 0x3ffe;
+ return u.f;
+}
+#endif
diff --git a/system/lib/libc/musl/src/math/lgamma.c b/system/lib/libc/musl/src/math/lgamma.c
index 36006682..e25ec8e6 100644
--- a/system/lib/libc/musl/src/math/lgamma.c
+++ b/system/lib/libc/musl/src/math/lgamma.c
@@ -1,9 +1,9 @@
#include <math.h>
-extern int signgam;
+extern int __signgam;
double __lgamma_r(double, int *);
double lgamma(double x)
{
- return __lgamma_r(x, &signgam);
+ 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
index 82e296f5..fff565d2 100644
--- a/system/lib/libc/musl/src/math/lgamma_r.c
+++ b/system/lib/libc/musl/src/math/lgamma_r.c
@@ -82,7 +82,6 @@
#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 */
@@ -147,91 +146,62 @@ w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */
static double sin_pi(double x)
{
- double y,z;
- int n,ix;
+ int n;
- GET_HIGH_WORD(ix, x);
- ix &= 0x7fffffff;
+ /* spurious inexact if odd int */
+ x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */
- if (ix < 0x3fd00000)
- return __sin(pi*x, 0.0, 0);
+ n = (int)(x*4.0);
+ n = (n+1)/2;
+ x -= n*0.5f;
+ x *= pi;
- 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;
+ default: /* case 4: */
+ case 0: return __sin(x, 0.0, 0);
+ case 1: return __cos(x, 0.0);
+ case 2: return __sin(-x, 0.0, 0);
+ case 3: return -__cos(x, 0.0);
}
- 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);
+ union {double f; uint64_t i;} u = {x};
+ double_t t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ uint32_t ix;
+ int sign,i;
/* purge off +-inf, NaN, +-0, tiny and negative arguments */
*signgamp = 1;
- ix = hx & 0x7fffffff;
+ sign = u.i>>63;
+ ix = u.i>>32 & 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) {
+ if (ix < (0x3ff-70)<<20) { /* |x|<2**-70, return -log(|x|) */
+ if(sign) {
+ x = -x;
*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;
+ if (sign) {
+ x = -x;
t = sin_pi(x);
if (t == 0.0) /* -integer */
- return 1.0/0.0;
- nadj = log(pi/fabs(t*x));
- if (t < 0.0)
+ return 1.0/(x-x);
+ if (t > 0.0)
*signgamp = -1;
- x = -x;
+ else
+ t = -t;
+ nadj = log(pi/(t*x));
}
/* purge off 1 and 2 */
- if (((ix - 0x3ff00000)|lx) == 0 || ((ix - 0x40000000)|lx) == 0)
+ if ((ix == 0x3ff00000 || ix == 0x40000000) && (uint32_t)u.i == 0)
r = 0;
/* for x < 2.0 */
else if (ix < 0x40000000) {
@@ -306,7 +276,7 @@ double __lgamma_r(double x, int *signgamp)
r = (x-0.5)*(t-1.0)+w;
} else /* 2**58 <= x <= inf */
r = x*(log(x)-1.0);
- if (hx < 0)
+ if (sign)
r = nadj - r;
return r;
}
diff --git a/system/lib/libc/musl/src/math/lgammaf.c b/system/lib/libc/musl/src/math/lgammaf.c
index 628e6ade..badb6dfe 100644
--- a/system/lib/libc/musl/src/math/lgammaf.c
+++ b/system/lib/libc/musl/src/math/lgammaf.c
@@ -1,9 +1,9 @@
#include <math.h>
-extern int signgam;
+extern int __signgam;
float __lgammaf_r(float, int *);
float lgammaf(float x)
{
- return __lgammaf_r(x, &signgam);
+ 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
index dc65bace..c5b43db5 100644
--- a/system/lib/libc/musl/src/math/lgammaf_r.c
+++ b/system/lib/libc/musl/src/math/lgammaf_r.c
@@ -17,7 +17,6 @@
#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 */
@@ -82,87 +81,58 @@ w4 = -5.9518753551e-04, /* 0xba1c065c */
w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
-static float sin_pif(float x)
+/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */
+static float sin_pi(float x)
{
- float y,z;
- int n,ix;
+ double_t y;
+ int n;
- GET_FLOAT_WORD(ix, x);
- ix &= 0x7fffffff;
+ /* spurious inexact if odd int */
+ x = 2*(x*0.5f - floorf(x*0.5f)); /* x mod 2.0 */
- 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;
- }
- }
+ n = (int)(x*4);
+ n = (n+1)/2;
+ y = x - n*0.5f;
+ y *= 3.14159265358979323846;
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;
+ default: /* case 4: */
+ case 0: return __sindf(y);
+ case 1: return __cosdf(y);
+ case 2: return __sindf(-y);
+ case 3: return -__cosdf(y);
}
- return -y;
}
-
float __lgammaf_r(float x, int *signgamp)
{
+ union {float f; uint32_t i;} u = {x};
float t,y,z,nadj,p,p1,p2,p3,q,r,w;
- int32_t hx;
- int i,ix;
-
- GET_FLOAT_WORD(hx, x);
+ uint32_t ix;
+ int i,sign;
/* purge off +-inf, NaN, +-0, tiny and negative arguments */
*signgamp = 1;
- ix = hx & 0x7fffffff;
+ sign = u.i>>31;
+ ix = u.i & 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) {
+ if (sign) {
*signgamp = -1;
- return -logf(-x);
+ x = -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 (sign) {
+ x = -x;
+ t = sin_pi(x);
if (t == 0.0f) /* -integer */
- return 1.0f/0.0f;
- nadj = logf(pi/fabsf(t*x));
- if (t < 0.0f)
+ return 1.0f/(x-x);
+ if (t > 0.0f)
*signgamp = -1;
- x = -x;
+ else
+ t = -t;
+ nadj = logf(pi/(t*x));
}
/* purge off 1 and 2 */
@@ -241,7 +211,7 @@ float __lgammaf_r(float x, int *signgamp)
r = (x-0.5f)*(t-1.0f)+w;
} else /* 2**58 <= x <= inf */
r = x*(logf(x)-1.0f);
- if (hx < 0)
+ if (sign)
r = nadj - r;
return r;
}
diff --git a/system/lib/libc/musl/src/math/lgammal.c b/system/lib/libc/musl/src/math/lgammal.c
index 9686d9ee..55ec5325 100644
--- a/system/lib/libc/musl/src/math/lgammal.c
+++ b/system/lib/libc/musl/src/math/lgammal.c
@@ -99,7 +99,6 @@ long double __lgammal_r(long double x, int *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
@@ -201,61 +200,27 @@ w5 = 8.412723297322498080632E-4L,
w6 = -1.880801938119376907179E-3L,
w7 = 4.885026142432270781165E-3L;
+/* sin(pi*x) assuming x > 2^-1000, if sin(pi*x)==0 the sign is arbitrary */
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 */
+ /* spurious inexact if odd int */
+ x *= 0.5;
+ x = 2.0*(x - floorl(x)); /* x mod 2.0 */
- /*
- * 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;
- }
- }
+ n = (int)(x*4.0);
+ n = (n+1)/2;
+ x -= n*0.5f;
+ x *= pi;
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;
+ default: /* case 4: */
+ case 0: return __sinl(x, 0.0, 0);
+ case 1: return __cosl(x, 0.0);
+ case 2: return __sinl(-x, 0.0, 0);
+ case 3: return -__cosl(x, 0.0);
}
- return -y;
}
long double __lgammal_r(long double x, int *sg) {
@@ -267,31 +232,32 @@ long double __lgammal_r(long double x, int *sg) {
*sg = 1;
- /* purge off +-inf, NaN, +-0, and negative arguments */
+ /* purge off +-inf, NaN, +-0, tiny 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);
+ x = -x;
}
return -logl(x);
}
if (sign) {
- t = sin_pi (x);
+ x = -x;
+ t = sin_pi(x);
if (t == 0.0)
- return 1.0 / fabsl(t); /* -integer */
- nadj = logl(pi / fabsl(t * x));
- if (t < 0.0)
+ return 1.0 / (x-x); /* -integer */
+ if (t > 0.0)
*sg = -1;
- x = -x;
+ else
+ t = -t;
+ nadj = logl(pi / (t * x));
}
- if (ix < 0x40008000) { /* x < 2.0 */
+ /* purge off 1 and 2 (so the sign is ok with downward rounding) */
+ if ((ix == 0x3fff8000 || ix == 0x40008000) && u.i.m == 0) {
+ r = 0;
+ } else if (ix < 0x40008000) { /* x < 2.0 */
if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */
/* lgamma(x) = lgamma(x+1) - log(x) */
r = -logl(x);
@@ -341,12 +307,12 @@ long double __lgammal_r(long double x, int *sg) {
} 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) */
+ z = 1.0;
+ /* lgamma(1+s) = log(s) + lgamma(s) */
switch (i) {
case 7:
z *= (y + 6.0); /* FALLTHRU */
@@ -376,11 +342,13 @@ long double __lgammal_r(long double x, int *sg) {
}
#endif
-extern int signgam;
+#if (LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024) || (LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384)
+extern int __signgam;
long double lgammal(long double x)
{
- return __lgammal_r(x, &signgam);
+ return __lgammal_r(x, &__signgam);
}
weak_alias(__lgammal_r, lgammal_r);
+#endif
diff --git a/system/lib/libc/musl/src/math/signgam.c b/system/lib/libc/musl/src/math/signgam.c
index ee5d70f1..cd728001 100644
--- a/system/lib/libc/musl/src/math/signgam.c
+++ b/system/lib/libc/musl/src/math/signgam.c
@@ -1,4 +1,6 @@
#include <math.h>
#include "libc.h"
-int signgam = 0;
+int __signgam = 0;
+
+weak_alias(__signgam, signgam);
diff --git a/system/lib/libc/musl/src/math/tgamma.c b/system/lib/libc/musl/src/math/tgamma.c
index f91af735..28f6e0f8 100644
--- a/system/lib/libc/musl/src/math/tgamma.c
+++ b/system/lib/libc/musl/src/math/tgamma.c
@@ -26,7 +26,7 @@ most ideas and constants are from boost and python
static const double pi = 3.141592653589793238462643383279502884;
-/* sin(pi x) with x > 0 && isnormal(x) assumption */
+/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */
static double sinpi(double x)
{
int n;
@@ -49,8 +49,7 @@ static double sinpi(double x)
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);
+ return __sin(-x, 0, 0);
case 3:
return -__cos(x, 0);
}
@@ -108,35 +107,33 @@ static double S(double x)
double tgamma(double x)
{
- double absx, y, dy, z, r;
+ union {double f; uint64_t i;} u = {x};
+ double absx, y;
+ double_t dy, z, r;
+ uint32_t ix = u.i>>32 & 0x7fffffff;
+ int sign = u.i>>63;
/* special cases */
- if (!isfinite(x))
+ if (ix >= 0x7ff00000)
/* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */
return x + INFINITY;
+ if (ix < (0x3ff-54)<<20)
+ /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */
+ return 1/x;
/* 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)
+ if (sign)
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) {
+ if (ix >= 0x40670000) { /* |x| >= 184 */
+ if (sign) {
FORCE_EVAL((float)(0x1p-126/x));
if (floor(x) * 0.5 == floor(x * 0.5))
return 0;
@@ -146,6 +143,8 @@ double tgamma(double x)
return x;
}
+ absx = sign ? -x : x;
+
/* handle the error of x + g - 0.5 */
y = absx + gmhalf;
if (absx > gmhalf) {
@@ -160,20 +159,21 @@ double tgamma(double x)
r = S(absx) * exp(-y);
if (x < 0) {
/* reflection formula for negative x */
+ /* sinpi(absx) is not 0, integers are already handled */
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;
+ y = r * z * z;
+ return y;
}
#if 0
double __lgamma_r(double x, int *sign)
{
- double r, absx, z, zz, w;
+ double r, absx;
*sign = 1;
diff --git a/system/lib/libc/musl/src/misc/ffs.c b/system/lib/libc/musl/src/misc/ffs.c
new file mode 100644
index 00000000..673ce5a9
--- /dev/null
+++ b/system/lib/libc/musl/src/misc/ffs.c
@@ -0,0 +1,7 @@
+#include <strings.h>
+#include "atomic.h"
+
+int ffs(int i)
+{
+ return i ? a_ctz_l(i)+1 : 0;
+}
diff --git a/system/lib/libc/musl/src/multibyte/internal.c b/system/lib/libc/musl/src/multibyte/internal.c
index ab22806e..1813b266 100644
--- a/system/lib/libc/musl/src/multibyte/internal.c
+++ b/system/lib/libc/musl/src/multibyte/internal.c
@@ -4,8 +4,6 @@
* unnecessary.
*/
-#include <inttypes.h>
-
#include "internal.h"
#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) )
diff --git a/system/lib/libc/musl/src/multibyte/internal.h b/system/lib/libc/musl/src/multibyte/internal.h
index 25ba240e..82f5a07e 100644
--- a/system/lib/libc/musl/src/multibyte/internal.h
+++ b/system/lib/libc/musl/src/multibyte/internal.h
@@ -6,6 +6,7 @@
#define bittab __fsmu8
+#include <stdint.h>
#include "libc.h"
extern const uint32_t bittab[] ATTR_LIBC_VISIBILITY;
diff --git a/system/lib/libc/musl/src/multibyte/mblen.c b/system/lib/libc/musl/src/multibyte/mblen.c
index 26d35649..96b47b12 100644
--- a/system/lib/libc/musl/src/multibyte/mblen.c
+++ b/system/lib/libc/musl/src/multibyte/mblen.c
@@ -5,11 +5,6 @@
*/
#include <stdlib.h>
-#include <inttypes.h>
-#include <wchar.h>
-#include <errno.h>
-
-#include "internal.h"
int mblen(const char *s, size_t n)
{
diff --git a/system/lib/libc/musl/src/multibyte/mbrlen.c b/system/lib/libc/musl/src/multibyte/mbrlen.c
index c9714ef8..3a5a7433 100644
--- a/system/lib/libc/musl/src/multibyte/mbrlen.c
+++ b/system/lib/libc/musl/src/multibyte/mbrlen.c
@@ -4,12 +4,7 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
-#include <errno.h>
-
-#include "internal.h"
size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict st)
{
diff --git a/system/lib/libc/musl/src/multibyte/mbrtowc.c b/system/lib/libc/musl/src/multibyte/mbrtowc.c
index db803661..35e834ee 100644
--- a/system/lib/libc/musl/src/multibyte/mbrtowc.c
+++ b/system/lib/libc/musl/src/multibyte/mbrtowc.c
@@ -4,11 +4,8 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
#include <errno.h>
-
#include "internal.h"
size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st)
diff --git a/system/lib/libc/musl/src/multibyte/mbsinit.c b/system/lib/libc/musl/src/multibyte/mbsinit.c
index c0e7e494..e001d844 100644
--- a/system/lib/libc/musl/src/multibyte/mbsinit.c
+++ b/system/lib/libc/musl/src/multibyte/mbsinit.c
@@ -4,12 +4,7 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
-#include <errno.h>
-
-#include "internal.h"
int mbsinit(const mbstate_t *st)
{
diff --git a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
index 33457f95..68b9960f 100644
--- a/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
+++ b/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c
@@ -4,13 +4,7 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "internal.h"
size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st)
{
diff --git a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
index 75a493c4..3c1343ae 100644
--- a/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
+++ b/system/lib/libc/musl/src/multibyte/mbsrtowcs.c
@@ -4,11 +4,9 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
+#include <stdint.h>
#include <wchar.h>
#include <errno.h>
-
#include "internal.h"
size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
@@ -54,9 +52,12 @@ resume0:
wn--;
c = 0;
} else for (;;) {
- if (!wn) return wn0;
+ if (!wn) {
+ *src = (const void *)s;
+ return wn0;
+ }
if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
- while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
+ while (wn>=5 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
*ws++ = *s++;
*ws++ = *s++;
*ws++ = *s++;
diff --git a/system/lib/libc/musl/src/multibyte/mbtowc.c b/system/lib/libc/musl/src/multibyte/mbtowc.c
index ec9e54ad..6710637a 100644
--- a/system/lib/libc/musl/src/multibyte/mbtowc.c
+++ b/system/lib/libc/musl/src/multibyte/mbtowc.c
@@ -4,13 +4,10 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
#include <errno.h>
-
#include "internal.h"
-#include <stdio.h>
+
int mbtowc(wchar_t *restrict wc, const char *restrict src, size_t n)
{
unsigned c;
diff --git a/system/lib/libc/musl/src/multibyte/wcrtomb.c b/system/lib/libc/musl/src/multibyte/wcrtomb.c
index 250649f5..59f733db 100644
--- a/system/lib/libc/musl/src/multibyte/wcrtomb.c
+++ b/system/lib/libc/musl/src/multibyte/wcrtomb.c
@@ -4,13 +4,9 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
#include <errno.h>
-#include "internal.h"
-
size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
{
if (!s) return 1;
diff --git a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
index a2e308b3..7eb05d45 100644
--- a/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
+++ b/system/lib/libc/musl/src/multibyte/wcsnrtombs.c
@@ -4,12 +4,7 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
-#include <errno.h>
-
-#include "internal.h"
size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st)
{
diff --git a/system/lib/libc/musl/src/multibyte/wcsrtombs.c b/system/lib/libc/musl/src/multibyte/wcsrtombs.c
index d48a65e7..30be415d 100644
--- a/system/lib/libc/musl/src/multibyte/wcsrtombs.c
+++ b/system/lib/libc/musl/src/multibyte/wcsrtombs.c
@@ -4,12 +4,7 @@
* unnecessary.
*/
-#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
-#include <errno.h>
-
-#include "internal.h"
size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstate_t *restrict st)
{
@@ -26,8 +21,13 @@ size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstat
}
return n;
}
- while (n>=4 && **ws) {
- if (**ws >= 0x80u) {
+ while (n>=4) {
+ if (**ws-1u >= 0x7fu) {
+ if (!**ws) {
+ *s = 0;
+ *ws = 0;
+ return N-n;
+ }
l = wcrtomb(s, **ws, 0);
if (!(l+1)) return -1;
s += l;
@@ -38,8 +38,13 @@ size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstat
}
(*ws)++;
}
- while (n && **ws) {
- if (**ws >= 0x80u) {
+ while (n) {
+ if (**ws-1u >= 0x7fu) {
+ if (!**ws) {
+ *s = 0;
+ *ws = 0;
+ return N-n;
+ }
l = wcrtomb(buf, **ws, 0);
if (!(l+1)) return -1;
if (l>n) return N-n;
@@ -52,7 +57,5 @@ size_t wcsrtombs(char *restrict s, const wchar_t **restrict ws, size_t n, mbstat
}
(*ws)++;
}
- if (n) *s = 0;
- *ws = 0;
- return N-n;
+ return N;
}
diff --git a/system/lib/libc/musl/src/multibyte/wctomb.c b/system/lib/libc/musl/src/multibyte/wctomb.c
index 6910ef37..de7ed84d 100644
--- a/system/lib/libc/musl/src/multibyte/wctomb.c
+++ b/system/lib/libc/musl/src/multibyte/wctomb.c
@@ -5,11 +5,7 @@
*/
#include <stdlib.h>
-#include <inttypes.h>
#include <wchar.h>
-#include <errno.h>
-
-#include "internal.h"
int wctomb(char *s, wchar_t wc)
{
diff --git a/system/lib/libc/musl/src/regex/fnmatch.c b/system/lib/libc/musl/src/regex/fnmatch.c
index ffd3ea0d..4df10a3c 100644
--- a/system/lib/libc/musl/src/regex/fnmatch.c
+++ b/system/lib/libc/musl/src/regex/fnmatch.c
@@ -19,7 +19,7 @@
#include <wchar.h>
#include <wctype.h>
-#define END -1
+#define END 0
#define UNMATCHABLE -2
#define BRACKET -3
#define QUESTION -4
@@ -53,7 +53,7 @@ static int pat_next(const char *pat, size_t m, size_t *step, int flags)
return END;
}
*step = 1;
- if (pat[0]=='\\' && !(flags & FNM_NOESCAPE)) {
+ if (pat[0]=='\\' && pat[1] && !(flags & FNM_NOESCAPE)) {
*step = 2;
pat++;
esc = 1;
@@ -288,12 +288,19 @@ int fnmatch(const char *pat, const char *str, int flags)
if (flags & FNM_PATHNAME) for (;;) {
for (s=str; *s && *s!='/'; s++);
for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc);
- if (*s && *p!=*s) return FNM_NOMATCH;
+ if (c!=*s && (!*s || !(flags & FNM_LEADING_DIR)))
+ return FNM_NOMATCH;
if (fnmatch_internal(pat, p-pat, str, s-str, flags))
return FNM_NOMATCH;
- if (!*s && c==END) return 0;
+ if (!c) return 0;
str = s+1;
- pat = p+1;
+ pat = p+inc;
+ } else if (flags & FNM_LEADING_DIR) {
+ for (s=str; *s; s++) {
+ if (*s != '/') continue;
+ if (!fnmatch_internal(pat, -1, str, s-str, flags))
+ return 0;
+ }
}
return fnmatch_internal(pat, -1, str, -1, flags);
}
diff --git a/system/lib/libc/musl/src/regex/regcomp.c b/system/lib/libc/musl/src/regex/regcomp.c
index 5cedfd52..d9076275 100644
--- a/system/lib/libc/musl/src/regex/regcomp.c
+++ b/system/lib/libc/musl/src/regex/regcomp.c
@@ -30,7 +30,6 @@
*/
#include <string.h>
-#include <errno.h>
#include <stdlib.h>
#include <regex.h>
#include <limits.h>
@@ -516,7 +515,7 @@ tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i,
if (*max_i > 1024)
return REG_ESPACE;
*max_i *= 2;
- new_items = xrealloc(array, sizeof(*items) * *max_i);
+ new_items = xrealloc(array, sizeof(*array) * *max_i);
if (new_items == NULL)
return REG_ESPACE;
*items = array = new_items;
@@ -765,7 +764,7 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
if (num_neg_classes > 0)
{
l->neg_classes = tre_mem_alloc(ctx->mem,
- (sizeof(l->neg_classes)
+ (sizeof(*l->neg_classes)
* (num_neg_classes + 1)));
if (l->neg_classes == NULL)
{
@@ -805,7 +804,7 @@ tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
if (num_neg_classes > 0)
{
l->neg_classes = tre_mem_alloc(ctx->mem,
- (sizeof(l->neg_classes)
+ (sizeof(*l->neg_classes)
* (num_neg_classes + 1)));
if (l->neg_classes == NULL)
{
@@ -3167,7 +3166,7 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
sizeof(*tag_directions) * (tnfa->num_tags + 1));
}
tnfa->minimal_tags = xcalloc((unsigned)tnfa->num_tags * 2 + 1,
- sizeof(tnfa->minimal_tags));
+ sizeof(*tnfa->minimal_tags));
if (tnfa->minimal_tags == NULL)
ERROR_EXIT(REG_ESPACE);
diff --git a/system/lib/libc/musl/src/stdio/__string_read.c b/system/lib/libc/musl/src/stdio/__string_read.c
new file mode 100644
index 00000000..7b50a7e1
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/__string_read.c
@@ -0,0 +1,16 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+size_t __string_read(FILE *f, unsigned char *buf, size_t len)
+{
+ char *src = f->cookie;
+ size_t k = len+256;
+ char *end = memchr(src, 0, k);
+ if (end) k = end-src;
+ if (k < len) len = k;
+ memcpy(buf, src, len);
+ f->rpos = (void *)(src+len);
+ f->rend = (void *)(src+k);
+ f->cookie = src+k;
+ return len;
+}
diff --git a/system/lib/libc/musl/src/stdio/__toread.c b/system/lib/libc/musl/src/stdio/__toread.c
index f00cc467..70427b21 100644
--- a/system/lib/libc/musl/src/stdio/__toread.c
+++ b/system/lib/libc/musl/src/stdio/__toread.c
@@ -12,3 +12,15 @@ int __toread(FILE *f)
f->rpos = f->rend = f->buf;
return 0;
}
+
+#ifndef __EMSCRIPTEN__
+static const int dummy = 0;
+weak_alias(dummy, __towrite_used);
+
+void __stdio_exit(void);
+
+void __seek_on_exit()
+{
+ if (!__towrite_used) __stdio_exit();
+}
+#endif
diff --git a/system/lib/libc/musl/src/stdio/__towrite.c b/system/lib/libc/musl/src/stdio/__towrite.c
index 3698d8b7..64f873f1 100644
--- a/system/lib/libc/musl/src/stdio/__towrite.c
+++ b/system/lib/libc/musl/src/stdio/__towrite.c
@@ -16,3 +16,14 @@ int __towrite(FILE *f)
return 0;
}
+
+#ifndef __EMSCRIPTEN__
+const int __towrite_used = 1;
+
+void __stdio_exit(void);
+
+void __flush_on_exit()
+{
+ __stdio_exit();
+}
+#endif
diff --git a/system/lib/libc/musl/src/stdio/asprintf.c b/system/lib/libc/musl/src/stdio/asprintf.c
new file mode 100644
index 00000000..4ec83534
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/asprintf.c
@@ -0,0 +1,13 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+
+int asprintf(char **s, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vasprintf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/system/lib/libc/musl/src/stdio/fputwc.c b/system/lib/libc/musl/src/stdio/fputwc.c
index 603fa615..128c40d1 100644
--- a/system/lib/libc/musl/src/stdio/fputwc.c
+++ b/system/lib/libc/musl/src/stdio/fputwc.c
@@ -8,7 +8,7 @@ wint_t __fputwc_unlocked(wchar_t c, FILE *f)
char mbc[MB_LEN_MAX];
int l;
-#if 0 // XXX EMSCRIPTEN
+#ifndef __EMSCRIPTEN__
f->mode |= f->mode+1;
if (isascii(c)) {
diff --git a/system/lib/libc/musl/src/stdio/fputws.c b/system/lib/libc/musl/src/stdio/fputws.c
index 70e004c9..94678f35 100644
--- a/system/lib/libc/musl/src/stdio/fputws.c
+++ b/system/lib/libc/musl/src/stdio/fputws.c
@@ -8,12 +8,12 @@ int fputws(const wchar_t *restrict ws, FILE *restrict f)
FLOCK(f);
-#if 0 // XXX EMSCRIPTEN
+#ifndef __EMSCRIPTEN__
f->mode |= f->mode+1;
#endif
while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1)
-#if 0 // XXX EMSCRIPTEN
+#ifndef __EMSCRIPTEN__
if (__fwritex(buf, l, f) < l) {
#else
if (fwrite(buf, 1, l, f) < l) {
diff --git a/system/lib/libc/musl/src/stdio/fwrite.c b/system/lib/libc/musl/src/stdio/fwrite.c
new file mode 100644
index 00000000..cbc3b22e
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/fwrite.c
@@ -0,0 +1,41 @@
+#include "stdio_impl.h"
+#include <string.h>
+
+size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
+{
+ size_t i=0;
+
+ if (!f->wend && __towrite(f)) return 0;
+
+ if (l > f->wend - f->wpos) return f->write(f, s, l);
+
+ if (f->lbf >= 0) {
+ /* Match /^(.*\n|)/ */
+ for (i=l; i && s[i-1] != '\n'; i--);
+ if (i) {
+ if (f->write(f, s, i) < i)
+ return i;
+ s += i;
+ l -= i;
+ }
+ }
+
+ memcpy(f->wpos, s, l);
+ f->wpos += l;
+ return l+i;
+}
+
+// XXX Emscripten: Not used, since we are not currently using musl file IO.
+#ifndef __EMSCRIPTEN__
+size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
+{
+ size_t k, l = size*nmemb;
+ if (!l) return l;
+ FLOCK(f);
+ k = __fwritex(src, l, f);
+ FUNLOCK(f);
+ return k==l ? nmemb : k/size;
+}
+
+weak_alias(fwrite, fwrite_unlocked);
+#endif
diff --git a/system/lib/libc/musl/src/stdio/snprintf.c b/system/lib/libc/musl/src/stdio/snprintf.c
new file mode 100644
index 00000000..771503b2
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/snprintf.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsnprintf(s, n, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
diff --git a/system/lib/libc/musl/src/stdio/sprintf.c b/system/lib/libc/musl/src/stdio/sprintf.c
new file mode 100644
index 00000000..9dff524c
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/sprintf.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+int sprintf(char *restrict s, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsprintf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/system/lib/libc/musl/src/stdio/sscanf.c b/system/lib/libc/musl/src/stdio/sscanf.c
new file mode 100644
index 00000000..8a2302ff
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/sscanf.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "libc.h"
+
+int sscanf(const char *restrict s, const char *restrict fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vsscanf(s, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+weak_alias(sscanf,__isoc99_sscanf);
diff --git a/system/lib/libc/musl/src/stdio/swprintf.c b/system/lib/libc/musl/src/stdio/swprintf.c
index cbf83d23..f75eb112 100644
--- a/system/lib/libc/musl/src/stdio/swprintf.c
+++ b/system/lib/libc/musl/src/stdio/swprintf.c
@@ -1,4 +1,3 @@
-#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
diff --git a/system/lib/libc/musl/src/stdio/vasprintf.c b/system/lib/libc/musl/src/stdio/vasprintf.c
new file mode 100644
index 00000000..68b7246b
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/vasprintf.c
@@ -0,0 +1,28 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define GUESS 240U
+
+int vasprintf(char **s, const char *fmt, va_list ap)
+{
+ va_list ap2;
+ char *a;
+ int l=GUESS;
+
+ if (!(a=malloc(GUESS))) return -1;
+
+ va_copy(ap2, ap);
+ l=vsnprintf(a, GUESS, fmt, ap2);
+ va_end(ap2);
+
+ if (l<GUESS) {
+ char *b = realloc(a, l+1U);
+ *s = b ? b : a;
+ return l;
+ }
+ free(a);
+ if (l<0 || !(*s=malloc(l+1U))) return -1;
+ return vsnprintf(*s, l+1U, fmt, ap);
+}
diff --git a/system/lib/libc/musl/src/stdio/vfprintf.c b/system/lib/libc/musl/src/stdio/vfprintf.c
new file mode 100644
index 00000000..4209e624
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/vfprintf.c
@@ -0,0 +1,689 @@
+#include "stdio_impl.h"
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <inttypes.h>
+#include <math.h>
+#include <float.h>
+
+/* Some useful macros */
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#define CONCAT2(x,y) x ## y
+#define CONCAT(x,y) CONCAT2(x,y)
+
+/* Convenient bit representation for modifier flags, which all fall
+ * within 31 codepoints of the space character. */
+
+#define ALT_FORM (1U<<'#'-' ')
+#define ZERO_PAD (1U<<'0'-' ')
+#define LEFT_ADJ (1U<<'-'-' ')
+#define PAD_POS (1U<<' '-' ')
+#define MARK_POS (1U<<'+'-' ')
+#define GROUPED (1U<<'\''-' ')
+
+#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
+
+#if UINT_MAX == ULONG_MAX
+#define LONG_IS_INT
+#endif
+
+#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
+#define ODD_TYPES
+#endif
+
+/* State machine to accept length modifiers + conversion specifiers.
+ * Result is 0 on failure, or an argument type to pop on success. */
+
+enum {
+ BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
+ ZTPRE, JPRE,
+ STOP,
+ PTR, INT, UINT, ULLONG,
+#ifndef LONG_IS_INT
+ LONG, ULONG,
+#else
+#define LONG INT
+#define ULONG UINT
+#endif
+ SHORT, USHORT, CHAR, UCHAR,
+#ifdef ODD_TYPES
+ LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
+#else
+#define LLONG ULLONG
+#define SIZET ULONG
+#define IMAX LLONG
+#define UMAX ULLONG
+#define PDIFF LONG
+#define UIPTR ULONG
+#endif
+ DBL, LDBL,
+ NOARG,
+ MAXSTATE
+};
+
+#define S(x) [(x)-'A']
+
+static const unsigned char states[]['z'-'A'+1] = {
+ { /* 0: bare types */
+ S('d') = INT, S('i') = INT,
+ S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
+ S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+ S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+ S('c') = CHAR, S('C') = INT,
+ S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
+ S('m') = NOARG,
+ S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
+ S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
+ }, { /* 1: l-prefixed */
+ S('d') = LONG, S('i') = LONG,
+ S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
+ S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
+ S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
+ S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('l') = LLPRE,
+ }, { /* 2: ll-prefixed */
+ S('d') = LLONG, S('i') = LLONG,
+ S('o') = ULLONG, S('u') = ULLONG,
+ S('x') = ULLONG, S('X') = ULLONG,
+ S('n') = PTR,
+ }, { /* 3: h-prefixed */
+ S('d') = SHORT, S('i') = SHORT,
+ S('o') = USHORT, S('u') = USHORT,
+ S('x') = USHORT, S('X') = USHORT,
+ S('n') = PTR,
+ S('h') = HHPRE,
+ }, { /* 4: hh-prefixed */
+ S('d') = CHAR, S('i') = CHAR,
+ S('o') = UCHAR, S('u') = UCHAR,
+ S('x') = UCHAR, S('X') = UCHAR,
+ S('n') = PTR,
+ }, { /* 5: L-prefixed */
+ S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
+ S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
+ S('n') = PTR,
+ }, { /* 6: z- or t-prefixed (assumed to be same size) */
+ S('d') = PDIFF, S('i') = PDIFF,
+ S('o') = SIZET, S('u') = SIZET,
+ S('x') = SIZET, S('X') = SIZET,
+ S('n') = PTR,
+ }, { /* 7: j-prefixed */
+ S('d') = IMAX, S('i') = IMAX,
+ S('o') = UMAX, S('u') = UMAX,
+ S('x') = UMAX, S('X') = UMAX,
+ S('n') = PTR,
+ }
+};
+
+#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
+
+union arg
+{
+ uintmax_t i;
+ long double f;
+ void *p;
+};
+
+static void pop_arg(union arg *arg, int type, va_list *ap)
+{
+ /* Give the compiler a hint for optimizing the switch. */
+ if ((unsigned)type > MAXSTATE) return;
+ switch (type) {
+ case PTR: arg->p = va_arg(*ap, void *);
+ break; case INT: arg->i = va_arg(*ap, int);
+ break; case UINT: arg->i = va_arg(*ap, unsigned int);
+#ifndef LONG_IS_INT
+ break; case LONG: arg->i = va_arg(*ap, long);
+ break; case ULONG: arg->i = va_arg(*ap, unsigned long);
+#endif
+ break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
+ break; case SHORT: arg->i = (short)va_arg(*ap, int);
+ break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
+ break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
+ break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
+#ifdef ODD_TYPES
+ break; case LLONG: arg->i = va_arg(*ap, long long);
+ break; case SIZET: arg->i = va_arg(*ap, size_t);
+ break; case IMAX: arg->i = va_arg(*ap, intmax_t);
+ break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
+ break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
+ break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
+#endif
+ break; case DBL: arg->f = va_arg(*ap, double);
+ break; case LDBL: arg->f = va_arg(*ap, long double);
+ }
+}
+
+static void out(FILE *f, const char *s, size_t l)
+{
+ __fwritex((void *)s, l, f);
+}
+
+static void pad(FILE *f, char c, int w, int l, int fl)
+{
+ char pad[256];
+ if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
+ l = w - l;
+ memset(pad, c, l>sizeof pad ? sizeof pad : l);
+ for (; l >= sizeof pad; l -= sizeof pad)
+ out(f, pad, sizeof pad);
+ out(f, pad, l);
+}
+
+static const char xdigits[16] = {
+ "0123456789ABCDEF"
+};
+
+static char *fmt_x(uintmax_t x, char *s, int lower)
+{
+ for (; x; x>>=4) *--s = xdigits[(x&15)]|lower;
+ return s;
+}
+
+static char *fmt_o(uintmax_t x, char *s)
+{
+ for (; x; x>>=3) *--s = '0' + (x&7);
+ return s;
+}
+
+static char *fmt_u(uintmax_t x, char *s)
+{
+ unsigned long y;
+ for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
+ for (y=x; y; y/=10) *--s = '0' + y%10;
+ return s;
+}
+
+/* Do not override this check. The floating point printing code below
+ * depends on the float.h constants being right. If they are wrong, it
+ * may overflow the stack. */
+#if LDBL_MANT_DIG == 53
+typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
+#endif
+
+static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
+{
+ uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
+ uint32_t *a, *d, *r, *z;
+ int e2=0, e, i, j, l;
+ char buf[9+LDBL_MANT_DIG/4], *s;
+ const char *prefix="-0X+0X 0X-0x+0x 0x";
+ int pl;
+ char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
+
+ pl=1;
+ if (signbit(y)) {
+ y=-y;
+ } else if (fl & MARK_POS) {
+ prefix+=3;
+ } else if (fl & PAD_POS) {
+ prefix+=6;
+ } else prefix++, pl=0;
+
+ if (!isfinite(y)) {
+ char *s = (t&32)?"inf":"INF";
+ if (y!=y) s=(t&32)?"nan":"NAN", pl=0;
+ pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
+ out(f, prefix, pl);
+ out(f, s, 3);
+ pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
+ return MAX(w, 3+pl);
+ }
+
+ y = frexpl(y, &e2) * 2;
+ if (y) e2--;
+
+ if ((t|32)=='a') {
+ long double round = 8.0;
+ int re;
+
+ if (t&32) prefix += 9;
+ pl += 2;
+
+ if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
+ else re=LDBL_MANT_DIG/4-1-p;
+
+ if (re) {
+ while (re--) round*=16;
+ if (*prefix=='-') {
+ y=-y;
+ y-=round;
+ y+=round;
+ y=-y;
+ } else {
+ y+=round;
+ y-=round;
+ }
+ }
+
+ estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
+ if (estr==ebuf) *--estr='0';
+ *--estr = (e2<0 ? '-' : '+');
+ *--estr = t+('p'-'a');
+
+ s=buf;
+ do {
+ int x=y;
+ *s++=xdigits[x]|(t&32);
+ y=16*(y-x);
+ if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
+ } while (y);
+
+ if (p && s-buf-2 < p)
+ l = (p+2) + (ebuf-estr);
+ else
+ l = (s-buf) + (ebuf-estr);
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+ out(f, buf, s-buf);
+ pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
+ out(f, estr, ebuf-estr);
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+ return MAX(w, pl+l);
+ }
+ if (p<0) p=6;
+
+ if (y) y *= 0x1p28, e2-=28;
+
+ if (e2<0) a=r=z=big;
+ else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
+
+ do {
+ *z = y;
+ y = 1000000000*(y-*z++);
+ } while (y);
+
+ while (e2>0) {
+ uint32_t carry=0;
+ int sh=MIN(29,e2);
+ for (d=z-1; d>=a; d--) {
+ uint64_t x = ((uint64_t)*d<<sh)+carry;
+ *d = x % 1000000000;
+ carry = x / 1000000000;
+ }
+ if (carry) *--a = carry;
+ while (z>a && !z[-1]) z--;
+ e2-=sh;
+ }
+ while (e2<0) {
+ uint32_t carry=0, *b;
+ int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3+8)/9;
+ for (d=a; d<z; d++) {
+ uint32_t rm = *d & (1<<sh)-1;
+ *d = (*d>>sh) + carry;
+ carry = (1000000000>>sh) * rm;
+ }
+ if (!*a) a++;
+ if (carry) *z++ = carry;
+ /* Avoid (slow!) computation past requested precision */
+ b = (t|32)=='f' ? r : a;
+ if (z-b > need) z = b+need;
+ e2+=sh;
+ }
+
+ if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ else e=0;
+
+ /* Perform rounding: j is precision after the radix (possibly neg) */
+ j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
+ if (j < 9*(z-r-1)) {
+ uint32_t x;
+ /* We avoid C's broken division of negative numbers */
+ d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
+ j += 9*LDBL_MAX_EXP;
+ j %= 9;
+ for (i=10, j++; j<9; i*=10, j++);
+ x = *d % i;
+ /* Are there any significant digits past j? */
+ if (x || d+1!=z) {
+ long double round = CONCAT(0x1p,LDBL_MANT_DIG);
+ long double small;
+ if (*d/i & 1) round += 2;
+ if (x<i/2) small=0x0.8p0;
+ else if (x==i/2 && d+1==z) small=0x1.0p0;
+ else small=0x1.8p0;
+ if (pl && *prefix=='-') round*=-1, small*=-1;
+ *d -= x;
+ /* Decide whether to round by probing round+small */
+ if (round+small != round) {
+ *d = *d + i;
+ while (*d > 999999999) {
+ *d--=0;
+ if (d<a) *--a=0;
+ (*d)++;
+ }
+ for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
+ }
+ }
+ if (z>d+1) z=d+1;
+ }
+ for (; z>a && !z[-1]; z--);
+
+ if ((t|32)=='g') {
+ if (!p) p++;
+ if (p>e && e>=-4) {
+ t--;
+ p-=e+1;
+ } else {
+ t-=2;
+ p--;
+ }
+ if (!(fl&ALT_FORM)) {
+ /* Count trailing zeros in last place */
+ if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
+ else j=9;
+ if ((t|32)=='f')
+ p = MIN(p,MAX(0,9*(z-r-1)-j));
+ else
+ p = MIN(p,MAX(0,9*(z-r-1)+e-j));
+ }
+ }
+ l = 1 + p + (p || (fl&ALT_FORM));
+ if ((t|32)=='f') {
+ if (e>0) l+=e;
+ } else {
+ estr=fmt_u(e<0 ? -e : e, ebuf);
+ while(ebuf-estr<2) *--estr='0';
+ *--estr = (e<0 ? '-' : '+');
+ *--estr = t;
+ l += ebuf-estr;
+ }
+
+ pad(f, ' ', w, pl+l, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+l, fl^ZERO_PAD);
+
+ if ((t|32)=='f') {
+ if (a>r) a=r;
+ for (d=a; d<=r; d++) {
+ char *s = fmt_u(*d, buf+9);
+ if (d!=a) while (s>buf) *--s='0';
+ else if (s==buf+9) *--s='0';
+ out(f, s, buf+9-s);
+ }
+ if (p || (fl&ALT_FORM)) out(f, ".", 1);
+ for (; d<z && p>0; d++, p-=9) {
+ char *s = fmt_u(*d, buf+9);
+ while (s>buf) *--s='0';
+ out(f, s, MIN(9,p));
+ }
+ pad(f, '0', p+9, 9, 0);
+ } else {
+ if (z<=a) z=a+1;
+ for (d=a; d<z && p>=0; d++) {
+ char *s = fmt_u(*d, buf+9);
+ if (s==buf+9) *--s='0';
+ if (d!=a) while (s>buf) *--s='0';
+ else {
+ out(f, s++, 1);
+ if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
+ }
+ out(f, s, MIN(buf+9-s, p));
+ p -= buf+9-s;
+ }
+ pad(f, '0', p+18, 18, 0);
+ out(f, estr, ebuf-estr);
+ }
+
+ pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
+
+ return MAX(w, pl+l);
+}
+
+static int getint(char **s) {
+ int i;
+ for (i=0; isdigit(**s); (*s)++)
+ i = 10*i + (**s-'0');
+ return i;
+}
+
+static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
+{
+ char *a, *z, *s=(char *)fmt;
+ unsigned l10n=0, fl;
+ int w, p;
+ union arg arg;
+ int argpos;
+ unsigned st, ps;
+ int cnt=0, l=0;
+ int i;
+ char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
+ const char *prefix;
+ int t, pl;
+ wchar_t wc[2], *ws;
+ char mb[4];
+
+ for (;;) {
+ /* Update output count, end loop when fmt is exhausted */
+ if (cnt >= 0) {
+ if (l > INT_MAX - cnt) {
+ errno = EOVERFLOW;
+ cnt = -1;
+ } else cnt += l;
+ }
+ if (!*s) break;
+
+ /* Handle literal text and %% format specifiers */
+ for (a=s; *s && *s!='%'; s++);
+ for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
+ l = z-a;
+ if (f) out(f, a, l);
+ if (l) continue;
+
+ if (isdigit(s[1]) && s[2]=='$') {
+ l10n=1;
+ argpos = s[1]-'0';
+ s+=3;
+ } else {
+ argpos = -1;
+ s++;
+ }
+
+ /* Read modifier flags */
+ for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
+ fl |= 1U<<*s-' ';
+
+ /* Read field width */
+ if (*s=='*') {
+ if (isdigit(s[1]) && s[2]=='$') {
+ l10n=1;
+ nl_type[s[1]-'0'] = INT;
+ w = nl_arg[s[1]-'0'].i;
+ s+=3;
+ } else if (!l10n) {
+ w = f ? va_arg(*ap, int) : 0;
+ s++;
+ } else return -1;
+ if (w<0) fl|=LEFT_ADJ, w=-w;
+ } else if ((w=getint(&s))<0) return -1;
+
+ /* Read precision */
+ if (*s=='.' && s[1]=='*') {
+ if (isdigit(s[2]) && s[3]=='$') {
+ nl_type[s[2]-'0'] = INT;
+ p = nl_arg[s[2]-'0'].i;
+ s+=4;
+ } else if (!l10n) {
+ p = f ? va_arg(*ap, int) : 0;
+ s+=2;
+ } else return -1;
+ } else if (*s=='.') {
+ s++;
+ p = getint(&s);
+ } else p = -1;
+
+ /* Format specifier state machine */
+ st=0;
+ do {
+ if (OOB(*s)) return -1;
+ ps=st;
+ st=states[st]S(*s++);
+ } while (st-1<STOP);
+ if (!st) return -1;
+
+ /* Check validity of argument type (nl/normal) */
+ if (st==NOARG) {
+ if (argpos>=0) return -1;
+ } else {
+ if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
+ else if (f) pop_arg(&arg, st, ap);
+ else return 0;
+ }
+
+ if (!f) continue;
+
+ z = buf + sizeof(buf);
+ prefix = "-+ 0X0x";
+ pl = 0;
+ t = s[-1];
+
+ /* Transform ls,lc -> S,C */
+ if (ps && (t&15)==3) t&=~32;
+
+ /* - and 0 flags are mutually exclusive */
+ if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
+
+ switch(t) {
+ case 'n':
+ switch(ps) {
+ case BARE: *(int *)arg.p = cnt; break;
+ case LPRE: *(long *)arg.p = cnt; break;
+ case LLPRE: *(long long *)arg.p = cnt; break;
+ case HPRE: *(unsigned short *)arg.p = cnt; break;
+ case HHPRE: *(unsigned char *)arg.p = cnt; break;
+ case ZTPRE: *(size_t *)arg.p = cnt; break;
+ case JPRE: *(uintmax_t *)arg.p = cnt; break;
+ }
+ continue;
+ case 'p':
+ p = MAX(p, 2*sizeof(void*));
+ t = 'x';
+ fl |= ALT_FORM;
+ case 'x': case 'X':
+ a = fmt_x(arg.i, z, t&32);
+ if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
+ if (0) {
+ case 'o':
+ a = fmt_o(arg.i, z);
+ if ((fl&ALT_FORM) && arg.i) prefix+=5, pl=1;
+ } if (0) {
+ case 'd': case 'i':
+ pl=1;
+ if (arg.i>INTMAX_MAX) {
+ arg.i=-arg.i;
+ } else if (fl & MARK_POS) {
+ prefix++;
+ } else if (fl & PAD_POS) {
+ prefix+=2;
+ } else pl=0;
+ case 'u':
+ a = fmt_u(arg.i, z);
+ }
+ if (p>=0) fl &= ~ZERO_PAD;
+ if (!arg.i && !p) {
+ a=z;
+ break;
+ }
+ p = MAX(p, z-a + !arg.i);
+ break;
+ case 'c':
+ *(a=z-(p=1))=arg.i;
+ fl &= ~ZERO_PAD;
+ break;
+ case 'm':
+ if (1) a = strerror(errno); else
+ case 's':
+ a = arg.p ? arg.p : "(null)";
+ z = memchr(a, 0, p);
+ if (!z) z=a+p;
+ else p=z-a;
+ fl &= ~ZERO_PAD;
+ break;
+ case 'C':
+ wc[0] = arg.i;
+ wc[1] = 0;
+ arg.p = wc;
+ p = -1;
+ case 'S':
+ ws = arg.p;
+ for (i=l=0; i<0U+p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=0U+p-i; i+=l);
+ if (l<0) return -1;
+ p = i;
+ pad(f, ' ', w, p, fl);
+ ws = arg.p;
+ for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l)
+ out(f, mb, l);
+ pad(f, ' ', w, p, fl^LEFT_ADJ);
+ l = w>p ? w : p;
+ continue;
+ case 'e': case 'f': case 'g': case 'a':
+ case 'E': case 'F': case 'G': case 'A':
+ l = fmt_fp(f, arg.f, w, p, fl, t);
+ continue;
+ }
+
+ if (p < z-a) p = z-a;
+ if (w < pl+p) w = pl+p;
+
+ pad(f, ' ', w, pl+p, fl);
+ out(f, prefix, pl);
+ pad(f, '0', w, pl+p, fl^ZERO_PAD);
+ pad(f, '0', p, z-a, 0);
+ out(f, a, z-a);
+ pad(f, ' ', w, pl+p, fl^LEFT_ADJ);
+
+ l = w;
+ }
+
+ if (f) return cnt;
+ if (!l10n) return 0;
+
+ for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
+ pop_arg(nl_arg+i, nl_type[i], ap);
+ for (; i<=NL_ARGMAX && !nl_type[i]; i++);
+ if (i<=NL_ARGMAX) return -1;
+ return 1;
+}
+
+//int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
+int MUSL_vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) /// XXX Emscripten: Only use musl-specific vfprintf when called from within sprintf.
+{
+ va_list ap2;
+ int nl_type[NL_ARGMAX+1] = {0};
+ union arg nl_arg[NL_ARGMAX+1];
+ unsigned char internal_buf[80], *saved_buf = 0;
+ int ret;
+
+ /* the copy allows passing va_list* even if va_list is an array */
+ va_copy(ap2, ap);
+ if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
+ va_end(ap2);
+ return -1;
+ }
+
+ FLOCK(f);
+ if (!f->buf_size) {
+ saved_buf = f->buf;
+ f->wpos = f->wbase = f->buf = internal_buf;
+ f->buf_size = sizeof internal_buf;
+ f->wend = internal_buf + sizeof internal_buf;
+ }
+ ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
+ if (saved_buf) {
+ f->write(f, 0, 0);
+ if (!f->wpos) ret = -1;
+ f->buf = saved_buf;
+ f->buf_size = 0;
+ f->wpos = f->wbase = f->wend = 0;
+ }
+ FUNLOCK(f);
+ va_end(ap2);
+ return ret;
+}
diff --git a/system/lib/libc/musl/src/stdio/vfscanf.c b/system/lib/libc/musl/src/stdio/vfscanf.c
new file mode 100644
index 00000000..653d2316
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/vfscanf.c
@@ -0,0 +1,333 @@
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "stdio_impl.h"
+#include "shgetc.h"
+#include "intscan.h"
+#include "floatscan.h"
+
+#define SIZE_hh -2
+#define SIZE_h -1
+#define SIZE_def 0
+#define SIZE_l 1
+#define SIZE_L 2
+#define SIZE_ll 3
+
+static void store_int(void *dest, int size, unsigned long long i)
+{
+ if (!dest) return;
+ switch (size) {
+ case SIZE_hh:
+ *(char *)dest = i;
+ break;
+ case SIZE_h:
+ *(short *)dest = i;
+ break;
+ case SIZE_def:
+ *(int *)dest = i;
+ break;
+ case SIZE_l:
+ *(long *)dest = i;
+ break;
+ case SIZE_ll:
+ *(long long *)dest = i;
+ break;
+ }
+}
+
+static void *arg_n(va_list ap, unsigned int n)
+{
+ void *p;
+ unsigned int i;
+ va_list ap2;
+ va_copy(ap2, ap);
+ for (i=n; i>1; i--) va_arg(ap2, void *);
+ p = va_arg(ap2, void *);
+ va_end(ap2);
+ return p;
+}
+
+//int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
+int MUSL_vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) // XXX Emscripten: Only use musl-specific vfscanf when called from within sscanf.
+{
+ int width;
+ int size;
+ int alloc;
+ int base;
+ const unsigned char *p;
+ int c, t;
+ char *s;
+ wchar_t *wcs;
+ mbstate_t st;
+ void *dest=NULL;
+ int invert;
+ int matches=0;
+ unsigned long long x;
+ long double y;
+ off_t pos = 0;
+ unsigned char scanset[257];
+ size_t i, k;
+ wchar_t wc;
+
+ FLOCK(f);
+
+ for (p=(const unsigned char *)fmt; *p; p++) {
+
+ alloc = 0;
+
+ if (isspace(*p)) {
+ while (isspace(p[1])) p++;
+ shlim(f, 0);
+ while (isspace(shgetc(f)));
+ shunget(f);
+ pos += shcnt(f);
+ continue;
+ }
+ if (*p != '%' || p[1] == '%') {
+ p += *p=='%';
+ shlim(f, 0);
+ c = shgetc(f);
+ if (c!=*p) {
+ shunget(f);
+ if (c<0) goto input_fail;
+ goto match_fail;
+ }
+ pos++;
+ continue;
+ }
+
+ p++;
+ if (*p=='*') {
+ dest = 0; p++;
+ } else if (isdigit(*p) && p[1]=='$') {
+ dest = arg_n(ap, *p-'0'); p+=2;
+ } else {
+ dest = va_arg(ap, void *);
+ }
+
+ for (width=0; isdigit(*p); p++) {
+ width = 10*width + *p - '0';
+ }
+
+ if (*p=='m') {
+ wcs = 0;
+ s = 0;
+ alloc = !!dest;
+ p++;
+ } else {
+ alloc = 0;
+ }
+
+ size = SIZE_def;
+ switch (*p++) {
+ case 'h':
+ if (*p == 'h') p++, size = SIZE_hh;
+ else size = SIZE_h;
+ break;
+ case 'l':
+ if (*p == 'l') p++, size = SIZE_ll;
+ else size = SIZE_l;
+ break;
+ case 'j':
+ size = SIZE_ll;
+ break;
+ case 'z':
+ case 't':
+ size = SIZE_l;
+ break;
+ case 'L':
+ size = SIZE_L;
+ break;
+ case 'd': case 'i': case 'o': case 'u': case 'x':
+ case 'a': case 'e': case 'f': case 'g':
+ case 'A': case 'E': case 'F': case 'G': case 'X':
+ case 's': case 'c': case '[':
+ case 'S': case 'C':
+ case 'p': case 'n':
+ p--;
+ break;
+ default:
+ goto fmt_fail;
+ }
+
+ t = *p;
+
+ /* C or S */
+ if ((t&0x2f) == 3) {
+ t |= 32;
+ size = SIZE_l;
+ }
+
+ switch (t) {
+ case 'c':
+ if (width < 1) width = 1;
+ case '[':
+ break;
+ case 'n':
+ store_int(dest, size, pos);
+ /* do not increment match count, etc! */
+ continue;
+ default:
+ shlim(f, 0);
+ while (isspace(shgetc(f)));
+ shunget(f);
+ pos += shcnt(f);
+ }
+
+ shlim(f, width);
+ if (shgetc(f) < 0) goto input_fail;
+ shunget(f);
+
+ switch (t) {
+ case 's':
+ case 'c':
+ case '[':
+ if (t == 'c' || t == 's') {
+ memset(scanset, -1, sizeof scanset);
+ scanset[0] = 0;
+ if (t == 's') {
+ scanset[1+'\t'] = 0;
+ scanset[1+'\n'] = 0;
+ scanset[1+'\v'] = 0;
+ scanset[1+'\f'] = 0;
+ scanset[1+'\r'] = 0;
+ scanset[1+' '] = 0;
+ }
+ } else {
+ if (*++p == '^') p++, invert = 1;
+ else invert = 0;
+ memset(scanset, invert, sizeof scanset);
+ scanset[0] = 0;
+ if (*p == '-') p++, scanset[1+'-'] = 1-invert;
+ else if (*p == ']') p++, scanset[1+']'] = 1-invert;
+ for (; *p != ']'; p++) {
+ if (!*p) goto fmt_fail;
+ if (*p=='-' && p[1] && p[1] != ']')
+ for (c=p++[-1]; c<*p; c++)
+ scanset[1+c] = 1-invert;
+ scanset[1+*p] = 1-invert;
+ }
+ }
+ wcs = 0;
+ s = 0;
+ i = 0;
+ k = t=='c' ? width+1U : 31;
+ if (size == SIZE_l) {
+ if (alloc) {
+ wcs = malloc(k*sizeof(wchar_t));
+ if (!wcs) goto alloc_fail;
+ } else {
+ wcs = dest;
+ }
+ st = (mbstate_t){0};
+ while (scanset[(c=shgetc(f))+1]) {
+ switch (mbrtowc(&wc, &(char){c}, 1, &st)) {
+ case -1:
+ goto input_fail;
+ case -2:
+ continue;
+ }
+ if (wcs) wcs[i++] = wc;
+ if (alloc && i==k) {
+ k+=k+1;
+ wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
+ if (!tmp) goto alloc_fail;
+ wcs = tmp;
+ }
+ }
+ if (!mbsinit(&st)) goto input_fail;
+ } else if (alloc) {
+ s = malloc(k);
+ if (!s) goto alloc_fail;
+ while (scanset[(c=shgetc(f))+1]) {
+ s[i++] = c;
+ if (i==k) {
+ k+=k+1;
+ char *tmp = realloc(s, k);
+ if (!tmp) goto alloc_fail;
+ s = tmp;
+ }
+ }
+ } else if ((s = dest)) {
+ while (scanset[(c=shgetc(f))+1])
+ s[i++] = c;
+ } else {
+ while (scanset[(c=shgetc(f))+1]);
+ }
+ shunget(f);
+ if (!shcnt(f)) goto match_fail;
+ if (t == 'c' && shcnt(f) != width) goto match_fail;
+ if (alloc) {
+ if (size == SIZE_l) *(wchar_t **)dest = wcs;
+ else *(char **)dest = s;
+ }
+ if (t != 'c') {
+ if (wcs) wcs[i] = 0;
+ if (s) s[i] = 0;
+ }
+ break;
+ case 'p':
+ case 'X':
+ case 'x':
+ base = 16;
+ goto int_common;
+ case 'o':
+ base = 8;
+ goto int_common;
+ case 'd':
+ case 'u':
+ base = 10;
+ goto int_common;
+ case 'i':
+ base = 0;
+ int_common:
+ x = __intscan(f, base, 0, ULLONG_MAX);
+ if (!shcnt(f)) goto match_fail;
+ if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x;
+ else store_int(dest, size, x);
+ break;
+ case 'a': case 'A':
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'g': case 'G':
+ y = __floatscan(f, size, 0);
+ if (!shcnt(f)) goto match_fail;
+ if (dest) switch (size) {
+ case SIZE_def:
+ *(float *)dest = y;
+ break;
+ case SIZE_l:
+ *(double *)dest = y;
+ break;
+ case SIZE_L:
+ *(long double *)dest = y;
+ break;
+ }
+ break;
+ }
+
+ pos += shcnt(f);
+ if (dest) matches++;
+ }
+ if (0) {
+fmt_fail:
+alloc_fail:
+input_fail:
+ if (!matches) matches--;
+match_fail:
+ if (alloc) {
+ free(s);
+ free(wcs);
+ }
+ }
+ FUNLOCK(f);
+ return matches;
+}
+
+weak_alias(vfscanf,__isoc99_vfscanf);
diff --git a/system/lib/libc/musl/src/stdio/vfwprintf.c b/system/lib/libc/musl/src/stdio/vfwprintf.c
index eb079312..984ff7b7 100644
--- a/system/lib/libc/musl/src/stdio/vfwprintf.c
+++ b/system/lib/libc/musl/src/stdio/vfwprintf.c
@@ -167,7 +167,7 @@ static const char sizeprefix['y'-'a'] = {
static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
{
- wchar_t *a, *z, *s=(wchar_t *)fmt, *s0;
+ wchar_t *a, *z, *s=(wchar_t *)fmt;
unsigned l10n=0, litpct, fl;
int w, p;
union arg arg;
@@ -242,7 +242,6 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
} else p = -1;
/* Format specifier state machine */
- s0=s;
st=0;
do {
if (OOB(*s)) return -1;
@@ -254,7 +253,6 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
/* Check validity of argument type (nl/normal) */
if (st==NOARG) {
if (argpos>=0) return -1;
- else if (!f) continue;
} else {
if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
else if (f) pop_arg(&arg, st, ap);
@@ -288,8 +286,7 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
case 'S':
a = arg.p;
z = wmemchr(a, 0, p);
- if (!z) z=a+p;
- else p=z-a;
+ if (z) p=z-a;
if (w<p) w=p;
if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
out(f, a, p);
@@ -350,8 +347,12 @@ int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
union arg nl_arg[NL_ARGMAX];
int ret;
+ /* the copy allows passing va_list* even if va_list is an array */
va_copy(ap2, ap);
- if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1;
+ if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
+ va_end(ap2);
+ return -1;
+ }
FLOCK(f);
ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
diff --git a/system/lib/libc/musl/src/stdio/vsnprintf.c b/system/lib/libc/musl/src/stdio/vsnprintf.c
new file mode 100644
index 00000000..9dcc84af
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/vsnprintf.c
@@ -0,0 +1,45 @@
+#include "stdio_impl.h"
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+static size_t sn_write(FILE *f, const unsigned char *s, size_t l)
+{
+ size_t k = f->wend - f->wpos;
+ if (k > l) k = l;
+ memcpy(f->wpos, s, k);
+ f->wpos += k;
+ /* pretend to succeed, but discard extra data */
+ return l;
+}
+
+// XXX Emscripten Call to musl-specific vfprintf for better asm.js performance, instead of the handwritten js function.
+#define vfprintf MUSL_vfprintf
+
+int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
+{
+ int r;
+ char b;
+ FILE f = { .lbf = EOF, .write = sn_write, .lock = -1 };
+
+ if (n-1 > INT_MAX-1) {
+ if (n) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ s = &b;
+ n = 1;
+ }
+
+ /* Ensure pointers don't wrap if "infinite" n is passed in */
+ if (n > (char *)0+SIZE_MAX-s-1) n = (char *)0+SIZE_MAX-s-1;
+ f.buf_size = n;
+ f.buf = f.wpos = (void *)s;
+ f.wbase = f.wend = (void *)(s+n);
+ r = vfprintf(&f, fmt, ap);
+
+ /* Null-terminate, overwriting last char if dest buffer is full */
+ if (n) f.wpos[-(f.wpos == f.wend)] = 0;
+ return r;
+}
diff --git a/system/lib/libc/musl/src/stdio/vsprintf.c b/system/lib/libc/musl/src/stdio/vsprintf.c
new file mode 100644
index 00000000..c57349d4
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/vsprintf.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <limits.h>
+
+int vsprintf(char *restrict s, const char *restrict fmt, va_list ap)
+{
+ return vsnprintf(s, INT_MAX, fmt, ap);
+}
diff --git a/system/lib/libc/musl/src/stdio/vsscanf.c b/system/lib/libc/musl/src/stdio/vsscanf.c
new file mode 100644
index 00000000..6492f78b
--- /dev/null
+++ b/system/lib/libc/musl/src/stdio/vsscanf.c
@@ -0,0 +1,20 @@
+#include "stdio_impl.h"
+#include "libc.h"
+
+static size_t do_read(FILE *f, unsigned char *buf, size_t len)
+{
+ return __string_read(f, buf, len);
+}
+
+#define vfscanf MUSL_vfscanf // XXX Emscripten: Call into musl version of vfscanf for asm.js performance, not the handwritten js version.
+
+int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap)
+{
+ FILE f = {
+ .buf = (void *)s, .cookie = (void *)s,
+ .read = do_read, .lock = -1
+ };
+ return vfscanf(&f, fmt, ap);
+}
+
+weak_alias(vsscanf,__isoc99_vsscanf);
diff --git a/system/lib/libc/musl/src/stdio/vswprintf.c b/system/lib/libc/musl/src/stdio/vswprintf.c
index e906f7ae..85057746 100644
--- a/system/lib/libc/musl/src/stdio/vswprintf.c
+++ b/system/lib/libc/musl/src/stdio/vswprintf.c
@@ -29,7 +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
+#ifndef __EMSCRIPTEN__
int r;
FILE f;
unsigned char buf[256];
diff --git a/system/lib/libc/musl/src/stdlib/ecvt.c b/system/lib/libc/musl/src/stdlib/ecvt.c
index 79c3de63..797b664e 100644
--- a/system/lib/libc/musl/src/stdlib/ecvt.c
+++ b/system/lib/libc/musl/src/stdlib/ecvt.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
diff --git a/system/lib/libc/musl/src/stdlib/gcvt.c b/system/lib/libc/musl/src/stdlib/gcvt.c
index 6c075e25..f29bc304 100644
--- a/system/lib/libc/musl/src/stdlib/gcvt.c
+++ b/system/lib/libc/musl/src/stdlib/gcvt.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
diff --git a/system/lib/libc/musl/src/stdlib/strtod.c b/system/lib/libc/musl/src/stdlib/strtod.c
index 35f640da..1810d0b4 100644
--- a/system/lib/libc/musl/src/stdlib/strtod.c
+++ b/system/lib/libc/musl/src/stdlib/strtod.c
@@ -32,6 +32,14 @@ long double strtold(const char *restrict s, char **restrict p)
return strtox(s, p, 2);
}
+#ifndef __EMSCRIPTEN__
+weak_alias(strtof, strtof_l);
+weak_alias(strtod, strtod_l);
+weak_alias(strtold, strtold_l);
+weak_alias(strtof, __strtof_l);
+weak_alias(strtod, __strtod_l);
+weak_alias(strtold, __strtold_l);
+#else
float strtof_l(const char *restrict s, char **restrict p, struct __locale_struct *loc)
{
return strtof(s, p);
@@ -50,3 +58,4 @@ long double strtold_l(const char *restrict s, char **restrict p, struct __locale
weak_alias(strtof_l, __strtof_l);
weak_alias(strtod_l, __strtod_l);
weak_alias(strtold_l, __strtold_l);
+#endif
diff --git a/system/lib/libc/musl/src/stdlib/wcstod.c b/system/lib/libc/musl/src/stdlib/wcstod.c
index 83f308d3..26fe9af8 100644
--- a/system/lib/libc/musl/src/stdlib/wcstod.c
+++ b/system/lib/libc/musl/src/stdlib/wcstod.c
@@ -1,6 +1,7 @@
#include "shgetc.h"
#include "floatscan.h"
#include "stdio_impl.h"
+#include <wchar.h>
#include <wctype.h>
/* This read function heavily cheats. It knows:
diff --git a/system/lib/libc/musl/src/string/bcmp.c b/system/lib/libc/musl/src/string/bcmp.c
index 5d6a388b..87c6007e 100644
--- a/system/lib/libc/musl/src/string/bcmp.c
+++ b/system/lib/libc/musl/src/string/bcmp.c
@@ -1,3 +1,4 @@
+#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
diff --git a/system/lib/libc/musl/src/string/bcopy.c b/system/lib/libc/musl/src/string/bcopy.c
index e76272fc..a07129f5 100644
--- a/system/lib/libc/musl/src/string/bcopy.c
+++ b/system/lib/libc/musl/src/string/bcopy.c
@@ -1,3 +1,4 @@
+#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
diff --git a/system/lib/libc/musl/src/string/bzero.c b/system/lib/libc/musl/src/string/bzero.c
index 0f98b4a5..ba536b07 100644
--- a/system/lib/libc/musl/src/string/bzero.c
+++ b/system/lib/libc/musl/src/string/bzero.c
@@ -1,3 +1,4 @@
+#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
diff --git a/system/lib/libc/musl/src/string/index.c b/system/lib/libc/musl/src/string/index.c
index dd611251..252948f9 100644
--- a/system/lib/libc/musl/src/string/index.c
+++ b/system/lib/libc/musl/src/string/index.c
@@ -1,3 +1,4 @@
+#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
diff --git a/system/lib/libc/musl/src/string/memccpy.c b/system/lib/libc/musl/src/string/memccpy.c
index b85009c8..7c233d5e 100644
--- a/system/lib/libc/musl/src/string/memccpy.c
+++ b/system/lib/libc/musl/src/string/memccpy.c
@@ -1,5 +1,4 @@
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
diff --git a/system/lib/libc/musl/src/string/memchr.c b/system/lib/libc/musl/src/string/memchr.c
index a0472f78..4daff7bb 100644
--- a/system/lib/libc/musl/src/string/memchr.c
+++ b/system/lib/libc/musl/src/string/memchr.c
@@ -1,5 +1,4 @@
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
diff --git a/system/lib/libc/musl/src/string/memmem.c b/system/lib/libc/musl/src/string/memmem.c
index 861fef2f..3b1ae183 100644
--- a/system/lib/libc/musl/src/string/memmem.c
+++ b/system/lib/libc/musl/src/string/memmem.c
@@ -1,6 +1,5 @@
#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)
@@ -121,7 +120,7 @@ static char *twoway_memmem(const unsigned char *h, const unsigned char *z, const
}
/* Compare left half */
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
- if (k == mem) return (char *)h;
+ if (k <= mem) return (char *)h;
h += p;
mem = mem0;
}
@@ -140,6 +139,7 @@ void *memmem(const void *h0, size_t k, const void *n0, size_t l)
/* Use faster algorithms for short needles */
h = memchr(h0, *n, k);
if (!h || l==1) return (void *)h;
+ k -= h - (const unsigned char *)h0;
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);
diff --git a/system/lib/libc/musl/src/string/mempcpy.c b/system/lib/libc/musl/src/string/mempcpy.c
index c23ca69e..a297985e 100644
--- a/system/lib/libc/musl/src/string/mempcpy.c
+++ b/system/lib/libc/musl/src/string/mempcpy.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <string.h>
void *mempcpy(void *dest, const void *src, size_t n)
diff --git a/system/lib/libc/musl/src/string/rindex.c b/system/lib/libc/musl/src/string/rindex.c
index 17df2bf2..693c750b 100644
--- a/system/lib/libc/musl/src/string/rindex.c
+++ b/system/lib/libc/musl/src/string/rindex.c
@@ -1,3 +1,4 @@
+#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
diff --git a/system/lib/libc/musl/src/string/stpcpy.c b/system/lib/libc/musl/src/string/stpcpy.c
index feb9eb81..06623c44 100644
--- a/system/lib/libc/musl/src/string/stpcpy.c
+++ b/system/lib/libc/musl/src/string/stpcpy.c
@@ -1,5 +1,4 @@
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include "libc.h"
diff --git a/system/lib/libc/musl/src/string/strchrnul.c b/system/lib/libc/musl/src/string/strchrnul.c
index ceae4d45..05700ad6 100644
--- a/system/lib/libc/musl/src/string/strchrnul.c
+++ b/system/lib/libc/musl/src/string/strchrnul.c
@@ -1,5 +1,4 @@
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include "libc.h"
diff --git a/system/lib/libc/musl/src/string/strcmp.c b/system/lib/libc/musl/src/string/strcmp.c
index 91eb7404..808bd837 100644
--- a/system/lib/libc/musl/src/string/strcmp.c
+++ b/system/lib/libc/musl/src/string/strcmp.c
@@ -2,6 +2,6 @@
int strcmp(const char *l, const char *r)
{
- for (; *l==*r && *l && *r; l++, r++);
+ for (; *l==*r && *l; l++, r++);
return *(unsigned char *)l - *(unsigned char *)r;
}
diff --git a/system/lib/libc/musl/src/string/strlcpy.c b/system/lib/libc/musl/src/string/strlcpy.c
index 4d3ff92a..193d7241 100644
--- a/system/lib/libc/musl/src/string/strlcpy.c
+++ b/system/lib/libc/musl/src/string/strlcpy.c
@@ -1,5 +1,5 @@
+#define _BSD_SOURCE
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include "libc.h"
diff --git a/system/lib/libc/musl/src/string/strstr.c b/system/lib/libc/musl/src/string/strstr.c
index 06491748..cd069127 100644
--- a/system/lib/libc/musl/src/string/strstr.c
+++ b/system/lib/libc/musl/src/string/strstr.c
@@ -1,5 +1,4 @@
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
static char *twobyte_strstr(const unsigned char *h, const unsigned char *n)
@@ -131,7 +130,7 @@ static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
}
/* Compare left half */
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
- if (k == mem) return (char *)h;
+ if (k <= mem) return (char *)h;
h += p;
mem = mem0;
}
diff --git a/system/lib/libc/musl/src/string/strverscmp.c b/system/lib/libc/musl/src/string/strverscmp.c
index 94d2e15c..6f37cc68 100644
--- a/system/lib/libc/musl/src/string/strverscmp.c
+++ b/system/lib/libc/musl/src/string/strverscmp.c
@@ -1,7 +1,6 @@
#define _GNU_SOURCE
#include <ctype.h>
#include <string.h>
-#include <sys/types.h>
int strverscmp(const char *l, const char *r)
{
diff --git a/system/lib/libc/musl/src/string/wcsstr.c b/system/lib/libc/musl/src/string/wcsstr.c
index 037d0965..4caaef3c 100644
--- a/system/lib/libc/musl/src/string/wcsstr.c
+++ b/system/lib/libc/musl/src/string/wcsstr.c
@@ -1,7 +1,4 @@
#include <wchar.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
@@ -87,7 +84,7 @@ static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n)
}
/* Compare left half */
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
- if (k == mem) return (wchar_t *)h;
+ if (k <= mem) return (wchar_t *)h;
h += p;
mem = mem0;
}
diff --git a/system/lib/libc/musl/src/string/wmemchr.c b/system/lib/libc/musl/src/string/wmemchr.c
index 37d69629..2bc2c270 100644
--- a/system/lib/libc/musl/src/string/wmemchr.c
+++ b/system/lib/libc/musl/src/string/wmemchr.c
@@ -1,4 +1,3 @@
-#include <string.h>
#include <wchar.h>
wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n)
diff --git a/system/lib/libc/musl/src/string/wmemcmp.c b/system/lib/libc/musl/src/string/wmemcmp.c
index 6788a383..2a193263 100644
--- a/system/lib/libc/musl/src/string/wmemcmp.c
+++ b/system/lib/libc/musl/src/string/wmemcmp.c
@@ -1,4 +1,3 @@
-#include <string.h>
#include <wchar.h>
int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n)
diff --git a/system/lib/libc/musl/src/string/wmemcpy.c b/system/lib/libc/musl/src/string/wmemcpy.c
index 55a8e1d8..52e6e6e0 100644
--- a/system/lib/libc/musl/src/string/wmemcpy.c
+++ b/system/lib/libc/musl/src/string/wmemcpy.c
@@ -1,4 +1,3 @@
-#include <string.h>
#include <wchar.h>
wchar_t *wmemcpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n)
diff --git a/system/lib/libc/musl/src/string/wmemmove.c b/system/lib/libc/musl/src/string/wmemmove.c
index cde4feec..e406f3d5 100644
--- a/system/lib/libc/musl/src/string/wmemmove.c
+++ b/system/lib/libc/musl/src/string/wmemmove.c
@@ -1,4 +1,3 @@
-#include <string.h>
#include <wchar.h>
wchar_t *wmemmove(wchar_t *d, const wchar_t *s, size_t n)
diff --git a/system/lib/libc/musl/src/string/wmemset.c b/system/lib/libc/musl/src/string/wmemset.c
index 1a2a8618..07a037a0 100644
--- a/system/lib/libc/musl/src/string/wmemset.c
+++ b/system/lib/libc/musl/src/string/wmemset.c
@@ -1,4 +1,3 @@
-#include <string.h>
#include <wchar.h>
wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n)
diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols
index 17e524e6..1ab849bd 100644
--- a/system/lib/libcextra.symbols
+++ b/system/lib/libcextra.symbols
@@ -21,6 +21,7 @@
T __wcscoll_l
T __wcsxfrm_l
W __wctype_l
+ T asprintf
T atoll
T bcmp
T bcopy
@@ -113,7 +114,6 @@
T mbstowcs
T mbtowc
T memccpy
- T memchr
T memmem
T mempcpy
W memrchr
@@ -131,6 +131,7 @@
T rindex
T scalbnf
D signgam
+ T sscanf
T stpcpy
T strcasecmp_l
T strcasestr
@@ -176,8 +177,11 @@
T towlower_l
T towupper
T towupper_l
+ T vasprintf
T verr
T verrx
+ T MUSL_vfscanf
+ T vsscanf
T vfwprintf
T vswprintf
T vwarn
@@ -187,7 +191,6 @@
T warnx
T wcpcpy
T wcpncpy
- T wcrtomb
T wcscasecmp
T wcscasecmp_l
T wcscat
@@ -227,7 +230,6 @@
T wcsxfrm
T wcsxfrm_l
T wctob
- T wctomb
T wctrans
T wctrans_l
T wctype
diff --git a/system/lib/libcxxabi/src/exception.cpp b/system/lib/libcxxabi/src/exception.cpp
index c47a9b76..c69db02d 100644
--- a/system/lib/libcxxabi/src/exception.cpp
+++ b/system/lib/libcxxabi/src/exception.cpp
@@ -25,6 +25,7 @@ const char* exception::what() const _NOEXCEPT
return "std::exception";
}
+#ifndef __EMSCRIPTEN__
// bad_exception
bad_exception::~bad_exception() _NOEXCEPT
@@ -35,6 +36,7 @@ const char* bad_exception::what() const _NOEXCEPT
{
return "std::bad_exception";
}
+#endif
} // std
diff --git a/system/lib/libcxxabi/symbols b/system/lib/libcxxabi/symbols
index f2925e4c..13d79901 100644
--- a/system/lib/libcxxabi/symbols
+++ b/system/lib/libcxxabi/symbols
@@ -235,3 +235,4 @@
D _ZTVSt8bad_cast
D _ZTVSt9type_info
T __dynamic_cast
+ T _ZNSt9exceptionD1Ev
diff --git a/system/lib/pkgconfig/egl.pc b/system/lib/pkgconfig/egl.pc
new file mode 100644
index 00000000..7d023da3
--- /dev/null
+++ b/system/lib/pkgconfig/egl.pc
@@ -0,0 +1,3 @@
+Name: egl
+Description: EGL library
+Version: 10.2.2
diff --git a/system/lib/pkgconfig/glesv2.pc b/system/lib/pkgconfig/glesv2.pc
new file mode 100644
index 00000000..97e47328
--- /dev/null
+++ b/system/lib/pkgconfig/glesv2.pc
@@ -0,0 +1,3 @@
+Name: glesv2
+Description: OpenGL ES 2.0 library
+Version: 10.2.2
diff --git a/system/lib/pkgconfig/libpng.pc b/system/lib/pkgconfig/libpng.pc
new file mode 100644
index 00000000..a39371a0
--- /dev/null
+++ b/system/lib/pkgconfig/libpng.pc
@@ -0,0 +1,3 @@
+Name: libpng
+Description: Loads and saves PNG files
+Version: 1.6.12
diff --git a/system/lib/pkgconfig/sdl.pc b/system/lib/pkgconfig/sdl.pc
new file mode 100644
index 00000000..5925707a
--- /dev/null
+++ b/system/lib/pkgconfig/sdl.pc
@@ -0,0 +1,4 @@
+Name: sdl
+Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
+Version: 1.2.15
+Cflags: -D_GNU_SOURCE=1 -D_REENTRANT
diff --git a/system/lib/pkgconfig/zlib.pc b/system/lib/pkgconfig/zlib.pc
new file mode 100644
index 00000000..a2a3c808
--- /dev/null
+++ b/system/lib/pkgconfig/zlib.pc
@@ -0,0 +1,3 @@
+Name: zlib
+Description: zlib compression library
+Version: 1.2.8
diff --git a/system/lib/test.cpp b/system/lib/test.cpp
new file mode 100644
index 00000000..653f9cc7
--- /dev/null
+++ b/system/lib/test.cpp
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <time.h>
+
+int clock_gettime(clockid_t clk_id, struct timespec *tp) {
+ printf("BAD\n");
+ return 0;
+}
+
+/*
+int main() {
+ printf("ok\n");
+}
+*/
+
diff --git a/system/local/include/README.txt b/system/local/include/README.txt
new file mode 100644
index 00000000..09bd03e0
--- /dev/null
+++ b/system/local/include/README.txt
@@ -0,0 +1,2 @@
+You may place local includes that you require here and they will
+be found by the default compiler search path.
diff --git a/tests/bullet/CMakeLists.txt b/tests/bullet/CMakeLists.txt
index 13f22e7c..55299a06 100644
--- a/tests/bullet/CMakeLists.txt
+++ b/tests/bullet/CMakeLists.txt
@@ -265,7 +265,7 @@ IF (USE_GLUT)
ENDIF (MSVC)
ENDIF (GLUT_FOUND)
- IF(NOT WIN32)
+ IF(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING)
# This is added for linux. This should always work if everything is installed and working fine.
INCLUDE_DIRECTORIES(/usr/include /usr/local/include)
ENDIF()
diff --git a/tests/cases/floatundefinvoke_fastcomp.ll b/tests/cases/floatundefinvoke_fastcomp.ll
new file mode 100644
index 00000000..215506ef
--- /dev/null
+++ b/tests/cases/floatundefinvoke_fastcomp.ll
@@ -0,0 +1,30 @@
+; ModuleID = 'a.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:128-n32-S128"
+target triple = "asmjs-unknown-emscripten"
+
+@.str = private unnamed_addr constant [11 x i8] c"float: %f\0A\00", align 1
+
+define void @_Z10printFloatf(float %f) #0 {
+entry:
+ %conv = fpext float %f to double
+ %call = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str, i32 0, i32 0), double %conv)
+ ret void
+}
+
+define i32 @main() #1 {
+entry:
+ tail call void @_Z10printFloatf(float 1.000000e+00)
+ call void @emscripten_preinvoke()
+ call void @_Z10printFloatf(float undef)
+ %last = call i32 @emscripten_postinvoke()
+ %lastf = sitofp i32 %last to float
+ tail call void @_Z10printFloatf(float %lastf)
+ ret i32 1
+}
+
+declare void @emscripten_preinvoke()
+declare i32 @emscripten_postinvoke()
+declare i32 @printf(i8* nocapture, ...) #1
+
+attributes #0 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
diff --git a/tests/cases/floatundefinvoke_fastcomp.txt b/tests/cases/floatundefinvoke_fastcomp.txt
new file mode 100644
index 00000000..5e19391e
--- /dev/null
+++ b/tests/cases/floatundefinvoke_fastcomp.txt
@@ -0,0 +1,3 @@
+float: 1.000000
+float: 0.000000
+float: 0.000000
diff --git a/tests/cmake/target_html/CMakeLists.txt b/tests/cmake/target_html/CMakeLists.txt
index ce26c541..968afb93 100644
--- a/tests/cmake/target_html/CMakeLists.txt
+++ b/tests/cmake/target_html/CMakeLists.txt
@@ -42,8 +42,38 @@ if (NOT CMAKE_C_SIZEOF_DATA_PTR)
message(FATAL_ERROR "CMAKE_C_SIZEOF_DATA_PTR was not defined!")
endif()
+# with NO_DEFAULT_PATH + ONLY_CMAKE_FIND_ROOT_PATH, we ensure that
+# only ${CMAKE_FIND_ROOT_PATH}/include will be searched for
+# emscripten/emscripten.h
+find_path(EMSCRIPTEN_INCLUDE_DIR emscripten/emscripten.h
+ PATHS /include
+ NO_DEFAULT_PATH
+ ONLY_CMAKE_FIND_ROOT_PATH
+ )
+
+if(NOT EMSCRIPTEN_INCLUDE_DIR)
+ message(FATAL_ERROR "emscripten.h could not be found! Is CMAKE_FIND_ROOT_PATH='${CMAKE_FIND_ROOT_PATH}' correct?")
+endif()
+
+include(CheckIncludeFile)
+
+check_include_file(stdlib.h HAVE_STDLIB_H)
+if (NOT ${HAVE_STDLIB_H})
+ message(FATAL_ERROR "CMake script check_include_file failed! Could not find stdlib.h via it!")
+endif()
+
+if (NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL ".js")
+ message(FATAL_ERROR "The default suffix for building executables should be .js!")
+endif()
SET(CMAKE_EXECUTABLE_SUFFIX ".html")
+# CMake built-in check_include_file() macro interacts with CMAKE_EXECUTABLE_SUFFIX, so make sure it works after user changes that.
+
+check_include_file(math.h HAVE_MATH_H)
+if (NOT ${HAVE_MATH_H})
+ message(FATAL_ERROR "CMake script check_include_file failed! Could not find math.h via it!")
+endif()
+
add_executable(hello_world_gles ${sourceFiles})
set_target_properties(hello_world_gles PROPERTIES LINK_FLAGS "${linkFlags}")
diff --git a/tests/cmake/target_js/CMakeLists.txt b/tests/cmake/target_js/CMakeLists.txt
index 244cc70a..1de5d97e 100644
--- a/tests/cmake/target_js/CMakeLists.txt
+++ b/tests/cmake/target_js/CMakeLists.txt
@@ -9,12 +9,47 @@ file(GLOB postJsFiles post*.js)
file(GLOB libraryJsFiles jslibrary*.js)
if (CMAKE_BUILD_TYPE STREQUAL Debug)
- SET(linkFlags "-g4")
+ SET(linkFlags "-g4 -s NO_EXIT_RUNTIME=1")
else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimizations enabled.
- SET(linkFlags "-O2")
+ SET(linkFlags "-O2 -s NO_EXIT_RUNTIME=1")
endif()
-SET(CMAKE_EXECUTABLE_SUFFIX ".js")
+# Test that the CMake-provided macro check_function_exists() works.
+include(CheckFunctionExists)
+check_function_exists("strtod" HAVE_STRTOD)
+if (NOT ${HAVE_STRTOD})
+ message(FATAL_ERROR "CMake script check_function_exists failed! Could not detect if strtod() is supported!")
+endif()
+
+# Test that the CMake-provided macro check_function_exists() is not actually trivially returning true for everything.
+check_function_exists("some_nonexisting_function" HAVE_NONEXISTING_FUNCTION)
+if (${HAVE_NONEXISTING_FUNCTION})
+ message(FATAL_ERROR "CMake script check_function_exists failed! It erroneously reports that function some_nonexisting_function() would exist!")
+endif()
+
+# Test that the CMake-provided macro check_include_file() works.
+include(CheckIncludeFile)
+check_include_file(stdlib.h HAVE_STDLIB_H)
+if (NOT ${HAVE_STDLIB_H})
+ message(FATAL_ERROR "CMake script check_include_file failed! Could not find stdlib.h via it!")
+endif()
+
+# Test that the CMake-provided macro check_include_file() is not actually trivially returning true for everything.
+check_include_file(some_nonexisting_include.h HAVE_NONEXISTING_INCLUDE_H)
+if (${HAVE_NONEXISTING_INCLUDE_H})
+ message(FATAL_ERROR "CMake script check_include_file failed! It erroneously reports that the C header some_nonexisting_include.h would exist!")
+endif()
+
+if (NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL ".js")
+ message(FATAL_ERROR "The default suffix for building executables should be .js!")
+endif()
+
+# CMake built-in check_include_file() macro interacts with CMAKE_EXECUTABLE_SUFFIX, so make sure it works after user changes that.
+
+check_include_file(math.h HAVE_MATH_H)
+if (NOT ${HAVE_MATH_H})
+ message(FATAL_ERROR "CMake script check_include_file failed! Could not find math.h via it!")
+endif()
if (WIN32)
message(FATAL_ERROR "WIN32 should not be defined when cross-compiling!")
diff --git a/tests/cmake/target_library/CMakeLists.txt b/tests/cmake/target_library/CMakeLists.txt
new file mode 100644
index 00000000..c7023192
--- /dev/null
+++ b/tests/cmake/target_library/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(test_cmake)
+
+option(BUILD_SHARED_LIBS "Build with shared libraries." OFF)
+
+if (CMAKE_BUILD_TYPE STREQUAL Debug)
+ SET(linkFlags "-g4")
+else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimizations enabled.
+ SET(linkFlags "-O2")
+endif()
+
+set(MAX_SRC_FILE_INDEX 30)
+SET(TEST_SRC_FILE_BASE_NAME "this_is_a_test_src_file_with_a_quite_lengthy_name_to_simulate_very_long_command_line_length_problems_on_windows_")
+
+
+foreach(i RANGE ${MAX_SRC_FILE_INDEX})
+ set (TEST_FUNCTION_NAME "FooBar_${i}")
+ configure_file("srcfile.cmake" "${TEST_SRC_FILE_BASE_NAME}${i}.c")
+ configure_file("srcfile.cmake" "${TEST_SRC_FILE_BASE_NAME}${i}.cpp")
+ list(APPEND TEST_SOURCES "${TEST_SRC_FILE_BASE_NAME}${i}.c" "${TEST_SRC_FILE_BASE_NAME}${i}.cpp")
+endforeach()
+
+add_library(test_cmake ${TEST_SOURCES})
+
+if (WIN32)
+ message(FATAL_ERROR "WIN32 should not be defined when cross-compiling!")
+endif()
+
+if (APPLE)
+ message(FATAL_ERROR "APPLE should not be defined when cross-compiling!")
+endif()
+
+if (NOT EMSCRIPTEN)
+ message(FATAL_ERROR "EMSCRIPTEN should be defined when cross-compiling!")
+endif()
+
+if (NOT CMAKE_C_SIZEOF_DATA_PTR)
+ message(FATAL_ERROR "CMAKE_C_SIZEOF_DATA_PTR was not defined!")
+endif()
+
+# GOTCHA: If your project has custom link flags, these must be set *before* calling any of the em_link_xxx functions!
+set_target_properties(test_cmake PROPERTIES LINK_FLAGS "${linkFlags}")
diff --git a/tests/cmake/target_library/srcfile.cmake b/tests/cmake/target_library/srcfile.cmake
new file mode 100644
index 00000000..10e9e6f8
--- /dev/null
+++ b/tests/cmake/target_library/srcfile.cmake
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void @TEST_FUNCTION_NAME@()
+{
+ printf("@TEST_FUNCTION_NAME@");
+}
diff --git a/tests/core/test_ccall.out b/tests/core/test_ccall.out
index 526ed80d..b4cddc5e 100644
--- a/tests/core/test_ccall.out
+++ b/tests/core/test_ccall.out
@@ -15,6 +15,7 @@ number,10
650
number,21
*
+5
atr
10
bret
diff --git a/tests/core/test_exceptions_white_list_empty.out b/tests/core/test_exceptions_white_list_empty.out
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/core/test_exceptions_white_list_empty.out
diff --git a/tests/core/test_floatvars.in b/tests/core/test_floatvars.in
index b6c94c82..d59b6028 100644
--- a/tests/core/test_floatvars.in
+++ b/tests/core/test_floatvars.in
@@ -15,13 +15,8 @@ int main(int argc, char **argv) {
printf("small: %.10f\n", argc * 0.000001);
- /*
- // Rounding behavior
- float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
- double ds[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
- for (int i = 0; i < 6; i++)
- printf("*int(%.2f)=%d,%d*\n", fs[i], int(fs[i]), int(ds[i]));
- */
+ double d = 1.12345678901234567890123e21;
+ printf("double: %f\n", d);
return 0;
}
diff --git a/tests/core/test_floatvars.out b/tests/core/test_floatvars.out
index 57635092..128c04ae 100644
--- a/tests/core/test_floatvars.out
+++ b/tests/core/test_floatvars.out
@@ -1,3 +1,4 @@
*1,10,10.5,1,1.2340,0.00*
0.50, 3.30, 3.30, 3.30
small: 0.0000010000
+double: 1.1234567890123457e+21
diff --git a/tests/core/test_i64_varargs.in b/tests/core/test_i64_varargs.in
index 7d2e4267..a0cbec64 100644
--- a/tests/core/test_i64_varargs.in
+++ b/tests/core/test_i64_varargs.in
@@ -16,6 +16,7 @@ int64_t ccv_cache_generate_signature(char *msg, int len, int64_t sig_start,
}
int main(int argc, char **argv) {
+ argv[0] = "...";
for (int i = 0; i < argc; i++) {
int64_t x;
if (i % 123123 == 0)
diff --git a/tests/core/test_i64_varargs.out b/tests/core/test_i64_varargs.out
index 8c7b7843..01832abc 100644
--- a/tests/core/test_i64_varargs.out
+++ b/tests/core/test_i64_varargs.out
@@ -1,6 +1,6 @@
-in/this.program
+.
nada
-1536
+1504
a
nada
5760
diff --git a/tests/core/test_random_device.cpp b/tests/core/test_random_device.cpp
new file mode 100644
index 00000000..2a539756
--- /dev/null
+++ b/tests/core/test_random_device.cpp
@@ -0,0 +1,16 @@
+#include <random>
+#include <iostream>
+#include <exception>
+
+auto main()
+ -> int
+try
+{
+ std::random_device rd;
+ std::cout << "random was read" << "\n";
+}
+catch( const std::exception& e )
+{
+ std::cerr << e.what();
+}
+
diff --git a/tests/core/test_random_device.txt b/tests/core/test_random_device.txt
new file mode 100644
index 00000000..4b386ac6
--- /dev/null
+++ b/tests/core/test_random_device.txt
@@ -0,0 +1 @@
+random was read
diff --git a/tests/core/test_set_align.c b/tests/core/test_set_align.c
new file mode 100644
index 00000000..26158ef4
--- /dev/null
+++ b/tests/core/test_set_align.c
@@ -0,0 +1,50 @@
+
+#include <stdio.h>
+#include <emscripten.h>
+
+volatile char data[16];
+
+__attribute__((noinline)) void *get_aligned(int align)
+{
+ char *ptr = (char*)(((int)(data + 7)) & ~7); // Make 8-byte aligned
+ ptr += align; // Now 'align' aligned
+ return (void*)ptr;
+}
+
+int main()
+{
+ emscripten_align4_double *d4 = (emscripten_align4_double*)get_aligned(4);
+ *d4 = 17.0;
+ printf("addr: %d, value: %f\n", ((int)d4) % 8, *d4);
+
+ emscripten_align2_double *d2 = (emscripten_align2_double*)get_aligned(2);
+ *d2 = 18.0;
+ printf("addr: %d, value: %f\n", ((int)d2) % 8, *d2);
+
+ emscripten_align1_double *d1 = (emscripten_align1_double*)get_aligned(1);
+ *d1 = 19.0;
+ printf("addr: %d, value: %f\n", ((int)d1) % 8, *d1);
+
+ emscripten_align2_float *f2 = (emscripten_align2_float*)get_aligned(2);
+ *f2 = 20.0;
+ printf("addr: %d, value: %f\n", ((int)f2) % 4, *f2);
+
+ emscripten_align1_float *f1 = (emscripten_align1_float*)get_aligned(1);
+ *f1 = 21.0;
+ printf("addr: %d, value: %f\n", ((int)f1) % 4, *f1);
+
+ emscripten_align2_int *i2 = (emscripten_align2_int*)get_aligned(2);
+ *i2 = 22;
+ printf("addr: %d, value: %d\n", ((int)i2) % 4, *i2);
+
+ emscripten_align1_int *i1 = (emscripten_align1_int*)get_aligned(1);
+ *i1 = 23;
+ printf("addr: %d, value: %d\n", ((int)i1) % 4, *i1);
+
+ emscripten_align1_short *s1 = (emscripten_align1_short*)get_aligned(1);
+ *s1 = 24;
+ printf("addr: %d, value: %d\n", ((int)s1) % 4, (int)*s1);
+
+ return 0;
+}
+
diff --git a/tests/core/test_set_align.out b/tests/core/test_set_align.out
new file mode 100644
index 00000000..55e377b0
--- /dev/null
+++ b/tests/core/test_set_align.out
@@ -0,0 +1,8 @@
+addr: 4, value: 17.000000
+addr: 2, value: 18.000000
+addr: 1, value: 19.000000
+addr: 2, value: 20.000000
+addr: 1, value: 21.000000
+addr: 2, value: 22
+addr: 1, value: 23
+addr: 1, value: 24
diff --git a/tests/core/test_simd4.in b/tests/core/test_simd4.in
new file mode 100644
index 00000000..b597d8a3
--- /dev/null
+++ b/tests/core/test_simd4.in
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <xmmintrin.h>
+
+static __inline__ __m128 __attribute__((__always_inline__))
+_mm_load_ps(const float *__p)
+{
+ return *(__m128*)__p;
+}
+
+float simdAverage(float *src, int len) {
+ __m128 sumx4 = _mm_setzero_ps();
+ for (int i = 0; i < len; i += 4) {
+ __m128 v = _mm_load_ps(src);
+ sumx4 = _mm_add_ps(sumx4, v);
+ src += 4;
+ }
+ float sumx4_mem[4];
+ float *sumx4_ptr = sumx4_mem;
+ _mm_store_ps(sumx4_ptr, sumx4);
+ return (sumx4_mem[0] + sumx4_mem[1] +
+ sumx4_mem[2] + sumx4_mem[3])/len;
+}
+
+void initArray(float *src, int len) {
+ for (int i = 0; i < len; ++i) {
+ src[i] = 0.1 * i;
+ }
+}
+
+int main() {
+ const int len = 100000;
+ float src[len];
+ float result = 0.0;
+
+ initArray(src, len);
+
+ result = simdAverage(src, len);
+ printf("averagex4 result: %.1f\n", result);
+} \ No newline at end of file
diff --git a/tests/core/test_simd4.out b/tests/core/test_simd4.out
new file mode 100644
index 00000000..99449772
--- /dev/null
+++ b/tests/core/test_simd4.out
@@ -0,0 +1 @@
+averagex4 result: 4999.9 \ No newline at end of file
diff --git a/tests/core/test_sscanf.in b/tests/core/test_sscanf.in
index 55a310c5..470aaf37 100644
--- a/tests/core/test_sscanf.in
+++ b/tests/core/test_sscanf.in
@@ -66,7 +66,8 @@ int main() {
char buf1[100], buf2[100], buf3[100], buf4[100];
memset(buf4, 0, 100);
- int numItems = sscanf("level=4:ref=3", "%255[^:=]=%255[^:]:%255[^=]=%255c",
+
+ int numItems = sscanf("level=4:ref=3", "%255[^:=]=%255[^:]:%255[^=]=%c",
buf1, buf2, buf3, buf4);
printf("%d, %s, %s, %s, %s\n", numItems, buf1, buf2, buf3, buf4);
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index a6b2e98c..0b5aa572 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -8,15 +8,12 @@ module({
cm.setDelayFunction(undefined);
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
- cm._mallocDebug(2);
assert.equal(0, cm.count_emval_handles());
- cm._mallocAssertAllMemoryFree();
}
});
this.tearDown(function() {
cm.flushPendingDeletes();
if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
- cm._mallocAssertAllMemoryFree();
assert.equal(0, cm.count_emval_handles());
}
});
@@ -29,35 +26,6 @@ module({
});
});
- if (typeof INVOKED_FROM_EMSCRIPTEN_TEST_RUNNER === "undefined") { // TODO: Enable this to work in Emscripten runner as well!
-
- BaseFixture.extend("leak testing", function() {
- test("no memory allocated at start of test", function() {
- cm._mallocAssertAllMemoryFree();
- });
- test("assert when memory is allocated", function() {
- var ptr = cm._malloc(42);
- assert.throws(cm._MemoryAllocationError, function() {
- cm._mallocAssertAllMemoryFree();
- });
- cm._free(ptr);
- });
- test("allocated memory counts down again for free", function() {
- var ptr = cm._malloc(42);
- cm._free(ptr);
- cm._mallocAssertAllMemoryFree();
- });
- test("free without malloc throws MemoryAllocationError", function() {
- var ptr = cm._malloc(42);
- cm._free(ptr);
- assert.throws(cm._MemoryAllocationError, function() {
- cm._free(ptr);
- });
- });
- });
-
- }
-
BaseFixture.extend("access to base class members", function() {
test("method name in derived class silently overrides inherited name", function() {
var derived = new cm.Derived();
@@ -604,6 +572,18 @@ module({
c.delete();
});
+ test("can pass unique_ptr", function() {
+ var p = cm.embind_test_return_unique_ptr(42);
+ var m = cm.embind_test_accept_unique_ptr(p);
+ assert.equal(42, m);
+ });
+
+ test("can pass unique_ptr to constructor", function() {
+ var c = new cm.embind_test_construct_class_with_unique_ptr(42);
+ assert.equal(42, c.getValue());
+ c.delete();
+ });
+
test("can get member classes then call its member functions", function() {
var p = new cm.ParentClass();
var c = p.getBigClass();
@@ -1580,8 +1560,6 @@ module({
};
var impl = cm.AbstractClass.implement(new MyImplementation);
- // TODO: remove .implement() as a public API. It interacts poorly with Class.extend.
- //assert.equal(expected, impl.optionalMethod(expected));
assert.equal(expected, cm.callOptionalMethod(impl, expected));
impl.delete();
});
@@ -1589,8 +1567,6 @@ module({
test("if not implemented then optional method runs default", function() {
var impl = cm.AbstractClass.implement({});
assert.equal("optionalfoo", impl.optionalMethod("foo"));
- // TODO: remove .implement() as a public API. It interacts poorly with Class.extend.
- //assert.equal("optionalfoo", cm.callOptionalMethod(impl, "foo"));
impl.delete();
});
@@ -1760,8 +1736,6 @@ module({
assert.equal("optionaljs_optional_123", result);
});
- // TODO: deriving from classes with constructors?
-
test("instanceof", function() {
var instance = new Empty;
assert.instanceof(instance, Empty);
@@ -2410,6 +2384,7 @@ module({
var back = holder.get();
assert.equal(back, instance);
holder.delete();
+ back.delete();
});
});
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index 30267994..34a7d164 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -856,6 +856,32 @@ void emval_test_call_function(val v, int i, float f, TupleVector tv, StructVecto
v(i, f, tv, sv);
}
+class UniquePtrToConstructor {
+public:
+ UniquePtrToConstructor(std::unique_ptr<int> p)
+ : value(*p)
+ {}
+
+ int getValue() const {
+ return value;
+ }
+
+private:
+ int value;
+};
+
+std::unique_ptr<int> embind_test_return_unique_ptr(int v) {
+ return std::unique_ptr<int>(new int(v));
+}
+
+UniquePtrToConstructor* embind_test_construct_class_with_unique_ptr(int v) {
+ return new UniquePtrToConstructor(embind_test_return_unique_ptr(v));
+}
+
+int embind_test_accept_unique_ptr(std::unique_ptr<int> p) {
+ return *p.get();
+}
+
std::unique_ptr<ValHolder> emval_test_return_unique_ptr() {
return std::unique_ptr<ValHolder>(new ValHolder(val::object()));
}
@@ -1114,9 +1140,6 @@ public:
std::string optionalMethod(std::string s) const {
return call<std::string>("optionalMethod", s);
- //return optional_call<std::string>(optionalMethod_symbol, [&] {
- // return AbstractClass::optionalMethod(s);
- //}, s);
}
std::shared_ptr<Derived> returnsSharedPtr() {
@@ -1175,6 +1198,8 @@ struct AbstractClassWithConstructor {
: s(s)
{}
+ virtual ~AbstractClassWithConstructor() {};
+
virtual std::string abstractMethod() = 0;
std::string concreteMethod() {
return s;
@@ -1818,6 +1843,15 @@ EMSCRIPTEN_BINDINGS(tests) {
function("embind_test_accept_small_class_instance", &embind_test_accept_small_class_instance);
function("embind_test_accept_big_class_instance", &embind_test_accept_big_class_instance);
+ class_<UniquePtrToConstructor>("UniquePtrToConstructor")
+ .constructor<std::unique_ptr<int>>()
+ .function("getValue", &UniquePtrToConstructor::getValue)
+ ;
+
+ function("embind_test_construct_class_with_unique_ptr", embind_test_construct_class_with_unique_ptr, allow_raw_pointer<ret_val>());
+ function("embind_test_return_unique_ptr", embind_test_return_unique_ptr);
+ function("embind_test_accept_unique_ptr", embind_test_accept_unique_ptr);
+
function("embind_test_return_raw_base_ptr", embind_test_return_raw_base_ptr, allow_raw_pointer<ret_val>());
function("embind_test_return_raw_derived_ptr_as_base", embind_test_return_raw_derived_ptr_as_base, allow_raw_pointer<ret_val>());
function("embind_test_return_raw_sibling_derived_ptr_as_base", embind_test_return_raw_sibling_derived_ptr_as_base, allow_raw_pointer<ret_val>());
diff --git a/tests/fs/test_append.c b/tests/fs/test_append.c
new file mode 100644
index 00000000..27909ba3
--- /dev/null
+++ b/tests/fs/test_append.c
@@ -0,0 +1,24 @@
+#include<assert.h>
+#include<stdio.h>
+
+int main (int argc, char *argv[])
+{
+ FILE *fp;
+ int res;
+ long len;
+
+ fp = fopen("testappend", "wb+");
+ res = fwrite("1234567890", 10, 1, fp);
+ fclose(fp);
+
+ fp = fopen("testappend", "ab+");
+ res = fwrite("1234567890", 10, 1, fp);
+
+ fseek(fp, -7, SEEK_END);
+ len = ftell(fp);
+ assert(len == 13);
+ fclose(fp);
+
+ puts("success");
+ return 0;
+}
diff --git a/tests/fs/test_emptyPath.c b/tests/fs/test_emptyPath.c
new file mode 100644
index 00000000..27d56ea1
--- /dev/null
+++ b/tests/fs/test_emptyPath.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int main() {
+ FILE* f1 = fopen("s", "r");
+ if (f1 == NULL) {
+ printf("file 's' not found!\n");
+ }
+
+ FILE* f2 = fopen("", "r");
+ if (f2 == NULL) {
+ printf("file '' not found!\n");
+ }
+ return 0;
+}
diff --git a/tests/fs/test_emptyPath.out b/tests/fs/test_emptyPath.out
new file mode 100644
index 00000000..78352877
--- /dev/null
+++ b/tests/fs/test_emptyPath.out
@@ -0,0 +1,2 @@
+file 's' not found!
+file '' not found!
diff --git a/tests/gl_teximage.c b/tests/gl_teximage.c
new file mode 100644
index 00000000..9cafce9c
--- /dev/null
+++ b/tests/gl_teximage.c
@@ -0,0 +1,120 @@
+/*
+ * GLES2 test for glTexImage2D parameters
+ *
+ * Original author: Jason Green <jason@transgaming.com>
+ *
+ */
+#include "GLES2/gl2.h"
+#include "SDL/SDL.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <emscripten.h>
+#include <unistd.h>
+
+typedef enum {
+ TEST_STATUS_SUCCESS = 0,
+ TEST_STATUS_FAILURE = 1
+} TestStatus;
+
+/* Report success or failure (1 or 0) to Emscripten's test harness. Also, exit
+ * with the given error code. */
+static void exit_with_status(TestStatus code)
+{
+#ifdef REPORT_RESULT
+ int result = (code == TEST_STATUS_SUCCESS) ? 1 : 0;
+ REPORT_RESULT();
+#endif
+
+ exit(code);
+}
+
+/* Loop over all glGetError() results until GL reports GL_NO_ERROR */
+static void clear_gl_errors()
+{
+ GLenum err;
+ do {
+ err = glGetError();
+ } while (err != GL_NO_ERROR);
+}
+
+int main(int argc, char *argv[])
+{
+ TestStatus passed = TEST_STATUS_SUCCESS;
+ SDL_Surface *screen;
+
+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+ printf("SDL_Init failed with %s\n", SDL_GetError());
+ exit_with_status(TEST_STATUS_FAILURE);
+ }
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ screen = SDL_SetVideoMode(640, 480, 16, SDL_OPENGL);
+ if (!screen) {
+ printf("SDL_SetVideoMode failed with %s\n", SDL_GetError());
+ exit_with_status(TEST_STATUS_FAILURE);
+ }
+
+ GLuint texture;
+ glGenTextures(1, &texture);
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ // Allocate space for a 32x32 image with 4 bytes per pixel.
+ // No need to fill it with any useful information, as these tests are
+ // only designed to make sure glTexImage2D doesn't crash on unsupported
+ // formats.
+ void* pixels = malloc(4 * 32 * 32);
+ if (pixels == NULL) {
+ printf("Unable to allocate pixel data\n");
+ exit_with_status(TEST_STATUS_FAILURE);
+ }
+
+ // First, try 0xffff for the internal format - should fail
+ glTexImage2D(GL_TEXTURE_2D, 0, 0xffff, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ GLenum err = glGetError();
+ if (err == GL_NO_ERROR) {
+ printf("internal format == 0xffff succeeded, but should have failed\n");
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Try 0xffff for the format - should fail
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, 0xffff, GL_UNSIGNED_BYTE, pixels);
+ err = glGetError();
+ if (err == GL_NO_ERROR) {
+ printf("format == 0xffff succeeded, but should have failed\n");
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Try 0xffff for the type - should fail
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, 0xffff, pixels);
+ err = glGetError();
+ if (err == GL_NO_ERROR) {
+ printf("type == 0xffff succeeded, but should have failed\n");
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Try GL_RGBA/GL_UNSIGNED_BYTE - should succeed
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ err = glGetError();
+ if (err != GL_NO_ERROR) {
+ printf("GL_RGBA/GL_UNSIGNED_BYTE failed with %x, but should have succeeded\n", err);
+ passed = TEST_STATUS_FAILURE;
+ }
+ clear_gl_errors();
+
+ // Clean up objects
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &texture);
+ free(pixels);
+
+ // 'screen' is freed implicitly by SDL_Quit()
+ SDL_Quit();
+
+ exit_with_status(passed);
+}
diff --git a/tests/gles2_uniform_arrays.cpp b/tests/gles2_uniform_arrays.cpp
index 7293f9a9..b6be5348 100644
--- a/tests/gles2_uniform_arrays.cpp
+++ b/tests/gles2_uniform_arrays.cpp
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include <emscripten.h>
void RunTest(int testVariant)
{
@@ -57,6 +58,7 @@ void RunTest(int testVariant)
// so to exhibit extra issues in old code (and to keep new code from regressing), must test both with and without excess glGetUniformLocation calls.
if ((testVariant&1) != 0)
{
+ printf("check glGetUniformLocation with indexes\n");
// Deliberately check in odd order to make sure any kind of lazy operations won't affect the indices we get.
assert(glGetUniformLocation(program, "colors[2]") == loc+2);
assert(glGetUniformLocation(program, "colors[0]") == loc);
@@ -65,6 +67,7 @@ void RunTest(int testVariant)
assert(glGetUniformLocation(program, "colors[]") == loc);
assert(glGetUniformLocation(program, "colors[-100]") == -1);
assert(glGetUniformLocation(program, "colors[bleh]") == -1);
+ printf(" ...ok\n");
}
float colors[4*3] = { 1,0,0, 0,0.5,0, 0,0,0.2, 1,1,1 };
@@ -95,13 +98,20 @@ void RunTest(int testVariant)
glDrawArrays(GL_TRIANGLES, 0, 6);
- unsigned char pixel[4];
- glReadPixels(1,1,1,1,GL_RGBA,GL_UNSIGNED_BYTE, pixel);
- //printf("%d,%d,%d,%d\n", pixel[0], pixel[1], pixel[2], pixel[3]);
- assert(pixel[0] == 255);
- assert(pixel[1] == 178);
- assert(pixel[2] == 102);
- assert(pixel[3] == 255);
+ int in_worker = EM_ASM_INT_V({
+ return typeof importScripts !== 'undefined'
+ });
+
+ if (!in_worker) {
+ printf("Doing readpixels check\n");
+ unsigned char pixel[4];
+ glReadPixels(1,1,1,1,GL_RGBA,GL_UNSIGNED_BYTE, pixel);
+ //printf("%d,%d,%d,%d\n", pixel[0], pixel[1], pixel[2], pixel[3]);
+ assert(pixel[0] == 255);
+ assert(pixel[1] == 178);
+ assert(pixel[2] == 102);
+ assert(pixel[3] == 255);
+ }
printf("OK: Case %d passed.\n", testVariant);
// Lazy, don't clean up afterwards.
@@ -126,5 +136,10 @@ int main(int argc, char *argv[])
for(int i = 0; i < 4; ++i)
RunTest(i);
+#ifdef REPORT_RESULT
+ int result = 1;
+ REPORT_RESULT();
+#endif
+
return 0;
}
diff --git a/tests/glfw.c b/tests/glfw.c
index 79199d9a..cbdc81fe 100644
--- a/tests/glfw.c
+++ b/tests/glfw.c
@@ -376,6 +376,10 @@ void PullInfo(){
extension = "GL_EXT_framebuffer_object";
printf("'%s' extension is %s.\n", extension, glfwExtensionSupported(extension) ? "supported" : "not supported");
+ extension = "glBindBuffer";
+ void* proc_addr = glfwGetProcAddress(extension);
+ printf("'%s' extension proc address is %p.\n", extension, proc_addr);
+
printf("Sleeping 1 sec...\n");
glfwSleep(1);
printf("...Done.\n");
diff --git a/tests/hello_malloc.cpp b/tests/hello_malloc.cpp
index d3774f70..d4398c3b 100644
--- a/tests/hello_malloc.cpp
+++ b/tests/hello_malloc.cpp
@@ -13,6 +13,6 @@ int main() {
void *another = malloc(1024);
assert(another == allocs[0]);
printf("hello, world!\n");
- return 1;
+ return 0;
}
diff --git a/tests/hello_world.c b/tests/hello_world.c
index cad52a2c..eb47ea81 100644
--- a/tests/hello_world.c
+++ b/tests/hello_world.c
@@ -2,6 +2,6 @@
int main() {
printf("hello, world!\n");
- return 1;
+ return 0;
}
diff --git a/tests/hello_world.cpp b/tests/hello_world.cpp
index 441d892b..c5f69b9e 100644
--- a/tests/hello_world.cpp
+++ b/tests/hello_world.cpp
@@ -4,6 +4,6 @@ class Test {}; // This will fail in C mode
int main() {
printf("hello, world!\n");
- return 1;
+ return 0;
}
diff --git a/tests/hello_world.ll b/tests/hello_world.ll
index 7090b732..7bab7361 100644
--- a/tests/hello_world.ll
+++ b/tests/hello_world.ll
@@ -9,7 +9,7 @@ entry:
%retval = alloca i32, align 4
store i32 0, i32* %retval
%call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0))
- ret i32 1
+ ret i32 0
}
declare i32 @printf(i8*, ...)
diff --git a/tests/hello_world_file.cpp b/tests/hello_world_file.cpp
index 71fb953b..97ea395e 100644
--- a/tests/hello_world_file.cpp
+++ b/tests/hello_world_file.cpp
@@ -1,6 +1,10 @@
#include <stdio.h>
int main() {
FILE *file = fopen("tests/hello_world_file.txt", "rb");
+ if (!file) {
+ printf("cannot open file\n");
+ return 1;
+ }
while (!feof(file)) {
char c = fgetc(file);
if (c != EOF) {
diff --git a/tests/hello_world_gles_proxy.c b/tests/hello_world_gles_proxy.c
new file mode 100644
index 00000000..1a8e5f61
--- /dev/null
+++ b/tests/hello_world_gles_proxy.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Ported to GLES2.
+ * Kristian Høgsberg <krh@bitplanet.net>
+ * May 3, 2010
+ *
+ * Improve GLES2 port:
+ * * Refactor gear drawing.
+ * * Use correct normals for surfaces.
+ * * Improve shader.
+ * * Use perspective projection transformation.
+ * * Add FPS count.
+ * * Add comments.
+ * Alexandros Frantzis <alexandros.frantzis@linaro.org>
+ * Jul 13, 2010
+ */
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#define _GNU_SOURCE
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#include <Glut/glut.h>
+#else
+#include <GL/gl.h>
+#include <GL/glut.h>
+#endif
+
+#define STRIPS_PER_TOOTH 7
+#define VERTICES_PER_TOOTH 34
+#define GEAR_VERTEX_STRIDE 6
+
+#ifndef HAVE_BUILTIN_SINCOS
+#define sincos _sincos
+static void
+sincos (double a, double *s, double *c)
+{
+ *s = sin (a);
+ *c = cos (a);
+}
+#endif
+
+/**
+ * Struct describing the vertices in triangle strip
+ */
+struct vertex_strip {
+ /** The first vertex in the strip */
+ GLint first;
+ /** The number of consecutive vertices in the strip after the first */
+ GLint count;
+};
+
+/* Each vertex consist of GEAR_VERTEX_STRIDE GLfloat attributes */
+typedef GLfloat GearVertex[GEAR_VERTEX_STRIDE];
+
+/**
+ * Struct representing a gear.
+ */
+struct gear {
+ /** The array of vertices comprising the gear */
+ GearVertex *vertices;
+ /** The number of vertices comprising the gear */
+ int nvertices;
+ /** The array of triangle strips comprising the gear */
+ struct vertex_strip *strips;
+ /** The number of triangle strips comprising the gear */
+ int nstrips;
+ /** The Vertex Buffer Object holding the vertices in the graphics card */
+ GLuint vbo;
+};
+
+/** The view rotation [x, y, z] */
+static GLfloat view_rot[3] = { 20.0, 30.0, 0.0 };
+/** The gears */
+static struct gear *gear1, *gear2, *gear3;
+/** The current gear rotation angle */
+static GLfloat angle = 0.0;
+/** The location of the shader uniforms */
+static GLuint ModelViewProjectionMatrix_location,
+ NormalMatrix_location,
+ LightSourcePosition_location,
+ MaterialColor_location;
+/** The projection matrix */
+static GLfloat ProjectionMatrix[16];
+/** The direction of the directional light for the scene */
+static const GLfloat LightSourcePosition[4] = { 5.0, 5.0, 10.0, 1.0};
+
+/**
+ * Fills a gear vertex.
+ *
+ * @param v the vertex to fill
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param z the z coortinate
+ * @param n pointer to the normal table
+ *
+ * @return the operation error code
+ */
+static GearVertex *
+vert(GearVertex *v, GLfloat x, GLfloat y, GLfloat z, GLfloat n[3])
+{
+ v[0][0] = x;
+ v[0][1] = y;
+ v[0][2] = z;
+ v[0][3] = n[0];
+ v[0][4] = n[1];
+ v[0][5] = n[2];
+
+ return v + 1;
+}
+
+/**
+ * Create a gear wheel.
+ *
+ * @param inner_radius radius of hole at center
+ * @param outer_radius radius at center of teeth
+ * @param width width of gear
+ * @param teeth number of teeth
+ * @param tooth_depth depth of tooth
+ *
+ * @return pointer to the constructed struct gear
+ */
+static struct gear *
+create_gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLfloat r0, r1, r2;
+ GLfloat da;
+ GearVertex *v;
+ struct gear *gear;
+ double s[5], c[5];
+ GLfloat normal[3];
+ int cur_strip = 0;
+ int i;
+
+ /* Allocate memory for the gear */
+ gear = malloc(sizeof *gear);
+ if (gear == NULL)
+ return NULL;
+
+ /* Calculate the radii used in the gear */
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ /* Allocate memory for the triangle strip information */
+ gear->nstrips = STRIPS_PER_TOOTH * teeth;
+ gear->strips = calloc(gear->nstrips, sizeof (*gear->strips));
+
+ /* Allocate memory for the vertices */
+ gear->vertices = calloc(VERTICES_PER_TOOTH * teeth, sizeof(*gear->vertices));
+ v = gear->vertices;
+
+ for (i = 0; i < teeth; i++) {
+ /* Calculate needed sin/cos for varius angles */
+ sincos(i * 2.0 * M_PI / teeth, &s[0], &c[0]);
+ sincos(i * 2.0 * M_PI / teeth + da, &s[1], &c[1]);
+ sincos(i * 2.0 * M_PI / teeth + da * 2, &s[2], &c[2]);
+ sincos(i * 2.0 * M_PI / teeth + da * 3, &s[3], &c[3]);
+ sincos(i * 2.0 * M_PI / teeth + da * 4, &s[4], &c[4]);
+
+ /* A set of macros for making the creation of the gears easier */
+#define GEAR_POINT(r, da) { (r) * c[(da)], (r) * s[(da)] }
+#define SET_NORMAL(x, y, z) do { \
+ normal[0] = (x); normal[1] = (y); normal[2] = (z); \
+} while(0)
+
+#define GEAR_VERT(v, point, sign) vert((v), p[(point)].x, p[(point)].y, (sign) * width * 0.5, normal)
+
+#define START_STRIP do { \
+ gear->strips[cur_strip].first = v - gear->vertices; \
+} while(0);
+
+#define END_STRIP do { \
+ int _tmp = (v - gear->vertices); \
+ gear->strips[cur_strip].count = _tmp - gear->strips[cur_strip].first; \
+ cur_strip++; \
+} while (0)
+
+#define QUAD_WITH_NORMAL(p1, p2) do { \
+ SET_NORMAL((p[(p1)].y - p[(p2)].y), -(p[(p1)].x - p[(p2)].x), 0); \
+ v = GEAR_VERT(v, (p1), -1); \
+ v = GEAR_VERT(v, (p1), 1); \
+ v = GEAR_VERT(v, (p2), -1); \
+ v = GEAR_VERT(v, (p2), 1); \
+} while(0)
+
+ struct point {
+ GLfloat x;
+ GLfloat y;
+ };
+
+ /* Create the 7 points (only x,y coords) used to draw a tooth */
+ struct point p[7] = {
+ GEAR_POINT(r2, 1), // 0
+ GEAR_POINT(r2, 2), // 1
+ GEAR_POINT(r1, 0), // 2
+ GEAR_POINT(r1, 3), // 3
+ GEAR_POINT(r0, 0), // 4
+ GEAR_POINT(r1, 4), // 5
+ GEAR_POINT(r0, 4), // 6
+ };
+
+ /* Front face */
+ START_STRIP;
+ SET_NORMAL(0, 0, 1.0);
+ v = GEAR_VERT(v, 0, +1);
+ v = GEAR_VERT(v, 1, +1);
+ v = GEAR_VERT(v, 2, +1);
+ v = GEAR_VERT(v, 3, +1);
+ v = GEAR_VERT(v, 4, +1);
+ v = GEAR_VERT(v, 5, +1);
+ v = GEAR_VERT(v, 6, +1);
+ END_STRIP;
+
+ /* Inner face */
+ START_STRIP;
+ QUAD_WITH_NORMAL(4, 6);
+ END_STRIP;
+
+ /* Back face */
+ START_STRIP;
+ SET_NORMAL(0, 0, -1.0);
+ v = GEAR_VERT(v, 6, -1);
+ v = GEAR_VERT(v, 5, -1);
+ v = GEAR_VERT(v, 4, -1);
+ v = GEAR_VERT(v, 3, -1);
+ v = GEAR_VERT(v, 2, -1);
+ v = GEAR_VERT(v, 1, -1);
+ v = GEAR_VERT(v, 0, -1);
+ END_STRIP;
+
+ /* Outer face */
+ START_STRIP;
+ QUAD_WITH_NORMAL(0, 2);
+ END_STRIP;
+
+ START_STRIP;
+ QUAD_WITH_NORMAL(1, 0);
+ END_STRIP;
+
+ START_STRIP;
+ QUAD_WITH_NORMAL(3, 1);
+ END_STRIP;
+
+ START_STRIP;
+ QUAD_WITH_NORMAL(5, 3);
+ END_STRIP;
+ }
+
+ gear->nvertices = (v - gear->vertices);
+
+ /* Store the vertices in a vertex buffer object (VBO) */
+ glGenBuffers(1, &gear->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
+ glBufferData(GL_ARRAY_BUFFER, gear->nvertices * sizeof(GearVertex),
+ gear->vertices, GL_STATIC_DRAW);
+
+ return gear;
+}
+
+/**
+ * Multiplies two 4x4 matrices.
+ *
+ * The result is stored in matrix m.
+ *
+ * @param m the first matrix to multiply
+ * @param n the second matrix to multiply
+ */
+static void
+multiply(GLfloat *m, const GLfloat *n)
+{
+ GLfloat tmp[16];
+ const GLfloat *row, *column;
+ div_t d;
+ int i, j;
+
+ for (i = 0; i < 16; i++) {
+ tmp[i] = 0;
+ d = div(i, 4);
+ row = n + d.quot * 4;
+ column = m + d.rem;
+ for (j = 0; j < 4; j++)
+ tmp[i] += row[j] * column[j * 4];
+ }
+ memcpy(m, &tmp, sizeof tmp);
+}
+
+/**
+ * Rotates a 4x4 matrix.
+ *
+ * @param[in,out] m the matrix to rotate
+ * @param angle the angle to rotate
+ * @param x the x component of the direction to rotate to
+ * @param y the y component of the direction to rotate to
+ * @param z the z component of the direction to rotate to
+ */
+static void
+rotate(GLfloat *m, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+ double s, c;
+
+ sincos(angle, &s, &c);
+ GLfloat r[16] = {
+ x * x * (1 - c) + c, y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
+ x * y * (1 - c) - z * s, y * y * (1 - c) + c, y * z * (1 - c) + x * s, 0,
+ x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c, 0,
+ 0, 0, 0, 1
+ };
+
+ multiply(m, r);
+}
+
+
+/**
+ * Translates a 4x4 matrix.
+ *
+ * @param[in,out] m the matrix to translate
+ * @param x the x component of the direction to translate to
+ * @param y the y component of the direction to translate to
+ * @param z the z component of the direction to translate to
+ */
+static void
+translate(GLfloat *m, GLfloat x, GLfloat y, GLfloat z)
+{
+ GLfloat t[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
+
+ multiply(m, t);
+}
+
+/**
+ * Creates an identity 4x4 matrix.
+ *
+ * @param m the matrix make an identity matrix
+ */
+static void
+identity(GLfloat *m)
+{
+ GLfloat t[16] = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0,
+ };
+
+ memcpy(m, t, sizeof(t));
+}
+
+/**
+ * Transposes a 4x4 matrix.
+ *
+ * @param m the matrix to transpose
+ */
+static void
+transpose(GLfloat *m)
+{
+ GLfloat t[16] = {
+ m[0], m[4], m[8], m[12],
+ m[1], m[5], m[9], m[13],
+ m[2], m[6], m[10], m[14],
+ m[3], m[7], m[11], m[15]};
+
+ memcpy(m, t, sizeof(t));
+}
+
+/**
+ * Inverts a 4x4 matrix.
+ *
+ * This function can currently handle only pure translation-rotation matrices.
+ * Read http://www.gamedev.net/community/forums/topic.asp?topic_id=425118
+ * for an explanation.
+ */
+static void
+invert(GLfloat *m)
+{
+ GLfloat t[16];
+ identity(t);
+
+ // Extract and invert the translation part 't'. The inverse of a
+ // translation matrix can be calculated by negating the translation
+ // coordinates.
+ t[12] = -m[12]; t[13] = -m[13]; t[14] = -m[14];
+
+ // Invert the rotation part 'r'. The inverse of a rotation matrix is
+ // equal to its transpose.
+ m[12] = m[13] = m[14] = 0;
+ transpose(m);
+
+ // inv(m) = inv(r) * inv(t)
+ multiply(m, t);
+}
+
+/**
+ * Calculate a perspective projection transformation.
+ *
+ * @param m the matrix to save the transformation in
+ * @param fovy the field of view in the y direction
+ * @param aspect the view aspect ratio
+ * @param zNear the near clipping plane
+ * @param zFar the far clipping plane
+ */
+void perspective(GLfloat *m, GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
+{
+ GLfloat tmp[16];
+ identity(tmp);
+
+ double sine, cosine, cotangent, deltaZ;
+ GLfloat radians = fovy / 2 * M_PI / 180;
+
+ deltaZ = zFar - zNear;
+ sincos(radians, &sine, &cosine);
+
+ if ((deltaZ == 0) || (sine == 0) || (aspect == 0))
+ return;
+
+ cotangent = cosine / sine;
+
+ tmp[0] = cotangent / aspect;
+ tmp[5] = cotangent;
+ tmp[10] = -(zFar + zNear) / deltaZ;
+ tmp[11] = -1;
+ tmp[14] = -2 * zNear * zFar / deltaZ;
+ tmp[15] = 0;
+
+ memcpy(m, tmp, sizeof(tmp));
+}
+
+/**
+ * Draws a gear.
+ *
+ * @param gear the gear to draw
+ * @param transform the current transformation matrix
+ * @param x the x position to draw the gear at
+ * @param y the y position to draw the gear at
+ * @param angle the rotation angle of the gear
+ * @param color the color of the gear
+ */
+static void
+draw_gear(struct gear *gear, GLfloat *transform,
+ GLfloat x, GLfloat y, GLfloat angle, const GLfloat color[4])
+{
+ GLfloat model_view[16];
+ GLfloat normal_matrix[16];
+ GLfloat model_view_projection[16];
+
+ /* Translate and rotate the gear */
+ memcpy(model_view, transform, sizeof (model_view));
+ translate(model_view, x, y, 0);
+ rotate(model_view, 2 * M_PI * angle / 360.0, 0, 0, 1);
+
+ /* Create and set the ModelViewProjectionMatrix */
+ memcpy(model_view_projection, ProjectionMatrix, sizeof(model_view_projection));
+ multiply(model_view_projection, model_view);
+
+ glUniformMatrix4fv(ModelViewProjectionMatrix_location, 1, GL_FALSE,
+ model_view_projection);
+
+ /*
+ * Create and set the NormalMatrix. It's the inverse transpose of the
+ * ModelView matrix.
+ */
+ memcpy(normal_matrix, model_view, sizeof (normal_matrix));
+ invert(normal_matrix);
+ transpose(normal_matrix);
+ glUniformMatrix4fv(NormalMatrix_location, 1, GL_FALSE, normal_matrix);
+
+ /* Set the gear color */
+ glUniform4fv(MaterialColor_location, 1, color);
+
+ /* Set the vertex buffer object to use */
+ glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
+
+ /* Set up the position of the attributes in the vertex buffer object */
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
+ 6 * sizeof(GLfloat), NULL);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
+ 6 * sizeof(GLfloat), (GLfloat *) 0 + 3);
+
+ /* Enable the attributes */
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+
+ /* Draw the triangle strips that comprise the gear */
+ int n;
+ for (n = 0; n < gear->nstrips; n++)
+ glDrawArrays(GL_TRIANGLE_STRIP, gear->strips[n].first, gear->strips[n].count);
+
+ /* Disable the attributes */
+ glDisableVertexAttribArray(1);
+ glDisableVertexAttribArray(0);
+}
+
+/**
+ * Draws the gears.
+ */
+static void
+gears_draw(void)
+{
+#ifdef __EMSCRIPTEN__
+ #include <emscripten.h>
+ glutIdleFunc (NULL);
+ glutReshapeFunc(NULL);
+ glutDisplayFunc(NULL);
+ glutSpecialFunc(NULL);
+#endif
+
+ const static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ const static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ const static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+ GLfloat transform[16];
+ identity(transform);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /* Translate and rotate the view */
+ translate(transform, 0, 0, -20);
+ rotate(transform, 2 * M_PI * view_rot[0] / 360.0, 1, 0, 0);
+ rotate(transform, 2 * M_PI * view_rot[1] / 360.0, 0, 1, 0);
+ rotate(transform, 2 * M_PI * view_rot[2] / 360.0, 0, 0, 1);
+
+ /* Draw the gears */
+ draw_gear(gear1, transform, -3.0, -2.0, angle, red);
+ draw_gear(gear2, transform, 3.1, -2.0, -2 * angle - 9.0, green);
+ draw_gear(gear3, transform, -3.1, 4.2, -2 * angle - 25.0, blue);
+
+ glutSwapBuffers();
+
+#ifdef LONGTEST
+ glutPostRedisplay(); // check for issues with not throttling calls
+#endif
+
+ EM_ASM(dump('close!!!\n'); window.close());
+}
+
+/**
+ * Handles a new window size or exposure.
+ *
+ * @param width the window width
+ * @param height the window height
+ */
+static void
+gears_reshape(int width, int height)
+{
+ /* Update the projection matrix */
+ perspective(ProjectionMatrix, 60.0, width / (float)height, 1.0, 1024.0);
+
+ /* Set the viewport */
+ glViewport(0, 0, (GLint) width, (GLint) height);
+}
+
+/**
+ * Handles special glut events.
+ *
+ * @param special the event to handle.
+ */
+static void
+gears_special(int special, int crap, int morecrap)
+{
+ switch (special) {
+ case GLUT_KEY_LEFT:
+ view_rot[1] += 5.0;
+ break;
+ case GLUT_KEY_RIGHT:
+ view_rot[1] -= 5.0;
+ break;
+ case GLUT_KEY_UP:
+ view_rot[0] += 5.0;
+ break;
+ case GLUT_KEY_DOWN:
+ view_rot[0] -= 5.0;
+ break;
+ case GLUT_KEY_F11:
+ glutFullScreen();
+ break;
+ }
+}
+
+static void
+gears_idle(void)
+{
+ static int frames = 0;
+ static double tRot0 = -1.0, tRate0 = -1.0;
+ double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+
+ if (tRot0 < 0.0)
+ tRot0 = t;
+ dt = t - tRot0;
+ tRot0 = t;
+
+ /* advance rotation for next frame */
+ angle += 70.0 * dt; /* 70 degrees per second */
+ if (angle > 3600.0)
+ angle -= 3600.0;
+
+ glutPostRedisplay();
+ frames++;
+
+ if (tRate0 < 0.0)
+ tRate0 = t;
+ if (t - tRate0 >= 5.0) {
+ GLfloat seconds = t - tRate0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ tRate0 = t;
+ frames = 0;
+#ifdef LONGTEST
+ static runs = 0;
+ runs++;
+ if (runs == 4) {
+ int result = fps;
+ REPORT_RESULT();
+ }
+#endif
+ }
+}
+
+static const char vertex_shader[] =
+"attribute vec3 position;\n"
+"attribute vec3 normal;\n"
+"\n"
+"uniform mat4 ModelViewProjectionMatrix;\n"
+"uniform mat4 NormalMatrix;\n"
+"uniform vec4 LightSourcePosition;\n"
+"uniform vec4 MaterialColor;\n"
+"\n"
+"varying vec4 Color;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" // Transform the normal to eye coordinates\n"
+" vec3 N = normalize(vec3(NormalMatrix * vec4(normal, 1.0)));\n"
+"\n"
+" // The LightSourcePosition is actually its direction for directional light\n"
+" vec3 L = normalize(LightSourcePosition.xyz);\n"
+"\n"
+" // Multiply the diffuse value by the vertex color (which is fixed in this case)\n"
+" // to get the actual color that we will use to draw this vertex with\n"
+" float diffuse = max(dot(N, L), 0.0);\n"
+" Color = diffuse * MaterialColor;\n"
+"\n"
+" // Transform the position to clip coordinates\n"
+" gl_Position = ModelViewProjectionMatrix * vec4(position, 1.0);\n"
+"}";
+
+static const char fragment_shader[] =
+"#ifdef GL_ES\n"
+"precision mediump float;\n"
+"#endif\n"
+"varying vec4 Color;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" gl_FragColor = Color;\n"
+"}";
+
+static void
+gears_init(void)
+{
+ GLuint v, f, program;
+ const char *p;
+ char msg[512];
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+
+ /* Compile the vertex shader */
+ p = vertex_shader;
+ v = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(v, 1, &p, NULL);
+ glCompileShader(v);
+ glGetShaderInfoLog(v, sizeof msg, NULL, msg);
+ printf("vertex shader info: %s\n", msg);
+
+ /* Compile the fragment shader */
+ p = fragment_shader;
+ f = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(f, 1, &p, NULL);
+ glCompileShader(f);
+ glGetShaderInfoLog(f, sizeof msg, NULL, msg);
+ printf("fragment shader info: %s\n", msg);
+
+ /* Create and link the shader program */
+ program = glCreateProgram();
+ glAttachShader(program, v);
+ glAttachShader(program, f);
+ glBindAttribLocation(program, 0, "position");
+ glBindAttribLocation(program, 1, "normal");
+
+ glLinkProgram(program);
+ glGetProgramInfoLog(program, sizeof msg, NULL, msg);
+ printf("info: %s\n", msg);
+
+ /* Enable the shaders */
+ glUseProgram(program);
+
+ /* Get the locations of the uniforms so we can access them */
+ ModelViewProjectionMatrix_location = glGetUniformLocation(program, "ModelViewProjectionMatrix");
+ NormalMatrix_location = glGetUniformLocation(program, "NormalMatrix");
+ LightSourcePosition_location = glGetUniformLocation(program, "LightSourcePosition");
+ MaterialColor_location = glGetUniformLocation(program, "MaterialColor");
+
+ /* Set the LightSourcePosition uniform which is constant throught the program */
+ glUniform4fv(LightSourcePosition_location, 1, LightSourcePosition);
+
+ /* make the gears */
+ gear1 = create_gear(1.0, 4.0, 1.0, 20, 0.7);
+ gear2 = create_gear(0.5, 2.0, 2.0, 10, 0.7);
+ gear3 = create_gear(1.3, 2.0, 0.5, 10, 0.7);
+}
+
+int
+main(int argc, char *argv[])
+{
+ /* Initialize the window */
+ glutInit(&argc, argv);
+ glutInitWindowSize(300, 300);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+
+ glutCreateWindow("es2gears");
+
+ /* Set up glut callback functions */
+ glutIdleFunc (gears_idle);
+ glutReshapeFunc(gears_reshape);
+ glutDisplayFunc(gears_draw);
+ glutSpecialFunc(gears_special);
+
+ /* Initialize the gears */
+ gears_init();
+
+ glutMainLoop();
+
+ return 0;
+}
diff --git a/tests/hello_world_loop.cpp b/tests/hello_world_loop.cpp
index 46ec9f23..17a85aac 100644
--- a/tests/hello_world_loop.cpp
+++ b/tests/hello_world_loop.cpp
@@ -16,6 +16,6 @@ int main() {
}
copy[strlen(copy)+1] = (int)&original; // force original to be on the stack
dump(copy);
- return 1;
+ return 0;
}
diff --git a/tests/hello_world_loop_malloc.cpp b/tests/hello_world_loop_malloc.cpp
index b9361834..dd95660c 100644
--- a/tests/hello_world_loop_malloc.cpp
+++ b/tests/hello_world_loop_malloc.cpp
@@ -16,6 +16,6 @@ int main() {
}
copy[strlen(copy)+1] = (int)&original; // force original to be on the stack
dump(copy);
- return 1;
+ return 0;
}
diff --git a/tests/mem_init.cpp b/tests/mem_init.cpp
index e642bfc9..eaa39574 100644
--- a/tests/mem_init.cpp
+++ b/tests/mem_init.cpp
@@ -5,7 +5,7 @@ extern "C" {
int noted = 0;
-void EMSCRIPTEN_KEEPALIVE note(int n) {
+char* EMSCRIPTEN_KEEPALIVE note(int n) {
EM_ASM_({ Module.print([$0, $1]) }, n, noted);
noted = noted | n;
EM_ASM_({ Module.print(['noted is now', $0]) }, noted);
@@ -13,6 +13,7 @@ void EMSCRIPTEN_KEEPALIVE note(int n) {
int result = noted;
REPORT_RESULT();
}
+ return "silly-string";
}
}
diff --git a/tests/openjpeg/codec/CMakeLists.txt b/tests/openjpeg/codec/CMakeLists.txt
index 88b1661f..a1ef69f3 100644
--- a/tests/openjpeg/codec/CMakeLists.txt
+++ b/tests/openjpeg/codec/CMakeLists.txt
@@ -1,14 +1,16 @@
# Build the demo app, small examples
# First thing define the common source:
-# XXX Emscripten: Force getopt.c
SET(common_SRCS
convert.c
index.c
${OPENJPEG_SOURCE_DIR}/common/color.c
- ${OPENJPEG_SOURCE_DIR}/common/getopt.c
)
+if (NOT CMAKE_HAVE_GETOPT_H)
+ SET(common_SRCS ${common_SRCS} ${OPENJPEG_SOURCE_DIR}/common/getopt.c)
+endif()
+
# Headers file are located here:
INCLUDE_DIRECTORIES(
${OPENJPEG_SOURCE_DIR}/libopenjpeg
diff --git a/tests/runner.py b/tests/runner.py
index 87f8a036..412f662c 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -240,15 +240,17 @@ process(sys.argv[1])
if output_processor is not None:
output_processor(open(filename + '.o.js').read())
- if self.emcc_args is not None and 'ASM_JS=1' in self.emcc_args:
+ if self.emcc_args is not None:
if '--memory-init-file' in self.emcc_args:
memory_init_file = int(self.emcc_args[self.emcc_args.index('--memory-init-file')+1])
else:
- memory_init_file = 0
+ memory_init_file = '-O2' in self.emcc_args or '-O3' in self.emcc_args
+ src = open(filename + '.o.js').read()
if memory_init_file:
- assert '/* memory initializer */' not in open(filename + '.o.js').read()
+ # side memory init file, or an empty one in the js
+ assert ('/* memory initializer */' not in src) or ('/* memory initializer */ allocate([]' in src)
else:
- assert 'memory initializer */' in open(filename + '.o.js').read()
+ assert 'memory initializer */' in src
def validate_asmjs(self, err):
if 'uccessfully compiled asm.js code' in err and 'asm.js link error' not in err:
@@ -258,7 +260,7 @@ process(sys.argv[1])
err = '\n'.join(filter(lambda line: 'uccessfully compiled asm.js code' not in line, err.split('\n')))
return err
- def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None):
+ def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None, assert_returncode=0):
stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us
stderr = os.path.join(self.get_dir(), 'stderr')
try:
@@ -266,7 +268,7 @@ process(sys.argv[1])
except:
cwd = None
os.chdir(self.get_dir())
- run_js(filename, engine, args, check_timeout, stdout=open(stdout, 'w'), stderr=open(stderr, 'w'))
+ run_js(filename, engine, args, check_timeout, stdout=open(stdout, 'w'), stderr=open(stderr, 'w'), assert_returncode=assert_returncode)
if cwd is not None:
os.chdir(cwd)
out = open(stdout, 'r').read()
@@ -445,7 +447,7 @@ process(sys.argv[1])
includes, force_c, build_ll_hook, extra_emscripten_args)
## Does a complete test - builds, runs, checks output, etc.
- def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
+ def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[], assert_returncode=None):
if force_c or (main_file is not None and main_file[-2:]) == '.c':
basename = 'src.c'
Building.COMPILER = to_cc(Building.COMPILER)
@@ -464,7 +466,7 @@ process(sys.argv[1])
js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
for engine in js_engines:
- js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
+ js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer, assert_returncode=assert_returncode)
self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
self.assertNotContained('ERROR', js_output)
@@ -477,7 +479,7 @@ process(sys.argv[1])
test_index += 1
# No building - just process an existing .ll file (or .bc, which we turn into .ll)
- def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]):
+ def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[], assert_returncode=None):
filename = os.path.join(self.get_dir(), 'src.cpp')
self.prep_ll_run(filename, ll_file, force_recompile, build_ll_hook)
@@ -485,12 +487,13 @@ process(sys.argv[1])
self.ll_to_js(filename, extra_emscripten_args, post_build)
self.do_run(None,
- expected_output,
- args,
- no_build=True,
- js_engines=js_engines,
- output_nicerizer=output_nicerizer,
- post_build=None) # post_build was already done in ll_to_js, this do_run call is just to test the output
+ expected_output,
+ args,
+ no_build=True,
+ js_engines=js_engines,
+ output_nicerizer=output_nicerizer,
+ post_build=None,
+ assert_returncode=assert_returncode) # post_build was already done in ll_to_js, this do_run call is just to test the output
# Run a server and a web page. When a test runs, we tell the server about it,
@@ -662,15 +665,35 @@ class BrowserCore(RunnerCore):
Module['preRun'].push(function() {
setTimeout(doReftest, 1000); // if run() throws an exception and postRun is not called, this will kick in
});
+
+ if (typeof WebGLClient !== 'undefined') {
+ // trigger reftest from RAF as well, needed for workers where there is no pre|postRun on the main thread
+ var realRAF = window.requestAnimationFrame;
+ window.requestAnimationFrame = function(func) {
+ realRAF(func);
+ setTimeout(doReftest, 1000);
+ };
+
+ // trigger reftest from canvas render too, for workers not doing GL
+ var realWOM = worker.onmessage;
+ worker.onmessage = function(event) {
+ realWOM(event);
+ if (event.data.target === 'canvas' && event.data.op === 'render') {
+ setTimeout(doReftest, 1000);
+ }
+ };
+ }
+
''' % basename)
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
+ args=[], outfile='test.html', message='.', also_proxied=False): # TODO: use in all other tests
# if we are provided the source and not a path, use that
filename_is_src = '\n' in filename
src = filename if filename_is_src else ''
filepath = path_from_root('tests', filename) if not filename_is_src else ('main.c' if force_c else 'main.cpp')
temp_filepath = os.path.join(self.get_dir(), os.path.basename(filepath))
+ original_args = args[:]
if filename_is_src:
with open(temp_filepath, 'w') as f: f.write(src)
if not reference:
@@ -678,16 +701,33 @@ class BrowserCore(RunnerCore):
with open(filepath) as f: src = f.read()
with open(temp_filepath, 'w') as f: f.write(self.with_report_result(src))
else:
+ self.reference = reference
expected = [str(i) for i in range(0, reference_slack+1)]
shutil.copyfile(filepath, temp_filepath)
self.reftest(path_from_root('tests', reference))
if not manual_reference:
args = args + ['--pre-js', 'reftest.js', '-s', 'GL_TESTING=1']
- Popen([PYTHON, EMCC, temp_filepath, '-o', outfile] + args).communicate()
+ all_args = [PYTHON, EMCC, temp_filepath, '-o', outfile] + args
+ #print 'all args:', all_args
+ Popen(all_args).communicate()
assert os.path.exists(outfile)
if post_build: post_build()
if type(expected) is str: expected = [expected]
self.run_browser(outfile, message, ['/report_result?' + e for e in expected])
+ if also_proxied:
+ print 'proxied...'
+ # save non-proxied
+ if not os.path.exists('normal'):
+ os.mkdir('normal')
+ shutil.copyfile('test.html', os.path.join('normal', 'test.html'))
+ shutil.copyfile('test.js', os.path.join('normal', 'test.js'))
+ if reference:
+ assert not manual_reference
+ manual_reference = True
+ assert not post_build
+ post_build = self.post_manual_reftest
+ # run proxied
+ self.btest(filename, expected, reference, force_c, reference_slack, manual_reference, post_build, original_args + ['--proxy-to-worker', '-s', 'GL_TESTING=1'], outfile, message)
###################################################################################################
@@ -695,7 +735,7 @@ class BrowserCore(RunnerCore):
def get_bullet_library(runner_core, use_cmake):
if use_cmake:
configure_commands = ['cmake', '.']
- configure_args = ['-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF']
+ configure_args = ['-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF', '-DUSE_GLUT=OFF']
# Depending on whether 'configure' or 'cmake' is used to build, Bullet places output files in different directory structures.
generated_libs = [os.path.join('src', 'BulletDynamics', 'libBulletDynamics.a'),
os.path.join('src', 'BulletCollision', 'libBulletCollision.a'),
diff --git a/tests/runtime_misuse.cpp b/tests/runtime_misuse.cpp
new file mode 100644
index 00000000..d74d05ea
--- /dev/null
+++ b/tests/runtime_misuse.cpp
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <emscripten.h>
+
+extern "C" {
+
+int noted = 0;
+
+char* EMSCRIPTEN_KEEPALIVE note(int n) {
+ EM_ASM_({ Module.print([$0, $1]) }, n, noted);
+ noted += n;
+ EM_ASM_({ Module.print(['noted is now', $0]) }, noted);
+ return "silly-string";
+}
+
+void free(void*) { // free is valid to call even after the runtime closes, so useful as a hack here for this test
+ EM_ASM_({ Module.print(['reporting', $0]) }, noted);
+ int result = noted;
+ REPORT_RESULT();
+}
+
+}
+
+int main() {
+ EM_ASM( myJSCallback() ); // calls a global JS func
+ return 0;
+}
+
diff --git a/tests/sdl_canvas_size.c b/tests/sdl_canvas_size.c
index 0d184823..1675bf2e 100644
--- a/tests/sdl_canvas_size.c
+++ b/tests/sdl_canvas_size.c
@@ -1,27 +1,3 @@
-/*******************************************************************
- * *
- * Using SDL With OpenGL *
- * *
- * Tutorial by Kyle Foley (sdw) *
- * *
- * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL *
- * *
- *******************************************************************/
-
-/*
-THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
-AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
-
-THE ORIGINAL AUTHOR IS KYLE FOLEY.
-
-THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
-OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
-MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
-ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
-RESULTING FROM THE USE, MODIFICATION, OR
-REDISTRIBUTION OF THIS SOFTWARE.
-*/
-
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_opengl.h"
@@ -30,9 +6,9 @@ REDISTRIBUTION OF THIS SOFTWARE.
#include <string.h>
#include <assert.h>
-#ifdef __EMSCRIPTEN__
#include <emscripten.h>
-#endif
+
+int result = 1;
int main(int argc, char *argv[])
{
@@ -44,9 +20,6 @@ int main(int argc, char *argv[])
return 1;
}
- SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new*
-
-#ifdef __EMSCRIPTEN__
// Test 1: Check that initializing video mode with size (0,0) will use the size from the <canvas> element.
screen = SDL_SetVideoMode( 0, 0, 16, SDL_OPENGL ); // *changed*
@@ -56,136 +29,15 @@ int main(int argc, char *argv[])
printf("w:%d,h:%d\n", w,h);
assert(w == 700);
assert(h == 200);
-
+
// Test 3: Check that resizing the canvas works as well.
emscripten_set_canvas_size(640, 480);
- // Set the OpenGL state after creating the context with SDL_SetVideoMode
-#else
- screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed*
-#endif
-
- if ( !screen ) {
- printf("Unable to set video mode: %s\n", SDL_GetError());
- return 1;
- }
-
- glClearColor( 0, 0, 0, 0 );
-
- glEnable( GL_TEXTURE_2D ); // Needed when we're using the fixed-function pipeline.
-
- glViewport( 0, 0, 640, 480 );
-
- glMatrixMode( GL_PROJECTION );
- glPushMatrix(); // just for testing
- glLoadIdentity();
-
- glOrtho( 0, 640, 480, 0, -1, 1 );
-
- glMatrixMode( GL_MODELVIEW );
- glLoadIdentity();
-
- // Load the OpenGL texture
-
- GLuint texture; // Texture object handle
- SDL_Surface *surface; // Gives us the information to make the texture
-
- if ( (surface = IMG_Load("screenshot.png")) ) {
-
- // Check that the image's width is a power of 2
- if ( (surface->w & (surface->w - 1)) != 0 ) {
- printf("warning: image.bmp's width is not a power of 2\n");
- }
-
- // Also check if the height is a power of 2
- if ( (surface->h & (surface->h - 1)) != 0 ) {
- printf("warning: image.bmp's height is not a power of 2\n");
- }
-
- // Have OpenGL generate a texture object handle for us
- glGenTextures( 1, &texture );
-
- // Bind the texture object
- glBindTexture( GL_TEXTURE_2D, texture );
-
- // Set the texture's stretching properties
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
- //SDL_LockSurface(surface);
-
- // Add some greyness
- memset(surface->pixels, 0x66, surface->w*surface->h);
-
- // Edit the texture object's image data using the information SDL_Surface gives us
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );
-
- //SDL_UnlockSurface(surface);
- }
- else {
- printf("SDL could not load image.bmp: %s\n", SDL_GetError());
- SDL_Quit();
- return 1;
- }
-
- // Free the SDL_Surface only if it was successfully created
- if ( surface ) {
- SDL_FreeSurface( surface );
- }
-
- // Clear the screen before drawing
- glClear( GL_COLOR_BUFFER_BIT );
-
- // Bind the texture to which subsequent calls refer to
- glBindTexture( GL_TEXTURE_2D, texture );
-
- glBegin( GL_QUADS );
- glTexCoord2i( 0, 0 ); glVertex3f( 10, 10, 0 );
- glTexCoord2i( 1, 0 ); glVertex3f( 300, 10, 0 );
- glTexCoord2i( 1, 1 ); glVertex3f( 300, 128, 0 );
- glTexCoord2i( 0, 1 ); glVertex3f( 10, 128, 0 );
-
- glTexCoord2f( 0, 0.5 ); glVertex3f( 410, 10, 0 );
- glTexCoord2f( 1, 0.5 ); glVertex3f( 600, 10, 0 );
- glTexCoord2f( 1, 1 ); glVertex3f( 630, 200, 0 );
- glTexCoord2f( 0.5, 1 ); glVertex3f( 310, 250, 0 );
- glEnd();
-
- glBegin( GL_TRIANGLE_STRIP );
- glTexCoord2i( 0, 0 ); glVertex3f( 100, 300, 0 );
- glTexCoord2i( 1, 0 ); glVertex3f( 300, 300, 0 );
- glTexCoord2i( 1, 1 ); glVertex3f( 300, 400, 0 );
- glTexCoord2i( 0, 1 ); glVertex3f( 500, 410, 0 );
- glEnd();
-
- glDisable(GL_TEXTURE_2D);
-
- glColor3ub(90, 255, 255);
- glBegin( GL_QUADS );
- glVertex3f( 10, 410, 0 );
- glVertex3f( 300, 410, 0 );
- glVertex3f( 300, 480, 0 );
- glVertex3f( 10, 470, 0 );
- glEnd();
-
- glBegin( GL_QUADS );
- glColor3f(1.0, 0, 1.0); glVertex3f( 410, 410, 0 );
- glColor3f(0, 1.0, 0); glVertex3f( 600, 410, 0 );
- glColor3f(0, 0, 1.0); glVertex3f( 600, 480, 0 );
- glColor3f(1.0, 1.0, 1.0); glVertex3f( 410, 470, 0 );
- glEnd();
-
- SDL_GL_SwapBuffers();
-
-#ifndef __EMSCRIPTEN__
- // Wait for 3 seconds to give us a chance to see the image
- SDL_Delay(3000);
-#endif
-
- // Now we can delete the OpenGL texture and close down SDL
- glDeleteTextures( 1, &texture );
+ emscripten_get_canvas_size(&w, &h, &fs);
+ printf("w:%d,h:%d\n", w,h);
+ assert(w == 640);
+ assert(h == 480);
SDL_Quit();
-
+ REPORT_RESULT();
return 0;
}
diff --git a/tests/sdl_image.c b/tests/sdl_image.c
index 523f8903..9639ea37 100644
--- a/tests/sdl_image.c
+++ b/tests/sdl_image.c
@@ -4,6 +4,7 @@
#include <assert.h>
#include <emscripten.h>
#include <unistd.h>
+#include <stdlib.h>
int testImage(SDL_Surface* screen, const char* fileName) {
SDL_Surface *image = IMG_Load(fileName);
@@ -18,7 +19,16 @@ int testImage(SDL_Surface* screen, const char* fileName) {
int result = image->w;
SDL_BlitSurface (image, NULL, screen, NULL);
+
+ int w, h;
+ char *data = emscripten_get_preloaded_image_data(fileName, &w, &h);
+
+ assert(data);
+ assert(w == image->w);
+ assert(h == image->h);
+
SDL_FreeSurface (image);
+ free(data);
return result;
}
diff --git a/tests/sdl_key.c b/tests/sdl_key.c
index 7a304fc1..1852d7f1 100644
--- a/tests/sdl_key.c
+++ b/tests/sdl_key.c
@@ -1,59 +1,71 @@
#include <stdio.h>
#include <SDL/SDL.h>
-#include <SDL/SDL_ttf.h>
#include <emscripten.h>
int result = 1;
+int SDLCALL EventHandler(void *userdata, SDL_Event *event) {
+ switch(event->type) {
+ case SDL_KEYDOWN:
+ break;
+ case SDL_KEYUP:
+ // don't handle the modifier key events
+ if (event->key.keysym.sym == SDLK_LCTRL ||
+ event->key.keysym.sym == SDLK_LSHIFT ||
+ event->key.keysym.sym == SDLK_LALT) {
+ return 0;
+ }
+ if ((event->key.keysym.mod & KMOD_LCTRL) || (event->key.keysym.mod & KMOD_RCTRL)) {
+ result *= 2;
+ }
+ if ((event->key.keysym.mod & KMOD_LSHIFT) || (event->key.keysym.mod & KMOD_RSHIFT)) {
+ result *= 3;
+ }
+ if ((event->key.keysym.mod & KMOD_LALT) || (event->key.keysym.mod & KMOD_RALT)) {
+ result *= 5;
+ }
+ switch (event->key.keysym.sym) {
+ case SDLK_RIGHT: printf("right\n"); result *= 7; break;
+ case SDLK_LEFT: printf("left\n"); result *= 11; break;
+ case SDLK_DOWN: printf("down\n"); result *= 13; break;
+ case SDLK_UP: printf("up\n"); result *= 17; break;
+ case SDLK_a: printf("a\n"); result *= 19; break;
+ default: {
+ if (event->key.keysym.scancode == SDL_SCANCODE_B) {
+ printf("b scancode\n"); result *= 23; break;
+ }
+ printf("unknown key: sym %d scancode %d\n", event->key.keysym.sym, event->key.keysym.scancode);
+ REPORT_RESULT();
+ emscripten_run_script("throw 'done'"); // comment this out to leave event handling active. Use the following to log DOM keys:
+ // addEventListener('keyup', function(event) { console.log(event->keyCode) }, true)
+ }
+ }
+ break;
+ default: /* Report an unhandled event */
+ printf("I don't know what this event is (type=%d)!\n", event->type);
+ }
+ return 0;
+}
+
void one() {
+#ifndef TEST_EMSCRIPTEN_SDL_SETEVENTHANDLER
SDL_Event event;
while (SDL_PollEvent(&event)) {
- switch(event.type) {
- case SDL_KEYDOWN:
- break;
- case SDL_KEYUP:
- // don't handle the modifier key events
- if (event.key.keysym.sym == SDLK_LCTRL ||
- event.key.keysym.sym == SDLK_LSHIFT ||
- event.key.keysym.sym == SDLK_LALT) {
- return;
- }
- if ((event.key.keysym.mod & KMOD_LCTRL) || (event.key.keysym.mod & KMOD_RCTRL)) {
- result *= 2;
- }
- if ((event.key.keysym.mod & KMOD_LSHIFT) || (event.key.keysym.mod & KMOD_RSHIFT)) {
- result *= 3;
- }
- if ((event.key.keysym.mod & KMOD_LALT) || (event.key.keysym.mod & KMOD_RALT)) {
- result *= 5;
- }
- switch (event.key.keysym.sym) {
- case SDLK_RIGHT: printf("right\n"); result *= 7; break;
- case SDLK_LEFT: printf("left\n"); result *= 11; break;
- case SDLK_DOWN: printf("down\n"); result *= 13; break;
- case SDLK_UP: printf("up\n"); result *= 17; break;
- case SDLK_a: printf("a\n"); result *= 19; break;
- default: {
- if (event.key.keysym.scancode == SDL_SCANCODE_B) {
- printf("b scancode\n"); result *= 23; break;
- }
- printf("unknown key: sym %d scancode %d\n", event.key.keysym.sym, event.key.keysym.scancode);
- REPORT_RESULT();
- emscripten_run_script("throw 'done'"); // comment this out to leave event handling active. Use the following to log DOM keys:
- // addEventListener('keyup', function(event) { console.log(event.keyCode) }, true)
- }
- }
- break;
- default: /* Report an unhandled event */
- printf("I don't know what this event is!\n");
- }
+ EventHandler(0, &event);
}
+#endif
}
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE);
+#ifdef TEST_EMSCRIPTEN_SDL_SETEVENTHANDLER
+ emscripten_SDL_SetEventHandler(EventHandler, 0);
+#else
+ if (argc == 1337) one(); // keep it alive
+#endif
+
emscripten_run_script("keydown(1250);keydown(38);keyup(38);keyup(1250);"); // alt, up
emscripten_run_script("keydown(1248);keydown(1249);keydown(40);keyup(40);keyup(1249);keyup(1248);"); // ctrl, shift, down
emscripten_run_script("keydown(37);keyup(37);"); // left
@@ -62,8 +74,6 @@ int main(int argc, char **argv) {
emscripten_run_script("keydown(66);keyup(66);"); // b
emscripten_run_script("keydown(100);keyup(100);"); // trigger the end
- if (argc == 1337) one(); // keep it alive
-
return 0;
}
diff --git a/tests/sdl_key_proxy.c b/tests/sdl_key_proxy.c
index bc233f29..c3b7517a 100644
--- a/tests/sdl_key_proxy.c
+++ b/tests/sdl_key_proxy.c
@@ -1,6 +1,5 @@
#include <stdio.h>
#include <SDL/SDL.h>
-#include <SDL/SDL_ttf.h>
#include <emscripten.h>
int result = 1;
diff --git a/tests/sdl_maprgba.c b/tests/sdl_maprgba.c
index 4b5c0026..615f02c5 100644
--- a/tests/sdl_maprgba.c
+++ b/tests/sdl_maprgba.c
@@ -1,25 +1,45 @@
#include <stdio.h>
#include <SDL/SDL.h>
+#include <assert.h>
int main() {
Uint32 c;
+ Uint8 r, g, b, a;
SDL_Rect rect = {0,0,300,450};
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE);
c = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00); // OPAQUE RED
+ SDL_GetRGB(c, screen->format, &r, &g, &b);
+ assert(r == 0xff);
+ assert(g == 0x00);
+ assert(b == 0x00);
SDL_FillRect(screen, &rect, c);
rect.x = 300;
c = SDL_MapRGB(screen->format, 0x7f, 0x7f, 0x00); // OPAQUE MUSTARD
+ SDL_GetRGB(c, screen->format, &r, &g, &b);
+ assert(r == 0x7f);
+ assert(g == 0x7f);
+ assert(b == 0x00);
SDL_FillRect(screen, &rect, c);
rect.x = 150;
rect.y = 112;
rect.w = 300;
rect.h = 225;
c = SDL_MapRGBA(screen->format, 0xff, 0xff, 0xff, 0xff); // OPAQUE WHITE
+ SDL_GetRGBA(c, screen->format, &r, &g, &b, &a);
+ assert(r == 0xff);
+ assert(g == 0xff);
+ assert(b == 0xff);
+ assert(a == 0xff);
SDL_FillRect(screen, &rect, c);
c = SDL_MapRGBA(screen->format, 0x00, 0x00, 0x00, 0x00); // TRANSPARENT BLACK
+ SDL_GetRGBA(c, screen->format, &r, &g, &b, &a);
+ assert(r == 0x00);
+ assert(g == 0x00);
+ assert(b == 0x00);
+ assert(a == 0x00);
SDL_FillRect(screen, &rect, c);
SDL_UpdateRect(screen, 0, 0, 600, 450);
diff --git a/tests/sdl_mouse.c b/tests/sdl_mouse.c
index ff4f522b..72d1ea57 100644
--- a/tests/sdl_mouse.c
+++ b/tests/sdl_mouse.c
@@ -1,6 +1,5 @@
#include <stdio.h>
#include <SDL/SDL.h>
-#include <SDL/SDL_ttf.h>
#include <assert.h>
#include <emscripten.h>
diff --git a/tests/sdlglshader2.c b/tests/sdlglshader2.c
new file mode 100644
index 00000000..c75a0f5f
--- /dev/null
+++ b/tests/sdlglshader2.c
@@ -0,0 +1,168 @@
+/*
+THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION
+AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN.
+
+THE ORIGINAL AUTHOR IS KYLE FOLEY.
+
+THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY
+OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF
+MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE,
+ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE
+RESULTING FROM THE USE, MODIFICATION, OR
+REDISTRIBUTION OF THIS SOFTWARE.
+*/
+
+#include "SDL/SDL.h"
+#include "SDL/SDL_opengl.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+// GL_ARB_shading_language_100, GL_ARB_shader_objects, GL_ARB_fragment_shader, GL_ARB_vertex_shader
+PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObject_ = NULL;
+PFNGLDELETEOBJECTARBPROC glDeleteObject_ = NULL;
+PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObject_ = NULL;
+PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObject_ = NULL;
+PFNGLSHADERSOURCEARBPROC glShaderSource_ = NULL;
+PFNGLCOMPILESHADERARBPROC glCompileShader_ = NULL;
+PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameteriv_ = NULL;
+PFNGLATTACHOBJECTARBPROC glAttachObject_ = NULL;
+PFNGLGETINFOLOGARBPROC glGetInfoLog_ = NULL;
+PFNGLLINKPROGRAMARBPROC glLinkProgram_ = NULL;
+PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocation_ = NULL;
+PFNGLUNIFORM1FARBPROC glUniform1f_ = NULL;
+PFNGLUNIFORM2FARBPROC glUniform2f_ = NULL;
+PFNGLUNIFORM3FARBPROC glUniform3f_ = NULL;
+PFNGLUNIFORM4FARBPROC glUniform4f_ = NULL;
+PFNGLUNIFORM1FVARBPROC glUniform1fv_ = NULL;
+PFNGLUNIFORM2FVARBPROC glUniform2fv_ = NULL;
+PFNGLUNIFORM3FVARBPROC glUniform3fv_ = NULL;
+PFNGLUNIFORM4FVARBPROC glUniform4fv_ = NULL;
+PFNGLUNIFORM1IARBPROC glUniform1i_ = NULL;
+PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocation_ = NULL;
+PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniform_ = NULL;
+
+void initARB() {
+ glCreateProgramObject_ = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
+ glDeleteObject_ = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
+ glUseProgramObject_ = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
+ glCreateShaderObject_ = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
+ glShaderSource_ = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
+ glCompileShader_ = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
+ glGetObjectParameteriv_ = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
+ glAttachObject_ = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
+ glGetInfoLog_ = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
+ glLinkProgram_ = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
+ glGetUniformLocation_ = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
+ glUniform1f_ = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
+ glUniform2f_ = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB");
+ glUniform3f_ = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB");
+ glUniform4f_ = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB");
+ glUniform1fv_ = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB");
+ glUniform2fv_ = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB");
+ glUniform3fv_ = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB");
+ glUniform4fv_ = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB");
+ glUniform1i_ = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
+ glBindAttribLocation_ = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB");
+ glGetActiveUniform_ = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB");
+}
+
+void setShaders() {
+ GLuint v, f, p;
+ GLint ok;
+
+ const char *vv = "#pragma CUBE2_uniform animdata AnimData 0 16\n"
+ "uniform vec4 animdata[246];\n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = ftransform() + animdata[0]; \n"
+ "}";
+ const char *ff = "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4(gl_FragCoord.y/480.0, gl_FragCoord.x/640.0, 0.66, 1.0); \n"
+ "}";
+
+ v = glCreateShaderObject_(GL_VERTEX_SHADER);
+ f = glCreateShaderObject_(GL_FRAGMENT_SHADER);
+
+ glShaderSource_(v, 1, &vv,NULL);
+ glShaderSource_(f, 1, &ff,NULL);
+
+ glCompileShader_(v);
+ glGetObjectParameteriv_(v, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
+ if (!ok) {
+ char msg[512];
+ glGetShaderInfoLog(v, sizeof msg, NULL, msg);
+ printf("shader compilation issue: %s\n", msg);
+ }
+ assert(ok);
+
+ glCompileShader_(f);
+ glGetObjectParameteriv_(f, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
+ assert(ok);
+
+ p = glCreateProgramObject_();
+ glAttachObject_(p,f);
+ glAttachObject_(p,v);
+
+ glLinkProgram_(p);
+ glGetObjectParameteriv_(p, GL_OBJECT_LINK_STATUS_ARB, &ok);
+ assert(ok);
+
+ int loc = glGetUniformLocation_(p, "animdata");
+ printf("loc: %d\n", loc);
+ assert(loc > 0);
+ int loc2 = glGetUniformLocation_(p, "animdata[0]");
+ printf("loc2: %d\n", loc2);
+ assert(loc2 == loc);
+
+ glUseProgramObject_(p);
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface *screen;
+
+ assert(SDL_Init(SDL_INIT_VIDEO) == 0);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL );
+ assert(screen);
+
+ glClearColor(0, 0, 0, 0);
+ glViewport(0, 0, 640, 480);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, 640, 480, 0, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ initARB();
+ setShaders();
+
+ glColor3f(0, 1, 1); // is overridden by the shader, useful for debugging native builds
+ glBegin( GL_TRIANGLES );
+ glTexCoord2i(0, 0); glVertex3f( 10, 10, 0);
+ glTexCoord2i(1, 0); glVertex3f( 300, 10, 0);
+ glTexCoord2i(1, 1); glVertex3f( 300, 328, 0);
+ glEnd();
+
+ glColor3f(1, 1, 0); // is overridden by the shader, useful for debugging native builds
+ glBegin( GL_TRIANGLES );
+ glTexCoord2f(0, 0.5); glVertex3f(410, 10, 0);
+ glTexCoord2f(1, 0.5); glVertex3f(600, 10, 0);
+ glTexCoord2f(1, 1 ); glVertex3f(630, 400, 0);
+ glEnd();
+
+ SDL_GL_SwapBuffers();
+
+#ifdef REPORT_RESULT
+ int result = 1;
+ REPORT_RESULT();
+#endif
+
+ SDL_Quit();
+ return 0;
+}
+
diff --git a/tests/sqlite/speedtest1.c b/tests/sqlite/speedtest1.c
new file mode 100644
index 00000000..29d7cd31
--- /dev/null
+++ b/tests/sqlite/speedtest1.c
@@ -0,0 +1,1393 @@
+/*
+** A program for performance testing.
+**
+** The available command-line options are described below:
+*/
+static const char zHelp[] =
+ "Usage: %s [--options] DATABASE\n"
+ "Options:\n"
+ " --autovacuum Enable AUTOVACUUM mode\n"
+ " --cachesize N Set the cache size to N\n"
+ " --exclusive Enable locking_mode=EXCLUSIVE\n"
+ " --explain Like --sqlonly but with added EXPLAIN keywords\n"
+ " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
+ " --incrvacuum Enable incremenatal vacuum mode\n"
+ " --journalmode M Set the journal_mode to MODE\n"
+ " --key KEY Set the encryption key to KEY\n"
+ " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
+ " --nosync Set PRAGMA synchronous=OFF\n"
+ " --notnull Add NOT NULL constraints to table columns\n"
+ " --pagesize N Set the page size to N\n"
+ " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
+ " --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n"
+ " --reprepare Reprepare each statement upon every invocation\n"
+ " --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n"
+ " --sqlonly No-op. Only show the SQL that would have been run.\n"
+ " --size N Relative test size. Default=100\n"
+ " --stats Show statistics at the end\n"
+ " --testset T Run test-set T\n"
+ " --trace Turn on SQL tracing\n"
+ " --utf16be Set text encoding to UTF-16BE\n"
+ " --utf16le Set text encoding to UTF-16LE\n"
+ " --verify Run additional verification steps.\n"
+ " --without-rowid Use WITHOUT ROWID where appropriate\n"
+;
+
+
+#include "sqlite3.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+/* All global state is held in this structure */
+static struct Global {
+ sqlite3 *db; /* The open database connection */
+ sqlite3_stmt *pStmt; /* Current SQL statement */
+ sqlite3_int64 iStart; /* Start-time for the current test */
+ sqlite3_int64 iTotal; /* Total time */
+ int bWithoutRowid; /* True for --without-rowid */
+ int bReprepare; /* True to reprepare the SQL on each rerun */
+ int bSqlOnly; /* True to print the SQL once only */
+ int bExplain; /* Print SQL with EXPLAIN prefix */
+ int bVerify; /* Try to verify that results are correct */
+ int szTest; /* Scale factor for test iterations */
+ const char *zWR; /* Might be WITHOUT ROWID */
+ const char *zNN; /* Might be NOT NULL */
+ const char *zPK; /* Might be UNIQUE or PRIMARY KEY */
+ unsigned int x, y; /* Pseudo-random number generator state */
+ int nResult; /* Size of the current result */
+ char zResult[3000]; /* Text of the current result */
+} g;
+
+
+/* Print an error message and exit */
+static void fatal_error(const char *zMsg, ...){
+ va_list ap;
+ va_start(ap, zMsg);
+ vfprintf(stderr, zMsg, ap);
+ va_end(ap);
+ exit(1);
+}
+
+/*
+** Return the value of a hexadecimal digit. Return -1 if the input
+** is not a hex digit.
+*/
+static int hexDigitValue(char c){
+ if( c>='0' && c<='9' ) return c - '0';
+ if( c>='a' && c<='f' ) return c - 'a' + 10;
+ if( c>='A' && c<='F' ) return c - 'A' + 10;
+ return -1;
+}
+
+/* Provide an alternative to sqlite3_stricmp() in older versions of
+** SQLite */
+#if SQLITE_VERSION_NUMBER<3007011
+# define sqlite3_stricmp strcmp
+#endif
+
+/*
+** Interpret zArg as an integer value, possibly with suffixes.
+*/
+static int integerValue(const char *zArg){
+ sqlite3_int64 v = 0;
+ static const struct { char *zSuffix; int iMult; } aMult[] = {
+ { "KiB", 1024 },
+ { "MiB", 1024*1024 },
+ { "GiB", 1024*1024*1024 },
+ { "KB", 1000 },
+ { "MB", 1000000 },
+ { "GB", 1000000000 },
+ { "K", 1000 },
+ { "M", 1000000 },
+ { "G", 1000000000 },
+ };
+ int i;
+ int isNeg = 0;
+ if( zArg[0]=='-' ){
+ isNeg = 1;
+ zArg++;
+ }else if( zArg[0]=='+' ){
+ zArg++;
+ }
+ if( zArg[0]=='0' && zArg[1]=='x' ){
+ int x;
+ zArg += 2;
+ while( (x = hexDigitValue(zArg[0]))>=0 ){
+ v = (v<<4) + x;
+ zArg++;
+ }
+ }else{
+ while( isdigit(zArg[0]) ){
+ v = v*10 + zArg[0] - '0';
+ zArg++;
+ }
+ }
+ for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
+ if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
+ v *= aMult[i].iMult;
+ break;
+ }
+ }
+ if( v>0x7fffffff ) fatal_error("parameter too large - max 2147483648");
+ return (int)(isNeg? -v : v);
+}
+
+/* Return the current wall-clock time, in milliseconds */
+sqlite3_int64 speedtest1_timestamp(void){
+ static sqlite3_vfs *clockVfs = 0;
+ sqlite3_int64 t;
+ if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
+#if SQLITE_VERSION_NUMBER>=3007000
+ if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
+ clockVfs->xCurrentTimeInt64(clockVfs, &t);
+ }else
+#endif
+ {
+ double r;
+ clockVfs->xCurrentTime(clockVfs, &r);
+ t = (sqlite3_int64)(r*86400000.0);
+ }
+ return t;
+}
+
+/* Return a pseudo-random unsigned integer */
+unsigned int speedtest1_random(void){
+ g.x = (g.x>>1) ^ ((1+~(g.x&1)) & 0xd0000001);
+ g.y = g.y*1103515245 + 12345;
+ return g.x ^ g.y;
+}
+
+/* Map the value in within the range of 1...limit into another
+** number in a way that is chatic and invertable.
+*/
+unsigned swizzle(unsigned in, unsigned limit){
+ unsigned out = 0;
+ while( limit ){
+ out = (out<<1) | (in&1);
+ in >>= 1;
+ limit >>= 1;
+ }
+ return out;
+}
+
+/* Round up a number so that it is a power of two minus one
+*/
+unsigned roundup_allones(unsigned limit){
+ unsigned m = 1;
+ while( m<limit ) m = (m<<1)+1;
+ return m;
+}
+
+/* The speedtest1_numbername procedure below converts its argment (an integer)
+** into a string which is the English-language name for that number.
+** The returned string should be freed with sqlite3_free().
+**
+** Example:
+**
+** speedtest1_numbername(123) -> "one hundred twenty three"
+*/
+int speedtest1_numbername(unsigned int n, char *zOut, int nOut){
+ static const char *ones[] = { "zero", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten", "eleven", "twelve",
+ "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
+ "eighteen", "nineteen" };
+ static const char *tens[] = { "", "ten", "twenty", "thirty", "forty",
+ "fifty", "sixty", "seventy", "eighty", "ninety" };
+ int i = 0;
+
+ if( n>=1000000000 ){
+ i += speedtest1_numbername(n/1000000000, zOut+i, nOut-i);
+ sqlite3_snprintf(nOut-i, zOut+i, " billion");
+ i += (int)strlen(zOut+i);
+ n = n % 1000000000;
+ }
+ if( n>=1000000 ){
+ if( i && i<nOut-1 ) zOut[i++] = ' ';
+ i += speedtest1_numbername(n/1000000, zOut+i, nOut-i);
+ sqlite3_snprintf(nOut-i, zOut+i, " million");
+ i += (int)strlen(zOut+i);
+ n = n % 1000000;
+ }
+ if( n>=1000 ){
+ if( i && i<nOut-1 ) zOut[i++] = ' ';
+ i += speedtest1_numbername(n/1000, zOut+i, nOut-i);
+ sqlite3_snprintf(nOut-i, zOut+i, " thousand");
+ i += (int)strlen(zOut+i);
+ n = n % 1000;
+ }
+ if( n>=100 ){
+ if( i && i<nOut-1 ) zOut[i++] = ' ';
+ sqlite3_snprintf(nOut-i, zOut+i, "%s hundred", ones[n/100]);
+ i += (int)strlen(zOut+i);
+ n = n % 100;
+ }
+ if( n>=20 ){
+ if( i && i<nOut-1 ) zOut[i++] = ' ';
+ sqlite3_snprintf(nOut-i, zOut+i, "%s", tens[n/10]);
+ i += (int)strlen(zOut+i);
+ n = n % 10;
+ }
+ if( n>0 ){
+ if( i && i<nOut-1 ) zOut[i++] = ' ';
+ sqlite3_snprintf(nOut-i, zOut+i, "%s", ones[n]);
+ i += (int)strlen(zOut+i);
+ }
+ if( i==0 ){
+ sqlite3_snprintf(nOut-i, zOut+i, "zero");
+ i += (int)strlen(zOut+i);
+ }
+ return i;
+}
+
+
+/* Start a new test case */
+#define NAMEWIDTH 60
+static const char zDots[] =
+ ".......................................................................";
+void speedtest1_begin_test(int iTestNum, const char *zTestName, ...){
+ int n = (int)strlen(zTestName);
+ char *zName;
+ va_list ap;
+ va_start(ap, zTestName);
+ zName = sqlite3_vmprintf(zTestName, ap);
+ va_end(ap);
+ n = (int)strlen(zName);
+ if( n>NAMEWIDTH ){
+ zName[NAMEWIDTH] = 0;
+ n = NAMEWIDTH;
+ }
+ if( g.bSqlOnly ){
+ printf("/* %4d - %s%.*s */\n", iTestNum, zName, NAMEWIDTH-n, zDots);
+ }else{
+ printf("%4d - %s%.*s ", iTestNum, zName, NAMEWIDTH-n, zDots);
+ fflush(stdout);
+ }
+ sqlite3_free(zName);
+ g.nResult = 0;
+ g.iStart = speedtest1_timestamp();
+ g.x = 0xad131d0b;
+ g.y = 0x44f9eac8;
+}
+
+/* Complete a test case */
+void speedtest1_end_test(void){
+ sqlite3_int64 iElapseTime = speedtest1_timestamp() - g.iStart;
+ if( !g.bSqlOnly ){
+ g.iTotal += iElapseTime;
+ printf("%4d.%03ds\n", (int)(iElapseTime/1000), (int)(iElapseTime%1000));
+ }
+ if( g.pStmt ){
+ sqlite3_finalize(g.pStmt);
+ g.pStmt = 0;
+ }
+}
+
+/* Report end of testing */
+void speedtest1_final(void){
+ if( !g.bSqlOnly ){
+ printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots,
+ (int)(g.iTotal/1000), (int)(g.iTotal%1000));
+ }
+}
+
+/* Print an SQL statement to standard output */
+static void printSql(const char *zSql){
+ int n = (int)strlen(zSql);
+ while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ){ n--; }
+ if( g.bExplain ) printf("EXPLAIN ");
+ printf("%.*s;\n", n, zSql);
+ if( g.bExplain
+#if SQLITE_VERSION_NUMBER>=3007010
+ && ( sqlite3_strglob("CREATE *", zSql)==0
+ || sqlite3_strglob("DROP *", zSql)==0
+ || sqlite3_strglob("ALTER *", zSql)==0
+ )
+#endif
+ ){
+ printf("%.*s;\n", n, zSql);
+ }
+}
+
+/* Run SQL */
+void speedtest1_exec(const char *zFormat, ...){
+ va_list ap;
+ char *zSql;
+ va_start(ap, zFormat);
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( g.bSqlOnly ){
+ printSql(zSql);
+ }else{
+ char *zErrMsg = 0;
+ int rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg);
+ if( zErrMsg ) fatal_error("SQL error: %s\n%s\n", zErrMsg, zSql);
+ if( rc!=SQLITE_OK ) fatal_error("exec error: %s\n", sqlite3_errmsg(g.db));
+ }
+ sqlite3_free(zSql);
+}
+
+/* Prepare an SQL statement */
+void speedtest1_prepare(const char *zFormat, ...){
+ va_list ap;
+ char *zSql;
+ va_start(ap, zFormat);
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( g.bSqlOnly ){
+ printSql(zSql);
+ }else{
+ int rc;
+ if( g.pStmt ) sqlite3_finalize(g.pStmt);
+ rc = sqlite3_prepare_v2(g.db, zSql, -1, &g.pStmt, 0);
+ if( rc ){
+ fatal_error("SQL error: %s\n", sqlite3_errmsg(g.db));
+ }
+ }
+ sqlite3_free(zSql);
+}
+
+/* Run an SQL statement previously prepared */
+void speedtest1_run(void){
+ int i, n, len;
+ if( g.bSqlOnly ) return;
+ assert( g.pStmt );
+ g.nResult = 0;
+ while( sqlite3_step(g.pStmt)==SQLITE_ROW ){
+ n = sqlite3_column_count(g.pStmt);
+ for(i=0; i<n; i++){
+ const char *z = (const char*)sqlite3_column_text(g.pStmt, i);
+ if( z==0 ) z = "nil";
+ len = (int)strlen(z);
+ if( g.nResult+len<sizeof(g.zResult)-2 ){
+ if( g.nResult>0 ) g.zResult[g.nResult++] = ' ';
+ memcpy(g.zResult + g.nResult, z, len+1);
+ g.nResult += len;
+ }
+ }
+ }
+ if( g.bReprepare ){
+ sqlite3_stmt *pNew;
+ sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0);
+ sqlite3_finalize(g.pStmt);
+ g.pStmt = pNew;
+ }else{
+ sqlite3_reset(g.pStmt);
+ }
+}
+
+/* The sqlite3_trace() callback function */
+static void traceCallback(void *NotUsed, const char *zSql){
+ int n = (int)strlen(zSql);
+ while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ) n--;
+ fprintf(stderr,"%.*s;\n", n, zSql);
+}
+
+/* Substitute random() function that gives the same random
+** sequence on each run, for repeatability. */
+static void randomFunc(
+ sqlite3_context *context,
+ int NotUsed,
+ sqlite3_value **NotUsed2
+){
+ sqlite3_result_int64(context, (sqlite3_int64)speedtest1_random());
+}
+
+/* Estimate the square root of an integer */
+static int est_square_root(int x){
+ int y0 = x/2;
+ int y1;
+ int n;
+ for(n=0; y0>0 && n<10; n++){
+ y1 = (y0 + x/y0)/2;
+ if( y1==y0 ) break;
+ y0 = y1;
+ }
+ return y0;
+}
+
+/*
+** The main and default testset
+*/
+void testset_main(void){
+ int i; /* Loop counter */
+ int n; /* iteration count */
+ int sz; /* Size of the tables */
+ int maxb; /* Maximum swizzled value */
+ unsigned x1, x2; /* Parameters */
+ int len; /* Length of the zNum[] string */
+ char zNum[2000]; /* A number name */
+
+ sz = n = g.szTest*500;
+ maxb = roundup_allones(sz);
+ speedtest1_begin_test(100, "%d INSERTs into table with no index", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_exec("CREATE TABLE t1(a INTEGER %s, b INTEGER %s, c TEXT %s);",
+ g.zNN, g.zNN, g.zNN);
+ speedtest1_prepare("INSERT INTO t1 VALUES(?1,?2,?3); -- %d times", n);
+ for(i=1; i<=n; i++){
+ x1 = swizzle(i,maxb);
+ speedtest1_numbername(x1, zNum, sizeof(zNum));
+ sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1);
+ sqlite3_bind_int(g.pStmt, 2, i);
+ sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = sz;
+ speedtest1_begin_test(110, "%d ordered INSERTS with one index/PK", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_exec("CREATE TABLE t2(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s",
+ g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
+ speedtest1_prepare("INSERT INTO t2 VALUES(?1,?2,?3); -- %d times", n);
+ for(i=1; i<=n; i++){
+ x1 = swizzle(i,maxb);
+ speedtest1_numbername(x1, zNum, sizeof(zNum));
+ sqlite3_bind_int(g.pStmt, 1, i);
+ sqlite3_bind_int64(g.pStmt, 2, (sqlite3_int64)x1);
+ sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = sz;
+ speedtest1_begin_test(120, "%d unordered INSERTS with one index/PK", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_exec("CREATE TABLE t3(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s",
+ g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
+ speedtest1_prepare("INSERT INTO t3 VALUES(?1,?2,?3); -- %d times", n);
+ for(i=1; i<=n; i++){
+ x1 = swizzle(i,maxb);
+ speedtest1_numbername(x1, zNum, sizeof(zNum));
+ sqlite3_bind_int(g.pStmt, 2, i);
+ sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1);
+ sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = 25;
+ speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
+ " WHERE b BETWEEN ?1 AND ?2; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ x2 = speedtest1_random()%10 + sz/5000 + x1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ sqlite3_bind_int(g.pStmt, 2, x2);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = 10;
+ speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
+ " WHERE c LIKE ?1; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ zNum[0] = '%';
+ len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2);
+ zNum[len] = '%';
+ zNum[len+1] = 0;
+ sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = 10;
+ speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT a, b, c FROM t1 WHERE c LIKE ?1\n"
+ " ORDER BY a; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ zNum[0] = '%';
+ len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2);
+ zNum[len] = '%';
+ zNum[len+1] = 0;
+ sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ n = 10; //g.szTest/5;
+ speedtest1_begin_test(145, "%d SELECTS w/ORDER BY and LIMIT, unindexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT a, b, c FROM t1 WHERE c LIKE ?1\n"
+ " ORDER BY a LIMIT 10; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ zNum[0] = '%';
+ len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2);
+ zNum[len] = '%';
+ zNum[len+1] = 0;
+ sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ speedtest1_begin_test(150, "CREATE INDEX five times");
+ speedtest1_exec("BEGIN;");
+ speedtest1_exec("CREATE UNIQUE INDEX t1b ON t1(b);");
+ speedtest1_exec("CREATE INDEX t1c ON t1(c);");
+ speedtest1_exec("CREATE UNIQUE INDEX t2b ON t2(b);");
+ speedtest1_exec("CREATE INDEX t2c ON t2(c DESC);");
+ speedtest1_exec("CREATE INDEX t3bc ON t3(b,c);");
+ speedtest1_exec("COMMIT;");
+ speedtest1_end_test();
+
+
+ n = sz/5;
+ speedtest1_begin_test(160, "%d SELECTS, numeric BETWEEN, indexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
+ " WHERE b BETWEEN ?1 AND ?2; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ x2 = speedtest1_random()%10 + sz/5000 + x1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ sqlite3_bind_int(g.pStmt, 2, x2);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = sz/5;
+ speedtest1_begin_test(161, "%d SELECTS, numeric BETWEEN, PK", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT count(*), avg(b), sum(length(c)) FROM t2\n"
+ " WHERE a BETWEEN ?1 AND ?2; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ x2 = speedtest1_random()%10 + sz/5000 + x1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ sqlite3_bind_int(g.pStmt, 2, x2);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = sz/5;
+ speedtest1_begin_test(170, "%d SELECTS, text BETWEEN, indexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
+ " WHERE c BETWEEN ?1 AND (?1||'~'); -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = swizzle(i, maxb);
+ len = speedtest1_numbername(x1, zNum, sizeof(zNum)-1);
+ sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ n = sz;
+ speedtest1_begin_test(180, "%d INSERTS with three indexes", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_exec(
+ "CREATE TABLE t4(\n"
+ " a INTEGER %s %s,\n"
+ " b INTEGER %s,\n"
+ " c TEXT %s\n"
+ ") %s",
+ g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
+ speedtest1_exec("CREATE INDEX t4b ON t4(b)");
+ speedtest1_exec("CREATE INDEX t4c ON t4(c)");
+ speedtest1_exec("INSERT INTO t4 SELECT * FROM t1");
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ n = sz;
+ speedtest1_begin_test(190, "DELETE and REFILL one table", n);
+ speedtest1_exec("DELETE FROM t2;");
+ speedtest1_exec("INSERT INTO t2 SELECT * FROM t1;");
+ speedtest1_end_test();
+
+// #include <emscripten.h>
+ speedtest1_begin_test(200, "VACUUM");
+// EM_ASM( alert('pre') );
+ speedtest1_exec("VACUUM");
+// EM_ASM( alert('post') );
+ speedtest1_end_test();
+
+
+ speedtest1_begin_test(210, "ALTER TABLE ADD COLUMN, and query");
+ speedtest1_exec("ALTER TABLE t2 ADD COLUMN d DEFAULT 123");
+ speedtest1_exec("SELECT sum(d) FROM t2");
+ speedtest1_end_test();
+
+
+ n = sz/5;
+ speedtest1_begin_test(230, "%d UPDATES, numeric BETWEEN, indexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "UPDATE t2 SET d=b*2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb;
+ x2 = speedtest1_random()%10 + sz/5000 + x1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ sqlite3_bind_int(g.pStmt, 2, x2);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = sz;
+ speedtest1_begin_test(240, "%d UPDATES of individual rows", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "UPDATE t2 SET d=b*3 WHERE a=?1; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%sz + 1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ speedtest1_begin_test(250, "One big UPDATE of the whole %d-row table", sz);
+ speedtest1_exec("UPDATE t2 SET d=b*4");
+ speedtest1_end_test();
+
+
+ speedtest1_begin_test(260, "Query added column after filling");
+ speedtest1_exec("SELECT sum(d) FROM t2");
+ speedtest1_end_test();
+
+
+
+ n = sz/5;
+ speedtest1_begin_test(270, "%d DELETEs, numeric BETWEEN, indexed", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "DELETE FROM t2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%maxb + 1;
+ x2 = speedtest1_random()%10 + sz/5000 + x1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ sqlite3_bind_int(g.pStmt, 2, x2);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ n = sz;
+ speedtest1_begin_test(280, "%d DELETEs of individual rows", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "DELETE FROM t3 WHERE a=?1; -- %d times", n
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%sz + 1;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+
+ speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz);
+ speedtest1_exec("REPLACE INTO t2(a,b,c) SELECT a,b,c FROM t1");
+ speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM t1");
+ speedtest1_end_test();
+
+ speedtest1_begin_test(300, "Refill a %d-row table using (b&1)==(a&1)", sz);
+ speedtest1_exec("DELETE FROM t2;");
+ speedtest1_exec("INSERT INTO t2(a,b,c)\n"
+ " SELECT a,b,c FROM t1 WHERE (b&1)==(a&1);");
+ speedtest1_exec("INSERT INTO t2(a,b,c)\n"
+ " SELECT a,b,c FROM t1 WHERE (b&1)<>(a&1);");
+ speedtest1_end_test();
+
+
+ n = sz/5;
+ speedtest1_begin_test(310, "%d four-ways joins", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_prepare(
+ "SELECT t1.c FROM t1, t2, t3, t4\n"
+ " WHERE t4.a BETWEEN ?1 AND ?2\n"
+ " AND t3.a=t4.b\n"
+ " AND t2.a=t3.b\n"
+ " AND t1.c=t2.c"
+ );
+ for(i=1; i<=n; i++){
+ x1 = speedtest1_random()%sz + 1;
+ x2 = speedtest1_random()%10 + x1 + 4;
+ sqlite3_bind_int(g.pStmt, 1, x1);
+ sqlite3_bind_int(g.pStmt, 2, x2);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ speedtest1_begin_test(320, "subquery in result set", n);
+ speedtest1_prepare(
+ "SELECT sum(a), max(c),\n"
+ " avg((SELECT a FROM t2 WHERE 5+t2.b=t1.b) AND rowid<?1), max(c)\n"
+ " FROM t1 WHERE rowid<?1;"
+ );
+ sqlite3_bind_int(g.pStmt, 1, est_square_root(g.szTest)*50);
+ speedtest1_run();
+ speedtest1_end_test();
+
+ speedtest1_begin_test(980, "PRAGMA integrity_check");
+ speedtest1_exec("PRAGMA integrity_check");
+ speedtest1_end_test();
+
+
+ speedtest1_begin_test(990, "ANALYZE");
+ speedtest1_exec("ANALYZE");
+ speedtest1_end_test();
+}
+
+/*
+** A testset for common table expressions. This exercises code
+** for views, subqueries, co-routines, etc.
+*/
+void testset_cte(void){
+ static const char *azPuzzle[] = {
+ /* Easy */
+ "534...9.."
+ "67.195..."
+ ".98....6."
+ "8...6...3"
+ "4..8.3..1"
+ "....2...6"
+ ".6....28."
+ "...419..5"
+ "...28..79",
+
+ /* Medium */
+ "53....9.."
+ "6..195..."
+ ".98....6."
+ "8...6...3"
+ "4..8.3..1"
+ "....2...6"
+ ".6....28."
+ "...419..5"
+ "....8..79",
+
+ /* Hard */
+ "53......."
+ "6..195..."
+ ".98....6."
+ "8...6...3"
+ "4..8.3..1"
+ "....2...6"
+ ".6....28."
+ "...419..5"
+ "....8..79",
+ };
+ const char *zPuz;
+ double rSpacing;
+ int nElem;
+
+ if( g.szTest<25 ){
+ zPuz = azPuzzle[0];
+ }else if( g.szTest<70 ){
+ zPuz = azPuzzle[1];
+ }else{
+ zPuz = azPuzzle[2];
+ }
+ speedtest1_begin_test(100, "Sudoku with recursive 'digits'");
+ speedtest1_prepare(
+ "WITH RECURSIVE\n"
+ " input(sud) AS (VALUES(?1)),\n"
+ " digits(z,lp) AS (\n"
+ " VALUES('1', 1)\n"
+ " UNION ALL\n"
+ " SELECT CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9\n"
+ " ),\n"
+ " x(s, ind) AS (\n"
+ " SELECT sud, instr(sud, '.') FROM input\n"
+ " UNION ALL\n"
+ " SELECT\n"
+ " substr(s, 1, ind-1) || z || substr(s, ind+1),\n"
+ " instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n"
+ " FROM x, digits AS z\n"
+ " WHERE ind>0\n"
+ " AND NOT EXISTS (\n"
+ " SELECT 1\n"
+ " FROM digits AS lp\n"
+ " WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n"
+ " OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n"
+ " OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n"
+ " + ((ind-1)/27) * 27 + lp\n"
+ " + ((lp-1) / 3) * 6, 1)\n"
+ " )\n"
+ " )\n"
+ "SELECT s FROM x WHERE ind=0;"
+ );
+ sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC);
+ speedtest1_run();
+ speedtest1_end_test();
+
+ speedtest1_begin_test(200, "Sudoku with VALUES 'digits'");
+ speedtest1_prepare(
+ "WITH RECURSIVE\n"
+ " input(sud) AS (VALUES(?1)),\n"
+ " digits(z,lp) AS (VALUES('1',1),('2',2),('3',3),('4',4),('5',5),\n"
+ " ('6',6),('7',7),('8',8),('9',9)),\n"
+ " x(s, ind) AS (\n"
+ " SELECT sud, instr(sud, '.') FROM input\n"
+ " UNION ALL\n"
+ " SELECT\n"
+ " substr(s, 1, ind-1) || z || substr(s, ind+1),\n"
+ " instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n"
+ " FROM x, digits AS z\n"
+ " WHERE ind>0\n"
+ " AND NOT EXISTS (\n"
+ " SELECT 1\n"
+ " FROM digits AS lp\n"
+ " WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n"
+ " OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n"
+ " OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n"
+ " + ((ind-1)/27) * 27 + lp\n"
+ " + ((lp-1) / 3) * 6, 1)\n"
+ " )\n"
+ " )\n"
+ "SELECT s FROM x WHERE ind=0;"
+ );
+ sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC);
+ speedtest1_run();
+ speedtest1_end_test();
+
+ rSpacing = 5.0/g.szTest;
+ speedtest1_begin_test(300, "Mandelbrot Set with spacing=%f", rSpacing);
+ speedtest1_prepare(
+ "WITH RECURSIVE \n"
+ " xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+?1 FROM xaxis WHERE x<1.2),\n"
+ " yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+?2 FROM yaxis WHERE y<1.0),\n"
+ " m(iter, cx, cy, x, y) AS (\n"
+ " SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis\n"
+ " UNION ALL\n"
+ " SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m \n"
+ " WHERE (x*x + y*y) < 4.0 AND iter<28\n"
+ " ),\n"
+ " m2(iter, cx, cy) AS (\n"
+ " SELECT max(iter), cx, cy FROM m GROUP BY cx, cy\n"
+ " ),\n"
+ " a(t) AS (\n"
+ " SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') \n"
+ " FROM m2 GROUP BY cy\n"
+ " )\n"
+ "SELECT group_concat(rtrim(t),x'0a') FROM a;"
+ );
+ sqlite3_bind_double(g.pStmt, 1, rSpacing*.05);
+ sqlite3_bind_double(g.pStmt, 2, rSpacing);
+ speedtest1_run();
+ speedtest1_end_test();
+
+ nElem = 10000*g.szTest;
+ speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem);
+ speedtest1_prepare(
+ "WITH RECURSIVE \n"
+ " t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<%d),\n"
+ " t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<%d)\n"
+ "SELECT count(x), avg(x) FROM (\n"
+ " SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1\n"
+ ");",
+ nElem, nElem
+ );
+ speedtest1_run();
+ speedtest1_end_test();
+
+}
+
+/* Generate two numbers between 1 and mx. The first number is less than
+** the second. Usually the numbers are near each other but can sometimes
+** be far apart.
+*/
+static void twoCoords(
+ int p1, int p2, /* Parameters adjusting sizes */
+ unsigned mx, /* Range of 1..mx */
+ unsigned *pX0, unsigned *pX1 /* OUT: write results here */
+){
+ unsigned d, x0, x1, span;
+
+ span = mx/100 + 1;
+ if( speedtest1_random()%3==0 ) span *= p1;
+ if( speedtest1_random()%p2==0 ) span = mx/2;
+ d = speedtest1_random()%span + 1;
+ x0 = speedtest1_random()%(mx-d) + 1;
+ x1 = x0 + d;
+ *pX0 = x0;
+ *pX1 = x1;
+}
+
+/* The following routine is an R-Tree geometry callback. It returns
+** true if the object overlaps a slice on the Y coordinate between the
+** two values given as arguments. In other words
+**
+** SELECT count(*) FROM rt1 WHERE id MATCH xslice(10,20);
+**
+** Is the same as saying:
+**
+** SELECT count(*) FROM rt1 WHERE y1>=10 AND y0<=20;
+*/
+static int xsliceGeometryCallback(
+ sqlite3_rtree_geometry *p,
+ int nCoord,
+ double *aCoord,
+ int *pRes
+){
+ *pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1];
+ return SQLITE_OK;
+}
+
+/*
+** A testset for the R-Tree virtual table
+*/
+void testset_rtree(int p1, int p2){
+ unsigned i, n;
+ unsigned mxCoord;
+ unsigned x0, x1, y0, y1, z0, z1;
+ unsigned iStep;
+ int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*100 );
+
+ mxCoord = 15000;
+ n = g.szTest*100;
+ speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
+ speedtest1_exec("BEGIN");
+ speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
+ speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)"
+ "VALUES(?1,?2,?3,?4,?5,?6,?7)");
+ for(i=1; i<=n; i++){
+ twoCoords(p1, p2, mxCoord, &x0, &x1);
+ twoCoords(p1, p2, mxCoord, &y0, &y1);
+ twoCoords(p1, p2, mxCoord, &z0, &z1);
+ sqlite3_bind_int(g.pStmt, 1, i);
+ sqlite3_bind_int(g.pStmt, 2, x0);
+ sqlite3_bind_int(g.pStmt, 3, x1);
+ sqlite3_bind_int(g.pStmt, 4, y0);
+ sqlite3_bind_int(g.pStmt, 5, y1);
+ sqlite3_bind_int(g.pStmt, 6, z0);
+ sqlite3_bind_int(g.pStmt, 7, z1);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ speedtest1_begin_test(101, "Copy from rtree to a regular table");
+ speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
+ speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
+ speedtest1_end_test();
+
+ n = g.szTest*20;
+ speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
+ speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
+ iStep = mxCoord/n;
+ for(i=0; i<n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i*iStep);
+ sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
+ speedtest1_run();
+ aCheck[i] = atoi(g.zResult);
+ }
+ speedtest1_end_test();
+
+ if( g.bVerify ){
+ n = g.szTest*20;
+ speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
+ speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
+ iStep = mxCoord/n;
+ for(i=0; i<n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i*iStep);
+ sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
+ speedtest1_run();
+ if( aCheck[i]!=atoi(g.zResult) ){
+ fatal_error("Count disagree step %d: %d..%d. %d vs %d",
+ i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
+ }
+ }
+ speedtest1_end_test();
+ }
+
+ n = g.szTest*20;
+ speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
+ speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
+ iStep = mxCoord/n;
+ for(i=0; i<n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i*iStep);
+ sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
+ speedtest1_run();
+ aCheck[i] = atoi(g.zResult);
+ }
+ speedtest1_end_test();
+
+ if( g.bVerify ){
+ n = g.szTest*20;
+ speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
+ speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
+ iStep = mxCoord/n;
+ for(i=0; i<n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i*iStep);
+ sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
+ speedtest1_run();
+ if( aCheck[i]!=atoi(g.zResult) ){
+ fatal_error("Count disagree step %d: %d..%d. %d vs %d",
+ i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
+ }
+ }
+ speedtest1_end_test();
+ }
+
+
+ n = g.szTest*20;
+ speedtest1_begin_test(125, "%d custom geometry callback queries", n);
+ //sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0);
+ speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)");
+ iStep = mxCoord/n;
+ for(i=0; i<n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i*iStep);
+ sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
+ speedtest1_run();
+ if( aCheck[i]!=atoi(g.zResult) ){
+ fatal_error("Count disagree step %d: %d..%d. %d vs %d",
+ i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
+ }
+ }
+ speedtest1_end_test();
+
+ n = g.szTest*80;
+ speedtest1_begin_test(130, "%d three-dimensional intersect box queries", n);
+ speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x1>=?1 AND x0<=?2"
+ " AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2");
+ iStep = mxCoord/n;
+ for(i=0; i<n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i*iStep);
+ sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
+ speedtest1_run();
+ aCheck[i] = atoi(g.zResult);
+ }
+ speedtest1_end_test();
+
+ n = g.szTest*100;
+ speedtest1_begin_test(140, "%d rowid queries", n);
+ speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1");
+ for(i=1; i<=n; i++){
+ sqlite3_bind_int(g.pStmt, 1, i);
+ speedtest1_run();
+ }
+ speedtest1_end_test();
+}
+
+/*
+** A testset used for debugging speedtest1 itself.
+*/
+void testset_debug1(void){
+ unsigned i, n;
+ unsigned x1, x2;
+ char zNum[2000]; /* A number name */
+
+ n = g.szTest;
+ for(i=1; i<=n; i++){
+ x1 = swizzle(i, n);
+ x2 = swizzle(x1, n);
+ speedtest1_numbername(x1, zNum, sizeof(zNum));
+ printf("%5d %5d %5d %s\n", i, x1, x2, zNum);
+ }
+}
+
+int main(int argc, char **argv){
+ int doAutovac = 0; /* True for --autovacuum */
+ int cacheSize = 0; /* Desired cache size. 0 means default */
+ int doExclusive = 0; /* True for --exclusive */
+ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */
+ int doIncrvac = 0; /* True for --incrvacuum */
+ const char *zJMode = 0; /* Journal mode */
+ const char *zKey = 0; /* Encryption key */
+ int nLook = 0, szLook = 0; /* --lookaside configuration */
+ int noSync = 0; /* True for --nosync */
+ int pageSize = 0; /* Desired page size. 0 means default */
+ int nPCache = 0, szPCache = 0;/* --pcache configuration */
+ int nScratch = 0, szScratch=0;/* --scratch configuration */
+ int showStats = 0; /* True for --stats */
+ const char *zTSet = "main"; /* Which --testset torun */
+ int doTrace = 0; /* True for --trace */
+ const char *zEncoding = 0; /* --utf16be or --utf16le */
+ const char *zDbName = 0; /* Name of the test database */
+
+ void *pHeap = 0; /* Allocated heap space */
+ void *pLook = 0; /* Allocated lookaside space */
+ void *pPCache = 0; /* Allocated storage for pcache */
+ void *pScratch = 0; /* Allocated storage for scratch */
+ int iCur, iHi; /* Stats values, current and "highwater" */
+ int i; /* Loop counter */
+ int rc; /* API return code */
+
+ /* Process command-line arguments */
+ g.zWR = "";
+ g.zNN = "";
+ g.zPK = "UNIQUE";
+ g.szTest = 100;
+ for(i=1; i<argc; i++){
+ const char *z = argv[i];
+ if( z[0]=='-' ){
+ do{ z++; }while( z[0]=='-' );
+ if( strcmp(z,"autovacuum")==0 ){
+ doAutovac = 1;
+ }else if( strcmp(z,"cachesize")==0 ){
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ i++;
+ cacheSize = integerValue(argv[i]);
+ }else if( strcmp(z,"exclusive")==0 ){
+ doExclusive = 1;
+ }else if( strcmp(z,"explain")==0 ){
+ g.bSqlOnly = 1;
+ g.bExplain = 1;
+ }else if( strcmp(z,"heap")==0 ){
+ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
+ nHeap = integerValue(argv[i+1]);
+ mnHeap = integerValue(argv[i+2]);
+ i += 2;
+ }else if( strcmp(z,"incrvacuum")==0 ){
+ doIncrvac = 1;
+ }else if( strcmp(z,"journal")==0 ){
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ zJMode = argv[++i];
+ }else if( strcmp(z,"key")==0 ){
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ zKey = argv[++i];
+ }else if( strcmp(z,"lookaside")==0 ){
+ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
+ nLook = integerValue(argv[i+1]);
+ szLook = integerValue(argv[i+2]);
+ i += 2;
+ }else if( strcmp(z,"nosync")==0 ){
+ noSync = 1;
+ }else if( strcmp(z,"notnull")==0 ){
+ g.zNN = "NOT NULL";
+ }else if( strcmp(z,"pagesize")==0 ){
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ pageSize = integerValue(argv[++i]);
+ }else if( strcmp(z,"pcache")==0 ){
+ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
+ nPCache = integerValue(argv[i+1]);
+ szPCache = integerValue(argv[i+2]);
+ i += 2;
+ }else if( strcmp(z,"primarykey")==0 ){
+ g.zPK = "PRIMARY KEY";
+ }else if( strcmp(z,"reprepare")==0 ){
+ g.bReprepare = 1;
+ }else if( strcmp(z,"scratch")==0 ){
+ if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
+ nScratch = integerValue(argv[i+1]);
+ szScratch = integerValue(argv[i+2]);
+ i += 2;
+ }else if( strcmp(z,"sqlonly")==0 ){
+ g.bSqlOnly = 1;
+ }else if( strcmp(z,"size")==0 ){
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ g.szTest = integerValue(argv[++i]);
+ }else if( strcmp(z,"stats")==0 ){
+ showStats = 1;
+ }else if( strcmp(z,"testset")==0 ){
+ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
+ zTSet = argv[++i];
+ }else if( strcmp(z,"trace")==0 ){
+ doTrace = 1;
+ }else if( strcmp(z,"utf16le")==0 ){
+ zEncoding = "utf16le";
+ }else if( strcmp(z,"utf16be")==0 ){
+ zEncoding = "utf16be";
+ }else if( strcmp(z,"verify")==0 ){
+ g.bVerify = 1;
+ }else if( strcmp(z,"without-rowid")==0 ){
+ g.zWR = "WITHOUT ROWID";
+ g.zPK = "PRIMARY KEY";
+ }else if( strcmp(z, "help")==0 || strcmp(z,"?")==0 ){
+ printf(zHelp, argv[0]);
+ exit(0);
+ }else{
+ fatal_error("unknown option: %s\nUse \"%s -?\" for help\n",
+ argv[i], argv[0]);
+ }
+ }else if( zDbName==0 ){
+ zDbName = argv[i];
+ }else{
+ fatal_error("surplus argument: %s\nUse \"%s -?\" for help\n",
+ argv[i], argv[0]);
+ }
+ }
+#if 0
+ if( zDbName==0 ){
+ fatal_error(zHelp, argv[0]);
+ }
+#endif
+ if( nHeap>0 ){
+ pHeap = malloc( nHeap );
+ if( pHeap==0 ) fatal_error("cannot allocate %d-byte heap\n", nHeap);
+ rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
+ if( rc ) fatal_error("heap configuration failed: %d\n", rc);
+ }
+ if( nPCache>0 && szPCache>0 ){
+ pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
+ if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n",
+ nPCache*(sqlite3_int64)szPCache);
+ rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache);
+ if( rc ) fatal_error("pcache configuration failed: %d\n", rc);
+ }
+ if( nScratch>0 && szScratch>0 ){
+ pScratch = malloc( nScratch*(sqlite3_int64)szScratch );
+ if( pScratch==0 ) fatal_error("cannot allocate %lld-byte scratch\n",
+ nScratch*(sqlite3_int64)szScratch);
+ rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch);
+ if( rc ) fatal_error("scratch configuration failed: %d\n", rc);
+ }
+ if( nLook>0 ){
+ sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
+ }
+
+ /* Open the database and the input file */
+ if( sqlite3_open(":memory:", &g.db) ){
+ fatal_error("Cannot open database file: %s\n", zDbName);
+ }
+ if( nLook>0 && szLook>0 ){
+ pLook = malloc( nLook*szLook );
+ rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook);
+ if( rc ) fatal_error("lookaside configuration failed: %d\n", rc);
+ }
+
+ /* Set database connection options */
+ sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0);
+ if( doTrace ) sqlite3_trace(g.db, traceCallback, 0);
+ if( zKey ){
+ speedtest1_exec("PRAGMA key('%s')", zKey);
+ }
+ if( zEncoding ){
+ speedtest1_exec("PRAGMA encoding=%s", zEncoding);
+ }
+ if( doAutovac ){
+ speedtest1_exec("PRAGMA auto_vacuum=FULL");
+ }else if( doIncrvac ){
+ speedtest1_exec("PRAGMA auto_vacuum=INCREMENTAL");
+ }
+ if( pageSize ){
+ speedtest1_exec("PRAGMA page_size=%d", pageSize);
+ }
+ if( cacheSize ){
+ speedtest1_exec("PRAGMA cache_size=%d", cacheSize);
+ }
+ if( noSync ) speedtest1_exec("PRAGMA synchronous=OFF");
+ if( doExclusive ){
+ speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE");
+ }
+ if( zJMode ){
+ speedtest1_exec("PRAGMA journal_mode=%s", zJMode);
+ }
+
+ if( g.bExplain ) printf(".explain\n.echo on\n");
+ if( strcmp(zTSet,"main")==0 ){
+ testset_main();
+ }else if( strcmp(zTSet,"debug1")==0 ){
+ testset_debug1();
+ }else if( strcmp(zTSet,"cte")==0 ){
+ testset_cte();
+ }else if( strcmp(zTSet,"rtree")==0 ){
+ testset_rtree(6, 147);
+ }else{
+ fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n",
+ zTSet);
+ }
+ speedtest1_final();
+
+ /* Database connection statistics printed after both prepared statements
+ ** have been finalized */
+#if SQLITE_VERSION_NUMBER>=3007009
+ if( showStats ){
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0);
+ printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHi);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0);
+ printf("-- Successful lookasides: %d\n", iHi);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0);
+ printf("-- Lookaside size faults: %d\n", iHi);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0);
+ printf("-- Lookaside OOM faults: %d\n", iHi);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0);
+ printf("-- Pager Heap Usage: %d bytes\n", iCur);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1);
+ printf("-- Page cache hits: %d\n", iCur);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1);
+ printf("-- Page cache misses: %d\n", iCur);
+#if SQLITE_VERSION_NUMBER>=3007012
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1);
+ printf("-- Page cache writes: %d\n", iCur);
+#endif
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0);
+ printf("-- Schema Heap Usage: %d bytes\n", iCur);
+ sqlite3_db_status(g.db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0);
+ printf("-- Statement Heap Usage: %d bytes\n", iCur);
+ }
+#endif
+
+ sqlite3_close(g.db);
+
+ /* Global memory usage statistics printed after the database connection
+ ** has closed. Memory usage should be zero at this point. */
+ if( showStats ){
+ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0);
+ printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHi);
+#if SQLITE_VERSION_NUMBER>=3007000
+ sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0);
+ printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi);
+#endif
+ sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0);
+ printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi);
+ sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHi, 0);
+ printf("-- Scratch Overflow Bytes: %d (max %d)\n", iCur,iHi);
+ sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0);
+ printf("-- Largest Allocation: %d bytes\n",iHi);
+ sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0);
+ printf("-- Largest Pcache Allocation: %d bytes\n",iHi);
+ sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0);
+ printf("-- Largest Scratch Allocation: %d bytes\n", iHi);
+ }
+
+ /* Release memory */
+ free( pLook );
+ free( pPCache );
+ free( pScratch );
+ free( pHeap );
+ return 0;
+}
diff --git a/tests/test_browser.py b/tests/test_browser.py
index aedc926a..37657393 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -693,7 +693,7 @@ If manually bisecting:
def test_sdl_image_prepare(self):
# load an image file, get pixel data.
shutil.copyfile(path_from_root('tests', 'screenshot.jpg'), os.path.join(self.get_dir(), 'screenshot.not'))
- self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'])
+ self.btest('sdl_image_prepare.c', reference='screenshot.jpg', args=['--preload-file', 'screenshot.not'], also_proxied=True)
def test_sdl_image_prepare_data(self):
# load an image file, get pixel data.
@@ -719,10 +719,11 @@ If manually bisecting:
self.clear()
self.btest('sdl_canvas.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1', '-O2', '-s', 'SAFE_HEAP=1'])
- def test_sdl_canvas_proxy(self):
- def post():
- html = open('test.html').read()
- html = html.replace('</body>', '''
+ def post_manual_reftest(self, reference=None):
+ self.reftest(path_from_root('tests', self.reference if reference is None else reference))
+
+ html = open('test.html').read()
+ html = html.replace('</body>', '''
<script>
function assert(x, y) { if (!x) throw 'assertion failed ' + y }
@@ -738,45 +739,56 @@ window.close = function() {
};
</script>
</body>''' % open('reftest.js').read())
- open('test.html', 'w').write(html)
+ open('test.html', 'w').write(html)
+ def test_sdl_canvas_proxy(self):
open('data.txt', 'w').write('datum')
+ self.btest('sdl_canvas_proxy.c', reference='sdl_canvas_proxy.png', args=['--proxy-to-worker', '--preload-file', 'data.txt'], manual_reference=True, post_build=self.post_manual_reftest)
+
+ def test_glgears_proxy(self):
+ self.btest('hello_world_gles_proxy.c', reference='gears.png', args=['--proxy-to-worker', '-s', 'GL_TESTING=1'], manual_reference=True, post_build=self.post_manual_reftest)
- self.btest('sdl_canvas_proxy.c', reference='sdl_canvas_proxy.png', args=['--proxy-to-worker', '--preload-file', 'data.txt'], manual_reference=True, post_build=post)
+ def test_glgears_proxy_jstarget(self):
+ # test .js target with --proxy-worker; emits 2 js files, client and worker
+ Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_gles_proxy.c'), '-o', 'test.js', '--proxy-to-worker', '-s', 'GL_TESTING=1']).communicate()
+ open('test.html', 'w').write(open(path_from_root('src', 'shell_minimal.html')).read().replace('{{{ SCRIPT }}}', '<script src="test.js"></script>'))
+ self.post_manual_reftest('gears.png')
+ self.run_browser('test.html', None, '/report_result?0')
def test_sdl_canvas_alpha(self):
self.btest('sdl_canvas_alpha.c', reference='sdl_canvas_alpha.png', reference_slack=9)
def test_sdl_key(self):
- open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
- Module.postRun = function() {
- function doOne() {
- Module._one();
+ for defines in [[], ['-DTEST_EMSCRIPTEN_SDL_SETEVENTHANDLER']]:
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
+ Module.postRun = function() {
+ function doOne() {
+ Module._one();
+ setTimeout(doOne, 1000/60);
+ }
setTimeout(doOne, 1000/60);
}
- setTimeout(doOne, 1000/60);
- }
- function keydown(c) {
- var event = document.createEvent("KeyboardEvent");
- event.initKeyEvent("keydown", true, true, window,
- 0, 0, 0, 0,
- c, c);
- document.dispatchEvent(event);
- }
+ function keydown(c) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keydown", true, true, window,
+ 0, 0, 0, 0,
+ c, c);
+ document.dispatchEvent(event);
+ }
- function keyup(c) {
- var event = document.createEvent("KeyboardEvent");
- event.initKeyEvent("keyup", true, true, window,
- 0, 0, 0, 0,
- c, c);
- document.dispatchEvent(event);
- }
- ''')
- open(os.path.join(self.get_dir(), 'sdl_key.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_key.c')).read()))
+ function keyup(c) {
+ var event = document.createEvent("KeyboardEvent");
+ event.initKeyEvent("keyup", true, true, window,
+ 0, 0, 0, 0,
+ c, c);
+ document.dispatchEvent(event);
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'sdl_key.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_key.c')).read()))
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html', '--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''', '-s', 'NO_EXIT_RUNTIME=1']).communicate()
- self.run_browser('page.html', '', '/report_result?223092870')
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'sdl_key.c'), '-o', 'page.html'] + defines + ['--pre-js', 'pre.js', '-s', '''EXPORTED_FUNCTIONS=['_main', '_one']''', '-s', 'NO_EXIT_RUNTIME=1']).communicate()
+ self.run_browser('page.html', '', '/report_result?223092870')
def test_sdl_key_proxy(self):
open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
@@ -1096,9 +1108,10 @@ keydown(100);keyup(100); // trigger the end
shutil.move('test.html', 'third.html')
def test_fs_idbfs_sync(self):
- secret = str(time.time())
- self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=['-DFIRST', '-DSECRET=\'' + secret + '\'', '-s', '''EXPORTED_FUNCTIONS=['_main', '_success']'''])
- self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=['-DSECRET=\'' + secret + '\'', '-s', '''EXPORTED_FUNCTIONS=['_main', '_success']'''])
+ for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]:
+ secret = str(time.time())
+ self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=mode + ['-DFIRST', '-DSECRET=\'' + secret + '\'', '-s', '''EXPORTED_FUNCTIONS=['_main', '_success']'''])
+ self.btest(path_from_root('tests', 'fs', 'test_idbfs_sync.c'), '1', force_c=True, args=mode + ['-DSECRET=\'' + secret + '\'', '-s', '''EXPORTED_FUNCTIONS=['_main', '_success']'''])
def test_sdl_pumpevents(self):
# key events should be detected using SDL_PumpEvents
@@ -1114,9 +1127,8 @@ keydown(100);keyup(100); // trigger the end
self.btest('sdl_pumpevents.c', expected='7', args=['--pre-js', 'pre.js'])
def test_sdl_canvas_size(self):
- self.btest('sdl_canvas_size.c', reference='screenshot-gray-purple.png', reference_slack=1,
- args=['-O2', '--minify', '0', '--shell-file', path_from_root('tests', 'sdl_canvas_size.html'), '--preload-file', path_from_root('tests', 'screenshot.png') + '@/', '-s', 'LEGACY_GL_EMULATION=1'],
- message='You should see an image with gray at the top.')
+ self.btest('sdl_canvas_size.c', expected='1',
+ args=['-O2', '--minify', '0', '--shell-file', path_from_root('tests', 'sdl_canvas_size.html')])
def test_sdl_gl_read(self):
# SDL, OpenGL, readPixels
@@ -1305,7 +1317,9 @@ keydown(100);keyup(100); // trigger the end
message='You should see animating gears.')
def test_glgears_long(self):
- self.btest('hello_world_gles.c', expected=map(str, range(30, 1000)), args=['-DHAVE_BUILTIN_SINCOS', '-DLONGTEST'])
+ for proxy in [0, 1]:
+ print 'proxy', proxy
+ self.btest('hello_world_gles.c', expected=map(str, range(30, 500)), args=['-DHAVE_BUILTIN_SINCOS', '-DLONGTEST'] + (['--proxy-to-worker'] if proxy else []))
def test_glgears_animation(self):
es2_suffix = ['', '_full', '_full_944']
@@ -1425,6 +1439,12 @@ keydown(100);keyup(100); // trigger the end
def test_sdlglshader(self):
self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1', '-s', 'LEGACY_GL_EMULATION=1'])
+ def test_sdlglshader2(self):
+ self.btest('sdlglshader2.c', expected='1', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True)
+
+ def test_gl_glteximage(self):
+ self.btest('gl_teximage.c', '1')
+
def test_gl_ps(self):
# pointers and a shader
shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png'))
@@ -1451,9 +1471,8 @@ keydown(100);keyup(100); // trigger the end
def test_gl_vertex_buffer(self):
self.btest('gl_vertex_buffer.c', reference='gl_vertex_buffer.png', args=['-s', 'GL_UNSAFE_OPTS=0', '-s', 'LEGACY_GL_EMULATION=1'], reference_slack=1)
- # Does not pass due to https://bugzilla.mozilla.org/show_bug.cgi?id=924264 so disabled for now.
- # def test_gles2_uniform_arrays(self):
- # self.btest('gles2_uniform_arrays.cpp', args=['-s', 'GL_ASSERTIONS=1'], expected=['1'])
+ def test_gles2_uniform_arrays(self):
+ self.btest('gles2_uniform_arrays.cpp', args=['-s', 'GL_ASSERTIONS=1'], expected=['1'], also_proxied=True)
def test_gles2_conformance(self):
self.btest('gles2_conformance.cpp', args=['-s', 'GL_ASSERTIONS=1'], expected=['1'])
@@ -1471,7 +1490,7 @@ keydown(100);keyup(100); // trigger the end
self.btest('cubegeom_pre3.c', reference='cubegeom_pre2.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
def test_cubegeom(self):
- self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1'])
+ self.btest('cubegeom.c', reference='cubegeom.png', args=['-O2', '-g', '-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True)
def test_cubegeom_proc(self):
open('side.c', 'w').write(r'''
@@ -1495,10 +1514,10 @@ void *getBindBuffer() {
self.btest('cubegeom_color.c', reference='cubegeom_color.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
def test_cubegeom_normal(self):
- self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+ self.btest('cubegeom_normal.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True)
def test_cubegeom_normal_dap(self): # draw is given a direct pointer to clientside memory, no element array buffer
- self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+ self.btest('cubegeom_normal_dap.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True)
def test_cubegeom_normal_dap_far(self): # indices do nto start from 0
self.btest('cubegeom_normal_dap_far.c', reference='cubegeom_normal.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
@@ -1516,7 +1535,7 @@ void *getBindBuffer() {
self.btest('cubegeom_mt.c', reference='cubegeom_mt.png', args=['-s', 'LEGACY_GL_EMULATION=1']) # multitexture
def test_cubegeom_color2(self):
- self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+ self.btest('cubegeom_color2.c', reference='cubegeom_color2.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True)
def test_cubegeom_texturematrix(self):
self.btest('cubegeom_texturematrix.c', reference='cubegeom_texturematrix.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
@@ -1534,7 +1553,7 @@ void *getBindBuffer() {
self.btest('cubegeom_pre2_vao2.c', reference='cubegeom_pre2_vao2.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
def test_cube_explosion(self):
- self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1'])
+ self.btest('cube_explosion.c', reference='cube_explosion.png', args=['-s', 'LEGACY_GL_EMULATION=1'], also_proxied=True)
def test_glgettexenv(self):
self.btest('glgettexenv.c', args=['-s', 'LEGACY_GL_EMULATION=1'], expected=['1'])
@@ -1629,7 +1648,7 @@ void *getBindBuffer() {
# 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')
+ self.run_generated_code(SPIDERMONKEY_ENGINE, 'a.out.js', assert_returncode=None)
print 'passed asm test'
shutil.copyfile(path_from_root('tests', 'water.dds'), 'water.dds')
@@ -1685,10 +1704,95 @@ void *getBindBuffer() {
};
''')
open(os.path.join(self.get_dir(), 'post.js'), 'w').write('''
+ var assert = function(check, text) {
+ if (!check) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'http://localhost:8888/report_result?9');
+ xhr.onload = function() {
+ window.close();
+ };
+ xhr.send();
+ }
+ }
Module._note(4); // this happens too early! and is overwritten when the mem init arrives
''')
- self.btest('mem_init.cpp', expected='3', args=['--pre-js', 'pre.js', '--post-js', 'post.js', '--memory-init-file', '1'])
+ # with assertions, we notice when memory was written to too early
+ self.btest('mem_init.cpp', expected='9', args=['--pre-js', 'pre.js', '--post-js', 'post.js', '--memory-init-file', '1'])
+ # otherwise, we just overwrite
+ self.btest('mem_init.cpp', expected='3', args=['--pre-js', 'pre.js', '--post-js', 'post.js', '--memory-init-file', '1', '-s', 'ASSERTIONS=0'])
+
+ def test_runtime_misuse(self):
+ post_prep = '''
+ var expected_ok = false;
+ function doCcall(n) {
+ ccall('note', 'string', ['number'], [n]);
+ }
+ var wrapped = cwrap('note', 'string', ['number']); // returns a string to suppress cwrap optimization
+ function doCwrapCall(n) {
+ var str = wrapped(n);
+ Module.print('got ' + str);
+ assert(str === 'silly-string');
+ }
+ function doDirectCall(n) {
+ Module['_note'](n);
+ }
+ '''
+ post_test = '''
+ var ok = false;
+ try {
+ doCcall(1);
+ ok = true; // should fail and not reach here, runtime is not ready yet so ccall will abort
+ } catch(e) {
+ Module.print('expected fail 1');
+ assert(e.toString().indexOf('assert') >= 0); // assertion, not something else
+ ABORT = false; // hackish
+ }
+ assert(ok === expected_ok);
+
+ ok = false;
+ try {
+ doCwrapCall(2);
+ ok = true; // should fail and not reach here, runtime is not ready yet so cwrap call will abort
+ } catch(e) {
+ Module.print('expected fail 2');
+ assert(e.toString().indexOf('assert') >= 0); // assertion, not something else
+ ABORT = false; // hackish
+ }
+ assert(ok === expected_ok);
+
+ ok = false;
+ try {
+ doDirectCall(3);
+ ok = true; // should fail and not reach here, runtime is not ready yet so any code execution
+ } catch(e) {
+ Module.print('expected fail 3');
+ assert(e.toString().indexOf('assert') >= 0); // assertion, not something else
+ ABORT = false; // hackish
+ }
+ assert(ok === expected_ok);
+ '''
+
+ post_hook = r'''
+ function myJSCallback() {
+ // called from main, this is an ok time
+ doCcall(100);
+ doCwrapCall(200);
+ doDirectCall(300);
+ }
+
+ setTimeout(Module['_free'], 1000); // free is valid to call even after the runtime closes
+ '''
+
+ print 'mem init, so async, call too early'
+ open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + post_test + post_hook)
+ self.btest('runtime_misuse.cpp', expected='600', args=['--post-js', 'post.js', '--memory-init-file', '1'])
+ print 'sync startup, call too late'
+ open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + 'Module.postRun.push(function() { ' + post_test + ' });' + post_hook);
+ self.btest('runtime_misuse.cpp', expected='600', args=['--post-js', 'post.js', '--memory-init-file', '0'])
+ print 'sync, runtime still alive, so all good'
+ open(os.path.join(self.get_dir(), 'post.js'), 'w').write(post_prep + 'expected_ok = true; Module.postRun.push(function() { ' + post_test + ' });' + post_hook);
+ self.btest('runtime_misuse.cpp', expected='606', args=['--post-js', 'post.js', '--memory-init-file', '0', '-s', 'NO_EXIT_RUNTIME=1'])
def test_worker_api(self):
Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate()
@@ -1752,15 +1856,15 @@ void *getBindBuffer() {
# 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()
+ Popen([PYTHON, EMCC, '-O2', '--closure', '1', path_from_root('tests', 'uuid', 'test.c'), '-o', 'test.js'], stdout=PIPE, stderr=PIPE).communicate()
- test_js_closure = open(path_from_root('tests', 'uuid', 'test.js')).read()
+ test_js_closure = open('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)
+ out = run_js('test.js', full_output=True)
print out
# Tidy up files that might have been created by this test.
diff --git a/tests/test_core.py b/tests/test_core.py
index a4a12236..ac3a2a5b 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -524,47 +524,25 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_cube2hash(self):
# extra testing for various codegen modes
- for x86 in [0, 1] if self.run_name == 'asm2' else [0]:
- print 'x86', x86
- try:
- old_x86 = os.environ.get('EMCC_LLVM_TARGET') or ''
- if x86:
- os.environ['EMCC_LLVM_TARGET'] = "i386-pc-linux-gnu"
- try:
- old_fastcomp = os.environ.get('EMCC_FAST_COMPILER') or ''
- if x86:
- os.environ['EMCC_FAST_COMPILER'] = "0"
- try:
- old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
-
- for chunk_size in ['1', old_chunk_size]: # test splitting out each function to a chunk in emscripten.py (21 functions here)
- print ' chunks', chunk_size
- os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = chunk_size
-
- # A good test of i64 math
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
- self.do_run('', 'Usage: hashstring <seed>',
- libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None, cache_name_extra=str(x86)),
- includes=[path_from_root('tests', 'cube2hash')])
-
- for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
- ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
- ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
- self.do_run('', 'hash value: ' + output, [text], no_build=True)
- finally:
- os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
- finally:
- if x86:
- if old_fastcomp:
- os.environ['EMCC_FAST_COMPILER'] = old_fastcomp
- else:
- del os.environ['EMCC_FAST_COMPILER']
- finally:
- if x86:
- if old_x86:
- os.environ['EMCC_LLVM_TARGET'] = old_x86
- else:
- del os.environ['EMCC_LLVM_TARGET']
+ try:
+ old_chunk_size = os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or ''
+
+ for chunk_size in ['1', old_chunk_size]: # test splitting out each function to a chunk in emscripten.py (21 functions here)
+ print ' chunks', chunk_size
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = chunk_size
+
+ # A good test of i64 math
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
+ self.do_run('', 'Usage: hashstring <seed>',
+ libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None),
+ includes=[path_from_root('tests', 'cube2hash')])
+
+ for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
+ ('fleefl2', 'AA2CC5F96FC9D540CA24FDAF1F71E2942753DB83E8A81B61'),
+ ('64bitisslow', '64D8470573635EC354FEE7B7F87C566FCAF1EFB491041670')]:
+ self.do_run('', 'hash value: ' + output, [text], no_build=True)
+ finally:
+ os.environ['EMSCRIPT_MAX_CHUNK_SIZE'] = old_chunk_size
def test_unaligned(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
@@ -797,6 +775,8 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_floatvars(self):
+ if self.run_name == 'slow2asm': return self.skip('FIXME in slow2asm')
+
test_path = path_from_root('tests', 'core', 'test_floatvars')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -863,6 +843,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
def test_math_lgamma(self):
if self.emcc_args is None: return self.skip('requires emcc')
if not self.is_emscripten_abi(): return self.skip('asmjs-unknown-emscripten needed for accurate math')
+ if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('fastcomp needed for proper handling of _signgam extern')
test_path = path_from_root('tests', 'math', 'lgamma')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -870,6 +851,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_frexp(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sprintf.')
test_path = path_from_root('tests', 'core', 'test_frexp')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -971,7 +953,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_strings(self):
- if Settings.USE_TYPED_ARRAYS != 2: return self.skip('musl libc needs ta2')
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_strings')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -1200,9 +1182,11 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
return 0;
}
'''
- for num in [Settings.MAX_SETJMPS, Settings.MAX_SETJMPS+1]:
- print num
- self.do_run(src.replace('NUM', str(num)), '0\n' * num if num <= Settings.MAX_SETJMPS or not Settings.ASM_JS else 'build with a higher value for MAX_SETJMPS')
+ for maxx in [Settings.MAX_SETJMPS/2, Settings.MAX_SETJMPS, 2*Settings.MAX_SETJMPS]:
+ Settings.MAX_SETJMPS = maxx
+ for num in [maxx, maxx+1]:
+ print maxx, num
+ self.do_run(src.replace('NUM', str(num)), '0\n' * num if num <= Settings.MAX_SETJMPS or not Settings.ASM_JS else 'build with a higher value for MAX_SETJMPS')
def test_setjmp_many_2(self):
if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('non-fastcomp do not hit the limit.')
@@ -1337,6 +1321,47 @@ too many setjmps in a function call, build with a higher value for MAX_SETJMPS''
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
+ def test_exceptions_3(self):
+ if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
+ if self.run_name == 'asm2x86': return self.skip('TODO')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+
+ src = r'''
+#include <iostream>
+#include <stdexcept>
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ std::cout << "need an arg" << std::endl;
+ return 1;
+ }
+
+ int arg = argv[1][0] - '0';
+ try {
+ if (arg == 0) throw "a c string";
+ if (arg == 1) throw std::exception();
+ if (arg == 2) throw std::runtime_error("Hello");
+ } catch(const char * ex) {
+ std::cout << "Caught C string: " << ex << std::endl;
+ } catch(const std::exception &ex) {
+ std::cout << "Caught exception: " << ex.what() << std::endl;
+ } catch(...) {
+ std::cout << "Caught something else" << std::endl;
+ }
+
+ std::cout << "Done.\n";
+}
+'''
+
+ print '0'
+ self.do_run(src, 'Caught C string: a c string\nDone.', ['0'])
+ print '1'
+ self.do_run(src, 'Caught exception: std::exception\nDone.', ['1'], no_build=True)
+ print '2'
+ self.do_run(src, 'Caught exception: Hello\nDone.', ['2'], no_build=True)
+
def test_exceptions_white_list(self):
Settings.DISABLE_EXCEPTION_CATCHING = 2
Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
@@ -1345,6 +1370,33 @@ too many setjmps in a function call, build with a higher value for MAX_SETJMPS''
test_path = path_from_root('tests', 'core', 'test_exceptions_white_list')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
+ size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'orig.js')
+
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
+ # check that an empty whitelist works properly (as in, same as exceptions disabled)
+ empty_output = path_from_root('tests', 'core', 'test_exceptions_white_list_empty.out')
+
+ Settings.EXCEPTION_CATCHING_WHITELIST = []
+ self.do_run_from_file(src, empty_output)
+ empty_size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'empty.js')
+
+ Settings.EXCEPTION_CATCHING_WHITELIST = ['fake']
+ self.do_run_from_file(src, empty_output)
+ fake_size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'fake.js')
+
+ Settings.DISABLE_EXCEPTION_CATCHING = 1
+ self.do_run_from_file(src, empty_output)
+ disabled_size = len(open('src.cpp.o.js').read())
+ shutil.copyfile('src.cpp.o.js', 'disabled.js')
+
+ assert size - empty_size > 2000, [empty_size, size] # big change when we disable entirely
+ assert size - fake_size > 2000, [fake_size, size]
+ assert empty_size == fake_size, [empty_size, fake_size]
+ assert empty_size - disabled_size < 100, [empty_size, disabled_size] # full disable removes a tiny bit more
+ assert fake_size - disabled_size < 100, [disabled_size, fake_size]
def test_exceptions_white_list_2(self):
Settings.DISABLE_EXCEPTION_CATCHING = 2
@@ -1425,30 +1477,12 @@ too many setjmps in a function call, build with a higher value for MAX_SETJMPS''
src, output = (test_path + s for s in ('.c', '.out'))
self.do_run_from_file(src, output)
- def test_async_exit(self):
- open('main.c', 'w').write(r'''
- #include <stdio.h>
- #include <stdlib.h>
- #include "emscripten.h"
-
- void main_loop() {
- exit(EXIT_SUCCESS);
- }
-
- int main() {
- emscripten_set_main_loop(main_loop, 60, 0);
- return 0;
- }
- ''')
-
- Popen([PYTHON, EMCC, 'main.c']).communicate()
- self.assertNotContained('Reached an unreachable!', run_js(self.in_dir('a.out.js'), stderr=STDOUT))
-
def test_exit_stack(self):
if self.emcc_args is None: return self.skip('requires emcc')
if Settings.ASM_JS: return self.skip('uses report_stack without exporting')
Settings.INLINING_LIMIT = 50
+ Settings.NO_EXIT_RUNTIME = 1
src = r'''
#include <stdio.h>
@@ -1490,7 +1524,7 @@ too many setjmps in a function call, build with a higher value for MAX_SETJMPS''
''')
self.emcc_args += ['--pre-js', 'pre.js']
- self.do_run(src, '''reported\nExit Status: 1\npostRun\nok.\n''')
+ self.do_run(src, '''reported\n*0*\nExit Status: 0\npostRun\nok.\n''')
def test_class(self):
test_path = path_from_root('tests', 'core', 'test_class')
@@ -1951,6 +1985,15 @@ too many setjmps in a function call, build with a higher value for MAX_SETJMPS''
self.do_run_from_file(src, output)
+ def test_set_align(self):
+ if self.run_name == 'slow2asm': return self.skip('FIXME in slow2asm')
+
+ Settings.SAFE_HEAP = 1
+
+ test_path = path_from_root('tests', 'core', 'test_set_align')
+ src, output = (test_path + s for s in ('.c', '.out'))
+ self.do_run_from_file(src, output)
+
def test_emscripten_api(self):
#if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME')
@@ -2066,10 +2109,10 @@ def process(filename):
if self.emcc_args and '-O2' in self.emcc_args:
# Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized)
- code_start = 'var TOTAL_MEMORY = '
+ code_start = 'var TOTAL_MEMORY'
fail = fail[fail.find(code_start):]
win = win[win.find(code_start):]
- assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller'
+ assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller' + str([len(fail), len(win)])
def test_ssr(self): # struct self-ref
src = '''
@@ -2186,6 +2229,7 @@ def process(filename):
self.do_run(src, '*4,3,4*\n*6,4,6*')
def test_varargs(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sprintf.')
if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
if not self.is_emscripten_abi(): return self.skip('we do not support all varargs stuff without asmjs-unknown-emscripten')
@@ -2813,11 +2857,8 @@ The current type of b is: 9
self.skip('todo in fastcomp')
return False
- if self.emcc_args and '--memory-init-file' in self.emcc_args:
- for i in range(len(self.emcc_args)):
- if self.emcc_args[i] == '--memory-init-file':
- self.emcc_args = self.emcc_args[:i] + self.emcc_args[i+2:]
- break
+ if self.emcc_args:
+ self.emcc_args += ['--memory-init-file', '0']
if Settings.ASM_JS:
Settings.DLOPEN_SUPPORT = 1
@@ -3242,7 +3283,7 @@ def process(filename):
break
else:
raise Exception('Could not find symbol table!')
- table = table[table.find('{'):table.rfind('}')+1]
+ table = table[table.find('{'):table.find('}')+1]
# ensure there aren't too many globals; we don't want unnamed_addr
assert table.count(',') <= 4
@@ -3296,6 +3337,7 @@ def process(filename):
self.do_run(src, 'success', force_c=True, post_build=self.dlfcn_post_build)
def test_dlfcn_stacks(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('snprintf needs ta2 to be able to bitcast int<->float')
if not self.can_dlfcn(): return
self.prep_dlfcn_lib()
@@ -3786,6 +3828,7 @@ int main()
self.do_run_from_file(src, output)
def test_printf_more(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sprintf.')
test_path = path_from_root('tests', 'core', 'test_printf_more')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -3884,18 +3927,21 @@ Pass: 0.000012 0.000012
Pass: 0.000012 0.000012''')
def test_sscanf_n(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_n')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
def test_sscanf_whitespace(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_whitespace')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
def test_sscanf_other_whitespace(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
Settings.SAFE_HEAP = 0 # use i16s in printf
test_path = path_from_root('tests', 'core', 'test_sscanf_other_whitespace')
@@ -3904,6 +3950,7 @@ Pass: 0.000012 0.000012''')
self.do_run_from_file(src, output)
def test_sscanf_3(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
# i64
if not Settings.USE_TYPED_ARRAYS == 2: return self.skip('64-bit sscanf only supported in ta2')
@@ -3913,23 +3960,27 @@ Pass: 0.000012 0.000012''')
self.do_run_from_file(src, output)
def test_sscanf_4(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_4')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
def test_sscanf_5(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_5')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
def test_sscanf_6(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_6')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
def test_sscanf_skip(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
if Settings.USE_TYPED_ARRAYS != 2: return self.skip("need ta2 for full i64")
test_path = path_from_root('tests', 'core', 'test_sscanf_skip')
@@ -3938,12 +3989,14 @@ Pass: 0.000012 0.000012''')
self.do_run_from_file(src, output)
def test_sscanf_caps(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_caps')
src, output = (test_path + s for s in ('.in', '.out'))
self.do_run_from_file(src, output)
def test_sscanf_hex(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
test_path = path_from_root('tests', 'core', 'test_sscanf_hex')
@@ -3952,6 +4005,7 @@ Pass: 0.000012 0.000012''')
self.do_run_from_file(src, output)
def test_sscanf_float(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
test_path = path_from_root('tests', 'core', 'test_sscanf_float')
src, output = (test_path + s for s in ('.in', '.out'))
@@ -3963,6 +4017,7 @@ Pass: 0.000012 0.000012''')
self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h'])
def test_files(self):
+ if self.run_name.startswith('s_'): return self.skip('This test requires linking to musl lib for sscanf.')
self.banned_js_engines = [SPIDERMONKEY_ENGINE] # closure can generate variables called 'gc', which pick up js shell stuff
if self.emcc_args is not None and '-O2' in self.emcc_args:
self.emcc_args += ['--closure', '1'] # Use closure here, to test we don't break FS stuff
@@ -3996,11 +4051,14 @@ def process(filename):
src = open(path_from_root('tests', 'files.cpp'), 'r').read()
mem_file = 'src.cpp.o.js.mem'
- try_delete(mem_file)
- self.do_run(src, ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\n'),
- post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
- if self.emcc_args and '--memory-init-file' in self.emcc_args:
- assert os.path.exists(mem_file)
+ orig_args = self.emcc_args
+ for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]:
+ self.emcc_args = orig_args + mode
+ try_delete(mem_file)
+ self.do_run(src, ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\n'),
+ post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+ if self.emcc_args and '-O2' in self.emcc_args:
+ assert os.path.exists(mem_file)
def test_files_m(self):
# Test for Module.stdin etc.
@@ -4043,7 +4101,10 @@ def process(filename):
test_path = path_from_root('tests', 'core', 'test_fwrite_0')
src, output = (test_path + s for s in ('.in', '.out'))
- self.do_run_from_file(src, output)
+ orig_args = self.emcc_args if self.emcc_args else []
+ for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]:
+ self.emcc_args = orig_args + mode
+ self.do_run_from_file(src, output)
def test_fgetc_ungetc(self):
src = open(path_from_root('tests', 'stdio', 'test_fgetc_ungetc.c'), 'r').read()
@@ -4241,7 +4302,10 @@ def process(filename):
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)
+ orig_args = self.emcc_args
+ for mode in [[], ['-s', 'MEMFS_APPEND_TO_TYPED_ARRAYS=1']]:
+ self.emcc_args = orig_args + mode
+ 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')
@@ -4305,6 +4369,17 @@ def process(filename):
out = path_from_root('tests', 'fs', 'test_writeFile.out')
self.do_run_from_file(src, out)
+ def test_fs_emptyPath(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = path_from_root('tests', 'fs', 'test_emptyPath.c')
+ out = path_from_root('tests', 'fs', 'test_emptyPath.out')
+ self.do_run_from_file(src, out)
+
+ def test_fs_append(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ src = open(path_from_root('tests', 'fs', 'test_append.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
def test_unistd_access(self):
self.clear()
if not self.is_emscripten_abi(): return self.skip('asmjs-unknown-emscripten needed for inline js')
@@ -4521,6 +4596,15 @@ PORT: 3979
self.do_run_from_file(src, output)
+ def test_random_device(self):
+ if self.emcc_args is None: return self.skip('requires emcc')
+ Building.COMPILER_TEST_OPTS += ['-std=c++11']
+
+ test_path = path_from_root('tests', 'core', 'test_random_device')
+ src, output = (test_path + s for s in ('.cpp', '.txt'))
+
+ self.do_run_from_file(src, output)
+
def test_reinterpreted_ptrs(self):
if self.emcc_args is None: return self.skip('needs emcc and libc')
@@ -4609,6 +4693,39 @@ PORT: 3979
'''
self.do_run(src, 'value\narray_item1\narray_item2\narray_item3\n3\n3.00\n2.20\nJansson: Node with ID `0` not found. Context has `10` nodes.\n0\nJansson: No JSON context.\njansson!')
+ def test_js_libraries(self):
+ if self.emcc_args == None: return self.skip('needs emcc')
+
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ extern "C" {
+ extern void printey();
+ extern int calcey(int x, int y);
+ }
+ int main() {
+ printey();
+ printf("*%d*\\n", calcey(10, 22));
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'mylib1.js'), 'w').write('''
+ mergeInto(LibraryManager.library, {
+ printey: function() {
+ Module.print('hello from lib!');
+ }
+ });
+ ''')
+ open(os.path.join(self.get_dir(), 'mylib2.js'), 'w').write('''
+ mergeInto(LibraryManager.library, {
+ calcey: function(x, y) {
+ return x + y;
+ }
+ });
+ ''')
+
+ self.emcc_args += ['--js-library', os.path.join(self.get_dir(), 'mylib1.js'), '--js-library', os.path.join(self.get_dir(), 'mylib2.js')]
+ self.do_run(open(os.path.join(self.get_dir(), 'main.cpp'), 'r').read(), 'hello from lib!\n*32*\n')
+
def test_constglobalunion(self):
if self.emcc_args is None: return self.skip('needs emcc')
self.emcc_args += ['-s', 'EXPORT_ALL=1']
@@ -4858,6 +4975,15 @@ return malloc(size);
self.do_run_from_file(src, output)
+ def test_simd4(self):
+ # test_simd4 is to test phi node handling of SIMD path
+ if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate
+
+ test_path = path_from_root('tests', 'core', 'test_simd4')
+ src, output = (test_path + s for s in ('.in', '.out'))
+
+ self.do_run_from_file(src, output)
+
def test_gcc_unmangler(self):
if os.environ.get('EMCC_FAST_COMPILER') == '0': Settings.NAMED_GLOBALS = 1 # test coverage for this; fastcomp never names globals
@@ -5052,6 +5178,7 @@ def process(filename):
Settings.CORRECT_OVERFLOWS = 1
Settings.CORRECT_SIGNS = 1
+ Settings.NO_EXIT_RUNTIME = 1
Building.COMPILER_TEST_OPTS += [
'-I' + path_from_root('tests', 'freetype', 'include'),
@@ -5074,7 +5201,7 @@ def process(filename):
\'\'\'
FS.createDataFile('/', 'paper.pdf', eval(Module.read('paper.pdf.js')), true, false);
Module.callMain(Module.arguments);
- Module.print("Data: " + JSON.stringify(FS.root.contents['filename-1.ppm'].contents.map(function(x) { return unSign(x, 8) })));
+ Module.print("Data: " + JSON.stringify(MEMFS.getFileDataAsRegularArray(FS.root.contents['filename-1.ppm']).map(function(x) { return unSign(x, 8) })));
\'\'\'
)
src.close()
@@ -5124,7 +5251,7 @@ def process(filename):
))
).replace(
'// {{POST_RUN_ADDITIONS}}',
- "Module.print('Data: ' + JSON.stringify(FS.analyzePath('image.raw').object.contents));"
+ "Module.print('Data: ' + JSON.stringify(MEMFS.getFileDataAsRegularArray(FS.analyzePath('image.raw').object)));"
)
open(filename, 'w').write(src)
'''
@@ -5178,6 +5305,8 @@ def process(filename):
self.emcc_args += ['--minify', '0'] # to compare the versions
+ Settings.NO_EXIT_RUNTIME = 1
+
def do_test():
self.do_run(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(),
'Successfully generated', # The real test for valid output is in image_compare
@@ -5262,8 +5391,10 @@ def process(filename):
emcc_args = self.emcc_args
+ # The following tests link to libc, and must be run with EMCC_LEAVE_INPUTS_RAW = 0
+ need_no_leave_inputs_raw = ['muli33_ta2', 'philoop_ta2']
+
try:
- os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
Settings.CHECK_OVERFLOWS = 0
for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
@@ -5277,6 +5408,15 @@ def process(filename):
'atomicrmw_unaligned', # TODO XXX
'emptyasm_aue' # we don't support inline asm
]: continue
+
+ if os.path.basename(shortname) in need_no_leave_inputs_raw:
+ if self.run_name.startswith('s_'):
+ print self.skip('case "%s" cannot be run in mode %s, since it would require EMCC_LEAVE_INPUTS_RAW=1' % (shortname, self.run_name))
+ continue
+ if 'EMCC_LEAVE_INPUTS_RAW' in os.environ: del os.environ['EMCC_LEAVE_INPUTS_RAW']
+ else:
+ os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
+
if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2:
print self.skip('case "%s" only relevant for ta2' % shortname)
continue
@@ -5312,7 +5452,7 @@ def process(filename):
exec(open(src_checker).read())
finally:
- del os.environ['EMCC_LEAVE_INPUTS_RAW']
+ if 'EMCC_LEAVE_INPUTS_RAW' in os.environ: del os.environ['EMCC_LEAVE_INPUTS_RAW']
self.emcc_args = emcc_args
def test_fuzz(self):
@@ -5451,9 +5591,6 @@ def process(filename):
### Integration tests
def test_ccall(self):
- if self.emcc_args is not None and '-O2' in self.emcc_args:
- self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
-
post = '''
def process(filename):
src = \'\'\'
@@ -5475,6 +5612,8 @@ def process(filename):
ret = ccall('pointer', 'pointer', ['pointer'], [p]); Module.print([typeof ret, getValue(ret, 'i32')]);
Module.print('*');
// part 2: cwrap
+ var noThirdParam = Module['cwrap']('get_int', 'number');
+ Module.print(noThirdParam());
var multi = Module['cwrap']('multi', 'number', ['number', 'number', 'number', 'string']);
Module.print(multi(2, 1.4, 3, 'atr'));
Module.print(multi(8, 5.4, 4, 'bret'));
@@ -5497,6 +5636,11 @@ def process(filename):
self.do_run_from_file(src, output, post_build=post)
+ if self.emcc_args is not None and '-O2' in self.emcc_args:
+ print 'with closure'
+ self.emcc_args += ['--closure', '1']
+ self.do_run_from_file(src, output, post_build=post)
+
def test_pgo(self):
if Settings.ASM_JS: return self.skip('PGO does not work in asm mode')
@@ -5650,12 +5794,15 @@ def process(filename):
src = r'''
#include <stdio.h>
#include <stdlib.h>
+ #include <emscripten.h>
int main(int argc, char **argv) {
int fp = atoi(argv[1]);
printf("fp: %d\n", fp);
void (*f)(int) = reinterpret_cast<void (*)(int)>(fp);
f(7);
+ EM_ASM_(Module.Runtime.removeFunction($0), f);
+ printf("ok\n");
return 0;
}
'''
@@ -5667,8 +5814,9 @@ def process(filename):
Module.callMain([newFuncPtr.toString()]);
''')
+ expected = '''Hello 7 from JS!\nok\n'''
self.emcc_args += ['--post-js', 'post.js']
- self.do_run(src, '''Hello 7 from JS!''')
+ self.do_run(src, expected)
if Settings.ASM_JS:
Settings.RESERVED_FUNCTION_POINTERS = 0
@@ -5678,7 +5826,14 @@ def process(filename):
Settings.RESERVED_FUNCTION_POINTERS = 1
Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS # flip the test
- self.do_run(src, '''Hello 7 from JS!''')
+ self.do_run(src, expected)
+
+ assert 'asm2' in test_modes
+ if self.run_name == 'asm2':
+ print 'closure'
+ self.banned_js_engines = [NODE_JS] # weird global handling in node
+ self.emcc_args += ['--closure', '1']
+ self.do_run(src, expected)
def test_demangle_stacks(self):
if Settings.ASM_JS: return self.skip('spidermonkey has stack trace issues')
@@ -6047,6 +6202,8 @@ def process(filename):
if self.emcc_args is not None and self.emcc_args != []: return self.skip('full LLVM opts optimize out all the code that uses the type')
Settings.RUNTIME_TYPE_INFO = 1
+ Settings.NO_EXIT_RUNTIME = 1
+ Settings.ASSERTIONS = 0
if Settings.QUANTUM_SIZE != 4: return self.skip('We assume normal sizes in the output here')
src = '''
@@ -6088,8 +6245,8 @@ def process(filename):
'''
self.do_run(src,
- '*ok:5*\n|i32,i8,i16|0,4,6|\n|0,4,8,10,12|\n|{"__size__":8,"x":0,"y":4,"z":6}|',
- post_build=post)
+ '*ok:5*\n|i32,i8,i16|0,4,6|\n|0,4,8,10,12|\n|{"__size__":8,"x":0,"y":4,"z":6}|',
+ post_build=post)
# Make sure that without the setting, we don't spam the .js with the type info
Settings.RUNTIME_TYPE_INFO = 0
@@ -6115,7 +6272,7 @@ def process(filename):
'''
try:
- self.do_run(src, '*nothingatall*')
+ self.do_run(src, '*nothingatall*', assert_returncode=None)
except Exception, e:
# This test *should* fail, by throwing this exception
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
@@ -6132,7 +6289,7 @@ def process(filename):
Settings.SAFE_HEAP_LINES = ["src.cpp:99"]
try:
- self.do_run(src, '*nothingatall*')
+ self.do_run(src, '*nothingatall*', assert_returncode=None)
except Exception, e:
# This test *should* fail, by throwing this exception
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
@@ -6182,7 +6339,7 @@ def process(filename):
Building.link([module_name + '.o', main_name + '.o'], all_name)
try:
- self.do_ll_run(all_name, '*nothingatall*')
+ self.do_ll_run(all_name, '*nothingatall*', assert_returncode=None)
except Exception, e:
# This test *should* fail, by throwing this exception
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
@@ -6199,7 +6356,7 @@ def process(filename):
for lines in [["module.cpp:22", "main.cpp:9"], ["module.cpp:7", "main.cpp:29"], ["module.cpp:127", "main.cpp:449"], ["module.cpp:7"], ["main.cpp:9"]]:
Settings.SAFE_HEAP_LINES = lines
try:
- self.do_ll_run(all_name, '*nothingatall*')
+ self.do_ll_run(all_name, '*nothingatall*', assert_returncode=None)
except Exception, e:
# This test *should* fail, by throwing this exception
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
@@ -6224,7 +6381,7 @@ def process(filename):
}
'''
try:
- self.do_run(src, '*nothingatall*')
+ self.do_run(src, '*nothingatall*', assert_returncode=None)
except Exception, e:
# This test *should* fail
assert 'Assertion failed: x < 15' in str(e), str(e)
@@ -6330,10 +6487,15 @@ def process(filename):
if (i < 10) throw i; // line 5
}
+ #include <iostream>
+ #include <string>
+
int main() {
+ std::string x = "ok"; // add libc++ stuff to make this big, test for #2410
int i;
scanf("%d", &i);
foo(i);
+ std::cout << x << std::endl;
return 0;
}
'''
@@ -6681,7 +6843,7 @@ asm1 = make_run("asm1", compiler=CLANG, emcc_args=["-O1"])
asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2"])
asm3 = make_run("asm3", compiler=CLANG, emcc_args=["-O3"])
asm2f = make_run("asm2f", compiler=CLANG, emcc_args=["-O2", "-s", "PRECISE_F32=1"])
-asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "--memory-init-file", "1", "-s", "SAFE_HEAP=1"])
+asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "-s", "SAFE_HEAP=1"])
# Legacy test modes -
slow2 = make_run("slow2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=0"], env={"EMCC_FAST_COMPILER": "0"})
diff --git a/tests/test_other.py b/tests/test_other.py
index 12dd7872..ab3bcc66 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -203,6 +203,11 @@ Options that are modified or new in %s include:
(['--typed-arrays', '1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
(['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'),
(['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'),
+ ([], lambda generated: '// The Module object' in generated, 'without opts, comments in shell code'),
+ (['-O2'], lambda generated: '// The Module object' not in generated, 'with opts, no comments in shell code'),
+ (['-O2', '-g2'], lambda generated: '// The Module object' not in generated, 'with -g2, no comments in shell code'),
+ (['-O2', '-g3'], lambda generated: '// The Module object' in generated, 'with -g3, yes comments in shell code'),
+ (['-O2', '-profiling'], lambda generated: '// The Module object' in generated or os.environ.get('EMCC_FAST_COMPILER') == '0', 'with -profiling, yes comments in shell code (in fastcomp)'),
]:
print params, text
self.clear()
@@ -239,7 +244,7 @@ Options that are modified or new in %s include:
output = Popen([PYTHON, compiler, 'twopart_main.o', '-O1', '-g'] + args, stdout=PIPE, stderr=PIPE).communicate()
assert os.path.exists(target), '\n'.join(output)
#print '\n'.join(output)
- self.assertContained('missing function', run_js(target, stderr=STDOUT))
+ self.assertContained('missing function', run_js(target, stderr=STDOUT, assert_returncode=None))
try_delete(target)
# Combining those bc files into js should work
@@ -272,6 +277,12 @@ f.close()
output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world' + suffix), '--js-transform', '%s t.py' % (PYTHON)], stdout=PIPE, stderr=PIPE).communicate()
assert open('a.out.js').read() == 'transformed!', 'Transformed output must be as expected'
+ for opts in [0, 1, 2, 3]:
+ print 'mem init in', opts
+ self.clear()
+ output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world.c'), '-O' + str(opts)], stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists('a.out.js.mem') == (opts >= 2), 'mem file should exist in -O2+'
+
# TODO: Add in files test a clear example of using disablePermissions, and link to it from the wiki
# TODO: test normal project linking, static and dynamic: get_library should not need to be told what to link!
# TODO: deprecate llvm optimizations, dlmalloc, etc. in emscripten.py.
@@ -349,9 +360,10 @@ f.close()
except KeyError:
postbuild = None
- cmake_cases = ['target_js', 'target_html']
- cmake_outputs = ['test_cmake.js', 'hello_world_gles.html']
- for i in range(0, 2):
+ cmake_cases = ['target_js', 'target_html', 'target_library', 'target_library']
+ cmake_outputs = ['test_cmake.js', 'hello_world_gles.html', 'libtest_cmake.a', 'libtest_cmake.so']
+ cmake_arguments = ['', '', '-DBUILD_SHARED_LIBS=OFF', '-DBUILD_SHARED_LIBS=ON']
+ for i in range(0, len(cmake_cases)):
for configuration in ['Debug', 'Release']:
# CMake can be invoked in two ways, using 'emconfigure cmake', or by directly running 'cmake'.
# Test both methods.
@@ -368,12 +380,12 @@ f.close()
# Run Cmake
if invoke_method == 'cmake':
# Test invoking cmake directly.
- cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Platform', 'Emscripten.cmake'),
- '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir]
+ cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'),
+ '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir]
else:
# Test invoking via 'emconfigure cmake'
- cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, '-G', generator, cmakelistsdir]
-
+ cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir]
+
ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE, stderr=None if verbose_level >= 1 else PIPE).communicate()
if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
@@ -386,7 +398,9 @@ f.close()
prebuild(configuration, tempdirname)
# Build
- cmd = make + (['VERBOSE=1'] if verbose_level >= 3 else [])
+ cmd = make
+ if verbose_level >= 3 and 'Ninja' not in generator:
+ cmd += ['VERBOSE=1']
ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE).communicate()
if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
@@ -542,7 +556,7 @@ f.close()
print args, expected, err_expected
out, err = Popen([PYTHON, EMCC, 'src.c'] + args, stderr=PIPE).communicate()
if err_expected: self.assertContained(err_expected, err)
- self.assertContained(expected, run_js(self.in_dir('a.out.js'), stderr=PIPE, full_output=True))
+ self.assertContained(expected, run_js(self.in_dir('a.out.js'), stderr=PIPE, full_output=True, assert_returncode=None))
return open(self.in_dir('a.out.js')).read()
if os.environ.get('EMCC_FAST_COMPILER') == '0':
@@ -909,7 +923,9 @@ This pointer might make sense in another type signature: i: 0
Popen([PYTHON, EMCC, src] + libs + ['-o', 'test.js', '-O2'] + debug + ['-s', 'OUTLINING_LIMIT=%d' % outlining_limit] + args).communicate()
assert os.path.exists('test.js')
shutil.copyfile('test.js', '%d_test.js' % outlining_limit)
+ assert len(JS_ENGINES) > 1
for engine in JS_ENGINES:
+ if engine == V8_ENGINE: continue # ban v8, weird failures
out = run_js('test.js', engine=engine, stderr=PIPE, full_output=True)
self.assertContained(expected, out)
if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
@@ -1299,38 +1315,6 @@ This pointer might make sense in another type signature: i: 0
self.assertContained('TestA\nTestB\nTestA\n', run_js('main.js', engine=SPIDERMONKEY_ENGINE))
- def test_js_libraries(self):
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
- #include <stdio.h>
- extern "C" {
- extern void printey();
- extern int calcey(int x, int y);
- }
- int main() {
- printey();
- printf("*%d*\\n", calcey(10, 22));
- return 0;
- }
- ''')
- open(os.path.join(self.get_dir(), 'mylib1.js'), 'w').write('''
- mergeInto(LibraryManager.library, {
- printey: function() {
- Module.print('hello from lib!');
- }
- });
- ''')
- open(os.path.join(self.get_dir(), 'mylib2.js'), 'w').write('''
- mergeInto(LibraryManager.library, {
- calcey: function(x, y) {
- return x + y;
- }
- });
- ''')
-
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--js-library', os.path.join(self.get_dir(), 'mylib1.js'),
- '--js-library', os.path.join(self.get_dir(), 'mylib2.js')]).communicate()
- self.assertContained('hello from lib!\n*32*\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
-
def test_identical_basenames(self):
# Issue 287: files in different dirs but with the same basename get confused as the same,
# causing multiply defined symbol errors
@@ -1614,7 +1598,7 @@ This pointer might make sense in another type signature: i: 0
Module.print(MESSAGE);
''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'before.js', '--post-js', 'after.js']).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'before.js', '--post-js', 'after.js', '-s', 'NO_EXIT_RUNTIME=1']).communicate()
self.assertContained('hello from main\nhello from js\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
def test_sdl_endianness(self):
@@ -1758,7 +1742,7 @@ This pointer might make sense in another type signature: i: 0
};
''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js']).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '-s', 'NO_EXIT_RUNTIME=1']).communicate()
self.assertContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
# never run, so no preRun or postRun
@@ -1769,7 +1753,7 @@ This pointer might make sense in another type signature: i: 0
# noInitialRun prevents run
for no_initial_run, run_dep in [(0, 0), (1, 0), (0, 1)]:
print no_initial_run, run_dep
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')]).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'NO_EXIT_RUNTIME=1']).communicate()
src = 'var Module = { noInitialRun: %d };\n' % no_initial_run + open(os.path.join(self.get_dir(), 'a.out.js')).read()
if run_dep:
src = src.replace('// {{PRE_RUN_ADDITIONS}}', '// {{PRE_RUN_ADDITIONS}}\naddRunDependency("test");') \
@@ -1792,7 +1776,7 @@ This pointer might make sense in another type signature: i: 0
preInit: function() { Module.print('pre-init') }
};
''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js']).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '-s', 'NO_EXIT_RUNTIME=1']).communicate()
self.assertContained('pre-init\npre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
def test_prepost2(self):
@@ -1811,7 +1795,7 @@ This pointer might make sense in another type signature: i: 0
open(os.path.join(self.get_dir(), 'pre2.js'), 'w').write('''
Module.postRun = function() { Module.print('post-run') };
''')
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js']).communicate()
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '--pre-js', 'pre2.js', '-s', 'NO_EXIT_RUNTIME=1']).communicate()
self.assertContained('pre-run\nhello from main\npost-run\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
def test_prepre(self):
@@ -1862,6 +1846,12 @@ This pointer might make sense in another type signature: i: 0
for input, expected, passes in [
(path_from_root('tools', 'test-js-optimizer.js'), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(),
['hoistMultiples', 'removeAssignsToUndefined', 'simplifyExpressions']),
+ (path_from_root('tools', 'test-js-optimizer-t2c.js'), open(path_from_root('tools', 'test-js-optimizer-t2c-output.js')).read(),
+ ['simplifyExpressions', 'optimizeShiftsConservative']),
+ (path_from_root('tools', 'test-js-optimizer-t2.js'), open(path_from_root('tools', 'test-js-optimizer-t2-output.js')).read(),
+ ['simplifyExpressions', 'optimizeShiftsAggressive']),
+ (path_from_root('tools', 'test-js-optimizer-t3.js'), open(path_from_root('tools', 'test-js-optimizer-t3-output.js')).read(),
+ ['optimizeShiftsAggressive']),
(path_from_root('tools', 'test-js-optimizer-si.js'), open(path_from_root('tools', 'test-js-optimizer-si-output.js')).read(),
['simplifyIfs']),
(path_from_root('tools', 'test-js-optimizer-regs.js'), open(path_from_root('tools', 'test-js-optimizer-regs-output.js')).read(),
@@ -1958,7 +1948,7 @@ This pointer might make sense in another type signature: i: 0
shutil.copytree(path_from_root('tools', 'scons', 'site_scons'), os.path.join(self.get_dir(), 'test', 'site_scons'))
os.chdir(os.path.join(self.get_dir(), 'test'))
Popen(['scons']).communicate()
- output = run_js('scons_integration.js')
+ output = run_js('scons_integration.js', assert_returncode=5)
assert 'If you see this - the world is all right!' in output
def test_embind(self):
@@ -2207,23 +2197,23 @@ void wakaw::Cm::RasterBase<wakaw::watwat::Polocator?>(unsigned int*, unsigned in
# Run with ./runner.py other.test_module_exports_with_closure
# First make sure test.js isn't present.
- try_delete(path_from_root('tests', 'Module-exports', 'test.js'))
- assert not os.path.exists(path_from_root('tests', 'Module-exports', 'test.js'))
+ self.clear()
# compile with -O2 --closure 0
- Popen([PYTHON, EMCC, path_from_root('tests', 'Module-exports', 'test.c'), '-o', path_from_root('tests', 'Module-exports', 'test.js'), '-O2', '--closure', '0', '--pre-js', path_from_root('tests', 'Module-exports', 'setup.js'), '-s', 'EXPORTED_FUNCTIONS=["_bufferTest"]'], stdout=PIPE, stderr=PIPE).communicate()
+ Popen([PYTHON, EMCC, path_from_root('tests', 'Module-exports', 'test.c'), '-o', 'test.js', '-O2', '--closure', '0', '--pre-js', path_from_root('tests', 'Module-exports', 'setup.js'), '-s', 'EXPORTED_FUNCTIONS=["_bufferTest"]'], stdout=PIPE, stderr=PIPE).communicate()
# Check that compilation was successful
- assert os.path.exists(path_from_root('tests', 'Module-exports', 'test.js'))
- test_js_closure_0 = open(path_from_root('tests', 'Module-exports', 'test.js')).read()
+ assert os.path.exists('test.js')
+ test_js_closure_0 = open('test.js').read()
# Check that test.js compiled with --closure 0 contains "module['exports'] = Module;"
- assert "module['exports'] = Module;" in test_js_closure_0
+ assert ("module['exports'] = Module;" in test_js_closure_0) or ('module["exports"]=Module' in test_js_closure_0)
# Check that main.js (which requires test.js) completes successfully when run in node.js
# in order to check that the exports are indeed functioning correctly.
+ shutil.copyfile(path_from_root('tests', 'Module-exports', 'main.js'), 'main.js')
if NODE_JS in JS_ENGINES:
- self.assertContained('bufferTest finished', run_js(path_from_root('tests', 'Module-exports', 'main.js'), engine=NODE_JS))
+ self.assertContained('bufferTest finished', run_js('main.js', engine=NODE_JS))
# Delete test.js again and check it's gone.
try_delete(path_from_root('tests', 'Module-exports', 'test.js'))
@@ -2243,7 +2233,7 @@ void wakaw::Cm::RasterBase<wakaw::watwat::Polocator?>(unsigned int*, unsigned in
# Check that main.js (which requires test.js) completes successfully when run in node.js
# in order to check that the exports are indeed functioning correctly.
if NODE_JS in JS_ENGINES:
- self.assertContained('bufferTest finished', run_js(path_from_root('tests', 'Module-exports', 'main.js'), engine=NODE_JS))
+ self.assertContained('bufferTest finished', run_js('main.js', engine=NODE_JS))
# Tidy up files that might have been created by this test.
try_delete(path_from_root('tests', 'Module-exports', 'test.js'))
@@ -2431,7 +2421,7 @@ var Module = { print: function(x) { throw '<{(' + x + ')}>' } };
''')
Popen([PYTHON, EMCC, 'code.cpp', '--pre-js', 'pre.js']).communicate()
- output = run_js(os.path.join(self.get_dir(), 'a.out.js'), stderr=PIPE, full_output=True, engine=NODE_JS)
+ output = run_js(os.path.join(self.get_dir(), 'a.out.js'), stderr=PIPE, full_output=True, engine=NODE_JS, assert_returncode=None)
assert r'<{(123456789)}>' in output, output
def test_precompiled_headers(self):
@@ -2818,7 +2808,7 @@ int main() {
cmd = [PYTHON, EMCC, 'src.cpp', '-O' + str(opts), '-s', 'SAFE_HEAP=' + str(safe)]
print cmd
Popen(cmd).communicate()
- output = run_js('a.out.js', stderr=PIPE, full_output=True)
+ output = run_js('a.out.js', stderr=PIPE, full_output=True, assert_returncode=None)
if safe:
assert 'Function table mask error' in output, output
else:
@@ -2885,3 +2875,143 @@ int main(int argc, char **argv) {
else:
self.assertContained('hello, world!', run_js('a.out.js'))
+ def test_no_dynamic_execution(self):
+ cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O1', '-s', 'NO_DYNAMIC_EXECUTION=1']
+ stdout, stderr = Popen(cmd, stderr=PIPE).communicate()
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ src = open('a.out.js').read()
+ assert 'eval(' not in src
+ assert 'eval.' not in src
+ assert 'new Function' not in src
+
+ def test_init_file_at_offset(self):
+ open('src.cpp', 'w').write(r'''
+ #include <stdio.h>
+ int main() {
+ int data = 0x12345678;
+ FILE *f = fopen("test.dat", "wb");
+ fseek(f, 100, SEEK_CUR);
+ fwrite(&data, 4, 1, f);
+ fclose(f);
+
+ int data2;
+ f = fopen("test.dat", "rb");
+ fread(&data2, 4, 1, f); // should read 0s, not that int we wrote at an offset
+ printf("read: %d\n", data2);
+ fseek(f, 0, SEEK_END);
+ int size = ftell(f); // should be 104, not 4
+ fclose(f);
+ printf("file size is %d\n", size);
+ }
+ ''')
+ Popen([PYTHON, EMCC, 'src.cpp']).communicate()
+ self.assertContained('read: 0\nfile size is 104\n', run_js('a.out.js'))
+
+ def test_argv0_node(self):
+ open('code.cpp', 'w').write(r'''
+#include <stdio.h>
+int main(int argc, char **argv) {
+ printf("I am %s.\n", argv[0]);
+ return 0;
+}
+''')
+
+ Popen([PYTHON, EMCC, 'code.cpp']).communicate()
+ self.assertContained('I am ' + self.get_dir().replace('\\', '/') + '/a.out.js', run_js('a.out.js', engine=NODE_JS).replace('\\', '/'))
+
+ def test_returncode(self):
+ open('src.cpp', 'w').write(r'''
+ #include <stdio.h>
+ int main() {
+ return 123;
+ }
+ ''')
+ Popen([PYTHON, EMCC, 'src.cpp']).communicate()
+ for engine in JS_ENGINES:
+ engine = listify(engine)
+ print engine
+ process = Popen(engine + ['a.out.js'], stdout=PIPE, stderr=PIPE)
+ output = process.communicate()
+ assert process.returncode == 123, process.returncode
+
+ def test_mkdir_silly(self):
+ open('src.cpp', 'w').write(r'''
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ printf("\n");
+ for (int i = 1; i < argc; i++) {
+ printf("%d:\n", i);
+ int ok = mkdir(argv[i], S_IRWXU|S_IRWXG|S_IRWXO);
+ printf(" make %s: %d\n", argv[i], ok);
+ DIR *dir = opendir(argv[i]);
+ printf(" open %s: %d\n", argv[i], dir != NULL);
+ if (dir) {
+ struct dirent *entry;
+ while ((entry = readdir(dir))) {
+ printf(" %s, %d\n", entry->d_name, entry->d_type);
+ }
+ }
+ }
+}
+ ''')
+ Popen([PYTHON, EMCC, 'src.cpp']).communicate()
+
+ # cannot create /, can open
+ self.assertContained(r'''
+1:
+ make /: -1
+ open /: 1
+ ., 4
+ .., 4
+ tmp, 4
+ dev, 4
+''', run_js('a.out.js', args=['/']))
+ # cannot create empty name, cannot open
+ self.assertContained(r'''
+1:
+ make : -1
+ open : 0
+''', run_js('a.out.js', args=['']))
+ # can create unnormalized path, can open
+ self.assertContained(r'''
+1:
+ make /a//: 0
+ open /a//: 1
+ ., 4
+ .., 4
+''', run_js('a.out.js', args=['/a//']))
+ # can create child unnormalized
+ self.assertContained(r'''
+1:
+ make /a: 0
+ open /a: 1
+ ., 4
+ .., 4
+2:
+ make /a//b//: 0
+ open /a//b//: 1
+ ., 4
+ .., 4
+''', run_js('a.out.js', args=['/a', '/a//b//']))
+
+ def test_emversion(self):
+ open('src.cpp', 'w').write(r'''
+ #include <stdio.h>
+ int main() {
+ printf("major: %d\n", __EMSCRIPTEN_major__);
+ printf("minor: %d\n", __EMSCRIPTEN_minor__);
+ printf("tiny: %d\n", __EMSCRIPTEN_tiny__);
+ }
+ ''')
+ Popen([PYTHON, EMCC, 'src.cpp']).communicate()
+ self.assertContained(r'''major: %d
+minor: %d
+tiny: %d
+''' % (EMSCRIPTEN_VERSION_MAJOR, EMSCRIPTEN_VERSION_MINOR, EMSCRIPTEN_VERSION_TINY), run_js('a.out.js'))
+
diff --git a/tests/test_sanity.py b/tests/test_sanity.py
index 3ebd49b6..5562ec4f 100644
--- a/tests/test_sanity.py
+++ b/tests/test_sanity.py
@@ -94,12 +94,10 @@ class sanity(RunnerCore):
self.assertContained('It contains our best guesses for the important paths, which are:', output)
self.assertContained('LLVM_ROOT', output)
self.assertContained('NODE_JS', output)
- self.assertContained('PYTHON', output)
if platform.system() is not 'Windows':
# os.chmod can't make files executable on Windows
self.assertIdentical(temp_bin, re.search("^ *LLVM_ROOT *= (.*)$", output, re.M).group(1))
self.assertIdentical(os.path.join(temp_bin, 'node'), re.search("^ *NODE_JS *= (.*)$", output, re.M).group(1))
- self.assertIdentical(os.path.join(temp_bin, 'python2'), re.search("^ *PYTHON *= (.*)$", output, re.M).group(1))
self.assertContained('Please edit the file if any of those are incorrect', output)
self.assertContained('This command will now exit. When you are done editing those paths, re-run it.', output)
assert output.split()[-1].endswith('===='), 'We should have stopped: ' + output
@@ -454,14 +452,14 @@ fi
assert os.stat(dcebc_name).st_size < os.stat(basebc_name).st_size/2, 'Dead code elimination must remove most of libc++'
# should only have metadata in -O0, not 1 and 2
if i > 0:
+ ll = None
for ll_name in ll_names:
- ll = None
- try:
- ll = open(ll_name).read()
+ if os.path.exists(ll_name):
+ check_call([LLVM_DIS, ll_name, '-o', ll_name + '.ll'])
+ ll = open(ll_name + '.ll').read()
break
- except:
- pass
assert ll
+ print 'metas:', ll.count('\n!')
assert ll.count('\n!') < 25 # a few lines are left even in -O1 and -O2
finally:
del os.environ['EMCC_DEBUG']
diff --git a/tests/twopart_main.cpp b/tests/twopart_main.cpp
index 6fac53c6..d4e73a86 100644
--- a/tests/twopart_main.cpp
+++ b/tests/twopart_main.cpp
@@ -3,6 +3,6 @@ extern void theFunc(char *str);
int main() {
theFunc("hello from main");
- return 1;
+ return 0;
}
diff --git a/tools/ffdb.py b/tools/ffdb.py
index c22fd9db..a948c700 100755
--- a/tools/ffdb.py
+++ b/tools/ffdb.py
@@ -1,7 +1,14 @@
#!/usr/bin/env python
-import socket, json, sys, uuid, datetime, time, logging, cgi, zipfile, os, tempfile, atexit, subprocess
+import socket, json, sys, uuid, datetime, time, logging, cgi, zipfile, os, tempfile, atexit, subprocess, re, base64, struct, imghdr
+WINDOWS = sys.platform == 'win32'
+if WINDOWS:
+ import ctypes
+ stdout_handle = ctypes.windll.kernel32.GetStdHandle(-11)
+
+LOG_FORMAT = 'short' # Either 'bare', 'short', or 'long'
+ADB = 'adb' # Path to the adb executable
LOG_VERBOSE = False # Verbose printing enabled with --verbose
HOST = 'localhost' # The remote host to connect to the B2G device
PORT = 6000 # The port on the host on which the B2G device listens on
@@ -18,7 +25,13 @@ def sizeof_fmt(num):
return "%3.1f%s" % (num, 'TB')
def zipdir(path, zipfilename):
- zipf = zipfile.ZipFile(zipfilename, 'w')
+ try:
+ import zlib
+ zip_mode = zipfile.ZIP_DEFLATED
+ except:
+ zip_mode = zipfile.ZIP_STORED
+
+ zipf = zipfile.ZipFile(zipfilename, 'w', zip_mode)
files_to_compress = []
for root, dirs, files in os.walk(path):
for file in files:
@@ -29,9 +42,10 @@ def zipdir(path, zipfilename):
(root, file) = tuple
filename = os.path.join(root, file)
filesize = os.path.getsize(filename)
- print 'Compressing ' + str(n) + '/' + str(len(files_to_compress)) + ': "' + os.path.relpath(filename, path) + '" (' + sizeof_fmt(filesize) + ')...'
+ path_in_archive = os.path.relpath(filename, path)
+ print 'Compressing ' + str(n) + '/' + str(len(files_to_compress)) + ': "' + path_in_archive + '" (' + sizeof_fmt(filesize) + ')...'
n += 1
- zipf.write(os.path.join(root, file))
+ zipf.write(os.path.join(root, file), path_in_archive)
zipf.close()
print 'Done. '
@@ -46,30 +60,50 @@ def format_html(msg):
# Prints a verbose log message to stdout channel. Only shown if run with --verbose.
def logv(msg):
if LOG_VERBOSE:
- sys.stdout.write(format_html(msg))
+ sys.stdout.write(format_html(msg) + '\n')
sys.stdout.flush()
# Reads data from the socket, and tries to parse what we have got so far as a JSON message.
# The messages are of form "bytelength:{jsondict}", where bytelength tells how many bytes
# there are in the data that comes after the colon.
# Returns a JSON dictionary of the received message.
-def read_b2g_response():
+def read_b2g_response(print_errors_to_console = True):
global read_queue, b2g_socket
- read_queue += b2g_socket.recv(65536*2)
- while ':' in read_queue:
- semicolon = read_queue.index(':')
- payload_len = int(read_queue[:semicolon])
+ payload = ''
+ while True:
+ semicolon = float('Inf')
+ payload_len = float('Inf')
+ try:
+ semicolon = read_queue.index(':')
+ payload_len = int(read_queue[:semicolon])
+ except:
+ pass
if semicolon+1+payload_len > len(read_queue):
- read_queue += b2g_socket.recv(65536*2)
+ try:
+ read_queue += b2g_socket.recv(4096)
+ except socket.timeout, e:
+ pass # We simulate blocking sockets with looping over reads that time out, since on Windows, the user cannot press Ctrl-C to break on blocking sockets.
+ except Exception, e:
+ if e[0] == 57: # Socket is not connected
+ print 'Error! Failed to receive data from the device: socket is not connected!'
+ sys.exit(1)
+ else:
+ print 'Got exception ' + str(e)
+ raise
continue
payload = read_queue[semicolon+1:semicolon+1+payload_len]
read_queue = read_queue[semicolon+1+payload_len:]
logv('Read a message of size ' + str(payload_len) + 'b from socket.')
payload = json.loads(payload)
+ # Log received errors immediately to console
+ if print_errors_to_console and 'error' in payload:
+ print >> sys.stderr, 'Received error "' + payload['error'] + '"! Reason: ' + payload['message']
+ else:
+ break
return payload
# Sends a command to the B2G device and waits for the response and returns it as a JSON dict.
-def send_b2g_cmd(to, cmd, data = {}):
+def send_b2g_cmd(to, cmd, data = {}, print_errors_to_console = True):
global b2g_socket
msg = { 'to': to, 'type': cmd}
msg = dict(msg.items() + data.items())
@@ -78,7 +112,7 @@ def send_b2g_cmd(to, cmd, data = {}):
msg = str(len(msg))+':'+msg
logv('Sending cmd:' + cmd + ' to:' + to)
b2g_socket.sendall(msg)
- return read_b2g_response()
+ return read_b2g_response(print_errors_to_console)
def escape_bytes(b):
return str(b)
@@ -102,7 +136,16 @@ def send_b2g_data_chunk(to, data_blob):
i += 1
message = '{"to":"'+to+'","type":"chunk","chunk":"' + ''.join(byte_str) + '"}'
message = str(len(message)) + ':' + message
+ logv('{"to":"'+to+'","type":"chunk","chunk":"<data>"}')
+ b2g_socket.sendall(message)
+ return read_b2g_response()
+
+def send_b2g_bulk_data(to, data_blob):
+ message = 'bulk ' + to + ' stream ' + str(len(data_blob)) + ':'
+ logv(message)
b2g_socket.sendall(message)
+ b2g_socket.sendall(data_blob)
+ # It seems that B2G doesn't send any response JSON back after a bulk transfer is finished, so no read_b2g_response() here.
# Queries the device for a list of all installed apps.
def b2g_get_appslist():
@@ -130,8 +173,303 @@ def print_applist(applist, running_app_manifests, print_removable):
num_printed += 1
return num_printed
+def adb_devices():
+ try:
+ devices = subprocess.check_output([ADB, 'devices'])
+ devices = devices.strip().split('\n')[1:]
+ devices = map(lambda x: x.strip().split('\t'), devices)
+ return devices
+ except Exception, e:
+ return []
+
+def b2g_get_prefs_filename():
+ return subprocess.check_output([ADB, 'shell', 'echo', '-n', '/data/b2g/mozilla/*.default/prefs.js'])
+
+def b2g_get_prefs_data():
+ return subprocess.check_output([ADB, 'shell', 'cat', '/data/b2g/mozilla/*.default/prefs.js'])
+
+def b2g_get_pref(sub):
+ prefs_data = b2g_get_prefs_data().split('\n')
+ # Filter to find all prefs that have the substring 'sub' in them.
+ r = re.compile('user_pref\w*\(\w*"([^"]*)"\w*,\w*([^\)]*)')
+ for line in prefs_data:
+ m = r.match(line)
+ if m and (sub is None or sub in m.group(1)):
+ print m.group(1) + ': ' + m.group(2).strip()
+
+def b2g_set_pref(pref, value):
+ prefs_data = b2g_get_prefs_data().split('\n')
+ # Remove any old value of this pref.
+ r = re.compile('user_pref\w*\(\w*"([^"]*)"\w*,\w*([^\)]*)')
+ new_prefs_data = []
+ for line in prefs_data:
+ m = r.match(line)
+ if not m or m.group(1) != pref:
+ new_prefs_data += [line]
+
+ if value != None:
+ print 'Setting pref "' + pref + '" = ' + value
+ new_prefs_data += ['user_pref("' + pref + '", ' + value + ');']
+ else:
+ print 'Unsetting pref "' + pref + '"'
+ (oshandle, tempfilename) = tempfile.mkstemp(suffix='.js', prefix='ffdb_temp_')
+ os.write(oshandle, '\n'.join(new_prefs_data));
+
+ # Write the new pref
+ subprocess.check_output([ADB, 'shell', 'stop', 'b2g'])
+ subprocess.check_output([ADB, 'push', tempfilename, b2g_get_prefs_filename()])
+ subprocess.check_output([ADB, 'shell', 'start', 'b2g'])
+ print 'Rebooting phone...'
+
+ def delete_temp_file():
+ os.remove(tempfilename)
+ atexit.register(delete_temp_file)
+
+def get_packaged_app_manifest(target_app_path):
+ if os.path.isdir(target_app_path):
+ manifest_file = os.path.join(target_app_path, 'manifest.webapp')
+ if not os.path.isfile(manifest_file):
+ print "Error: Failed to find FFOS packaged app manifest file '" + manifest_file + "'! That directory does not contain a packaged app?"
+ sys.exit(1)
+ return json.loads(open(manifest_file, 'r').read())
+ elif target_app_path.endswith('.zip') and os.path.isfile(target_app_path):
+ try:
+ z = zipfile.ZipFile(target_app_path, "r")
+ bytes = z.read('manifest.webapp')
+ except Exception, e:
+ print "Error: Failed to read FFOS packaged app manifest file 'manifest.webapp' in zip file '" + target_app_path + "'! Error: " + str(e)
+ sys.exit(1)
+ return None
+ return json.loads(str(bytes))
+ else:
+ print "Error: Path '" + target_app_path + "' is neither a directory or a .zip file to represent the location of a FFOS packaged app!"
+ sys.exit(1)
+ return None
+
+def b2g_install(target_app_path):
+ if os.path.isdir(target_app_path):
+ print 'Zipping up the contents of directory "' + target_app_path + '"...'
+ (oshandle, tempzip) = tempfile.mkstemp(suffix='.zip', prefix='ffdb_temp_')
+ zipdir(target_app_path, tempzip)
+ target_app_path = tempzip
+ # Remember to delete the temporary package after we quit.
+ def delete_temp_file():
+ os.remove(tempzip)
+ atexit.register(delete_temp_file)
+
+ print 'Uploading application package "' + target_app_path + '"...'
+ print 'Size of compressed package: ' + sizeof_fmt(os.path.getsize(target_app_path)) + '.'
+ app_file = open(target_app_path, 'rb')
+ data = app_file.read()
+ file_size = len(data)
+
+ uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage', { 'bulk': 'true'}, print_errors_to_console = False) # This may fail if on old device.
+ start_time = time.time()
+ if 'actor' in uploadResponse and 'BulkActor' in uploadResponse['actor']: # New B2G 2.0 hotness: binary data transfer
+ packageUploadActor = uploadResponse['actor']
+ send_b2g_bulk_data(packageUploadActor, data)
+ else: # Old B2G 1.4 and older, serialize binary data in JSON text strings (SLOW!)
+ print 'Bulk upload is not supported, uploading binary data with old slow format. Consider flashing your device to FFOS 2.0 or newer to enjoy faster upload speeds.'
+ uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage')
+ packageUploadActor = uploadResponse['actor']
+ chunk_size = 4*1024*1024
+ i = 0
+ while i < file_size:
+ chunk = data[i:i+chunk_size]
+
+ send_b2g_data_chunk(packageUploadActor, chunk)
+ i += chunk_size
+ bytes_uploaded = min(i, file_size)
+ cur_time = time.time()
+ secs_elapsed = cur_time - start_time
+ percentage_done = bytes_uploaded * 1.0 / file_size
+ total_time = secs_elapsed / percentage_done
+ time_left = total_time - secs_elapsed
+ print sizeof_fmt(bytes_uploaded) + " uploaded, {:5.1f} % done.".format(percentage_done*100.0) + ' Elapsed: ' + str(int(secs_elapsed)) + ' seconds. Time left: ' + str(datetime.timedelta(seconds=int(time_left))) + '. Data rate: {:5.2f} KB/second.'.format(bytes_uploaded / 1024.0 / secs_elapsed)
+
+ app_local_id = str(uuid.uuid4())
+ reply = send_b2g_cmd(webappsActorName, 'install', { 'appId': app_local_id, 'upload': packageUploadActor })
+ cur_time = time.time()
+ secs_elapsed = cur_time - start_time
+ print 'Upload of ' + sizeof_fmt(file_size) + ' finished. Total time elapsed: ' + str(int(secs_elapsed)) + ' seconds. Data rate: {:5.2f} KB/second.'.format(file_size / 1024.0 / secs_elapsed)
+ if not 'appId' in reply:
+ print 'Error: Application install failed! ' + str(reply)
+ sys.exit()
+ return reply['appId']
+
+def b2g_app_command(app_command, app_name, print_errors_to_console = True):
+ apps = b2g_get_appslist()
+ for app in apps:
+ if str(app['localId']) == app_name or app['name'] == app_name or app['manifestURL'] == app_name or app['id'] == app_name:
+ send_b2g_cmd(webappsActorName, app_command, { 'manifestURL': app['manifestURL'] })
+ return 0
+ if print_errors_to_console:
+ print 'Error! Application "' + app_name + '" was not found! Use the \'list\' command to find installed applications.'
+ return 1
+
+def b2g_memory(app_name):
+ apps = b2g_get_appslist()
+ appActor = ''
+ for app in apps:
+ if str(app['localId']) == app_name or app['name'] == app_name or app['manifestURL'] == app_name or app['id'] == app_name:
+ appActor = send_b2g_cmd(webappsActorName, 'getAppActor', { 'manifestURL': app['manifestURL'] })
+ break
+ if 'actor' in appActor:
+ memoryActor = appActor['actor']['memoryActor']
+ measure = send_b2g_cmd(memoryActor, 'measure')
+ for k,v in measure.items():
+ if k != 'from':
+ if k in ['otherSize', 'jsStringsSize', 'jsObjectsSize', 'styleSize', 'jsOtherSize', 'domSize', 'total']: # These are formatted in bytes
+ print k + ': ' + sizeof_fmt(v)
+ else:
+ print k + ': ' + str(v)
+
+def b2g_log(app_name, clear=False):
+ global LOG_FORMAT
+ apps = b2g_get_appslist()
+ appActor = ''
+ for app in apps:
+ if str(app['localId']) == app_name or app['name'] == app_name or app['manifestURL'] == app_name or app['id'] == app_name:
+ appActor = send_b2g_cmd(webappsActorName, 'getAppActor', { 'manifestURL': app['manifestURL'] })
+ break
+ if 'actor' in appActor:
+ consoleActor = appActor['actor']['consoleActor']
+
+ if clear:
+ send_b2g_cmd(consoleActor, 'clearMessagesCache')
+ print 'Cleared message log.'
+ return 0
+
+ msgs = send_b2g_cmd(consoleActor, 'startListeners', { 'listeners': ['PageError','ConsoleAPI','NetworkActivity','FileActivity'] })
+
+ if WINDOWS:
+ WARNING = 14 # FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
+ FAIL = 12 # FOREGROUND_RED | FOREGROUND_INTENSITY
+ INFO = 7 # FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+ ENDC = ''
+ BOLD = ''
+ else:
+ WARNING = '\033[93m'
+ FAIL = '\033[91m'
+ INFO = ENDC = '\033[0m'
+ BOLD = "\033[1m"
+
+ def set_color(string, color):
+ if WINDOWS:
+ ctypes.windll.kernel32.SetConsoleTextAttribute(stdout_handle, color)
+ return string
+ else:
+ return color + string + ENDC
+
+ def reset_color():
+ if WINDOWS:
+ ctypes.windll.kernel32.SetConsoleTextAttribute(stdout_handle, INFO)
+
+ def log_b2g_message(msg):
+ msgs = []
+ if 'type' in msg and msg['type'] == 'consoleAPICall':
+ msgs = [msg['message']]
+ elif 'messages' in msg:
+ msgs = msg['messages']
+
+ for m in msgs:
+ args = m['arguments']
+
+ for arg in args:
+ if LOG_FORMAT == 'long':
+ text = str(m['functionName']) + '@' + str(m['filename']) + ':' + str(m['lineNumber']) + ': ' + str(arg)
+ elif LOG_FORMAT == 'bare':
+ text = str(arg)
+ else: # Default to 'short'
+ text = str(m['functionName']) + '@' + os.path.basename(str(m['filename'])) + ':' + str(m['lineNumber']) + ': ' + str(arg)
+
+ if m['level'] == 'log':
+ color = INFO
+ channel = 'I/'
+ elif m['level'] == 'warn':
+ color = WARNING
+ channel = 'W/'
+ elif m['level'] == 'error':
+ color = FAIL
+ channel = 'E/'
+ else:
+ color = INFO
+ channel = m['level'] + '/'
+
+ text = set_color(channel + text, color)
+ print text
+ reset_color()
+
+ msgs = send_b2g_cmd(consoleActor, 'getCachedMessages', { 'messageTypes': ['PageError', 'ConsoleAPI'] })
+ log_b2g_message(msgs)
+
+ while True:
+ msg = read_b2g_response()
+ log_b2g_message(msg)
+ else:
+ print 'Application "' + sys.argv[2] + '" is not running!'
+
+def b2g_screenshot(filename):
+ global deviceActorName
+ data_reply = send_b2g_cmd(deviceActorName, 'screenshotToDataURL')
+ data = data_reply['value']
+ if not isinstance(data, basestring): # The device is sending the screenshot in multiple fragments since it's too long to fit in one message?
+ data_get_actor = data['actor']
+ data_len = int(data['length'])
+ data = data['initial']
+ chunk_size = 65000
+ pos = len(data)
+ # Pull and assemble individual screenshot fragments.
+ while pos < data_len:
+ bytes_to_read = min(data_len - pos, chunk_size)
+ data_reply = send_b2g_cmd(data_get_actor, 'substring', { 'start': str(pos), 'end': str(pos + bytes_to_read) })
+ if len(data_reply['substring']) != bytes_to_read:
+ print >> sys.stderr, 'Error! Expected to receive ' + str(bytes_to_read) + ' bytes of image data, but got ' + str(len(data_reply['substring'])) + ' bytes instead!'
+ sys.exit(1)
+ data += data_reply['substring']
+ pos += bytes_to_read
+ send_b2g_cmd(data_get_actor, 'release') # We need to explicitly free the screenshot image string from the device, or the Devtools connection leaks resources!
+
+ # Expected format is "data:image/png;base64,<base64data>"
+ delim = re.search(",", data).start()
+ data_format = data[:delim]
+ if data_format != "data:image/png;base64":
+ print >> sys.stderr, "Error: Received screenshot from device in an unexpected format '" + data_format + "'!"
+ sys.exit(1)
+ data = data[delim+1:]
+
+ binary_data = base64.b64decode(data)
+ open(filename, 'wb').write(binary_data)
+
+ def get_png_image_size(filename):
+ fhandle = open(filename, 'rb')
+ head = fhandle.read(24)
+ if len(head) != 24:
+ return (-1, -1)
+ check = struct.unpack('>i', head[4:8])[0]
+ if check != 0x0d0a1a0a:
+ return (-1, -1)
+ return struct.unpack('>ii', head[16:24])
+
+ width, height = get_png_image_size(filename)
+ if width <= 0 or height <= 0:
+ print >> sys.stderr, "Wrote " + sizeof_fmt(len(binary_data)) + " to file '" + filename + "', but the contents may be corrupted!"
+ else:
+ print "Wrote " + sizeof_fmt(len(binary_data)) + " to file '" + filename + "' (" + str(width) + 'x' + str(height) + ' pixels).'
+
+def b2g_get_description(desc):
+ global deviceActorName
+ data_reply = send_b2g_cmd(deviceActorName, 'getDescription')
+ # First try an exact match to requested desc
+ if desc and desc in data_reply['value']:
+ print desc + ': ' + str(data_reply['value'][desc])
+ else: # Print all with case-insensitive substring search
+ for k,v in data_reply['value'].items():
+ if not desc or desc.lower() in k.lower():
+ print k + ': ' + str(v)
+
def main():
- global b2g_socket, webappsActorName
+ global b2g_socket, webappsActorName, deviceActorName, HOST, PORT, VERBOSE, ADB
if len(sys.argv) < 2 or '--help' in sys.argv or 'help' in sys.argv or '-v' in sys.argv:
print '''Firefox OS Debug Bridge, a tool for automating FFOS device tasks from the command line.
@@ -140,30 +478,96 @@ def main():
list [--running] [--all]: Prints out the user applications installed on the device.
If --running is passed, only the currently opened apps are shown.
If --all is specified, then also uninstallable system applications are listed.
- launch <app>: Starts the given application. If already running, brings to front.
+ launch <app> [--log]: Starts the given application. If already running, brings to front. If the --log option is passed, ffdb will
+ start persistently logging the execution of the given application.
close <app>: Terminates the execution of the given application.
uninstall <app>: Removes the given application from the device.
- install <path>: Uploads and installs a packaged app that resides in the given local directory.
+ install <path> [--run] [--log]: Uploads and installs a packaged app that resides in the given local directory.
<path> may either refer to a directory containing a packaged app, or to a prepackaged zip file.
+ If the --run option is passed, the given application is immediately launched after the installation finishes.
+ If the --log option is passed, ffdb will start persistently logging the execution of the installed application.
log <app> [--clear]: Starts a persistent log listener that reads web console messages from the given application.
If --clear is passed, the message log for that application is cleared instead.
+ memory <app>: Dumps a memory usage summary for the given application.
navigate <url>: Opens the given web page in the B2G browser.
+ screenshot [filename.png]: Takes a screenshot of the current contents displayed on the device. If an optional
+ filename is specified, the screenshot is saved to that file. Otherwise the filename
+ will be autogenerated.
+ get [pref]: Fetches the value of the given developer pref option from the FFOS device and prints it to console. The parameter pref
+ is optional and may either be the full name of a pref, or a substring to search for. All matching prefs will be printed.
+ If no pref parameter is given, all prefs are printed.
+ NOTE: This function (currently at least) only reports prefs that have been explicitly set and don't have their default value.
+ set <pref> <value>: Writes the given pref option to the FFOS device and restarts the B2G process on it for the change to take effect.
+ unset <pref>: Removes the given pref option from the FFOS device and restarts the B2G process on it for the change to take effect.
+
+ hide-prompt: Permanently removes the remote debugging connection dialog from showing up, and reboots the phone. This command is
+ provided for conveniency, and is the same as calling './ffdb.py set devtools.debugger.prompt-connection false'
+ restore-prompt: Restores the remote debugging connection dialog prompt to its default state.
+
+ desc [desc]: Fetches the value of the given device description field. These fields are read-only and describe the current system.
+ If the optional desc parameter is omitted, all device descriptions are printed. Otherwise the given description is
+ printed if it is an exact match, or all descriptions containing desc as the substring are printed.
+
+ Options: Additionally, the following options may be passed to control FFDB execution:
+
+ --host <hostname>: Specifies the target network address to connect to. Default: 'localhost'.
+ --port <number>: Specifies the network port to connect to. Default: 6000.
+ --verbose: Enables verbose printing, mostly useful for debugging.
+ --simulator: Signal that we will be connecting to a FFOS simulator and not a real device.
In the above, whenever a command requires an <app> to be specified, either the human-readable name,
localId or manifestURL of the application can be used.'''
sys.exit(0)
+ connect_to_simulator = False
+
+ options_with_value = ['--host', '--port']
+ options = options_with_value + ['--verbose', '--simulator']
+ # Process options
+ for i in range(0, len(sys.argv)):
+ if sys.argv[i] in options_with_value:
+ if i+1 >= sys.argv or sys.argv[i+1].startswith('-'):
+ print >> sys.stderr, "Missing value for option " + sys.argv[i] +'!'
+ sys.exit(1)
+ if sys.argv[i] == '--host':
+ HOST = sys.argv[i+1]
+ elif sys.argv[i] == '--port':
+ PORT = int(sys.argv[i+1])
+ elif sys.argv[i] == '--verbose':
+ VERBOSE = True
+ elif sys.argv[i] == '--simulator':
+ connect_to_simulator = True
+
+ # Clear the processed options so that parsing the commands below won't trip up on these.
+ if sys.argv[i] in options: sys.argv[i] = ''
+ if sys.argv[i] in options_with_value: sys.argv[i+1] = ''
+
+ sys.argv = filter(lambda x: len(x) > 0, sys.argv)
+
+ # Double-check that the device is found via adb:
+ if (HOST == 'localhost' or HOST == '127.0.0.1') and not connect_to_simulator:
+ devices = adb_devices()
+ if len(devices) == 0:
+ print 'Error! Failed to connect to B2G device debugger socket at address ' + HOST + ':' + str(PORT) + ' and no devices were detected via adb. Please double-check the following and try again: '
+ print ' 1) The device is powered on and connected to the computer with an USB cable.'
+ print ' 2) ADB and DevTools debugging is enabled on the device. (Settings -> Developer -> Debugging via USB: "ADB and DevTools"'
+ print ' 3) The device is listed when you run "adb devices" on the command line.'
+ print ' 4) When launching ffdb, remember to acknowledge the "incoming debug connection" dialog if it pops up on the device.'
+ sys.exit(1)
b2g_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if WINDOWS:
+ # Python Windows issue: user cannot press Ctrl-C to abort from a socket .recv() Therefore simulate blocking sockets with looping over reads that time out.
+ b2g_socket.settimeout(0.5)
try:
b2g_socket.connect((HOST, PORT))
except Exception, e:
if e[0] == 61: # Connection refused
- if HOST == 'localhost' or HOST == '127.0.0.1':
- cmd = ['adb', 'forward', 'tcp:'+str(PORT), 'localfilesystem:/data/local/debugger-socket']
+ if (HOST == 'localhost' or HOST == '127.0.0.1') and not connect_to_simulator:
+ cmd = [ADB, 'forward', 'tcp:'+str(PORT), 'localfilesystem:/data/local/debugger-socket']
print 'Connection to ' + HOST + ':' + str(PORT) + ' refused, attempting to forward device debugger-socket to local address by calling ' + str(cmd) + ':'
else:
- print 'Error! Failed to connect to B2G device debugger socket at address ' + HOST + ':' + str(PORT) + '!'
+ print 'Error! Failed to connect to B2G ' + ('simulator' if connect_to_simulator else 'device') + ' debugger socket at address ' + HOST + ':' + str(PORT) + '!'
sys.exit(1)
try:
retcode = subprocess.check_call(cmd)
@@ -187,6 +591,9 @@ def main():
logv('Connected. Handshake: ' + str(handshake))
data = send_b2g_cmd('root', 'listTabs')
+ if not 'deviceActor' in data:
+ print 'Error! Debugging connection was not available. Make sure that the "Remote debugging" developer option on the device is set to "ADB and Devtools".'
+ sys.exit(1)
deviceActorName = data['deviceActor']
logv('deviceActor: ' + deviceActorName)
webappsActorName = data['webappsActor']
@@ -195,9 +602,8 @@ def main():
send_b2g_cmd(deviceActorName, 'getDescription')
send_b2g_cmd(deviceActorName, 'getRawPermissionsTable')
- apps = b2g_get_appslist()
-
if sys.argv[1] == 'list':
+ apps = b2g_get_appslist()
running_app_manifests = b2g_get_runningapps()
printed_apps = apps
print_only_running = '--running' in sys.argv and not '--all' in sys.argv
@@ -218,54 +624,27 @@ def main():
if len(sys.argv) < 3:
print 'Error! No application name given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <app>'
return 1
- for app in apps:
- if str(app['localId']) == sys.argv[2] or app['name'] == sys.argv[2] or app['manifestURL'] == sys.argv[2]:
- send_b2g_cmd(webappsActorName, sys.argv[1], { 'manifestURL': app['manifestURL'] })
- return 0
- print 'Error! Application "' + sys.argv[2] + '" was not found! Use the \'list\' command to find installed applications.'
- return 1
+ ret = b2g_app_command(sys.argv[1], sys.argv[2])
+ if ret == 0 and '--log' in sys.argv:
+ b2g_log(sys.argv[2])
elif sys.argv[1] == 'install':
if len(sys.argv) < 3:
print 'Error! No application path given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <path>'
return 1
target_app_path = sys.argv[2]
- if os.path.isdir(target_app_path):
- print 'Zipping up the contents of directory "' + target_app_path + '"...'
- (oshandle, tempzip) = tempfile.mkstemp(suffix='.zip', prefix='ffdb_temp_')
- zipdir(target_app_path, tempzip)
- target_app_path = tempzip
- # Remember to delete the temporary package after we quit.
- def delete_temp_file():
- os.remove(tempzip)
- atexit.register(delete_temp_file)
-
- print 'Uploading application package "' + target_app_path + '"...'
- print 'Size of compressed package: ' + sizeof_fmt(os.path.getsize(target_app_path)) + '.'
- uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage')
- packageUploadActor = uploadResponse['actor']
- app_file = open(target_app_path, 'rb')
- data = app_file.read()
- file_size = len(data)
- chunk_size = 4*1024*1024
- i = 0
- start_time = time.time()
- while i < file_size:
- chunk = data[i:i+chunk_size]
-
- send_b2g_data_chunk(packageUploadActor, chunk)
- i += chunk_size
- bytes_uploaded = min(i, file_size)
- cur_time = time.time()
- secs_elapsed = cur_time - start_time
- percentage_done = bytes_uploaded * 1.0 / file_size
- total_time = secs_elapsed / percentage_done
- time_left = total_time - secs_elapsed
- print sizeof_fmt(bytes_uploaded) + " uploaded, {:5.1f} % done.".format(percentage_done*100.0) + ' Elapsed: ' + str(int(secs_elapsed)) + ' seconds. Time left: ' + str(datetime.timedelta(seconds=int(time_left))) + '. Data rate: {:5.2f} KB/second.'.format(bytes_uploaded / 1024.0 / secs_elapsed)
- send_b2g_cmd(webappsActorName, 'install', { 'appId': str(uuid.uuid4()), 'upload': packageUploadActor })
-
- cur_time = time.time()
- secs_elapsed = cur_time - start_time
- print 'Upload of ' + sizeof_fmt(file_size) + ' finished. Total time elapsed: ' + str(int(secs_elapsed)) + ' seconds. Data rate: {:5.2f} KB/second.'.format(file_size / 1024.0 / secs_elapsed)
+ # Kill and uninstall old running app execution before starting.
+ if '--run' in sys.argv:
+ app_manifest = get_packaged_app_manifest(target_app_path)
+ b2g_app_command('close', app_manifest['name'], print_errors_to_console=False)
+ b2g_app_command('uninstall', app_manifest['name'], print_errors_to_console=False)
+ # Upload package
+ app_id = b2g_install(target_app_path)
+ # Launch it immediately if requested.
+ if '--run' in sys.argv:
+ b2g_app_command('launch', app_id)
+ # Don't quit, but keep logging the app if requested.
+ if '--log' in sys.argv:
+ b2g_log(app_id)
elif sys.argv[1] == 'navigate':
if len(sys.argv) < 3:
print 'Error! No URL given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <url>'
@@ -281,55 +660,44 @@ def main():
else:
print 'Web browser is not running!'
elif sys.argv[1] == 'log':
- appActor = ''
- for app in apps:
- if str(app['localId']) == sys.argv[2] or app['name'] == sys.argv[2] or app['manifestURL'] == sys.argv[2]:
- appActor = send_b2g_cmd(webappsActorName, 'getAppActor', { 'manifestURL': app['manifestURL'] })
- break
- if 'actor' in appActor:
- consoleActor = appActor['actor']['consoleActor']
-
- if '-c' in sys.argv or '-clear' in sys.argv or '--clear' in sys.argv:
- send_b2g_cmd(consoleActor, 'clearMessagesCache')
- print 'Cleared message log.'
- sys.exit(0)
-
- msgs = send_b2g_cmd(consoleActor, 'startListeners', { 'listeners': ['PageError','ConsoleAPI','NetworkActivity','FileActivity'] })
-
- def log_b2g_message(msg):
- WARNING = '\033[93m'
- FAIL = '\033[91m'
- ENDC = '\033[0m'
- BOLD = "\033[1m"
- msgs = []
- if 'type' in msg and msg['type'] == 'consoleAPICall':
- msgs = [msg['message']]
- elif 'messages' in msg:
- msgs = msg['messages']
-
- for m in msgs:
- args = m['arguments']
-
- for arg in args:
- if m['level'] == 'log':
- color = 'I/'
- elif m['level'] == 'warn':
- color = WARNING + 'W/'
- elif m['level'] == 'error':
- color = FAIL + 'E/'
- else:
- color = m['level'] + '/'
-
- print color + str(m['functionName']) + '@' + str(m['filename']) + ':' + str(m['lineNumber']) + ': ' + str(arg) + ENDC
-
- msgs = send_b2g_cmd(consoleActor, 'getCachedMessages', { 'messageTypes': ['PageError', 'ConsoleAPI'] })
- log_b2g_message(msgs)
-
- while True:
- msg = read_b2g_response()
- log_b2g_message(msg)
+ clear = '-c' in sys.argv or '-clear' in sys.argv or '--clear' in sys.argv
+ b2g_log(sys.argv[2], clear)
+ elif sys.argv[1] == 'memory':
+ b2g_memory(sys.argv[2])
+ elif sys.argv[1] == 'screenshot':
+ if len(sys.argv) >= 3:
+ filename = sys.argv[2]
+ if not filename.endswith('.png'):
+ print >> sys.stderr, "Writing screenshots only to .png files are supported!"
+ sys.exit(1)
else:
- print 'Application "' + sys.argv[2] + '" is not running!'
+ filename = time.strftime("screen_%Y%m%d_%H%M%S.png", time.gmtime())
+
+ b2g_screenshot(filename)
+ elif sys.argv[1] == 'get':
+ b2g_get_pref(sys.argv[2] if len(sys.argv) >= 3 else None)
+ elif sys.argv[1] == 'set':
+ if len(sys.argv) < 3:
+ print 'Error! No pref name to set given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <pref> <value>'
+ sys.exit(1)
+ if len(sys.argv) < 4:
+ print 'Error! No value given to set! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <pref> <value>'
+ sys.exit(1)
+ if len(sys.argv) > 4:
+ print 'Error! Too many arguments given (' + str(sys.argv) + '), need exactly four! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <pref> <value>'
+ sys.exit(1)
+ b2g_set_pref(sys.argv[2], sys.argv[3])
+ elif sys.argv[1] == 'unset':
+ if len(sys.argv) < 3:
+ print 'Error! No pref name given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' <pref>'
+ sys.exit(1)
+ b2g_set_pref(sys.argv[2], None)
+ elif sys.argv[1] == 'hide-prompt':
+ b2g_set_pref('devtools.debugger.prompt-connection', 'false')
+ elif sys.argv[1] == 'restore-prompt':
+ b2g_set_pref('devtools.debugger.prompt-connection', None)
+ elif sys.argv[1] == 'desc':
+ b2g_get_description(sys.argv[2] if len(sys.argv) >= 3 else None)
else:
print "Unknown command '" + sys.argv[1] + "'! Pass --help for instructions."
@@ -337,6 +705,10 @@ def main():
return 0
if __name__ == '__main__':
- returncode = main()
- logv('ffdb.py quitting with process exit code ' + str(returncode))
- sys.exit(returncode)
+ try:
+ returncode = main()
+ logv('ffdb.py quitting with process exit code ' + str(returncode))
+ sys.exit(returncode)
+ except KeyboardInterrupt:
+ print ('^C' if WINDOWS else '') + ' Aborted by user'
+ sys.exit(1)
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 5b01dae0..40945d9b 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -128,10 +128,8 @@ load('utility.js');
// Utilities
-var FUNCTION = set('defun', 'function');
var LOOP = set('do', 'while', 'for');
var LOOP_FLOW = set('break', 'continue');
-var ASSIGN_OR_ALTER = set('assign', 'unary-postfix', 'unary-prefix');
var CONTROL_FLOW = set('do', 'while', 'for', 'if', 'switch');
var NAME_OR_NUM = set('name', 'num');
var ASSOCIATIVE_BINARIES = set('+', '*', '|', '&', '^');
@@ -145,10 +143,7 @@ var COMMABLE = set('assign', 'binary', 'unary-prefix', 'unary-postfix', 'name',
var FUNCTIONS_THAT_ALWAYS_THROW = set('abort', '___resumeException', '___cxa_throw', '___cxa_rethrow');
-var NULL_NODE = ['name', 'null'];
var UNDEFINED_NODE = ['unary-prefix', 'void', ['num', 0]];
-var TRUE_NODE = ['unary-prefix', '!', ['num', 0]];
-var FALSE_NODE = ['unary-prefix', '!', ['num', 1]];
var GENERATED_FUNCTIONS_MARKER = '// EMSCRIPTEN_GENERATED_FUNCTIONS';
var generatedFunctions = false; // whether we have received only generated functions
@@ -980,6 +975,405 @@ function simplifyIfs(ast) {
});
}
+// In typed arrays mode 2, we can have
+// HEAP[x >> 2]
+// very often. We can in some cases do the shift on the variable itself when it is set,
+// to greatly reduce the number of shift operations.
+function optimizeShiftsInternal(ast, conservative) {
+ assert(!asm);
+ var MAX_SHIFTS = 3;
+ traverseGeneratedFunctions(ast, function(fun) {
+ var funMore = true;
+ var funFinished = {};
+ while (funMore) {
+ funMore = false;
+ // Recognize variables and parameters
+ var vars = {};
+ function newVar(name, param, addUse) {
+ if (!vars[name]) {
+ vars[name] = {
+ param: param,
+ defs: addUse ? 1 : 0,
+ uses: 0,
+ timesShifted: [0, 0, 0, 0], // zero shifts of size 0, 1, 2, 3
+ benefit: 0,
+ primaryShift: -1
+ };
+ }
+ }
+ // params
+ if (fun[2]) {
+ fun[2].forEach(function(arg) {
+ newVar(arg, true, true);
+ });
+ }
+ // vars
+ // XXX if var has >>=, ignore it here? That means a previous pass already optimized it
+ var hasSwitch = traverse(fun, function(node, type) {
+ if (type === 'var') {
+ node[1].forEach(function(arg) {
+ newVar(arg[0], false, arg[1]);
+ });
+ } else if (type === 'switch') {
+ // The relooper can't always optimize functions, and we currently don't work with
+ // switch statements when optimizing shifts. Bail.
+ return true;
+ }
+ });
+ if (hasSwitch) {
+ break;
+ }
+ // uses and defs TODO: weight uses by being inside a loop (powers). without that, we
+ // optimize for code size, not speed.
+ var stack = [];
+ traverse(fun, function(node, type) {
+ stack.push(node);
+ if (type === 'name' && vars[node[1]] && stack[stack.length-2][0] != 'assign') {
+ vars[node[1]].uses++;
+ } else if (type === 'assign' && node[2][0] === 'name' && vars[node[2][1]]) {
+ vars[node[2][1]].defs++;
+ }
+ }, function() {
+ stack.pop();
+ });
+ // First, break up elements inside a shift. This lets us see clearly what to do next.
+ traverse(fun, function(node, type) {
+ if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num') {
+ var shifts = node[3][1];
+ if (shifts <= MAX_SHIFTS) {
+ // Check for validity. It is ok to have a single element that might have non-zeroed lower bits, but no more.
+ // x + 4 >> 2 === (x >> 2) + (4 >> 2), but not x + 3 >> 2 === (x >> 2) + (3 >> 2) (c.f. x=1, we get 1 !== 0)
+ var seen = '', ok = true;
+ function checkShift(subNode) {
+ if (subNode[0] === 'binary') {
+ switch (subNode[1]) {
+ case '+': case '|': case '&': { // this could be more comprehensive, but likely not needed
+ checkShift(subNode[2]);
+ checkShift(subNode[3]);
+ break;
+ }
+ case '>>': case '>>>': {
+ checkShift(subNode[2]);
+ break;
+ }
+ case '<<': {
+ if (subNode[3][0] === 'num' && subNode[3][1] >= shifts) break; // bits are clear, all good
+ checkShift(subNode[2]);
+ break;
+ }
+ case '*': {
+ if (subNode[3][0] === 'num') {
+ var value = subNode[3][1];
+ if (((value >> shifts) << shifts) === value) return; // bits are clear, all good
+ }
+ checkShift(subNode[2]);
+ checkShift(subNode[3]);
+ break;
+ }
+ default: ok = false;
+ }
+ return;
+ }
+ if (subNode[0] === 'name') {
+ var name = subNode[1];
+ if (!seen) {
+ seen = name;
+ } else if (name !== seen) {
+ ok = false;
+ }
+ return;
+ }
+ if (subNode[0] === 'num') {
+ var value = subNode[1];
+ if (((value >> shifts) << shifts) !== value) ok = false;
+ return;
+ }
+ if (subNode[0] === 'sub') {
+ if (seen) ok = false;
+ seen = 'heap access';
+ return;
+ }
+ ok = false; // anything else is bad
+ }
+ checkShift(node[2]);
+ if (!ok) return;
+
+ // Push the >> inside the value elements
+ function addShift(subNode) {
+ if (subNode[0] === 'binary' && subNode[1] === '+') {
+ subNode[2] = addShift(subNode[2]);
+ subNode[3] = addShift(subNode[3]);
+ return subNode;
+ }
+ if (subNode[0] === 'name' && !subNode[2]) { // names are returned with a shift, but we also note their being shifted
+ var name = subNode[1];
+ if (vars[name]) {
+ vars[name].timesShifted[shifts]++;
+ subNode[2] = true;
+ }
+ }
+ return ['binary', '>>', subNode, ['num', shifts]];
+ }
+ return addShift(node[2]);
+ }
+ }
+ });
+ traverse(fun, function(node, type) {
+ if (node[0] === 'name' && node[2]) {
+ return node.slice(0, 2); // clean up our notes
+ }
+ });
+ // At this point, shifted expressions are split up, and we know who the vars are and their info, so we can decide
+ // TODO: vars that depend on other vars
+ for (var name in vars) {
+ var data = vars[name];
+ var totalTimesShifted = sum(data.timesShifted);
+ if (totalTimesShifted === 0) {
+ continue;
+ }
+ if (totalTimesShifted != Math.max.apply(null, data.timesShifted)) {
+ // TODO: Handle multiple different shifts
+ continue;
+ }
+ if (funFinished[name]) continue;
+ // We have one shift size (and possible unshifted uses). Consider replacing this variable with a shifted clone. If
+ // the estimated benefit is >0, we will do it
+ if (data.defs === 1) {
+ data.benefit = totalTimesShifted - 2*(data.defs + (data.param ? 1 : 0));
+ }
+ if (conservative) data.benefit = 0;
+ if (data.benefit > 0) {
+ funMore = true; // We will reprocess this function
+ for (var i = 0; i < 4; i++) {
+ if (data.timesShifted[i]) {
+ data.primaryShift = i;
+ }
+ }
+ }
+ }
+ //printErr(JSON.stringify(vars));
+ function cleanNotes() { // We need to mark 'name' nodes as 'processed' in some passes here; this cleans the notes up
+ traverse(fun, function(node, type) {
+ if (node[0] === 'name' && node[2]) {
+ return node.slice(0, 2);
+ }
+ });
+ }
+ cleanNotes();
+ // Apply changes
+ function needsShift(name) {
+ return vars[name] && vars[name].primaryShift >= 0;
+ }
+ for (var name in vars) { // add shifts for params and var's for all new variables
+ var data = vars[name];
+ if (needsShift(name)) {
+ if (data.param) {
+ fun[3].unshift(['var', [[name + '$s' + data.primaryShift, ['binary', '>>', ['name', name], ['num', data.primaryShift]]]]]);
+ } else {
+ fun[3].unshift(['var', [[name + '$s' + data.primaryShift]]]);
+ }
+ }
+ }
+ var stack = [];
+ traverse(fun, function(node, type) { // add shift to assignments
+ stack.push(node);
+ if (node[0] === 'assign' && node[1] === true && node[2][0] === 'name' && needsShift(node[2][1]) && !node[2][2]) {
+ var name = node[2][1];
+ var data = vars[name];
+ var parent = stack[stack.length-3];
+ var statements = getStatements(parent);
+ assert(statements, 'Invalid parent for assign-shift: ' + dump(parent));
+ var i = statements.indexOf(stack[stack.length-2]);
+ statements.splice(i+1, 0, ['stat', ['assign', true, ['name', name + '$s' + data.primaryShift], ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]]);
+ } else if (node[0] === 'var') {
+ var args = node[1];
+ for (var i = 0; i < args.length; i++) {
+ var arg = args[i];
+ var name = arg[0];
+ var data = vars[name];
+ if (arg[1] && needsShift(name)) {
+ args.splice(i+1, 0, [name + '$s' + data.primaryShift, ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]);
+ }
+ }
+ return node;
+ }
+ }, function() {
+ stack.pop();
+ });
+ cleanNotes();
+ var stack = [];
+ traverse(fun, function(node, type) { // replace shifted name with new variable
+ stack.push(node);
+ if (node[0] === 'binary' && node[1] === '>>' && node[2][0] === 'name' && needsShift(node[2][1]) && node[3][0] === 'num') {
+ var name = node[2][1];
+ var data = vars[name];
+ var parent = stack[stack.length-2];
+ // Don't modify in |x$sN = x >> 2|, in normal assigns and in var assigns
+ if (parent[0] === 'assign' && parent[2][0] === 'name' && parent[2][1] === name + '$s' + data.primaryShift) return;
+ if (parent[0] === name + '$s' + data.primaryShift) return;
+ if (node[3][1] === data.primaryShift) {
+ return ['name', name + '$s' + data.primaryShift];
+ }
+ }
+ }, function() {
+ stack.pop();
+ });
+ cleanNotes();
+ var SIMPLE_SHIFTS = set('<<', '>>');
+ var more = true;
+ while (more) { // combine shifts in the same direction as an optimization
+ more = false;
+ traverse(fun, function(node, type) {
+ if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] === 'binary' && node[2][1] === node[1] &&
+ node[3][0] === 'num' && node[2][3][0] === 'num') { // do not turn a << b << c into a << b + c; while logically identical, it is slower
+ more = true;
+ return ['binary', node[1], node[2][2], ['num', node[3][1] + node[2][3][1]]];
+ }
+ });
+ }
+ // Before recombining, do some additional optimizations
+ traverse(fun, function(node, type) {
+ // Apply constant shifts onto constants
+ if (type === 'binary' && node[1] === '>>' && node[2][0] === 'num' && node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) {
+ var subNode = node[2];
+ var shifts = node[3][1];
+ var result = subNode[1] / Math.pow(2, shifts);
+ if (result % 1 === 0) {
+ subNode[1] = result;
+ return subNode;
+ }
+ }
+ // Optimize the case of ($a*80)>>2 into ($a*20)|0
+ if (type === 'binary' && node[1] in SIMPLE_SHIFTS &&
+ node[2][0] === 'binary' && node[2][1] === '*') {
+ var mulNode = node[2];
+ if (mulNode[2][0] === 'num') {
+ var temp = mulNode[2];
+ mulNode[2] = mulNode[3];
+ mulNode[3] = temp;
+ }
+ if (mulNode[3][0] === 'num') {
+ if (node[1] === '<<') {
+ mulNode[3][1] *= Math.pow(2, node[3][1]);
+ node[1] = '|';
+ node[3][1] = 0;
+ return node;
+ } else {
+ if (mulNode[3][1] % Math.pow(2, node[3][1]) === 0) {
+ mulNode[3][1] /= Math.pow(2, node[3][1]);
+ node[1] = '|';
+ node[3][1] = 0;
+ return node;
+ }
+ }
+ }
+ }
+ /* XXX - theoretically useful optimization(s), but commented out as not helpful in practice
+ // Transform (x << 2) >> 2 into x & mask or something even simpler
+ if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
+ node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' && node[3][1] === node[2][3][1]) {
+ var subNode = node[2];
+ var shifts = node[3][1];
+ var mask = ((0xffffffff << shifts) >>> shifts) | 0;
+ return ['binary', '&', subNode[2], ['num', mask]];
+ //return ['binary', '|', subNode[2], ['num', 0]];
+ //return subNode[2];
+ }
+ */
+ });
+ // Re-combine remaining shifts, to undo the breaking up we did before. may require reordering inside +'s
+ var stack = [];
+ traverse(fun, function(node, type) {
+ stack.push(node);
+ if (type === 'binary' && node[1] === '+' && (stack[stack.length-2][0] != 'binary' || stack[stack.length-2][1] !== '+')) {
+ // 'Flatten' added items
+ var addedItems = [];
+ function flatten(node) {
+ if (node[0] === 'binary' && node[1] === '+') {
+ flatten(node[2]);
+ flatten(node[3]);
+ } else {
+ addedItems.push(node);
+ }
+ }
+ flatten(node);
+ var originalOrder = addedItems.slice();
+ function key(node) { // a unique value for all relevant shifts for recombining, non-unique for stuff we don't need to bother with
+ function originalOrderKey(item) {
+ return -originalOrder.indexOf(item);
+ }
+ if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS) {
+ if (node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) return 2*node[3][1] + (node[1] === '>>' ? 100 : 0); // 0-106
+ return (node[1] === '>>' ? 20000 : 10000) + originalOrderKey(node);
+ }
+ if (node[0] === 'num') return -20000 + node[1];
+ return -10000 + originalOrderKey(node); // Don't modify the original order if we don't modify anything
+ }
+ for (var i = 0; i < addedItems.length; i++) {
+ if (addedItems[i][0] === 'string') return; // this node is not relevant for us
+ }
+ addedItems.sort(function(node1, node2) {
+ return key(node1) - key(node2);
+ });
+ // Regenerate items, now sorted
+ var i = 0;
+ while (i < addedItems.length-1) { // re-combine inside addedItems
+ var k = key(addedItems[i]), k1 = key(addedItems[i+1]);
+ if (k === k1 && k >= 0 && k1 <= 106) {
+ addedItems[i] = ['binary', addedItems[i][1], ['binary', '+', addedItems[i][2], addedItems[i+1][2]], addedItems[i][3]];
+ addedItems.splice(i+1, 1);
+ } else {
+ i++;
+ }
+ }
+ var num = 0;
+ for (i = 0; i < addedItems.length; i++) { // combine all numbers into one
+ if (addedItems[i][0] === 'num') {
+ num += addedItems[i][1];
+ addedItems.splice(i, 1);
+ i--;
+ }
+ }
+ if (num != 0) { // add the numbers into an existing shift, we
+ // prefer (x+5)>>7 over (x>>7)+5 , since >>'s result is known to be 32-bit and is more easily optimized.
+ // Also, in the former we can avoid the parentheses, which saves a little space (the number will be bigger,
+ // so it might take more space, but normally at most one more digit).
+ var added = false;
+ for (i = 0; i < addedItems.length; i++) {
+ if (addedItems[i][0] === 'binary' && addedItems[i][1] === '>>' && addedItems[i][3][0] === 'num' && addedItems[i][3][1] <= MAX_SHIFTS) {
+ addedItems[i] = ['binary', '>>', ['binary', '+', addedItems[i][2], ['num', num << addedItems[i][3][1]]], addedItems[i][3]];
+ added = true;
+ }
+ }
+ if (!added) {
+ addedItems.unshift(['num', num]);
+ }
+ }
+ var ret = addedItems.pop();
+ while (addedItems.length > 0) { // re-create AST from addedItems
+ ret = ['binary', '+', ret, addedItems.pop()];
+ }
+ return ret;
+ }
+ }, function() {
+ stack.pop();
+ });
+ // Note finished variables
+ for (var name in vars) {
+ funFinished[name] = true;
+ }
+ }
+ });
+}
+
+function optimizeShiftsConservative(ast) {
+ optimizeShiftsInternal(ast, true);
+}
+
+function optimizeShiftsAggressive(ast) {
+ optimizeShiftsInternal(ast, false);
+}
+
// We often have branchings that are simplified so one end vanishes, and
// we then get
// if (!(x < 5))
@@ -2087,12 +2481,18 @@ function registerizeHarder(ast) {
function pushActiveLabels(onContinue, onBreak) {
// Push the target junctions for continuing/breaking a loop.
// This should be called before traversing into a loop.
- var newLabels = copy(activeLabels[activeLabels.length-1]);
+ var prevLabels = activeLabels[activeLabels.length-1];
+ var newLabels = copy(prevLabels);
newLabels[null] = [onContinue, onBreak];
if (nextLoopLabel) {
newLabels[nextLoopLabel] = [onContinue, onBreak];
nextLoopLabel = null;
}
+ // An unlabelled 'continue' should jump to innermost loop,
+ // ignoring any nested 'switch' statements.
+ if (onContinue === null && prevLabels[null]) {
+ newLabels[null][0] = prevLabels[null][0];
+ }
activeLabels.push(newLabels);
}
@@ -5165,7 +5565,9 @@ function prepDotZero(ast) {
function fixDotZero(js) {
return js.replace(/DOT\$ZERO\(([-+]?(0x)?[0-9a-f]*\.?[0-9]+([eE][-+]?[0-9]+)?)\)/g, function(m, num) {
if (num.substr(0, 2) === '0x' || num.substr(0, 3) === '-0x') {
- return eval(num) + '.0';
+ var ret = eval(num).toString();
+ if (ret.indexOf('.') < 0) return ret + '.0';
+ return ret;
}
if (num.indexOf('.') >= 0) return num;
var e = num.indexOf('e');
@@ -5175,8 +5577,11 @@ function fixDotZero(js) {
}
function asmLastOpts(ast) {
+ var statsStack = [];
traverseGeneratedFunctions(ast, function(fun) {
traverse(fun, function(node, type) {
+ var stats = getStatements(node);
+ if (stats) statsStack.push(stats);
if (type === 'while' && node[1][0] === 'num' && node[1][1] === 1 && node[2][0] === 'block' && node[2].length == 2) {
// This is at the end of the pipeline, we can assume all other optimizations are done, and we modify loops
// into shapes that might confuse other passes
@@ -5184,15 +5589,28 @@ function asmLastOpts(ast) {
// while (1) { .. if (..) { break } } ==> do { .. } while(..)
var stats = node[2][1];
var last = stats[stats.length-1];
- if (last && last[0] === 'if' && !last[3] && last[2][0] === 'block' && last[2][1][0] && last[2][1][0][0] === 'break' && !last[2][1][0][1]) {
+ if (last && last[0] === 'if' && !last[3] && last[2][0] === 'block' && last[2][1][0]) {
+ var lastStats = last[2][1];
+ var lastNum = lastStats.length;
+ var lastLast = lastStats[lastNum-1];
+ if (!(lastLast[0] === 'break' && !lastLast[1])) return;// if not a simple break, dangerous
+ for (var i = 0; i < lastNum; i++) {
+ if (lastStats[i][0] !== 'stat' && lastStats[i][0] !== 'break') return; // something dangerous
+ }
+ // ok, a bunch of statements ending in a break
var abort = false;
var stack = 0;
+ var breaks = 0;
traverse(stats, function(node, type) {
- if (type == 'continue') {
- if (stack == 0 || node[1]) { // abort if labeled (we do not analyze labels here yet), or a continue directly on us
+ if (type === 'continue') {
+ if (stack === 0 || node[1]) { // abort if labeled (we do not analyze labels here yet), or a continue directly on us
abort = true;
return true;
}
+ } else if (type === 'break') {
+ if (stack === 0 || node[1]) { // relevant if labeled (we do not analyze labels here yet), or a break directly on us
+ breaks++;
+ }
} else if (type in LOOP) {
stack++;
}
@@ -5202,6 +5620,15 @@ function asmLastOpts(ast) {
}
});
if (abort) return;
+ assert(breaks > 0);
+ if (lastStats.length > 1 && breaks !== 1) return; // if we have code aside from the break, we can only move it out if there is just one break
+ // start to optimize
+ if (lastStats.length > 1) {
+ var parent = statsStack[statsStack.length-1];
+ var me = parent.indexOf(node);
+ if (me < 0) return; // not always directly on a stats, could be in a label for example
+ parent.splice.apply(parent, [me+1, 0].concat(lastStats.slice(0, lastStats.length-1)));
+ }
var conditionToBreak = last[1];
stats.pop();
node[0] = 'do';
@@ -5230,6 +5657,9 @@ function asmLastOpts(ast) {
}
}
}
+ }, function(node, type) {
+ var stats = getStatements(node);
+ if (stats) statsStack.pop();
});
});
}
@@ -5245,6 +5675,8 @@ var passes = {
removeAssignsToUndefined: removeAssignsToUndefined,
//removeUnneededLabelSettings: removeUnneededLabelSettings,
simplifyExpressions: simplifyExpressions,
+ optimizeShiftsConservative: optimizeShiftsConservative,
+ optimizeShiftsAggressive: optimizeShiftsAggressive,
simplifyIfs: simplifyIfs,
hoistMultiples: hoistMultiples,
loopOptimizer: loopOptimizer,
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index d0284528..2fad08b3 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -137,6 +137,10 @@ def run_on_js(filename, passes, js_engine, jcache, source_map=False, extra_info=
if closure:
passes = filter(lambda p: p != 'closure', passes) # we will do it manually
+ cleanup = 'cleanup' in passes
+ if cleanup:
+ passes = filter(lambda p: p != 'cleanup', passes) # we will do it manually
+
if not know_generated and jcache:
# JCache cannot be used without metadata, since it might reorder stuff, and that's dangerous since only generated can be reordered
# This means jcache does not work after closure compiler runs, for example. But you won't get much benefit from jcache with closure
@@ -216,10 +220,6 @@ EMSCRIPTEN_FUNCS();
funcs = split_funcs(js)
js = None
- if 'last' in passes and len(funcs) > 0:
- if max([len(func[1]) for func in funcs]) > 200000:
- print >> sys.stderr, 'warning: Output contains some very large functions, consider using OUTLINING_LIMIT to break them up (see settings.js)'
-
# if we are making source maps, we want our debug numbering to start from the
# top of the file, so avoid breaking the JS into chunks
cores = 1 if source_map else int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count())
@@ -291,23 +291,29 @@ EMSCRIPTEN_FUNCS();
for filename in filenames: temp_files.note(filename)
- if closure:
- # run closure on the shell code, everything but what we js-optimize
+ if closure or cleanup:
+ # run on the shell code, everything but what we js-optimize
start_asm = '// EMSCRIPTEN_START_ASM\n'
end_asm = '// EMSCRIPTEN_END_ASM\n'
- closure_sep = 'wakaUnknownBefore(); var asm=wakaUnknownAfter(global,env,buffer)\n'
+ cl_sep = 'wakaUnknownBefore(); var asm=wakaUnknownAfter(global,env,buffer)\n'
- closuree = temp_files.get('.closure.js').name
- c = open(closuree, 'w')
+ cle = temp_files.get('.cl.js').name
+ c = open(cle, 'w')
pre_1, pre_2 = pre.split(start_asm)
post_1, post_2 = post.split(end_asm)
c.write(pre_1)
- c.write(closure_sep)
+ c.write(cl_sep)
c.write(post_2)
c.close()
- closured = shared.Building.closure_compiler(closuree, pretty='minifyWhitespace' not in passes)
- temp_files.note(closured)
- coutput = open(closured).read()
+ if closure:
+ if DEBUG: print >> sys.stderr, 'running closure on shell code'
+ cld = shared.Building.closure_compiler(cle, pretty='minifyWhitespace' not in passes)
+ else:
+ if DEBUG: print >> sys.stderr, 'running cleanup on shell code'
+ cld = cle + '.js'
+ subprocess.Popen(js_engine + [JS_OPTIMIZER, cle, 'noPrintMetadata'] + (['minifyWhitespace'] if 'minifyWhitespace' in passes else []), stdout=open(cld, 'w')).communicate()
+ temp_files.note(cld)
+ coutput = open(cld).read()
coutput = coutput.replace('wakaUnknownBefore();', '')
after = 'wakaUnknownAfter'
start = coutput.find(after)
@@ -333,6 +339,12 @@ EMSCRIPTEN_FUNCS();
elif x[0] > y[0]: return -1
return 0
funcs.sort(sorter)
+
+ if 'last' in passes and len(funcs) > 0:
+ count = funcs[0][1].count('\n')
+ if count > 3000:
+ print >> sys.stderr, 'warning: Output contains some very large functions (%s lines in %s), consider building source files with -Os or -Oz, and/or trying OUTLINING_LIMIT to break them up (see settings.js; note that the parameter there affects AST nodes, while we measure lines here, so the two may not match up)' % (count, funcs[0][0])
+
for func in funcs:
f.write(func[1])
funcs = None
diff --git a/tools/jsrun.py b/tools/jsrun.py
index d63451db..6b7e295b 100644
--- a/tools/jsrun.py
+++ b/tools/jsrun.py
@@ -17,7 +17,7 @@ def timeout_run(proc, timeout=None, note='unnamed process', full_output=False):
logging.info('Process ' + str(proc.pid) + ' finished after ' + str(time.time() - start) + ' seconds. Exit code: ' + str(proc.returncode))
return '\n'.join(out) if full_output else out[0]
-def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False, assert_returncode=None):
+def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False, assert_returncode=0, error_limit=-1):
if type(engine) is not list:
engine = [engine]
command = engine + [filename] + (['--'] if 'd8' in engine[0] or 'jsc' in engine[0] else []) + args
@@ -36,5 +36,6 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo
'Execution',
full_output=full_output)
if assert_returncode is not None and proc.returncode is not assert_returncode:
- raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret))
+ raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)[:error_limit])
return ret
+
diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py
index a2a16f19..efaec8a3 100644
--- a/tools/settings_template_readonly.py
+++ b/tools/settings_template_readonly.py
@@ -7,7 +7,9 @@ import os
# this helps projects using emscripten find it
EMSCRIPTEN_ROOT = os.path.expanduser(os.getenv('EMSCRIPTEN') or '{{{ EMSCRIPTEN_ROOT }}}') # directory
LLVM_ROOT = os.path.expanduser(os.getenv('LLVM') or '{{{ LLVM_ROOT }}}') # directory
-PYTHON = os.path.expanduser(os.getenv('PYTHON') or '{{{ PYTHON }}}') # executable
+
+# If not specified, defaults to sys.executable.
+#PYTHON = 'python'
# See below for notes on which JS engine(s) you need
NODE_JS = os.path.expanduser(os.getenv('NODE') or '{{{ NODE }}}') # executable
diff --git a/tools/shared.py b/tools/shared.py
index 7aaa4136..0570d0a0 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -216,9 +216,6 @@ else:
config_file = config_file.replace('\'{{{ LLVM_ROOT }}}\'', repr(llvm_root))
node = find_executable('node') or find_executable('nodejs') or 'node'
config_file = config_file.replace('\'{{{ NODE }}}\'', repr(node))
- python = find_executable('python2') or find_executable('python') or \
- sys.executable or 'python'
- config_file = config_file.replace('\'{{{ PYTHON }}}\'', repr(python))
if WINDOWS:
tempdir = os.environ.get('TEMP') or os.environ.get('TMP') or 'c:\\temp'
else:
@@ -238,7 +235,6 @@ A settings file has been copied to %s, at absolute path: %s
It contains our best guesses for the important paths, which are:
LLVM_ROOT = %s
- PYTHON = %s
NODE_JS = %s
EMSCRIPTEN_ROOT = %s
@@ -246,7 +242,7 @@ Please edit the file if any of those are incorrect.
This command will now exit. When you are done editing those paths, re-run it.
==============================================================================
-''' % (EM_CONFIG, CONFIG_FILE, llvm_root, python, node, __rootpath__)
+''' % (EM_CONFIG, CONFIG_FILE, llvm_root, node, __rootpath__)
sys.exit(0)
try:
config_text = open(CONFIG_FILE, 'r').read() if CONFIG_FILE else EM_CONFIG
@@ -370,6 +366,17 @@ def find_temp_directory():
try:
EMSCRIPTEN_VERSION = open(path_from_root('emscripten-version.txt')).read().strip()
+ try:
+ parts = map(int, EMSCRIPTEN_VERSION.split('.'))
+ EMSCRIPTEN_VERSION_MAJOR = parts[0]
+ EMSCRIPTEN_VERSION_MINOR = parts[1]
+ EMSCRIPTEN_VERSION_TINY = parts[2]
+ except Exception, e:
+ logging.warning('emscripten version ' + EMSCRIPTEN_VERSION + ' lacks standard parts')
+ EMSCRIPTEN_VERSION_MAJOR = 0
+ EMSCRIPTEN_VERSION_MINOR = 0
+ EMSCRIPTEN_VERSION_TINY = 0
+ raise e
except Exception, e:
logging.error('cannot find emscripten version ' + str(e))
EMSCRIPTEN_VERSION = 'unknown'
@@ -640,8 +647,8 @@ except:
try:
PYTHON
except:
- logging.debug('PYTHON not defined in ~/.emscripten, using "python"')
- PYTHON = 'python'
+ logging.debug('PYTHON not defined in ~/.emscripten, using "%s"' % (sys.executable,))
+ PYTHON = sys.executable
try:
JAVA
@@ -666,7 +673,10 @@ try:
except:
COMPILER_OPTS = []
COMPILER_OPTS = COMPILER_OPTS + [#'-fno-threadsafe-statics', # disabled due to issue 1289
- '-target', LLVM_TARGET]
+ '-target', LLVM_TARGET,
+ '-D__EMSCRIPTEN_major__=' + str(EMSCRIPTEN_VERSION_MAJOR),
+ '-D__EMSCRIPTEN_minor__=' + str(EMSCRIPTEN_VERSION_MINOR),
+ '-D__EMSCRIPTEN_tiny__=' + str(EMSCRIPTEN_VERSION_TINY)]
# COMPILER_STANDARDIZATION_OPTS: Options to correct various predefined macro options.
COMPILER_STANDARDIZATION_OPTS = []
@@ -706,10 +716,9 @@ if USE_EMSDK:
path_from_root('system', 'include', 'compat'),
path_from_root('system', 'include'),
path_from_root('system', 'include', 'emscripten'),
- path_from_root('system', 'include', 'bsd'), # posix stuff
path_from_root('system', 'include', 'libc'),
+ path_from_root('system', 'lib', 'libc', 'musl', 'arch', 'js'),
path_from_root('system', 'include', 'gfx'),
- path_from_root('system', 'include', 'net'),
path_from_root('system', 'include', 'SDL'),
]
@@ -1004,7 +1013,7 @@ class Building:
# Append the Emscripten toolchain file if the user didn't specify one.
if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'):
- args.append('-DCMAKE_TOOLCHAIN_FILE=' + path_from_root('cmake', 'Platform', 'Emscripten.cmake'))
+ args.append('-DCMAKE_TOOLCHAIN_FILE=' + path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'))
# On Windows specify MinGW Makefiles if we have MinGW and no other toolchain was specified, to avoid CMake
# pulling in a native Visual Studio, or Unix Makefiles.
@@ -1019,16 +1028,21 @@ class Building:
return
if env is None:
env = Building.get_building_env()
- env['EMMAKEN_JUST_CONFIGURE'] = '1'
if 'cmake' in args[0]:
+ # Note: EMMAKEN_JUST_CONFIGURE shall not be enabled when configuring with CMake. This is because CMake
+ # does expect to be able to do config-time builds with emcc.
args = Building.handle_CMake_toolchain(args, env)
+ else:
+ # When we configure via a ./configure script, don't do config-time compilation with emcc, but instead
+ # do builds natively with Clang. This is a heuristic emulation that may or may not work.
+ env['EMMAKEN_JUST_CONFIGURE'] = '1'
try:
process = Popen(args, stdout=stdout, stderr=stderr, env=env)
process.communicate()
except Exception, e:
logging.error('Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args))
raise
- del env['EMMAKEN_JUST_CONFIGURE']
+ if 'EMMAKEN_JUST_CONFIGURE' in env: del env['EMMAKEN_JUST_CONFIGURE']
if process.returncode is not 0:
logging.error('Configure step failed with non-zero return code ' + str(process.returncode) + '! Command line: ' + str(args))
raise subprocess.CalledProcessError(cmd=args, returncode=process.returncode)
@@ -1422,16 +1436,22 @@ class Building:
os.environ['EMSCRIPTEN_SUPPRESS_USAGE_WARNING'] = '1'
# Run Emscripten
- Settings.RELOOPER = Cache.get_path('relooper.js')
+ if not os.path.exists(Settings.RELOOPER):
+ Settings.RELOOPER = Cache.get_path('relooper.js')
settings = Settings.serialize()
args = settings + extra_args
if WINDOWS:
- args = ['@' + response_file.create_response_file(args, TEMP_DIR)]
+ rsp_file = response_file.create_response_file(args, TEMP_DIR)
+ args = ['@' + rsp_file]
cmdline = [PYTHON, EMSCRIPTEN, filename + ('.o.ll' if append_ext else ''), '-o', filename + '.o.js'] + args
if jsrun.TRACK_PROCESS_SPAWNS:
logging.info('Executing emscripten.py compiler with cmdline "' + ' '.join(cmdline) + '"')
jsrun.timeout_run(Popen(cmdline, stdout=PIPE), None, 'Compiling')
+ # Clean up .rsp file the compiler used after we are finished.
+ if WINDOWS:
+ try_delete(rsp_file)
+
# Detect compilation crashes and errors
assert os.path.exists(filename + '.o.js'), 'Emscripten failed to generate .js'
@@ -1888,6 +1908,14 @@ def check_execute(cmd, *args, **kw):
logging.error("'%s' failed with output:\n%s" % (" ".join(e.cmd), e.output))
raise
+def check_call(cmd, *args, **kw):
+ try:
+ subprocess.check_call(cmd, *args, **kw)
+ logging.debug("Successfuly executed %s" % " ".join(cmd))
+ except subprocess.CalledProcessError as e:
+ logging.error("'%s' failed" % " ".join(cmd))
+ raise
+
def suffix(name):
parts = name.split('.')
if len(parts) > 1:
diff --git a/tools/system_libs.py b/tools/system_libs.py
index bc81a351..9e904b80 100644
--- a/tools/system_libs.py
+++ b/tools/system_libs.py
@@ -1,8 +1,23 @@
import os, json, logging
import shared
-from tools.shared import execute
+from subprocess import Popen, CalledProcessError
+import multiprocessing
+from tools.shared import check_call
+
+stdout = None
+stderr = None
+
+def call_process(cmd):
+ proc = Popen(cmd, stdout=stdout, stderr=stderr)
+ proc.communicate()
+ if proc.returncode != 0:
+ raise CalledProcessError(proc.returncode, cmd)
+
+def calculate(temp_files, in_temp, stdout_, stderr_):
+ global stdout, stderr
+ stdout = stdout_
+ stderr = stderr_
-def calculate(temp_files, in_temp, stdout, stderr):
# Check if we need to include some libraries that we compile. (We implement libc ourselves in js, but
# compile a malloc implementation and stdlibc++.)
@@ -24,26 +39,40 @@ def calculate(temp_files, in_temp, stdout, stderr):
# XXX we should disable EMCC_DEBUG when building libs, just like in the relooper
+ def run_commands(commands):
+ cores = int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count())
+ cores = min(len(commands), cores)
+ if cores <= 1:
+ for command in commands:
+ call_process(command)
+ else:
+ pool = multiprocessing.Pool(processes=cores)
+ pool.map(call_process, commands, chunksize=1)
+
def build_libc(lib_filename, files):
o_s = []
prev_cxx = os.environ.get('EMMAKEN_CXX')
if prev_cxx: os.environ['EMMAKEN_CXX'] = ''
musl_internal_includes = ['-I', shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal'), '-I', shared.path_from_root('system', 'lib', 'libc', 'musl', 'arch', 'js')]
+ commands = []
for src in files:
o = in_temp(os.path.basename(src) + '.o')
- execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o] + musl_internal_includes + lib_opts, stdout=stdout, stderr=stderr)
+ commands.append([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o] + musl_internal_includes + lib_opts)
o_s.append(o)
+ run_commands(commands)
if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
shared.Building.link(o_s, in_temp(lib_filename))
return in_temp(lib_filename)
def build_libcxx(src_dirname, lib_filename, files):
o_s = []
+ commands = []
for src in files:
o = in_temp(src + '.o')
srcfile = shared.path_from_root(src_dirname, src)
- execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + lib_opts, stdout=stdout, stderr=stderr)
+ commands.append([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + lib_opts)
o_s.append(o)
+ run_commands(commands)
shared.Building.link(o_s, in_temp(lib_filename))
return in_temp(lib_filename)
@@ -67,14 +96,27 @@ def calculate(temp_files, in_temp, stdout, stderr):
'shgetc.c',
]],
['math', [
+ 'frexp.c',
+ 'frexpf.c',
+ 'frexpl.c',
'scalbn.c',
'scalbnl.c',
]],
+ ['multibyte', [
+ 'wctomb.c',
+ 'wcrtomb.c',
+ ]],
['stdio', [
'__overflow.c',
'__toread.c',
'__towrite.c',
'__uflow.c',
+ 'fwrite.c',
+ 'snprintf.c',
+ 'sprintf.c',
+ 'vfprintf.c',
+ 'vsnprintf.c',
+ 'vsprintf.c',
]],
['stdlib', [
'atof.c',
@@ -84,6 +126,7 @@ def calculate(temp_files, in_temp, stdout, stderr):
'strtol.c',
]],
['string', [
+ 'memchr.c',
'memcmp.c',
'strcasecmp.c',
'strcmp.c',
@@ -220,6 +263,7 @@ def calculate(temp_files, in_temp, stdout, stderr):
'tgammal.c'
]],
['misc', [
+ 'ffs.c',
'getopt.c',
'getopt_long.c',
]],
@@ -234,12 +278,10 @@ def calculate(temp_files, in_temp, stdout, stderr):
'mbsrtowcs.c',
'mbstowcs.c',
'mbtowc.c',
- 'wcrtomb.c',
'wcsnrtombs.c',
'wcsrtombs.c',
'wcstombs.c',
'wctob.c',
- 'wctomb.c',
]],
['regex', [
'fnmatch.c',
@@ -249,6 +291,8 @@ def calculate(temp_files, in_temp, stdout, stderr):
'tre-mem.c',
]],
['stdio', [
+ '__string_read.c',
+ 'asprintf.c',
'fwprintf.c',
'swprintf.c',
'vfwprintf.c',
@@ -257,6 +301,10 @@ def calculate(temp_files, in_temp, stdout, stderr):
'wprintf.c',
'fputwc.c',
'fputws.c',
+ 'sscanf.c',
+ 'vasprintf.c',
+ 'vfscanf.c',
+ 'vsscanf.c',
]],
['stdlib', [
'atoll.c',
@@ -276,7 +324,6 @@ def calculate(temp_files, in_temp, stdout, stderr):
'memccpy.c',
'memmem.c',
'mempcpy.c',
- 'memchr.c',
'memrchr.c',
'rindex.c',
'stpcpy.c',
@@ -373,8 +420,9 @@ def calculate(temp_files, in_temp, stdout, stderr):
def create_libcxxabi():
logging.debug('building libcxxabi for cache')
libcxxabi_files = [
+ 'exception.cpp',
'typeinfo.cpp',
- 'private_typeinfo.cpp'
+ 'private_typeinfo.cpp',
]
return build_libcxx(os.path.join('system', 'lib', 'libcxxabi', 'src'), 'libcxxabi.bc', libcxxabi_files)
@@ -389,7 +437,7 @@ def calculate(temp_files, in_temp, stdout, stderr):
prev_cxx = os.environ.get('EMMAKEN_CXX')
if prev_cxx: os.environ['EMMAKEN_CXX'] = ''
o = in_temp('gl.o')
- execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
+ check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
return o
@@ -410,12 +458,18 @@ def calculate(temp_files, in_temp, stdout, stderr):
# TODO: Move all __deps from src/library*.js to deps_info.json, and use that single source of info
# both here and in the JS compiler.
deps_info = json.loads(open(shared.path_from_root('src', 'deps_info.json')).read())
+ added = set()
def add_back_deps(need):
+ more = False
for ident, deps in deps_info.iteritems():
- if ident in need.undefs:
+ if ident in need.undefs and not ident in added:
+ added.add(ident)
+ more = True
for dep in deps:
need.undefs.add(dep)
shared.Settings.EXPORTED_FUNCTIONS.append('_' + dep)
+ if more:
+ add_back_deps(need) # recurse to get deps of deps
for symbols in symbolses:
add_back_deps(symbols)
diff --git a/tools/test-js-optimizer-asm-last-output.js b/tools/test-js-optimizer-asm-last-output.js
index 1b9ac585..95afaeb7 100644
--- a/tools/test-js-optimizer-asm-last-output.js
+++ b/tools/test-js-optimizer-asm-last-output.js
@@ -30,6 +30,7 @@ function finall(x) {
a = -999999984306749400.0;
a = -999999984306749400.0;
a = -0xde0b6b000000000;
+ a = 1.1234567890123457e+21;
f(g() | 0);
return 12.0e10;
}
@@ -71,5 +72,31 @@ function looop() {
break;
}
}
+ do {
+ blah();
+ } while (!shah());
+ a = b;
+ LABELED : while (1) {
+ blah();
+ if (shah()) {
+ c = d;
+ break;
+ }
+ }
+ while (1) {
+ blah();
+ if (check) break;
+ if (shah()) {
+ e = f;
+ break;
+ }
+ }
+ do {
+ blah();
+ while (1) {
+ if (check) break;
+ }
+ } while (!shah());
+ g = h;
}
diff --git a/tools/test-js-optimizer-asm-last.js b/tools/test-js-optimizer-asm-last.js
index 1d39b1a6..6261e915 100644
--- a/tools/test-js-optimizer-asm-last.js
+++ b/tools/test-js-optimizer-asm-last.js
@@ -30,6 +30,7 @@ function finall(x) {
a = +-0xde0b6b000000000;
a = -+0xde0b6b000000000;
a = -0xde0b6b000000000;
+ a = +0x3ce7184d470dd60000;
f(g() & -1);
return +12e10;
}
@@ -86,6 +87,38 @@ function looop() {
break;
}
}
+ while (1) {
+ blah();
+ if (shah()) {
+ a = b;
+ break;
+ }
+ }
+ LABELED: while (1) {
+ blah();
+ if (shah()) {
+ c = d;
+ break;
+ }
+ }
+ while (1) {
+ blah();
+ if (check) break; // prevents optimization
+ if (shah()) {
+ e = f;
+ break;
+ }
+ }
+ while (1) {
+ blah();
+ while (1) {
+ if (check) break; // safe to optimize
+ }
+ if (shah()) {
+ g = h;
+ break;
+ }
+ }
}
// EMSCRIPTEN_GENERATED_FUNCTIONS: ["finall", "looop"]
diff --git a/tools/test-js-optimizer-t2-output.js b/tools/test-js-optimizer-t2-output.js
new file mode 100644
index 00000000..691d0a66
--- /dev/null
+++ b/tools/test-js-optimizer-t2-output.js
@@ -0,0 +1,108 @@
+function shifty($id2) {
+ var c1$s2;
+ var $tp$s2;
+ var $parameters_addr$s2;
+ var $wavelet38$s2;
+ var _dwt_norms_real$s2;
+ var $a_addr$s2;
+ var _idents$s2;
+ var $id3$s3;
+ var $id2$s1 = $id2 >> 1;
+ q(HEAP32[$id >> 2]);
+ q(HEAP32[$id + 40 >> 2]);
+ q(HEAP32[$id + 80 >> 2]);
+ q(HEAP32[unknown1 + unknown2 + $id >> 2]);
+ q(HEAP32[unknown1 + $id + unknown2 >> 2]);
+ var localUnchanged1 = get(1), localUnchanged2 = get(1);
+ q(HEAP32[localUnchanged1 + $id + localUnchanged2 >> 2]);
+ q($id >> _something_);
+ $id = q("..");
+ q($id << _somethingElse_);
+ pause(-1);
+ q(HEAP32[$id2$s1]);
+ q(HEAP32[$id2$s1]);
+ q(HEAP32[$id2$s1]);
+ q(HEAP32[$id2$s1]);
+ q(HEAP32[$id2$s1 + 20]);
+ q(HEAP32[$id2$s1 + 40]);
+ var $id3 = get(74), $id3$s3 = $id3 >> 3;
+ q(HEAP32[$id3$s3]);
+ q(HEAP32[$id3$s3 + 5]);
+ q(HEAP32[$id3$s3 + 10]);
+ q($id3);
+ pause(0);
+ var _idents = get("abc"), _idents$s2 = _idents >> 2;
+ q(HEAP32[HEAP32[_idents$s2] + 8 >> 2]);
+ q(HEAP32[HEAP32[_idents$s2] + 8 >> 2]);
+ q(HEAP32[HEAP32[_idents$s2] + 8 >> 2]);
+ pause(1);
+ var $sn_addr = get(12), $a_addr = get(999), $a_addr$s2 = $a_addr >> 2;
+ var $i = get(112233);
+ q(HEAP32[(($sn_addr - 1 << 1) + 1 << 2 >> 2) + $a_addr$s2]);
+ q(HEAP32[(($i - 1 << 1) + 1 << 2 >> 2) + $a_addr$s2]);
+ q(HEAP32[($i << 3 >> 2) + $a_addr$s2]);
+ q(HEAP32[($i << 2 >> 2) + $a_addr$s2]);
+ q($a_addr$s2, z($a_addr$s2));
+ pause(2);
+ var $level = HEAP[get(322) >> 2];
+ var _dwt_norms_real = get("a"), _dwt_norms_real$s2 = _dwt_norms_real >> 2, $orient = get("cheez");
+ q(HEAP32[($level << 3 >> 2) + _dwt_norms_real$s2 + ($orient * 20 | 0)]);
+ q(HEAP32[(($level << 3) + 4 >> 2) + _dwt_norms_real$s2 + ($orient * 20 | 0)]);
+ q(HEAP32[(($level << 3) + 8 >> 2) + _dwt_norms_real$s2 + ($orient * 20 | 0)]);
+ pause(3);
+ var $wavelet38 = get(38), $wavelet38$s2 = $wavelet38 >> 2;
+ $k = $a_addr;
+ q(HEAPF32[HEAP32[$wavelet38$s2] + ($k << 4) + 8 >> 2]);
+ q(HEAPF32[HEAP32[$wavelet38$s2] + ($k << 4) + 12 >> 2]);
+ q(HEAPF32[HEAP32[$wavelet38$s2] + ($k << 4) + 400 >> 2]);
+ pause(4);
+ var $p = $k, $parameters_addr = get("burger"), $parameters_addr$s2 = $parameters_addr >> 2;
+ q(HEAP32[(($p << 2) + 5624 >> 2) + $parameters_addr$s2]);
+ q(HEAP32[(($p << 2) + 5644 >> 2) + $parameters_addr$s2]);
+ q(HEAP32[(($p << 2) + 5664 >> 2) + $parameters_addr$s2]);
+ pause(5);
+ var $res_spec242 = get($real), $cp = get("b"), $tileno = arguments[2];
+ q(HEAP32[(($res_spec242 - 1 << 2) + 5624 >> 2) + $parameters_addr$s2]);
+ q(HEAP32[(HEAP32[$cp + 108 >> 2] + 420 >> 2) + ($tileno * 1397 | 0)]);
+ pause(6);
+ q($idx << 3);
+ q(1 << $idx << 1);
+ print(INDENT + "Entering: _main" + "hi");
+ pause(7);
+ var $tp = get("tp"), $tp$s2 = $tp >> 2;
+ q($tp$s2);
+ q($tp$s2);
+ q($tp$s2);
+ HEAP32[$H400] = $tp;
+ HEAP32[$tp] = 5;
+ HEAP32[$tp$s2] = 5;
+ HEAP32[HEAP[$tp$s2]] = 5;
+ HEAP32[HEAP[$tp$s2] >> 2] = 5;
+ pause(7);
+ q(go() >> 1 << 1);
+ q(go() << 1 >> 1);
+ q(go() >> 2);
+ q(go() << 2);
+ q(go() >> 8 << 8);
+ q(go() << 8 >> 8);
+ q(go() >> 16);
+ q(go() << 16);
+ q(go() + 2 >> 2);
+ var c1 = get(), c1$s2 = c1 >> 2;
+ HEAP32[c1$s2] = 1;
+ HEAP32[c1$s2 + 1] = 1;
+ HEAP32[(get() << 2 >> 2) + c1$s2] = 1;
+ var c2 = get();
+ HEAP32[c2 >> 2] = 1;
+ HEAP32[c2 + 3 >> 2] = 1;
+ HEAP32[c2 + (get() << 2) >> 2] = 1;
+ var c3 = get();
+ HEAP32[c3 >> 2] = 1;
+ HEAP32[c3 + 4 >> 2] = 1;
+ HEAP32[(get() << 1) + c3 >> 2] = 1;
+ var c4 = get(), c5 = get();
+ HEAP32[c4 >> 2] = 1;
+ HEAP32[c4 + 4 >> 2] = 1;
+ HEAP32[c4 + c5 >> 2] = 1;
+}
+
diff --git a/tools/test-js-optimizer-t2.js b/tools/test-js-optimizer-t2.js
new file mode 100644
index 00000000..d3b26996
--- /dev/null
+++ b/tools/test-js-optimizer-t2.js
@@ -0,0 +1,109 @@
+// TODO also with >> 1 and >> 3
+// also HEAP*U*, and HEAP8, 16
+function shifty($id2) {
+ // $id is a non-ssa, $id2 is a param. both should be replaced with a shifted version
+ q(HEAP32[$id >> 2]);
+ q(HEAP32[($id + 40) >> 2]);
+ q(HEAP32[($id + 80 | 0) >> 2]);
+ q(HEAP32[(unknown1 + unknown2 + $id) >> 2]);
+ q(HEAP32[(unknown1 + $id + unknown2) >> 2]); // unknowns should be shifted together
+ var localUnchanged1 = get(1), localUnchanged2 = get(1);
+ q(HEAP32[(localUnchanged1 + $id + localUnchanged2) >> 2]); // unknowns should be shifted together
+ q($id >> _something_); // non-fixed shift
+ $id = q('..');
+ q($id << _somethingElse_); // non-fixed shift
+ pause(-1);
+ q(HEAP32[$id2 >> 1]);
+ q(HEAP32[$id2 >> 1]);
+ q(HEAP32[$id2 >> 1]);
+ q(HEAP32[$id2 >> 1]);
+ q(HEAP32[($id2 + 40) >> 1]);
+ q(HEAP32[($id2 + 80 | 0) >> 1]);
+ var $id3 = get(74);
+ q(HEAP32[$id3 >> 3]);
+ q(HEAP32[($id3 + 40) >> 3]);
+ q(HEAP32[($id3 + 80 | 0) >> 3]);
+ q($id3);
+ pause(0);
+ // similar, but inside another HEAP
+ var _idents = get('abc');
+ q(HEAP32[(HEAP32[_idents >> 2] + 8 | 0) >> 2]);
+ q(HEAP32[(HEAP32[_idents >> 2] + 8 | 0) >> 2]);
+ q(HEAP32[(HEAP32[_idents >> 2] + 8 | 0) >> 2]);
+ pause(1);
+ // $i's shifts should consolidate (the last should be 0..?
+ // since we may have had |0 in the middle!)
+ var $sn_addr = get(12), $a_addr = get(999);
+ var $i = get(112233);
+ q(HEAP32[($a_addr + ((($sn_addr - 1 << 1) + 1 | 0) << 2) | 0) >> 2]);
+ q(HEAP32[($a_addr + ((($i - 1 << 1) + 1 | 0) << 2) | 0) >> 2]);
+ q(HEAP32[($a_addr + (($i << 1 | 0) << 2) | 0) >> 2]);
+ q(HEAP32[($a_addr + ($i << 2)) >> 2]);
+ q($a_addr >> 2, z($a_addr >> 2));
+ pause(2);
+ var $level = HEAP[get(322) >> 2]; // ignore this
+ var _dwt_norms_real = get('a'), $orient = get('cheez');
+ q(HEAP32[(_dwt_norms_real + $orient * 80 + ($level << 3) | 0) >> 2]);
+ q(HEAP32[(_dwt_norms_real + $orient * 80 + ($level << 3) + 4 | 0) >> 2]);
+ q(HEAP32[(_dwt_norms_real + $orient * 80 + ($level << 3) + 8 | 0) >> 2]);
+ pause(3);
+ // reuse $a_addr here
+ var $wavelet38 = get(38);
+ $k = $a_addr;
+ q(HEAPF32[(HEAP32[$wavelet38 >> 2] + ($k << 4) + 8 | 0) >> 2]);
+ q(HEAPF32[(HEAP32[$wavelet38 >> 2] + ($k << 4) + 12 | 0) >> 2]);
+ q(HEAPF32[(HEAP32[$wavelet38 >> 2] + ($k << 4) + 400 | 0) >> 2]);
+ pause(4);
+ // reuse $k, which already reuses $a_addr
+ var $p = $k, $parameters_addr = get('burger')
+ q(HEAP32[($parameters_addr + 5624 + ($p << 2) | 0) >> 2]);
+ q(HEAP32[($parameters_addr + 5644 + ($p << 2) | 0) >> 2]);
+ q(HEAP32[($parameters_addr + 5664 + ($p << 2) | 0) >> 2]);
+ pause(5);
+ // loops count as more uses!
+ var $res_spec242 = get($real), $cp = get('b'), $tileno = arguments[2];
+ q(HEAP32[($parameters_addr + 5624 + (($res_spec242 - 1 | 0) << 2) | 0) >> 2]);
+ q(HEAP32[(HEAP32[($cp + 108 | 0) >> 2] + $tileno * 5588 + 420 | 0) >> 2]);
+ pause(6);
+ q($idx << 1 << 2);
+ q(1 << $idx << 1); // Do not turn this into the slower 1 << $idx + 1 (which is identical though)
+ print(INDENT + "Entering: _main" + "hi"); // this order should not be modified
+ pause(7);
+ var $tp = get('tp');
+ q($tp >> 2);
+ q($tp >> 2);
+ q($tp >> 2);
+ HEAP32[$H400] = $tp;
+ HEAP32[$tp] = 5;
+ HEAP32[$tp >> 2] = 5;
+ HEAP32[HEAP[$tp >> 2]] = 5;
+ HEAP32[HEAP[$tp >> 2] >> 2] = 5;
+ pause(7);
+ q(go() >> 1 << 1);
+ q(go() << 1 >> 1);
+ q(go() >> 1 >> 1);
+ q(go() << 1 << 1);
+ q(go() >> 8 << 8);
+ q(go() << 8 >> 8);
+ q(go() >> 8 >> 8);
+ q(go() << 8 << 8);
+ q((go() + 2) >> 2); // the 2 >> 2 can't be simplified
+ // only values provable to have lower bits clear are ok
+ var c1 = get(); // ok
+ HEAP32[c1 >> 2] = 1;
+ HEAP32[c1 + 4 >> 2] = 1;
+ HEAP32[c1 + (get() << 2) >> 2] = 1;
+ var c2 = get(); // bad constant
+ HEAP32[c2 >> 2] = 1;
+ HEAP32[c2 + 3 >> 2] = 1;
+ HEAP32[c2 + (get() << 2) >> 2] = 1;
+ var c3 = get(); // bad revshift
+ HEAP32[c3 >> 2] = 1;
+ HEAP32[c3 + 4 >> 2] = 1;
+ HEAP32[c3 + (get() << 1) >> 2] = 1;
+ var c4 = get(), c5 = get(); // bad unknown var
+ HEAP32[c4 >> 2] = 1;
+ HEAP32[c4 + 4 >> 2] = 1;
+ HEAP32[c4 + c5 >> 2] = 1;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["shifty"]
diff --git a/tools/test-js-optimizer-t2c-output.js b/tools/test-js-optimizer-t2c-output.js
new file mode 100644
index 00000000..43cdf889
--- /dev/null
+++ b/tools/test-js-optimizer-t2c-output.js
@@ -0,0 +1,17 @@
+function shifty() {
+ $pPage = HEAP32[$pCur_addr + ($26 << 16 >> 16 << 2) + 116 >> 2];
+ var $ead_192394 = HEAP32[$pCur_addr + ($26 << 16 >> 16 << 2) + 116 >> 2];
+ $pPage2 = HEAP32[($26 << 16 >> 16 << 2) + $pCur_addr + 116];
+ var $ead_192394b = HEAP32[($26 << 16 >> 16 << 2) + $pCur_addr + 116];
+ $pPage2 = HEAP32[($26 << 16 >> 16) + $pCur_addr + 116];
+ var $ead_192394b = HEAP32[($26 << 16 >> 16) + $pCur_addr + 116];
+ q(4);
+ q($13 + 8 >> 2);
+ q($13 + 28 >> 2);
+ q($13 + 60 >> 2);
+ q($13 + $15 + 12 >> 2);
+ q(HEAPF32[$output + ($j37 << 4) + 4 >> 2]);
+ q($13 + 13 << 2);
+ q(h() >> 2 << 2);
+}
+
diff --git a/tools/test-js-optimizer-t2c.js b/tools/test-js-optimizer-t2c.js
new file mode 100644
index 00000000..85292ba5
--- /dev/null
+++ b/tools/test-js-optimizer-t2c.js
@@ -0,0 +1,18 @@
+function shifty() {
+ $pPage = HEAP32[$pCur_addr + 116 + ($26 << 16 >> 16 << 2) >> 2];
+ var $ead_192394 = HEAP32[$pCur_addr + 116 + ($26 << 16 >> 16 << 2) >> 2];
+ $pPage2 = HEAP32[$pCur_addr + 116 + ($26 << 16 >> 16 << 2)];
+ var $ead_192394b = HEAP32[$pCur_addr + 116 + ($26 << 16 >> 16 << 2)];
+ $pPage2 = HEAP32[$pCur_addr + 116 + ($26 << 16 >> 16)];
+ var $ead_192394b = HEAP32[$pCur_addr + 116 + ($26 << 16 >> 16)];
+ // We prefer to do additions then shifts, so the shift happens last, because the shift output is known to be 32-bit. So these should not change
+ q(16 >> 2);
+ q($13 + 8 >> 2);
+ q(28 + $13 >> 2);
+ q(48 + $13 + 12 >> 2);
+ q($13 + $15 + 12 >> 2);
+ q(HEAPF32[$output + ($j37 << 4) + 4 >> 2]);
+ q(5 + $13 + 8 << 2);
+ q(((h() | 0) >> 2) << 2); // removing the shifts is dangerous
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["shifty"]
diff --git a/tools/test-js-optimizer-t3-output.js b/tools/test-js-optimizer-t3-output.js
new file mode 100644
index 00000000..9a16c2ac
--- /dev/null
+++ b/tools/test-js-optimizer-t3-output.js
@@ -0,0 +1,49 @@
+function _png_create_write_struct_2($user_png_ver, $error_ptr, $error_fn, $warn_fn, $mem_ptr, $malloc_fn, $free_fn) {
+ var $png_ptr$s2;
+ var label;
+ label = 2;
+ var setjmpTable = {
+ "2": (function(value) {
+ label = 5;
+ $call1 = value;
+ }),
+ dummy: 0
+ };
+ while (1) try {
+ switch (label) {
+ case 2:
+ var $png_ptr;
+ var $call = _png_create_struct(1);
+ $png_ptr = $call;
+ var $call1 = (HEAP32[$png_ptr >> 2] = label, 0);
+ label = 5;
+ break;
+ case 5:
+ var $2 = $png_ptr;
+ if (($call1 | 0) == 0) {
+ label = 4;
+ break;
+ } else {
+ label = 3;
+ break;
+ }
+ case 3:
+ var $4 = HEAP32[($png_ptr >> 2) + (148 >> 2)];
+ _png_free($2, $4);
+ HEAP32[($png_ptr >> 2) + (148 >> 2)] = 0;
+ _png_destroy_struct($png_ptr);
+ var $retval_0 = 0;
+ label = 4;
+ break;
+ case 4:
+ var $retval_0;
+ return $retval_0;
+ default:
+ assert(0, "bad label: " + label);
+ }
+ } catch (e) {
+ if (!e.longjmp) throw e;
+ setjmpTable[e.label](e.value);
+ }
+}
+
diff --git a/tools/test-js-optimizer-t3.js b/tools/test-js-optimizer-t3.js
new file mode 100644
index 00000000..0e02f72b
--- /dev/null
+++ b/tools/test-js-optimizer-t3.js
@@ -0,0 +1,50 @@
+function _png_create_write_struct_2($user_png_ver, $error_ptr, $error_fn, $warn_fn, $mem_ptr, $malloc_fn, $free_fn) {
+ var $png_ptr$s2;
+ var label;
+ label = 2;
+ var setjmpTable = {
+ "2": (function(value) {
+ label = 5;
+ $call1 = value;
+ }),
+ dummy: 0
+ };
+ while (1) try {
+ switch (label) {
+ case 2:
+ var $png_ptr;
+ var $call = _png_create_struct(1);
+ $png_ptr = $call;
+ var $call1 = (HEAP32[$png_ptr >> 2] = label, 0);
+ label = 5;
+ break;
+ case 5:
+ var $2 = $png_ptr;
+ if (($call1 | 0) == 0) {
+ label = 4;
+ break;
+ } else {
+ label = 3;
+ break;
+ }
+ case 3:
+ var $4 = HEAP32[($png_ptr >> 2) + (148 >> 2)];
+ _png_free($2, $4);
+ HEAP32[($png_ptr >> 2) + (148 >> 2)] = 0;
+ _png_destroy_struct($png_ptr);
+ var $retval_0 = 0;
+ label = 4;
+ break;
+ case 4:
+ var $retval_0;
+ return $retval_0;
+ default:
+ assert(0, "bad label: " + label);
+ }
+ } catch (e) {
+ if (!e.longjmp) throw e;
+ setjmpTable[e.label](e.value);
+ }
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["_png_create_write_struct_2"]
+
diff --git a/tools/validate_asmjs.py b/tools/validate_asmjs.py
index 4136af93..02ff506d 100644
--- a/tools/validate_asmjs.py
+++ b/tools/validate_asmjs.py
@@ -16,7 +16,7 @@ import shared
# Looks up SpiderMonkey engine using the variable SPIDERMONKEY_ENGINE in ~/.emscripten, and if not set up there, via PATH.
def find_spidermonkey_engine():
- sm_engine = shared.SPIDERMONKEY_ENGINE if hasattr(shared, 'SPIDERMONKEY_ENGINE') else ['']
+ sm_engine = shared.listify(shared.SPIDERMONKEY_ENGINE) if hasattr(shared, 'SPIDERMONKEY_ENGINE') else ['']
if not sm_engine or len(sm_engine[0]) == 0 or not os.path.exists(sm_engine[0]):
sm_engine[0] = shared.Building.which('js')
if sm_engine[0] == None:
@@ -25,17 +25,25 @@ def find_spidermonkey_engine():
# Given a .js file, returns True/False depending on if that file is valid asm.js
def validate_asmjs_jsfile(filename, muteOutput):
- process = subprocess.Popen(find_spidermonkey_engine() + ['-c', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ cmd = find_spidermonkey_engine() + ['-c', filename]
+ if cmd[0] == 'js-not-found':
+ print >> sys.stderr, 'Could not find SpiderMonkey engine! Please set tis location to SPIDERMONKEY_ENGINE in your ~/.emscripten configuration file!'
+ return False
+ try:
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ except Exception, e:
+ print >> sys.stderr, 'Executing command ' + str(cmd) + ' failed due to an exception: ' + str(e) + '!'
+ return False
(stdout, stderr) = process.communicate()
if not muteOutput:
if len(stdout.strip()) > 0:
print stdout.strip()
if len(stderr.strip()) > 0:
# Pretty-print the output not to contain a spurious warning.
- stderr = stderr.replace('warning: successfully compiled asm.js', ' successfully compiled asm.js')
-
+ warning_re = re.compile(re.escape('warning: successfully compiled asm.js'), re.IGNORECASE)
+ stderr = warning_re.sub(' successfully compiled asm.js', stderr)
print >> sys.stderr, stderr.strip()
- if 'successfully compiled asm.js' in stderr:
+ if 'successfully compiled asm.js' in stderr.lower():
return True
else:
return False