webruby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/webruby +36 -0
- data/driver/driver.c +50 -0
- data/driver/main.c +40 -0
- data/lib/webruby/app.rb +13 -0
- data/lib/webruby/config.rb +61 -0
- data/lib/webruby/environment.rb +32 -0
- data/lib/webruby/rake/files.rake +66 -0
- data/lib/webruby/rake/general.rake +22 -0
- data/lib/webruby/rake/mruby.rake +44 -0
- data/lib/webruby/utility.rb +132 -0
- data/lib/webruby.rb +10 -0
- data/modules/emscripten/AUTHORS +89 -0
- data/modules/emscripten/LICENSE +68 -0
- data/modules/emscripten/README.markdown +14 -0
- data/modules/emscripten/cmake/Platform/Emscripten.cmake +61 -0
- data/modules/emscripten/cmake/Platform/Emscripten_unix.cmake +24 -0
- data/modules/emscripten/em++ +12 -0
- data/modules/emscripten/em++.bat +2 -0
- data/modules/emscripten/em-config +24 -0
- data/modules/emscripten/em-config.bat +2 -0
- data/modules/emscripten/emar +24 -0
- data/modules/emscripten/emar.bat +2 -0
- data/modules/emscripten/emcc +1744 -0
- data/modules/emscripten/emcc.bat +2 -0
- data/modules/emscripten/emcc.py +5 -0
- data/modules/emscripten/emconfigure +27 -0
- data/modules/emscripten/emconfigure.bat +2 -0
- data/modules/emscripten/emlibtool +11 -0
- data/modules/emscripten/emlibtool.bat +2 -0
- data/modules/emscripten/emlink.py +293 -0
- data/modules/emscripten/emmake +29 -0
- data/modules/emscripten/emmake.bat +2 -0
- data/modules/emscripten/emranlib +9 -0
- data/modules/emscripten/emranlib.bat +2 -0
- data/modules/emscripten/emscons +20 -0
- data/modules/emscripten/emscripten.py +835 -0
- data/modules/emscripten/patches/README +4 -0
- data/modules/emscripten/patches/series +2 -0
- data/modules/emscripten/scons-tools/closure.py +28 -0
- data/modules/emscripten/scons-tools/emscripten.py +359 -0
- data/modules/emscripten/scons-tools/llvm.py +33 -0
- data/modules/emscripten/src/analyzer.js +1695 -0
- data/modules/emscripten/src/compiler.html +48 -0
- data/modules/emscripten/src/compiler.js +298 -0
- data/modules/emscripten/src/corruptionCheck.js +98 -0
- data/modules/emscripten/src/determinstic.js +20 -0
- data/modules/emscripten/src/embind/embind.js +1677 -0
- data/modules/emscripten/src/embind/emval.js +283 -0
- data/modules/emscripten/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff +97 -0
- data/modules/emscripten/src/experimental/batching.diff +44 -0
- data/modules/emscripten/src/experimental/functypeopt.diff +113 -0
- data/modules/emscripten/src/experimental/multiple_heaps.diff +175 -0
- data/modules/emscripten/src/experimental/noncallgraphprofiling.diff +197 -0
- data/modules/emscripten/src/experimental/optimize_memcpy_for_ta1.diff +124 -0
- data/modules/emscripten/src/experimental/remove__label__s.diff +140 -0
- data/modules/emscripten/src/experimental/renderer_cache_hash.diff +99 -0
- data/modules/emscripten/src/experimental/sdl_key_forwarding.diff +57 -0
- data/modules/emscripten/src/experimental/simplifyGeneratedFunctionsDetection.diff +336 -0
- data/modules/emscripten/src/experimental/stringCache.diff +147 -0
- data/modules/emscripten/src/fastLong.js +299 -0
- data/modules/emscripten/src/framework.js +257 -0
- data/modules/emscripten/src/gl-matrix.js +1952 -0
- data/modules/emscripten/src/headless.js +904 -0
- data/modules/emscripten/src/intertyper.js +1050 -0
- data/modules/emscripten/src/jsifier.js +1827 -0
- data/modules/emscripten/src/library.js +8270 -0
- data/modules/emscripten/src/library_browser.js +911 -0
- data/modules/emscripten/src/library_egl.js +491 -0
- data/modules/emscripten/src/library_gc.js +236 -0
- data/modules/emscripten/src/library_gl.js +4452 -0
- data/modules/emscripten/src/library_glfw.js +576 -0
- data/modules/emscripten/src/library_glut.js +449 -0
- data/modules/emscripten/src/library_jansson.js +320 -0
- data/modules/emscripten/src/library_openal.js +602 -0
- data/modules/emscripten/src/library_sdl.js +2024 -0
- data/modules/emscripten/src/library_strtok_r.c +97 -0
- data/modules/emscripten/src/library_xlib.js +23 -0
- data/modules/emscripten/src/long.js +1609 -0
- data/modules/emscripten/src/modules.js +491 -0
- data/modules/emscripten/src/parseTools.js +2474 -0
- data/modules/emscripten/src/postamble.js +170 -0
- data/modules/emscripten/src/postamble_sharedlib.js +16 -0
- data/modules/emscripten/src/preamble.js +914 -0
- data/modules/emscripten/src/preamble_sharedlib.js +25 -0
- data/modules/emscripten/src/relooper/README.markdown +14 -0
- data/modules/emscripten/src/relooper/Relooper.cpp +1236 -0
- data/modules/emscripten/src/relooper/Relooper.h +250 -0
- data/modules/emscripten/src/relooper/doit.sh +70 -0
- data/modules/emscripten/src/relooper/emscripten/glue.js +57 -0
- data/modules/emscripten/src/relooper/emscripten/test.js +44 -0
- data/modules/emscripten/src/relooper/fuzzer.py +116 -0
- data/modules/emscripten/src/relooper/ministring.h +35 -0
- data/modules/emscripten/src/relooper/paper.pdf +0 -0
- data/modules/emscripten/src/relooper/test.cpp +262 -0
- data/modules/emscripten/src/relooper/test.txt +155 -0
- data/modules/emscripten/src/relooper/test2.c +44 -0
- data/modules/emscripten/src/relooper/test2.txt +12 -0
- data/modules/emscripten/src/relooper/test3.c +42 -0
- data/modules/emscripten/src/relooper/test3.txt +27 -0
- data/modules/emscripten/src/relooper/test4.cpp +40 -0
- data/modules/emscripten/src/relooper/test4.txt +23 -0
- data/modules/emscripten/src/relooper/test5.cpp +40 -0
- data/modules/emscripten/src/relooper/test5.txt +32 -0
- data/modules/emscripten/src/relooper/test6.cpp +31 -0
- data/modules/emscripten/src/relooper/test6.txt +12 -0
- data/modules/emscripten/src/relooper/test_dead.cpp +28 -0
- data/modules/emscripten/src/relooper/test_dead.txt +9 -0
- data/modules/emscripten/src/relooper/test_debug.cpp +30 -0
- data/modules/emscripten/src/relooper/test_debug.txt +128 -0
- data/modules/emscripten/src/relooper/test_fuzz1.cpp +52 -0
- data/modules/emscripten/src/relooper/test_fuzz1.txt +32 -0
- data/modules/emscripten/src/relooper/test_fuzz2.cpp +34 -0
- data/modules/emscripten/src/relooper/test_fuzz2.txt +13 -0
- data/modules/emscripten/src/relooper/test_fuzz3.cpp +36 -0
- data/modules/emscripten/src/relooper/test_fuzz3.txt +9 -0
- data/modules/emscripten/src/relooper/test_fuzz4.cpp +38 -0
- data/modules/emscripten/src/relooper/test_fuzz4.txt +19 -0
- data/modules/emscripten/src/relooper/test_fuzz5.cpp +57 -0
- data/modules/emscripten/src/relooper/test_fuzz5.txt +52 -0
- data/modules/emscripten/src/relooper/test_fuzz6.cpp +322 -0
- data/modules/emscripten/src/relooper/test_fuzz6.txt +108 -0
- data/modules/emscripten/src/relooper/test_inf.cpp +813 -0
- data/modules/emscripten/src/relooper/test_inf.txt +385 -0
- data/modules/emscripten/src/relooper/testit.sh +62 -0
- data/modules/emscripten/src/relooper/updateit.sh +17 -0
- data/modules/emscripten/src/relooper.js +11516 -0
- data/modules/emscripten/src/relooper.js.raw.js +11511 -0
- data/modules/emscripten/src/runtime.js +546 -0
- data/modules/emscripten/src/settings.js +1284 -0
- data/modules/emscripten/src/shell.html +92 -0
- data/modules/emscripten/src/shell.js +153 -0
- data/modules/emscripten/src/shell_sharedlib.js +12 -0
- data/modules/emscripten/src/socket.io.js +3870 -0
- data/modules/emscripten/src/utility.js +379 -0
- data/modules/emscripten/src/wrtcp.js +821 -0
- data/modules/emscripten/system/include/AL/al.h +172 -0
- data/modules/emscripten/system/include/AL/alc.h +84 -0
- data/modules/emscripten/system/include/EGL/egl.h +329 -0
- data/modules/emscripten/system/include/EGL/eglext.h +398 -0
- data/modules/emscripten/system/include/EGL/eglplatform.h +141 -0
- data/modules/emscripten/system/include/GL/freeglut_std.h +628 -0
- data/modules/emscripten/system/include/GL/gl.h +2241 -0
- data/modules/emscripten/system/include/GL/glew.h +6 -0
- data/modules/emscripten/system/include/GL/glext.h +11127 -0
- data/modules/emscripten/system/include/GL/glfw.h +518 -0
- data/modules/emscripten/system/include/GL/glu.h +353 -0
- data/modules/emscripten/system/include/GL/glut.h +21 -0
- data/modules/emscripten/system/include/GLES/gl.h +770 -0
- data/modules/emscripten/system/include/GLES/glext.h +1278 -0
- data/modules/emscripten/system/include/GLES/glplatform.h +30 -0
- data/modules/emscripten/system/include/GLES2/gl2.h +621 -0
- data/modules/emscripten/system/include/GLES2/gl2ext.h +803 -0
- data/modules/emscripten/system/include/GLES2/gl2platform.h +30 -0
- data/modules/emscripten/system/include/KHR/khrplatform.h +277 -0
- data/modules/emscripten/system/include/SDL/COPYING +19 -0
- data/modules/emscripten/system/include/SDL/SDL.h +162 -0
- data/modules/emscripten/system/include/SDL/SDL_assert.h +241 -0
- data/modules/emscripten/system/include/SDL/SDL_atomic.h +318 -0
- data/modules/emscripten/system/include/SDL/SDL_audio.h +509 -0
- data/modules/emscripten/system/include/SDL/SDL_blendmode.h +60 -0
- data/modules/emscripten/system/include/SDL/SDL_clipboard.h +75 -0
- data/modules/emscripten/system/include/SDL/SDL_compat.h +365 -0
- data/modules/emscripten/system/include/SDL/SDL_config.h +48 -0
- data/modules/emscripten/system/include/SDL/SDL_config.h.in +297 -0
- data/modules/emscripten/system/include/SDL/SDL_config_android.h +133 -0
- data/modules/emscripten/system/include/SDL/SDL_config_iphoneos.h +148 -0
- data/modules/emscripten/system/include/SDL/SDL_config_macosx.h +172 -0
- data/modules/emscripten/system/include/SDL/SDL_config_minimal.h +74 -0
- data/modules/emscripten/system/include/SDL/SDL_config_nintendods.h +129 -0
- data/modules/emscripten/system/include/SDL/SDL_config_pandora.h +125 -0
- data/modules/emscripten/system/include/SDL/SDL_config_windows.h +207 -0
- data/modules/emscripten/system/include/SDL/SDL_config_wiz.h +119 -0
- data/modules/emscripten/system/include/SDL/SDL_copying.h +20 -0
- data/modules/emscripten/system/include/SDL/SDL_cpuinfo.h +150 -0
- data/modules/emscripten/system/include/SDL/SDL_endian.h +248 -0
- data/modules/emscripten/system/include/SDL/SDL_error.h +77 -0
- data/modules/emscripten/system/include/SDL/SDL_events.h +639 -0
- data/modules/emscripten/system/include/SDL/SDL_gesture.h +91 -0
- data/modules/emscripten/system/include/SDL/SDL_gfxPrimitives.h +246 -0
- data/modules/emscripten/system/include/SDL/SDL_haptic.h +1200 -0
- data/modules/emscripten/system/include/SDL/SDL_hints.h +206 -0
- data/modules/emscripten/system/include/SDL/SDL_image.h +138 -0
- data/modules/emscripten/system/include/SDL/SDL_input.h +87 -0
- data/modules/emscripten/system/include/SDL/SDL_joystick.h +208 -0
- data/modules/emscripten/system/include/SDL/SDL_keyboard.h +169 -0
- data/modules/emscripten/system/include/SDL/SDL_keycode.h +344 -0
- data/modules/emscripten/system/include/SDL/SDL_loadso.h +85 -0
- data/modules/emscripten/system/include/SDL/SDL_log.h +211 -0
- data/modules/emscripten/system/include/SDL/SDL_main.h +98 -0
- data/modules/emscripten/system/include/SDL/SDL_mixer.h +634 -0
- data/modules/emscripten/system/include/SDL/SDL_mouse.h +213 -0
- data/modules/emscripten/system/include/SDL/SDL_mutex.h +248 -0
- data/modules/emscripten/system/include/SDL/SDL_name.h +11 -0
- data/modules/emscripten/system/include/SDL/SDL_opengl.h +11116 -0
- data/modules/emscripten/system/include/SDL/SDL_opengles.h +38 -0
- data/modules/emscripten/system/include/SDL/SDL_opengles2.h +38 -0
- data/modules/emscripten/system/include/SDL/SDL_pixels.h +423 -0
- data/modules/emscripten/system/include/SDL/SDL_platform.h +160 -0
- data/modules/emscripten/system/include/SDL/SDL_power.h +79 -0
- data/modules/emscripten/system/include/SDL/SDL_quit.h +58 -0
- data/modules/emscripten/system/include/SDL/SDL_rect.h +136 -0
- data/modules/emscripten/system/include/SDL/SDL_render.h +615 -0
- data/modules/emscripten/system/include/SDL/SDL_revision.h +2 -0
- data/modules/emscripten/system/include/SDL/SDL_revision.h.orig +2 -0
- data/modules/emscripten/system/include/SDL/SDL_rotozoom.h +123 -0
- data/modules/emscripten/system/include/SDL/SDL_rwops.h +220 -0
- data/modules/emscripten/system/include/SDL/SDL_scancode.h +398 -0
- data/modules/emscripten/system/include/SDL/SDL_shape.h +147 -0
- data/modules/emscripten/system/include/SDL/SDL_stdinc.h +764 -0
- data/modules/emscripten/system/include/SDL/SDL_surface.h +499 -0
- data/modules/emscripten/system/include/SDL/SDL_syswm.h +241 -0
- data/modules/emscripten/system/include/SDL/SDL_thread.h +182 -0
- data/modules/emscripten/system/include/SDL/SDL_timer.h +108 -0
- data/modules/emscripten/system/include/SDL/SDL_touch.h +124 -0
- data/modules/emscripten/system/include/SDL/SDL_ttf.h +249 -0
- data/modules/emscripten/system/include/SDL/SDL_types.h +29 -0
- data/modules/emscripten/system/include/SDL/SDL_version.h +166 -0
- data/modules/emscripten/system/include/SDL/SDL_video.h +820 -0
- data/modules/emscripten/system/include/SDL/begin_code.h +135 -0
- data/modules/emscripten/system/include/SDL/close_code.h +37 -0
- data/modules/emscripten/system/include/X11/X.h +717 -0
- data/modules/emscripten/system/include/X11/Xatom.h +79 -0
- data/modules/emscripten/system/include/X11/Xfuncproto.h +127 -0
- data/modules/emscripten/system/include/X11/Xlib.h +4023 -0
- data/modules/emscripten/system/include/X11/Xosdefs.h +116 -0
- data/modules/emscripten/system/include/X11/Xutil.h +826 -0
- data/modules/emscripten/system/include/X11/keysym.h +73 -0
- data/modules/emscripten/system/include/X11/keysymdef.h +2389 -0
- data/modules/emscripten/system/include/bsd/float.h +91 -0
- data/modules/emscripten/system/include/bsd/readme.txt +2 -0
- data/modules/emscripten/system/include/bsd/sys/mman.h +180 -0
- data/modules/emscripten/system/include/bsd/sys/utsname.h +70 -0
- data/modules/emscripten/system/include/dlfcn.h +31 -0
- data/modules/emscripten/system/include/emscripten/bind.h +1210 -0
- data/modules/emscripten/system/include/emscripten/emscripten.h +388 -0
- data/modules/emscripten/system/include/emscripten/val.h +311 -0
- data/modules/emscripten/system/include/emscripten/wire.h +393 -0
- data/modules/emscripten/system/include/err.h +95 -0
- data/modules/emscripten/system/include/execinfo.h +44 -0
- data/modules/emscripten/system/include/features.h +3 -0
- data/modules/emscripten/system/include/gc.h +70 -0
- data/modules/emscripten/system/include/gfx/png.h +3798 -0
- data/modules/emscripten/system/include/gfx/pngconf.h +1665 -0
- data/modules/emscripten/system/include/gfx/tiff.h +654 -0
- data/modules/emscripten/system/include/gfx/tiffconf.h +104 -0
- data/modules/emscripten/system/include/gfx/tiffio.h +526 -0
- data/modules/emscripten/system/include/gfx/tiffvers.h +9 -0
- data/modules/emscripten/system/include/jansson.h +323 -0
- data/modules/emscripten/system/include/jansson_config.h +54 -0
- data/modules/emscripten/system/include/libc/_ansi.h +135 -0
- data/modules/emscripten/system/include/libc/_syslist.h +40 -0
- data/modules/emscripten/system/include/libc/alloca.h +21 -0
- data/modules/emscripten/system/include/libc/ar.h +69 -0
- data/modules/emscripten/system/include/libc/argz.h +33 -0
- data/modules/emscripten/system/include/libc/assert.h +46 -0
- data/modules/emscripten/system/include/libc/complex.h +124 -0
- data/modules/emscripten/system/include/libc/ctype.h +196 -0
- data/modules/emscripten/system/include/libc/dirent.h +16 -0
- data/modules/emscripten/system/include/libc/endian.h +3 -0
- data/modules/emscripten/system/include/libc/envlock.h +15 -0
- data/modules/emscripten/system/include/libc/envz.h +16 -0
- data/modules/emscripten/system/include/libc/errno.h +11 -0
- data/modules/emscripten/system/include/libc/fastmath.h +13 -0
- data/modules/emscripten/system/include/libc/fcntl.h +1 -0
- data/modules/emscripten/system/include/libc/fnmatch.h +55 -0
- data/modules/emscripten/system/include/libc/getopt.h +196 -0
- data/modules/emscripten/system/include/libc/glob.h +89 -0
- data/modules/emscripten/system/include/libc/grp.h +94 -0
- data/modules/emscripten/system/include/libc/iconv.h +62 -0
- data/modules/emscripten/system/include/libc/ieeefp.h +256 -0
- data/modules/emscripten/system/include/libc/ifaddrs.h +64 -0
- data/modules/emscripten/system/include/libc/inttypes.h +290 -0
- data/modules/emscripten/system/include/libc/iso646.h +43 -0
- data/modules/emscripten/system/include/libc/langinfo.h +316 -0
- data/modules/emscripten/system/include/libc/libgen.h +23 -0
- data/modules/emscripten/system/include/libc/limits.h +155 -0
- data/modules/emscripten/system/include/libc/locale.h +80 -0
- data/modules/emscripten/system/include/libc/machine/_default_types.h +121 -0
- data/modules/emscripten/system/include/libc/machine/_types.h +8 -0
- data/modules/emscripten/system/include/libc/machine/ansi.h +1 -0
- data/modules/emscripten/system/include/libc/machine/endian.h +31 -0
- data/modules/emscripten/system/include/libc/machine/fastmath.h +100 -0
- data/modules/emscripten/system/include/libc/machine/ieeefp.h +376 -0
- data/modules/emscripten/system/include/libc/machine/malloc.h +8 -0
- data/modules/emscripten/system/include/libc/machine/param.h +1 -0
- data/modules/emscripten/system/include/libc/machine/setjmp-dj.h +43 -0
- data/modules/emscripten/system/include/libc/machine/setjmp.h +361 -0
- data/modules/emscripten/system/include/libc/machine/stdlib.h +8 -0
- data/modules/emscripten/system/include/libc/machine/termios.h +1 -0
- data/modules/emscripten/system/include/libc/machine/time.h +19 -0
- data/modules/emscripten/system/include/libc/machine/types.h +30 -0
- data/modules/emscripten/system/include/libc/malloc.h +169 -0
- data/modules/emscripten/system/include/libc/math.h +594 -0
- data/modules/emscripten/system/include/libc/newlib.h +2 -0
- data/modules/emscripten/system/include/libc/paths.h +7 -0
- data/modules/emscripten/system/include/libc/process.h +44 -0
- data/modules/emscripten/system/include/libc/pthread.h +362 -0
- data/modules/emscripten/system/include/libc/pwd.h +78 -0
- data/modules/emscripten/system/include/libc/readme.txt +3 -0
- data/modules/emscripten/system/include/libc/reent.h +183 -0
- data/modules/emscripten/system/include/libc/regdef.h +7 -0
- data/modules/emscripten/system/include/libc/regex.h +102 -0
- data/modules/emscripten/system/include/libc/sched.h +97 -0
- data/modules/emscripten/system/include/libc/search.h +59 -0
- data/modules/emscripten/system/include/libc/setjmp.h +20 -0
- data/modules/emscripten/system/include/libc/signal.h +30 -0
- data/modules/emscripten/system/include/libc/stdarg.h +50 -0
- data/modules/emscripten/system/include/libc/stddef.h +64 -0
- data/modules/emscripten/system/include/libc/stdint.h +493 -0
- data/modules/emscripten/system/include/libc/stdio.h +694 -0
- data/modules/emscripten/system/include/libc/stdlib.h +230 -0
- data/modules/emscripten/system/include/libc/string.h +105 -0
- data/modules/emscripten/system/include/libc/strings.h +35 -0
- data/modules/emscripten/system/include/libc/sys/_default_fcntl.h +223 -0
- data/modules/emscripten/system/include/libc/sys/_types.h +93 -0
- data/modules/emscripten/system/include/libc/sys/cdefs.h +123 -0
- data/modules/emscripten/system/include/libc/sys/config.h +255 -0
- data/modules/emscripten/system/include/libc/sys/custom_file.h +2 -0
- data/modules/emscripten/system/include/libc/sys/dir.h +10 -0
- data/modules/emscripten/system/include/libc/sys/dirent.h +58 -0
- data/modules/emscripten/system/include/libc/sys/errno.h +190 -0
- data/modules/emscripten/system/include/libc/sys/fcntl.h +4 -0
- data/modules/emscripten/system/include/libc/sys/features.h +212 -0
- data/modules/emscripten/system/include/libc/sys/file.h +2 -0
- data/modules/emscripten/system/include/libc/sys/iconvnls.h +77 -0
- data/modules/emscripten/system/include/libc/sys/lock.h +24 -0
- data/modules/emscripten/system/include/libc/sys/param.h +25 -0
- data/modules/emscripten/system/include/libc/sys/queue.h +471 -0
- data/modules/emscripten/system/include/libc/sys/reent.h +843 -0
- data/modules/emscripten/system/include/libc/sys/resource.h +59 -0
- data/modules/emscripten/system/include/libc/sys/sched.h +67 -0
- data/modules/emscripten/system/include/libc/sys/signal.h +314 -0
- data/modules/emscripten/system/include/libc/sys/stat.h +222 -0
- data/modules/emscripten/system/include/libc/sys/stdio.h +27 -0
- data/modules/emscripten/system/include/libc/sys/string.h +2 -0
- data/modules/emscripten/system/include/libc/sys/syslimits.h +65 -0
- data/modules/emscripten/system/include/libc/sys/termios.h +280 -0
- data/modules/emscripten/system/include/libc/sys/time.h +85 -0
- data/modules/emscripten/system/include/libc/sys/timeb.h +39 -0
- data/modules/emscripten/system/include/libc/sys/times.h +28 -0
- data/modules/emscripten/system/include/libc/sys/ttydefaults.h +97 -0
- data/modules/emscripten/system/include/libc/sys/types.h +481 -0
- data/modules/emscripten/system/include/libc/sys/unistd.h +514 -0
- data/modules/emscripten/system/include/libc/sys/utime.h +26 -0
- data/modules/emscripten/system/include/libc/sys/wait.h +40 -0
- data/modules/emscripten/system/include/libc/tar.h +39 -0
- data/modules/emscripten/system/include/libc/termios.h +7 -0
- data/modules/emscripten/system/include/libc/time.h +273 -0
- data/modules/emscripten/system/include/libc/unctrl.h +46 -0
- data/modules/emscripten/system/include/libc/unistd.h +6 -0
- data/modules/emscripten/system/include/libc/utime.h +12 -0
- data/modules/emscripten/system/include/libc/utmp.h +8 -0
- data/modules/emscripten/system/include/libc/wchar.h +194 -0
- data/modules/emscripten/system/include/libc/wctype.h +47 -0
- data/modules/emscripten/system/include/libc/wordexp.h +53 -0
- data/modules/emscripten/system/include/libcxx/CREDITS.TXT +91 -0
- data/modules/emscripten/system/include/libcxx/LICENSE.txt +76 -0
- data/modules/emscripten/system/include/libcxx/__bit_reference +1268 -0
- data/modules/emscripten/system/include/libcxx/__config +485 -0
- data/modules/emscripten/system/include/libcxx/__debug +193 -0
- data/modules/emscripten/system/include/libcxx/__functional_03 +2130 -0
- data/modules/emscripten/system/include/libcxx/__functional_base +437 -0
- data/modules/emscripten/system/include/libcxx/__functional_base_03 +1087 -0
- data/modules/emscripten/system/include/libcxx/__hash_table +1945 -0
- data/modules/emscripten/system/include/libcxx/__locale +1435 -0
- data/modules/emscripten/system/include/libcxx/__mutex_base +438 -0
- data/modules/emscripten/system/include/libcxx/__split_buffer +654 -0
- data/modules/emscripten/system/include/libcxx/__sso_allocator +77 -0
- data/modules/emscripten/system/include/libcxx/__std_stream +317 -0
- data/modules/emscripten/system/include/libcxx/__tree +2293 -0
- data/modules/emscripten/system/include/libcxx/__tuple +305 -0
- data/modules/emscripten/system/include/libcxx/__tuple_03 +27 -0
- data/modules/emscripten/system/include/libcxx/__undef_min_max +19 -0
- data/modules/emscripten/system/include/libcxx/algorithm +5458 -0
- data/modules/emscripten/system/include/libcxx/array +341 -0
- data/modules/emscripten/system/include/libcxx/atomic +1521 -0
- data/modules/emscripten/system/include/libcxx/bitset +1081 -0
- data/modules/emscripten/system/include/libcxx/cassert +25 -0
- data/modules/emscripten/system/include/libcxx/ccomplex +29 -0
- data/modules/emscripten/system/include/libcxx/cctype +164 -0
- data/modules/emscripten/system/include/libcxx/cerrno +393 -0
- data/modules/emscripten/system/include/libcxx/cfenv +82 -0
- data/modules/emscripten/system/include/libcxx/cfloat +78 -0
- data/modules/emscripten/system/include/libcxx/chrono +898 -0
- data/modules/emscripten/system/include/libcxx/cinttypes +259 -0
- data/modules/emscripten/system/include/libcxx/ciso646 +25 -0
- data/modules/emscripten/system/include/libcxx/climits +48 -0
- data/modules/emscripten/system/include/libcxx/clocale +53 -0
- data/modules/emscripten/system/include/libcxx/cmath +1683 -0
- data/modules/emscripten/system/include/libcxx/codecvt +547 -0
- data/modules/emscripten/system/include/libcxx/complex +1526 -0
- data/modules/emscripten/system/include/libcxx/complex.h +35 -0
- data/modules/emscripten/system/include/libcxx/condition_variable +256 -0
- data/modules/emscripten/system/include/libcxx/csetjmp +52 -0
- data/modules/emscripten/system/include/libcxx/csignal +58 -0
- data/modules/emscripten/system/include/libcxx/cstdarg +48 -0
- data/modules/emscripten/system/include/libcxx/cstdbool +32 -0
- data/modules/emscripten/system/include/libcxx/cstddef +103 -0
- data/modules/emscripten/system/include/libcxx/cstdint +191 -0
- data/modules/emscripten/system/include/libcxx/cstdio +175 -0
- data/modules/emscripten/system/include/libcxx/cstdlib +172 -0
- data/modules/emscripten/system/include/libcxx/cstring +112 -0
- data/modules/emscripten/system/include/libcxx/ctgmath +29 -0
- data/modules/emscripten/system/include/libcxx/ctime +72 -0
- data/modules/emscripten/system/include/libcxx/cwchar +208 -0
- data/modules/emscripten/system/include/libcxx/cwctype +213 -0
- data/modules/emscripten/system/include/libcxx/deque +2846 -0
- data/modules/emscripten/system/include/libcxx/exception +250 -0
- data/modules/emscripten/system/include/libcxx/ext/__hash +46 -0
- data/modules/emscripten/system/include/libcxx/ext/hash_map +1003 -0
- data/modules/emscripten/system/include/libcxx/ext/hash_set +657 -0
- data/modules/emscripten/system/include/libcxx/forward_list +1636 -0
- data/modules/emscripten/system/include/libcxx/fstream +1415 -0
- data/modules/emscripten/system/include/libcxx/functional +2063 -0
- data/modules/emscripten/system/include/libcxx/future +2505 -0
- data/modules/emscripten/system/include/libcxx/initializer_list +105 -0
- data/modules/emscripten/system/include/libcxx/iomanip +504 -0
- data/modules/emscripten/system/include/libcxx/ios +988 -0
- data/modules/emscripten/system/include/libcxx/iosfwd +194 -0
- data/modules/emscripten/system/include/libcxx/iostream +60 -0
- data/modules/emscripten/system/include/libcxx/istream +1713 -0
- data/modules/emscripten/system/include/libcxx/iterator +1869 -0
- data/modules/emscripten/system/include/libcxx/limits +809 -0
- data/modules/emscripten/system/include/libcxx/list +2275 -0
- data/modules/emscripten/system/include/libcxx/locale +4591 -0
- data/modules/emscripten/system/include/libcxx/map +1924 -0
- data/modules/emscripten/system/include/libcxx/memory +5437 -0
- data/modules/emscripten/system/include/libcxx/mutex +566 -0
- data/modules/emscripten/system/include/libcxx/new +117 -0
- data/modules/emscripten/system/include/libcxx/numeric +197 -0
- data/modules/emscripten/system/include/libcxx/ostream +1286 -0
- data/modules/emscripten/system/include/libcxx/queue +717 -0
- data/modules/emscripten/system/include/libcxx/random +6750 -0
- data/modules/emscripten/system/include/libcxx/ratio +487 -0
- data/modules/emscripten/system/include/libcxx/readme.txt +1 -0
- data/modules/emscripten/system/include/libcxx/regex +6439 -0
- data/modules/emscripten/system/include/libcxx/scoped_allocator +578 -0
- data/modules/emscripten/system/include/libcxx/set +1025 -0
- data/modules/emscripten/system/include/libcxx/sstream +888 -0
- data/modules/emscripten/system/include/libcxx/stack +292 -0
- data/modules/emscripten/system/include/libcxx/stdexcept +162 -0
- data/modules/emscripten/system/include/libcxx/streambuf +564 -0
- data/modules/emscripten/system/include/libcxx/string +3987 -0
- data/modules/emscripten/system/include/libcxx/strstream +400 -0
- data/modules/emscripten/system/include/libcxx/support/solaris/floatingpoint.h +5 -0
- data/modules/emscripten/system/include/libcxx/support/solaris/wchar.h +38 -0
- data/modules/emscripten/system/include/libcxx/support/solaris/xlocale.h +146 -0
- data/modules/emscripten/system/include/libcxx/support/win32/limits_win32.h +79 -0
- data/modules/emscripten/system/include/libcxx/support/win32/locale_win32.h +116 -0
- data/modules/emscripten/system/include/libcxx/support/win32/math_win32.h +113 -0
- data/modules/emscripten/system/include/libcxx/support/win32/support.h +115 -0
- data/modules/emscripten/system/include/libcxx/system_error +636 -0
- data/modules/emscripten/system/include/libcxx/tgmath.h +29 -0
- data/modules/emscripten/system/include/libcxx/thread +459 -0
- data/modules/emscripten/system/include/libcxx/tuple +1092 -0
- data/modules/emscripten/system/include/libcxx/type_traits +3040 -0
- data/modules/emscripten/system/include/libcxx/typeindex +103 -0
- data/modules/emscripten/system/include/libcxx/typeinfo +124 -0
- data/modules/emscripten/system/include/libcxx/unordered_map +1864 -0
- data/modules/emscripten/system/include/libcxx/unordered_set +1144 -0
- data/modules/emscripten/system/include/libcxx/utility +583 -0
- data/modules/emscripten/system/include/libcxx/valarray +4779 -0
- data/modules/emscripten/system/include/libcxx/vector +3228 -0
- data/modules/emscripten/system/include/memory.h +10 -0
- data/modules/emscripten/system/include/mntent.h +23 -0
- data/modules/emscripten/system/include/net/arpa/inet.h +32 -0
- data/modules/emscripten/system/include/net/arpa/nameser.h +535 -0
- data/modules/emscripten/system/include/net/arpa/nameser_compat.h +187 -0
- data/modules/emscripten/system/include/net/if.h +87 -0
- data/modules/emscripten/system/include/net/netinet/in.h +166 -0
- data/modules/emscripten/system/include/net/netinet/tcp.h +246 -0
- data/modules/emscripten/system/include/net/resolv.h +389 -0
- data/modules/emscripten/system/include/netdb.h +94 -0
- data/modules/emscripten/system/include/nl_types.h +19 -0
- data/modules/emscripten/system/include/poll.h +3 -0
- data/modules/emscripten/system/include/pty.h +6 -0
- data/modules/emscripten/system/include/semaphore.h +31 -0
- data/modules/emscripten/system/include/spawn.h +105 -0
- data/modules/emscripten/system/include/stdbool.h +16 -0
- data/modules/emscripten/system/include/sys/bitypes.h +3 -0
- data/modules/emscripten/system/include/sys/io.h +14 -0
- data/modules/emscripten/system/include/sys/ioctl.h +26 -0
- data/modules/emscripten/system/include/sys/poll.h +31 -0
- data/modules/emscripten/system/include/sys/select.h +14 -0
- data/modules/emscripten/system/include/sys/socket.h +101 -0
- data/modules/emscripten/system/include/sys/socketvar.h +3 -0
- data/modules/emscripten/system/include/sys/statvfs.h +32 -0
- data/modules/emscripten/system/include/sys/sysctl.h +14 -0
- data/modules/emscripten/system/include/sys/uio.h +22 -0
- data/modules/emscripten/system/include/sys/un.h +66 -0
- data/modules/emscripten/system/include/sysexits.h +108 -0
- data/modules/emscripten/system/include/unwind.h +154 -0
- data/modules/emscripten/system/include/xlocale.h +47 -0
- data/modules/emscripten/system/include/zconf.h +428 -0
- data/modules/emscripten/system/include/zlib.h +1613 -0
- data/modules/emscripten/system/lib/compiler-rt/LICENSE.TXT +97 -0
- data/modules/emscripten/system/lib/compiler-rt/divdi3.c +47 -0
- data/modules/emscripten/system/lib/compiler-rt/int_endianness.h +116 -0
- data/modules/emscripten/system/lib/compiler-rt/int_lib.h +46 -0
- data/modules/emscripten/system/lib/compiler-rt/int_math.h +67 -0
- data/modules/emscripten/system/lib/compiler-rt/int_types.h +140 -0
- data/modules/emscripten/system/lib/compiler-rt/int_util.h +29 -0
- data/modules/emscripten/system/lib/compiler-rt/muldi3.c +56 -0
- data/modules/emscripten/system/lib/compiler-rt/readme.txt +20 -0
- data/modules/emscripten/system/lib/compiler-rt/udivdi3.c +36 -0
- data/modules/emscripten/system/lib/compiler-rt/udivmoddi4.c +251 -0
- data/modules/emscripten/system/lib/debugging.cpp +24 -0
- data/modules/emscripten/system/lib/dlmalloc.c +6299 -0
- data/modules/emscripten/system/lib/embind/bind.cpp +63 -0
- data/modules/emscripten/system/lib/libc/gen/err.c +49 -0
- data/modules/emscripten/system/lib/libc/gen/errx.c +49 -0
- data/modules/emscripten/system/lib/libc/gen/verr.c +58 -0
- data/modules/emscripten/system/lib/libc/gen/verrx.c +51 -0
- data/modules/emscripten/system/lib/libc/gen/vwarn.c +55 -0
- data/modules/emscripten/system/lib/libc/gen/vwarnx.c +48 -0
- data/modules/emscripten/system/lib/libc/gen/warn.c +49 -0
- data/modules/emscripten/system/lib/libc/gen/warnx.c +49 -0
- data/modules/emscripten/system/lib/libc/musl/COPYRIGHT +92 -0
- data/modules/emscripten/system/lib/libc/musl/readme.txt +1 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/alpha.h +125 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswalnum.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswalpha.c +14 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswblank.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswcntrl.c +10 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswctype.c +63 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswdigit.c +9 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswgraph.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswlower.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswprint.c +19 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswpunct.c +12 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswspace.c +19 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswupper.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/iswxdigit.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/nonspacing.h +62 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/punct.h +109 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/towctrans.c +268 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/wcswidth.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/wctrans.c +16 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/wcwidth.c +29 -0
- data/modules/emscripten/system/lib/libc/musl/src/ctype/wide.h +42 -0
- data/modules/emscripten/system/lib/libc/musl/src/internal/libc.c +22 -0
- data/modules/emscripten/system/lib/libc/musl/src/internal/libc.h +71 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/btowc.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/internal.c +38 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/internal.h +22 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mblen.c +17 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbrlen.c +18 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbrtowc.c +57 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbsinit.c +17 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbsnrtowcs.c +65 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbsrtowcs.c +100 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbstowcs.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/mbtowc.c +53 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/wcrtomb.c +38 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/wcsnrtombs.c +52 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/wcsrtombs.c +58 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/wcstombs.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/wctob.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/multibyte/wctomb.c +18 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcpcpy.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcpncpy.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcscasecmp.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcscasecmp_l.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcscat.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcschr.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcscmp.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcscpy.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcscspn.c +10 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsdup.c +11 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcslen.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsncasecmp.c +9 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsncasecmp_l.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsncat.c +10 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsncmp.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsncpy.c +9 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsnlen.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcspbrk.c +7 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsrchr.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsspn.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcsstr.c +108 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcstok.c +12 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wcswcs.c +6 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wmemchr.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wmemcmp.c +8 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wmemcpy.c +9 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wmemmove.c +12 -0
- data/modules/emscripten/system/lib/libc/musl/src/string/wmemset.c +9 -0
- data/modules/emscripten/system/lib/libc/stdlib/getopt_long.c +511 -0
- data/modules/emscripten/system/lib/libc/stdlib/strtod.c +305 -0
- data/modules/emscripten/system/lib/libc.symbols +81 -0
- data/modules/emscripten/system/lib/libcextra.symbols +61 -0
- data/modules/emscripten/system/lib/libcxx/CREDITS.TXT +91 -0
- data/modules/emscripten/system/lib/libcxx/LICENSE.txt +76 -0
- data/modules/emscripten/system/lib/libcxx/algorithm.cpp +83 -0
- data/modules/emscripten/system/lib/libcxx/bind.cpp +30 -0
- data/modules/emscripten/system/lib/libcxx/chrono.cpp +132 -0
- data/modules/emscripten/system/lib/libcxx/condition_variable.cpp +81 -0
- data/modules/emscripten/system/lib/libcxx/debug.cpp +504 -0
- data/modules/emscripten/system/lib/libcxx/exception.cpp +226 -0
- data/modules/emscripten/system/lib/libcxx/future.cpp +285 -0
- data/modules/emscripten/system/lib/libcxx/hash.cpp +564 -0
- data/modules/emscripten/system/lib/libcxx/ios.cpp +455 -0
- data/modules/emscripten/system/lib/libcxx/iostream.cpp +68 -0
- data/modules/emscripten/system/lib/libcxx/locale.cpp +6093 -0
- data/modules/emscripten/system/lib/libcxx/memory.cpp +223 -0
- data/modules/emscripten/system/lib/libcxx/mutex.cpp +250 -0
- data/modules/emscripten/system/lib/libcxx/new.cpp +205 -0
- data/modules/emscripten/system/lib/libcxx/random.cpp +48 -0
- data/modules/emscripten/system/lib/libcxx/readme.txt +1 -0
- data/modules/emscripten/system/lib/libcxx/regex.cpp +325 -0
- data/modules/emscripten/system/lib/libcxx/stdexcept.cpp +196 -0
- data/modules/emscripten/system/lib/libcxx/string.cpp +687 -0
- data/modules/emscripten/system/lib/libcxx/strstream.cpp +329 -0
- data/modules/emscripten/system/lib/libcxx/support/solaris/README +4 -0
- data/modules/emscripten/system/lib/libcxx/support/solaris/mbsnrtowcs.inc +76 -0
- data/modules/emscripten/system/lib/libcxx/support/solaris/wcsnrtombs.inc +93 -0
- data/modules/emscripten/system/lib/libcxx/support/solaris/xlocale.c +245 -0
- data/modules/emscripten/system/lib/libcxx/support/win32/locale_win32.cpp +94 -0
- data/modules/emscripten/system/lib/libcxx/support/win32/support.cpp +70 -0
- data/modules/emscripten/system/lib/libcxx/symbols +2927 -0
- data/modules/emscripten/system/lib/libcxx/system_error.cpp +201 -0
- data/modules/emscripten/system/lib/libcxx/thread.cpp +208 -0
- data/modules/emscripten/system/lib/libcxx/typeinfo.cpp +60 -0
- data/modules/emscripten/system/lib/libcxx/utility.cpp +17 -0
- data/modules/emscripten/system/lib/libcxx/valarray.cpp +54 -0
- data/modules/emscripten/system/lib/libcxxabi/CREDITS.TXT +38 -0
- data/modules/emscripten/system/lib/libcxxabi/LICENSE.TXT +76 -0
- data/modules/emscripten/system/lib/libcxxabi/include/cxa_demangle.h +167 -0
- data/modules/emscripten/system/lib/libcxxabi/include/cxxabi.h +175 -0
- data/modules/emscripten/system/lib/libcxxabi/lib/buildit +99 -0
- data/modules/emscripten/system/lib/libcxxabi/readme.txt +1 -0
- data/modules/emscripten/system/lib/libcxxabi/src/abort_message.cpp +50 -0
- data/modules/emscripten/system/lib/libcxxabi/src/abort_message.h +33 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_aux_runtime.cpp +34 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_demangle.cpp +11036 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_exception.cpp +622 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_exception.hpp +123 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_exception_storage.cpp +91 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_guard.cpp +231 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_handlers.cpp +125 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_handlers.hpp +54 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_new_delete.cpp +242 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_personality.cpp +1055 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_unexpected.cpp +27 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_vector.cpp +367 -0
- data/modules/emscripten/system/lib/libcxxabi/src/cxa_virtual.cpp +31 -0
- data/modules/emscripten/system/lib/libcxxabi/src/exception.cpp +41 -0
- data/modules/emscripten/system/lib/libcxxabi/src/fallback_malloc.ipp +174 -0
- data/modules/emscripten/system/lib/libcxxabi/src/private_typeinfo.cpp +1146 -0
- data/modules/emscripten/system/lib/libcxxabi/src/private_typeinfo.h +248 -0
- data/modules/emscripten/system/lib/libcxxabi/src/stdexcept.cpp +169 -0
- data/modules/emscripten/system/lib/libcxxabi/src/typeinfo.cpp +53 -0
- data/modules/emscripten/system/lib/libcxxabi/symbols +236 -0
- data/modules/emscripten/system/lib/sdl.cpp +13 -0
- data/modules/emscripten/system/lib/sdl.symbols +1 -0
- data/modules/emscripten/tests/hello_world.js +92 -0
- data/modules/emscripten/third_party/CppHeaderParser/CppHeaderParser/CppHeaderParser.py +2347 -0
- data/modules/emscripten/third_party/CppHeaderParser/CppHeaderParser/__init__.py +4 -0
- data/modules/emscripten/third_party/CppHeaderParser/CppHeaderParser/doc/CppHeaderParser.html +657 -0
- data/modules/emscripten/third_party/CppHeaderParser/CppHeaderParser/examples/SampleClass.h +147 -0
- data/modules/emscripten/third_party/CppHeaderParser/CppHeaderParser/examples/readSampleClass.py +74 -0
- data/modules/emscripten/third_party/CppHeaderParser/PKG-INFO +249 -0
- data/modules/emscripten/third_party/CppHeaderParser/README.html +544 -0
- data/modules/emscripten/third_party/CppHeaderParser/README.txt +226 -0
- data/modules/emscripten/third_party/CppHeaderParser/setup.py +43 -0
- data/modules/emscripten/third_party/ansidecl.h +371 -0
- data/modules/emscripten/third_party/closure-compiler/COPYING +202 -0
- data/modules/emscripten/third_party/closure-compiler/README +292 -0
- data/modules/emscripten/third_party/closure-compiler/compiler.jar +0 -0
- data/modules/emscripten/third_party/closure-compiler/readme.txt +3 -0
- data/modules/emscripten/third_party/cp-demangle.h +161 -0
- data/modules/emscripten/third_party/demangle.h +549 -0
- data/modules/emscripten/third_party/demangler.py +49 -0
- data/modules/emscripten/third_party/gcc_demangler.c +4226 -0
- data/modules/emscripten/third_party/gcc_demangler.js +21282 -0
- data/modules/emscripten/third_party/jni/emjvm.cpp +133 -0
- data/modules/emscripten/third_party/jni/emjvm.h +8 -0
- data/modules/emscripten/third_party/jni/emjvm.js +185 -0
- data/modules/emscripten/third_party/jni/jni.h +1154 -0
- data/modules/emscripten/third_party/libiberty.h +634 -0
- data/modules/emscripten/third_party/lzma.js/README.markdown +37 -0
- data/modules/emscripten/third_party/lzma.js/doit.sh +37 -0
- data/modules/emscripten/third_party/lzma.js/lzip/AUTHORS +7 -0
- data/modules/emscripten/third_party/lzma.js/lzip/COPYING +676 -0
- data/modules/emscripten/third_party/lzma.js/lzip/ChangeLog +201 -0
- data/modules/emscripten/third_party/lzma.js/lzip/INSTALL +56 -0
- data/modules/emscripten/third_party/lzma.js/lzip/Makefile +160 -0
- data/modules/emscripten/third_party/lzma.js/lzip/Makefile.in +138 -0
- data/modules/emscripten/third_party/lzma.js/lzip/NEWS +22 -0
- data/modules/emscripten/third_party/lzma.js/lzip/README +77 -0
- data/modules/emscripten/third_party/lzma.js/lzip/arg_parser.cc +204 -0
- data/modules/emscripten/third_party/lzma.js/lzip/arg_parser.h +106 -0
- data/modules/emscripten/third_party/lzma.js/lzip/configure +192 -0
- data/modules/emscripten/third_party/lzma.js/lzip/decoder.cc +252 -0
- data/modules/emscripten/third_party/lzma.js/lzip/decoder.h +268 -0
- data/modules/emscripten/third_party/lzma.js/lzip/encoder.cc +643 -0
- data/modules/emscripten/third_party/lzma.js/lzip/encoder.h +582 -0
- data/modules/emscripten/third_party/lzma.js/lzip/fast_encoder.cc +378 -0
- data/modules/emscripten/third_party/lzma.js/lzip/fast_encoder.h +171 -0
- data/modules/emscripten/third_party/lzma.js/lzip/lzip.h +264 -0
- data/modules/emscripten/third_party/lzma.js/lzip/main.cc +545 -0
- data/modules/emscripten/third_party/lzma.js/lzma-decoder.js +27 -0
- data/modules/emscripten/third_party/lzma.js/lzma-full.js +27 -0
- data/modules/emscripten/third_party/lzma.js/native_test.sh +5 -0
- data/modules/emscripten/third_party/lzma.js/post.js +13 -0
- data/modules/emscripten/third_party/lzma.js/pre.js +13 -0
- data/modules/emscripten/third_party/lzma.js/test-decoder.js +39 -0
- data/modules/emscripten/third_party/lzma.js/test-full.html +9 -0
- data/modules/emscripten/third_party/lzma.js/test-full.js +78 -0
- data/modules/emscripten/third_party/ply/ANNOUNCE +40 -0
- data/modules/emscripten/third_party/ply/CHANGES +1093 -0
- data/modules/emscripten/third_party/ply/PKG-INFO +22 -0
- data/modules/emscripten/third_party/ply/README +271 -0
- data/modules/emscripten/third_party/ply/TODO +16 -0
- data/modules/emscripten/third_party/ply/doc/internal.html +874 -0
- data/modules/emscripten/third_party/ply/doc/makedoc.py +194 -0
- data/modules/emscripten/third_party/ply/doc/ply.html +3262 -0
- data/modules/emscripten/third_party/ply/example/BASIC/README +79 -0
- data/modules/emscripten/third_party/ply/example/BASIC/basic.py +71 -0
- data/modules/emscripten/third_party/ply/example/BASIC/basiclex.py +74 -0
- data/modules/emscripten/third_party/ply/example/BASIC/basiclog.py +79 -0
- data/modules/emscripten/third_party/ply/example/BASIC/basinterp.py +441 -0
- data/modules/emscripten/third_party/ply/example/BASIC/basparse.py +424 -0
- data/modules/emscripten/third_party/ply/example/BASIC/dim.bas +14 -0
- data/modules/emscripten/third_party/ply/example/BASIC/func.bas +5 -0
- data/modules/emscripten/third_party/ply/example/BASIC/gcd.bas +22 -0
- data/modules/emscripten/third_party/ply/example/BASIC/gosub.bas +13 -0
- data/modules/emscripten/third_party/ply/example/BASIC/hello.bas +4 -0
- data/modules/emscripten/third_party/ply/example/BASIC/linear.bas +17 -0
- data/modules/emscripten/third_party/ply/example/BASIC/maxsin.bas +12 -0
- data/modules/emscripten/third_party/ply/example/BASIC/powers.bas +13 -0
- data/modules/emscripten/third_party/ply/example/BASIC/rand.bas +4 -0
- data/modules/emscripten/third_party/ply/example/BASIC/sales.bas +20 -0
- data/modules/emscripten/third_party/ply/example/BASIC/sears.bas +18 -0
- data/modules/emscripten/third_party/ply/example/BASIC/sqrt1.bas +5 -0
- data/modules/emscripten/third_party/ply/example/BASIC/sqrt2.bas +4 -0
- data/modules/emscripten/third_party/ply/example/GardenSnake/GardenSnake.py +709 -0
- data/modules/emscripten/third_party/ply/example/GardenSnake/README +5 -0
- data/modules/emscripten/third_party/ply/example/README +10 -0
- data/modules/emscripten/third_party/ply/example/ansic/README +2 -0
- data/modules/emscripten/third_party/ply/example/ansic/clex.py +164 -0
- data/modules/emscripten/third_party/ply/example/ansic/cparse.py +863 -0
- data/modules/emscripten/third_party/ply/example/calc/calc.py +107 -0
- data/modules/emscripten/third_party/ply/example/calcdebug/calc.py +113 -0
- data/modules/emscripten/third_party/ply/example/classcalc/calc.py +157 -0
- data/modules/emscripten/third_party/ply/example/cleanup.sh +2 -0
- data/modules/emscripten/third_party/ply/example/closurecalc/calc.py +130 -0
- data/modules/emscripten/third_party/ply/example/hedit/hedit.py +48 -0
- data/modules/emscripten/third_party/ply/example/newclasscalc/calc.py +160 -0
- data/modules/emscripten/third_party/ply/example/optcalc/README +9 -0
- data/modules/emscripten/third_party/ply/example/optcalc/calc.py +119 -0
- data/modules/emscripten/third_party/ply/example/unicalc/calc.py +117 -0
- data/modules/emscripten/third_party/ply/example/yply/README +41 -0
- data/modules/emscripten/third_party/ply/example/yply/ylex.py +112 -0
- data/modules/emscripten/third_party/ply/example/yply/yparse.py +217 -0
- data/modules/emscripten/third_party/ply/example/yply/yply.py +53 -0
- data/modules/emscripten/third_party/ply/ply/__init__.py +4 -0
- data/modules/emscripten/third_party/ply/ply/cpp.py +898 -0
- data/modules/emscripten/third_party/ply/ply/ctokens.py +133 -0
- data/modules/emscripten/third_party/ply/ply/lex.py +1058 -0
- data/modules/emscripten/third_party/ply/ply/yacc.py +3276 -0
- data/modules/emscripten/third_party/ply/setup.py +31 -0
- data/modules/emscripten/third_party/ply/test/README +7 -0
- data/modules/emscripten/third_party/ply/test/calclex.py +49 -0
- data/modules/emscripten/third_party/ply/test/cleanup.sh +4 -0
- data/modules/emscripten/third_party/ply/test/lex_closure.py +54 -0
- data/modules/emscripten/third_party/ply/test/lex_doc1.py +26 -0
- data/modules/emscripten/third_party/ply/test/lex_dup1.py +29 -0
- data/modules/emscripten/third_party/ply/test/lex_dup2.py +33 -0
- data/modules/emscripten/third_party/ply/test/lex_dup3.py +31 -0
- data/modules/emscripten/third_party/ply/test/lex_empty.py +20 -0
- data/modules/emscripten/third_party/ply/test/lex_error1.py +24 -0
- data/modules/emscripten/third_party/ply/test/lex_error2.py +26 -0
- data/modules/emscripten/third_party/ply/test/lex_error3.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_error4.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_hedit.py +47 -0
- data/modules/emscripten/third_party/ply/test/lex_ignore.py +31 -0
- data/modules/emscripten/third_party/ply/test/lex_ignore2.py +29 -0
- data/modules/emscripten/third_party/ply/test/lex_literal1.py +25 -0
- data/modules/emscripten/third_party/ply/test/lex_literal2.py +25 -0
- data/modules/emscripten/third_party/ply/test/lex_many_tokens.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_module.py +10 -0
- data/modules/emscripten/third_party/ply/test/lex_module_import.py +42 -0
- data/modules/emscripten/third_party/ply/test/lex_object.py +55 -0
- data/modules/emscripten/third_party/ply/test/lex_opt_alias.py +54 -0
- data/modules/emscripten/third_party/ply/test/lex_optimize.py +50 -0
- data/modules/emscripten/third_party/ply/test/lex_optimize2.py +50 -0
- data/modules/emscripten/third_party/ply/test/lex_optimize3.py +52 -0
- data/modules/emscripten/third_party/ply/test/lex_re1.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_re2.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_re3.py +29 -0
- data/modules/emscripten/third_party/ply/test/lex_rule1.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_rule2.py +29 -0
- data/modules/emscripten/third_party/ply/test/lex_rule3.py +27 -0
- data/modules/emscripten/third_party/ply/test/lex_state1.py +40 -0
- data/modules/emscripten/third_party/ply/test/lex_state2.py +40 -0
- data/modules/emscripten/third_party/ply/test/lex_state3.py +42 -0
- data/modules/emscripten/third_party/ply/test/lex_state4.py +41 -0
- data/modules/emscripten/third_party/ply/test/lex_state5.py +40 -0
- data/modules/emscripten/third_party/ply/test/lex_state_noerror.py +39 -0
- data/modules/emscripten/third_party/ply/test/lex_state_norule.py +40 -0
- data/modules/emscripten/third_party/ply/test/lex_state_try.py +45 -0
- data/modules/emscripten/third_party/ply/test/lex_token1.py +19 -0
- data/modules/emscripten/third_party/ply/test/lex_token2.py +22 -0
- data/modules/emscripten/third_party/ply/test/lex_token3.py +24 -0
- data/modules/emscripten/third_party/ply/test/lex_token4.py +26 -0
- data/modules/emscripten/third_party/ply/test/lex_token5.py +31 -0
- data/modules/emscripten/third_party/ply/test/lex_token_dup.py +29 -0
- data/modules/emscripten/third_party/ply/test/testlex.py +606 -0
- data/modules/emscripten/third_party/ply/test/testyacc.py +347 -0
- data/modules/emscripten/third_party/ply/test/yacc_badargs.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_badid.py +77 -0
- data/modules/emscripten/third_party/ply/test/yacc_badprec.py +64 -0
- data/modules/emscripten/third_party/ply/test/yacc_badprec2.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_badprec3.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_badrule.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_badtok.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_dup.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_error1.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_error2.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_error3.py +67 -0
- data/modules/emscripten/third_party/ply/test/yacc_error4.py +72 -0
- data/modules/emscripten/third_party/ply/test/yacc_inf.py +56 -0
- data/modules/emscripten/third_party/ply/test/yacc_literal.py +69 -0
- data/modules/emscripten/third_party/ply/test/yacc_misplaced.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_missing1.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_nested.py +33 -0
- data/modules/emscripten/third_party/ply/test/yacc_nodoc.py +67 -0
- data/modules/emscripten/third_party/ply/test/yacc_noerror.py +66 -0
- data/modules/emscripten/third_party/ply/test/yacc_nop.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_notfunc.py +66 -0
- data/modules/emscripten/third_party/ply/test/yacc_notok.py +67 -0
- data/modules/emscripten/third_party/ply/test/yacc_prec1.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_rr.py +72 -0
- data/modules/emscripten/third_party/ply/test/yacc_rr_unused.py +30 -0
- data/modules/emscripten/third_party/ply/test/yacc_simple.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_sr.py +63 -0
- data/modules/emscripten/third_party/ply/test/yacc_term1.py +68 -0
- data/modules/emscripten/third_party/ply/test/yacc_unused.py +77 -0
- data/modules/emscripten/third_party/ply/test/yacc_unused_rule.py +72 -0
- data/modules/emscripten/third_party/ply/test/yacc_uprec.py +63 -0
- data/modules/emscripten/third_party/ply/test/yacc_uprec2.py +63 -0
- data/modules/emscripten/third_party/readme.txt +7 -0
- data/modules/emscripten/third_party/websockify/CHANGES.txt +23 -0
- data/modules/emscripten/third_party/websockify/LICENSE.txt +16 -0
- data/modules/emscripten/third_party/websockify/MANIFEST.in +1 -0
- data/modules/emscripten/third_party/websockify/Makefile +11 -0
- data/modules/emscripten/third_party/websockify/README.md +168 -0
- data/modules/emscripten/third_party/websockify/Windows/Windows Service Readme.txt +39 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/Program.cs +24 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/ProjectInstaller.Designer.cs +61 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/ProjectInstaller.cs +19 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/ProjectInstaller.resx +129 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/Properties/AssemblyInfo.cs +36 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/Service1.Designer.cs +37 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/Service1.cs +41 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/noVNC Websocket.csproj +75 -0
- data/modules/emscripten/third_party/websockify/Windows/noVNC Websocket Service Project/noVNC Websocket.sln +20 -0
- data/modules/emscripten/third_party/websockify/docs/LICENSE.GPL-3 +621 -0
- data/modules/emscripten/third_party/websockify/docs/LICENSE.LGPL-3 +165 -0
- data/modules/emscripten/third_party/websockify/docs/LICENSE.MPL-2.0 +373 -0
- data/modules/emscripten/third_party/websockify/docs/TODO +9 -0
- data/modules/emscripten/third_party/websockify/docs/flash_policy.txt +4 -0
- data/modules/emscripten/third_party/websockify/docs/latency_results.txt +114 -0
- data/modules/emscripten/third_party/websockify/docs/notes +17 -0
- data/modules/emscripten/third_party/websockify/docs/release.txt +9 -0
- data/modules/emscripten/third_party/websockify/docs/websockify.1 +110 -0
- data/modules/emscripten/third_party/websockify/include/VT100.js +919 -0
- data/modules/emscripten/third_party/websockify/include/base64.js +114 -0
- data/modules/emscripten/third_party/websockify/include/keysym.js +99 -0
- data/modules/emscripten/third_party/websockify/include/util.js +359 -0
- data/modules/emscripten/third_party/websockify/include/web-socket-js/README.txt +109 -0
- data/modules/emscripten/third_party/websockify/include/web-socket-js/WebSocketMain.swf +0 -0
- data/modules/emscripten/third_party/websockify/include/web-socket-js/swfobject.js +4 -0
- data/modules/emscripten/third_party/websockify/include/web-socket-js/web_socket.js +391 -0
- data/modules/emscripten/third_party/websockify/include/websock.js +422 -0
- data/modules/emscripten/third_party/websockify/include/webutil.js +216 -0
- data/modules/emscripten/third_party/websockify/include/wsirc.js +235 -0
- data/modules/emscripten/third_party/websockify/include/wstelnet.js +335 -0
- data/modules/emscripten/third_party/websockify/other/Makefile +14 -0
- data/modules/emscripten/third_party/websockify/other/README.md +51 -0
- data/modules/emscripten/third_party/websockify/other/launch.sh +108 -0
- data/modules/emscripten/third_party/websockify/other/project.clj +13 -0
- data/modules/emscripten/third_party/websockify/other/websocket.c +802 -0
- data/modules/emscripten/third_party/websockify/other/websocket.h +84 -0
- data/modules/emscripten/third_party/websockify/other/websocket.rb +456 -0
- data/modules/emscripten/third_party/websockify/other/websockify.c +385 -0
- data/modules/emscripten/third_party/websockify/other/websockify.clj +233 -0
- data/modules/emscripten/third_party/websockify/other/websockify.js +196 -0
- data/modules/emscripten/third_party/websockify/other/websockify.rb +171 -0
- data/modules/emscripten/third_party/websockify/other/wswrap +22 -0
- data/modules/emscripten/third_party/websockify/rebind +18 -0
- data/modules/emscripten/third_party/websockify/rebind.c +94 -0
- data/modules/emscripten/third_party/websockify/run +5 -0
- data/modules/emscripten/third_party/websockify/setup.py +30 -0
- data/modules/emscripten/third_party/websockify/tests/b64_vs_utf8.py +29 -0
- data/modules/emscripten/third_party/websockify/tests/base64.html +91 -0
- data/modules/emscripten/third_party/websockify/tests/base64.js +12 -0
- data/modules/emscripten/third_party/websockify/tests/echo.html +148 -0
- data/modules/emscripten/third_party/websockify/tests/echo.py +75 -0
- data/modules/emscripten/third_party/websockify/tests/echo.rb +62 -0
- data/modules/emscripten/third_party/websockify/tests/latency.html +290 -0
- data/modules/emscripten/third_party/websockify/tests/latency.py +75 -0
- data/modules/emscripten/third_party/websockify/tests/load.html +250 -0
- data/modules/emscripten/third_party/websockify/tests/load.py +167 -0
- data/modules/emscripten/third_party/websockify/tests/plain_echo.html +168 -0
- data/modules/emscripten/third_party/websockify/tests/simple.html +68 -0
- data/modules/emscripten/third_party/websockify/tests/utf8-list.py +22 -0
- data/modules/emscripten/third_party/websockify/websockify/__init__.py +2 -0
- data/modules/emscripten/third_party/websockify/websockify/websocket.py +982 -0
- data/modules/emscripten/third_party/websockify/websockify/websocketproxy.py +393 -0
- data/modules/emscripten/third_party/websockify/websockify.py +5 -0
- data/modules/emscripten/third_party/websockify/wsirc.html +99 -0
- data/modules/emscripten/third_party/websockify/wstelnet.html +74 -0
- data/modules/emscripten/tools/__init__.py +0 -0
- data/modules/emscripten/tools/__init__.pyc +0 -0
- data/modules/emscripten/tools/autodebugger.py +289 -0
- data/modules/emscripten/tools/autodebugger_c.py +37 -0
- data/modules/emscripten/tools/autodebugger_indenter.py +18 -0
- data/modules/emscripten/tools/autodebugger_js.py +47 -0
- data/modules/emscripten/tools/autodediffer.py +60 -0
- data/modules/emscripten/tools/bindings_generator.py +832 -0
- data/modules/emscripten/tools/bisect_pair.py +88 -0
- data/modules/emscripten/tools/cache.py +198 -0
- data/modules/emscripten/tools/cache.pyc +0 -0
- data/modules/emscripten/tools/clean_webconsole.py +34 -0
- data/modules/emscripten/tools/crunch-worker.js +124 -0
- data/modules/emscripten/tools/diff_autodebugger.py +15 -0
- data/modules/emscripten/tools/eliminator/asm-eliminator-test-output.js +5129 -0
- data/modules/emscripten/tools/eliminator/asm-eliminator-test.js +6861 -0
- data/modules/emscripten/tools/eliminator/eliminator-test-output.js +6122 -0
- data/modules/emscripten/tools/eliminator/eliminator-test.js +8856 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/README.html +888 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/README.org +463 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/bin/uglifyjs +317 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/docstyle.css +75 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/lib/object-ast.js +75 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/lib/parse-js.js +1363 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/lib/process.js +2005 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/lib/squeeze-more.js +51 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/package.json +22 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/beautify.js +28 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/testparser.js +402 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/array1.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/array2.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/array3.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/array4.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/assignment.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/concatstring.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/const.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/empty-blocks.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/forstatement.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/if.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/ifreturn.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/ifreturn2.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue10.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue11.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue13.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue14.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue16.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue17.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue20.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue21.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue25.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue27.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue28.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue29.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue30.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue34.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue4.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue48.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue50.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue53.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue54.1.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue68.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue69.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/issue9.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/mangle.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/strict-equals.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/var.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/expected/with.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/array1.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/array2.js +4 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/array3.js +4 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/array4.js +6 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/assignment.js +20 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/concatstring.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/const.js +5 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/empty-blocks.js +4 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/forstatement.js +10 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/if.js +6 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/ifreturn.js +9 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/ifreturn2.js +16 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue10.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue11.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue13.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue14.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue16.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue17.js +4 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue20.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue21.js +6 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue25.js +7 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue27.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue28.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue29.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue30.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue34.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue4.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue48.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue50.js +9 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue53.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue54.1.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue68.js +5 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue69.js +1 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/issue9.js +4 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/mangle.js +5 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/strict-equals.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/var.js +3 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/compress/test/with.js +2 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/test/unit/scripts.js +55 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/tmp/hoist.js +33 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/tmp/instrument.js +97 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/tmp/instrument2.js +138 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/tmp/test.js +16 -0
- data/modules/emscripten/tools/eliminator/node_modules/uglify-js/uglify-js.js +17 -0
- data/modules/emscripten/tools/eliminator/safe-eliminator-test-output.js +85 -0
- data/modules/emscripten/tools/eliminator/safe-eliminator-test.js +103 -0
- data/modules/emscripten/tools/emconfiguren.py +19 -0
- data/modules/emscripten/tools/emmaken.py +230 -0
- data/modules/emscripten/tools/emmakenxx.py +18 -0
- data/modules/emscripten/tools/exec_llvm.py +50 -0
- data/modules/emscripten/tools/file2json.py +49 -0
- data/modules/emscripten/tools/file_packager.py +649 -0
- data/modules/emscripten/tools/find_bigfuncs.py +23 -0
- data/modules/emscripten/tools/find_bigis.py +18 -0
- data/modules/emscripten/tools/fix_closure.py +88 -0
- data/modules/emscripten/tools/ie7_fix.py +14 -0
- data/modules/emscripten/tools/js-optimizer.js +3440 -0
- data/modules/emscripten/tools/js_optimizer.py +341 -0
- data/modules/emscripten/tools/js_optimizer.pyc +0 -0
- data/modules/emscripten/tools/jsrun.py +27 -0
- data/modules/emscripten/tools/jsrun.pyc +0 -0
- data/modules/emscripten/tools/ll-strip.py +56 -0
- data/modules/emscripten/tools/make_file.py +19 -0
- data/modules/emscripten/tools/make_minigzip.py +13 -0
- data/modules/emscripten/tools/namespacer.py +95 -0
- data/modules/emscripten/tools/nativize_llvm.py +34 -0
- data/modules/emscripten/tools/node_modules/source-map/CHANGELOG.md +58 -0
- data/modules/emscripten/tools/node_modules/source-map/LICENSE +28 -0
- data/modules/emscripten/tools/node_modules/source-map/Makefile.dryice.js +166 -0
- data/modules/emscripten/tools/node_modules/source-map/README.md +347 -0
- data/modules/emscripten/tools/node_modules/source-map/build/assert-shim.js +56 -0
- data/modules/emscripten/tools/node_modules/source-map/build/mini-require.js +152 -0
- data/modules/emscripten/tools/node_modules/source-map/build/prefix-source-map.jsm +20 -0
- data/modules/emscripten/tools/node_modules/source-map/build/prefix-utils.jsm +18 -0
- data/modules/emscripten/tools/node_modules/source-map/build/suffix-browser.js +8 -0
- data/modules/emscripten/tools/node_modules/source-map/build/suffix-source-map.jsm +6 -0
- data/modules/emscripten/tools/node_modules/source-map/build/suffix-utils.jsm +21 -0
- data/modules/emscripten/tools/node_modules/source-map/build/test-prefix.js +8 -0
- data/modules/emscripten/tools/node_modules/source-map/build/test-suffix.js +3 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/array-set.js +96 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/base64-vlq.js +144 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/base64.js +42 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/binary-search.js +81 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/source-map-consumer.js +430 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/source-map-generator.js +381 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/source-node.js +353 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map/util.js +117 -0
- data/modules/emscripten/tools/node_modules/source-map/lib/source-map.js +8 -0
- data/modules/emscripten/tools/node_modules/source-map/node_modules/amdefine/LICENSE +58 -0
- data/modules/emscripten/tools/node_modules/source-map/node_modules/amdefine/README.md +119 -0
- data/modules/emscripten/tools/node_modules/source-map/node_modules/amdefine/amdefine.js +299 -0
- data/modules/emscripten/tools/node_modules/source-map/node_modules/amdefine/package.json +33 -0
- data/modules/emscripten/tools/node_modules/source-map/package.json +74 -0
- data/modules/emscripten/tools/node_modules/source-map/test/run-tests.js +73 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-api.js +26 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-array-set.js +71 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-base64-vlq.js +24 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-base64.js +35 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-binary-search.js +54 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-dog-fooding.js +72 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-source-map-consumer.js +306 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-source-map-generator.js +391 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/test-source-node.js +282 -0
- data/modules/emscripten/tools/node_modules/source-map/test/source-map/util.js +152 -0
- data/modules/emscripten/tools/reproduceriter.js +216 -0
- data/modules/emscripten/tools/reproduceriter.py +160 -0
- data/modules/emscripten/tools/response_file.py +28 -0
- data/modules/emscripten/tools/response_file.pyc +0 -0
- data/modules/emscripten/tools/scan_js.py +20 -0
- data/modules/emscripten/tools/scan_ll.py +18 -0
- data/modules/emscripten/tools/scons/site_scons/site_tools/emscripten/__init__.py +3 -0
- data/modules/emscripten/tools/scons/site_scons/site_tools/emscripten/emscripten.py +46 -0
- data/modules/emscripten/tools/settings_template_readonly.py +47 -0
- data/modules/emscripten/tools/shared.py +1437 -0
- data/modules/emscripten/tools/shared.pyc +0 -0
- data/modules/emscripten/tools/source-maps/sourcemap2json.js +15 -0
- data/modules/emscripten/tools/source-maps/sourcemapper.js +177 -0
- data/modules/emscripten/tools/split.py +97 -0
- data/modules/emscripten/tools/tempfiles.py +40 -0
- data/modules/emscripten/tools/tempfiles.pyc +0 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-last-output.js +75 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-last.js +91 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-outline-output.js +570 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-outline.js +606 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-pre-output.js +540 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-pre.js +550 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-regs-min-output.js +36 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-regs-min.js +37 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-regs-output.js +106 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-regs.js +110 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-relocate-output.js +9 -0
- data/modules/emscripten/tools/test-js-optimizer-asm-relocate.js +12 -0
- data/modules/emscripten/tools/test-js-optimizer-output.js +291 -0
- data/modules/emscripten/tools/test-js-optimizer-regs-output.js +232 -0
- data/modules/emscripten/tools/test-js-optimizer-regs.js +237 -0
- data/modules/emscripten/tools/test-js-optimizer-t2-output.js +91 -0
- data/modules/emscripten/tools/test-js-optimizer-t2.js +92 -0
- data/modules/emscripten/tools/test-js-optimizer-t2c-output.js +17 -0
- data/modules/emscripten/tools/test-js-optimizer-t2c.js +18 -0
- data/modules/emscripten/tools/test-js-optimizer-t3-output.js +49 -0
- data/modules/emscripten/tools/test-js-optimizer-t3.js +50 -0
- data/modules/emscripten/tools/test-js-optimizer.js +401 -0
- data/modules/mruby/AUTHORS +18 -0
- data/modules/mruby/CONTRIBUTING.md +65 -0
- data/modules/mruby/ChangeLog +15 -0
- data/modules/mruby/INSTALL +29 -0
- data/modules/mruby/LEGAL +6 -0
- data/modules/mruby/MITL +20 -0
- data/modules/mruby/Makefile +18 -0
- data/modules/mruby/NEWS +13 -0
- data/modules/mruby/README.md +116 -0
- data/modules/mruby/Rakefile +114 -0
- data/modules/mruby/TODO +11 -0
- data/modules/mruby/benchmark/ao-render.rb +315 -0
- data/modules/mruby/benchmark/bm_so_lists.rb +47 -0
- data/modules/mruby/benchmark/fib39.rb +8 -0
- data/modules/mruby/build_config.rb +88 -0
- data/modules/mruby/doc/compile/README.md +376 -0
- data/modules/mruby/doc/mrbgems/README.md +254 -0
- data/modules/mruby/examples/mrbgems/c_and_ruby_extension_example/README.md +4 -0
- data/modules/mruby/examples/mrbgems/c_and_ruby_extension_example/mrbgem.rake +23 -0
- data/modules/mruby/examples/mrbgems/c_and_ruby_extension_example/mrblib/example.rb +5 -0
- data/modules/mruby/examples/mrbgems/c_and_ruby_extension_example/src/example.c +20 -0
- data/modules/mruby/examples/mrbgems/c_and_ruby_extension_example/test/example.rb +7 -0
- data/modules/mruby/examples/mrbgems/c_extension_example/README.md +4 -0
- data/modules/mruby/examples/mrbgems/c_extension_example/mrbgem.rake +23 -0
- data/modules/mruby/examples/mrbgems/c_extension_example/src/example.c +20 -0
- data/modules/mruby/examples/mrbgems/c_extension_example/test/example.c +7 -0
- data/modules/mruby/examples/mrbgems/c_extension_example/test/example.rb +3 -0
- data/modules/mruby/examples/mrbgems/ruby_extension_example/README.md +4 -0
- data/modules/mruby/examples/mrbgems/ruby_extension_example/mrbgem.rake +23 -0
- data/modules/mruby/examples/mrbgems/ruby_extension_example/mrblib/example.rb +5 -0
- data/modules/mruby/examples/mrbgems/ruby_extension_example/test/example.rb +3 -0
- data/modules/mruby/examples/targets/ArduinoDue.rb +65 -0
- data/modules/mruby/examples/targets/chipKitMax32.rb +68 -0
- data/modules/mruby/include/mrbconf.h +87 -0
- data/modules/mruby/include/mruby/array.h +63 -0
- data/modules/mruby/include/mruby/class.h +75 -0
- data/modules/mruby/include/mruby/compile.h +176 -0
- data/modules/mruby/include/mruby/data.h +53 -0
- data/modules/mruby/include/mruby/dump.h +151 -0
- data/modules/mruby/include/mruby/gc.h +17 -0
- data/modules/mruby/include/mruby/hash.h +54 -0
- data/modules/mruby/include/mruby/irep.h +40 -0
- data/modules/mruby/include/mruby/khash.h +257 -0
- data/modules/mruby/include/mruby/numeric.h +32 -0
- data/modules/mruby/include/mruby/proc.h +62 -0
- data/modules/mruby/include/mruby/range.h +35 -0
- data/modules/mruby/include/mruby/string.h +78 -0
- data/modules/mruby/include/mruby/value.h +483 -0
- data/modules/mruby/include/mruby/variable.h +78 -0
- data/modules/mruby/include/mruby.h +388 -0
- data/modules/mruby/minirake +477 -0
- data/modules/mruby/mrbgems/default.gembox +61 -0
- data/modules/mruby/mrbgems/full-core.gembox +9 -0
- data/modules/mruby/mrbgems/mruby-array-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-array-ext/mrblib/array.rb +204 -0
- data/modules/mruby/mrbgems/mruby-array-ext/src/array.c +140 -0
- data/modules/mruby/mrbgems/mruby-array-ext/test/array.rb +109 -0
- data/modules/mruby/mrbgems/mruby-bin-mirb/mrbgem.rake +5 -0
- data/modules/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +365 -0
- data/modules/mruby/mrbgems/mruby-bin-mruby/mrbgem.rake +5 -0
- data/modules/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +243 -0
- data/modules/mruby/mrbgems/mruby-enum-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-enum-ext/mrblib/enum.rb +164 -0
- data/modules/mruby/mrbgems/mruby-enum-ext/test/enum.rb +44 -0
- data/modules/mruby/mrbgems/mruby-eval/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-eval/src/eval.c +23 -0
- data/modules/mruby/mrbgems/mruby-fiber/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-fiber/src/fiber.c +251 -0
- data/modules/mruby/mrbgems/mruby-fiber/test/fiber.rb +64 -0
- data/modules/mruby/mrbgems/mruby-hash-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-hash-ext/mrblib/hash.rb +13 -0
- data/modules/mruby/mrbgems/mruby-hash-ext/src/hash-ext.c +62 -0
- data/modules/mruby/mrbgems/mruby-hash-ext/test/hash.rb +26 -0
- data/modules/mruby/mrbgems/mruby-math/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-math/src/math.c +685 -0
- data/modules/mruby/mrbgems/mruby-math/test/math.rb +136 -0
- data/modules/mruby/mrbgems/mruby-numeric-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-numeric-ext/src/numeric_ext.c +31 -0
- data/modules/mruby/mrbgems/mruby-numeric-ext/test/numeric.rb +10 -0
- data/modules/mruby/mrbgems/mruby-object-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-object-ext/src/object.c +108 -0
- data/modules/mruby/mrbgems/mruby-object-ext/test/nil.rb +11 -0
- data/modules/mruby/mrbgems/mruby-object-ext/test/object.rb +9 -0
- data/modules/mruby/mrbgems/mruby-objectspace/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-objectspace/src/mruby_objectspace.c +117 -0
- data/modules/mruby/mrbgems/mruby-objectspace/test/objectspace.rb +38 -0
- data/modules/mruby/mrbgems/mruby-print/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-print/mrblib/print.rb +64 -0
- data/modules/mruby/mrbgems/mruby-print/src/print.c +44 -0
- data/modules/mruby/mrbgems/mruby-proc-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-proc-ext/mrblib/proc.rb +40 -0
- data/modules/mruby/mrbgems/mruby-proc-ext/src/proc.c +97 -0
- data/modules/mruby/mrbgems/mruby-proc-ext/test/proc.rb +41 -0
- data/modules/mruby/mrbgems/mruby-random/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-random/src/mt19937ar.c +193 -0
- data/modules/mruby/mrbgems/mruby-random/src/mt19937ar.h +48 -0
- data/modules/mruby/mrbgems/mruby-random/src/random.c +231 -0
- data/modules/mruby/mrbgems/mruby-random/src/random.h +12 -0
- data/modules/mruby/mrbgems/mruby-random/test/random.rb +32 -0
- data/modules/mruby/mrbgems/mruby-range-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-range-ext/src/range.c +141 -0
- data/modules/mruby/mrbgems/mruby-range-ext/test/range.rb +20 -0
- data/modules/mruby/mrbgems/mruby-sprintf/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-sprintf/src/kernel.c +30 -0
- data/modules/mruby/mrbgems/mruby-sprintf/src/sprintf.c +1102 -0
- data/modules/mruby/mrbgems/mruby-sprintf/test/sprintf.rb +3 -0
- data/modules/mruby/mrbgems/mruby-string-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-string-ext/mrblib/string.rb +52 -0
- data/modules/mruby/mrbgems/mruby-string-ext/src/string.c +175 -0
- data/modules/mruby/mrbgems/mruby-string-ext/test/string.rb +112 -0
- data/modules/mruby/mrbgems/mruby-struct/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-struct/mrblib/struct.rb +50 -0
- data/modules/mruby/mrbgems/mruby-struct/src/struct.c +818 -0
- data/modules/mruby/mrbgems/mruby-struct/test/struct.rb +77 -0
- data/modules/mruby/mrbgems/mruby-symbol-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-symbol-ext/mrblib/symbol.rb +9 -0
- data/modules/mruby/mrbgems/mruby-symbol-ext/src/symbol.c +55 -0
- data/modules/mruby/mrbgems/mruby-symbol-ext/test/symbol.rb +12 -0
- data/modules/mruby/mrbgems/mruby-time/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-time/src/time.c +749 -0
- data/modules/mruby/mrbgems/mruby-time/test/time.rb +201 -0
- data/modules/mruby/mrbgems/mruby-toplevel-ext/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-toplevel-ext/mrblib/toplevel.rb +11 -0
- data/modules/mruby/mrbgems/mruby-toplevel-ext/test/toplevel.rb +24 -0
- data/modules/mruby/mrblib/array.rb +111 -0
- data/modules/mruby/mrblib/class.rb +26 -0
- data/modules/mruby/mrblib/compar.rb +104 -0
- data/modules/mruby/mrblib/enum.rb +398 -0
- data/modules/mruby/mrblib/error.rb +66 -0
- data/modules/mruby/mrblib/hash.rb +193 -0
- data/modules/mruby/mrblib/init_mrblib.c +14 -0
- data/modules/mruby/mrblib/kernel.rb +46 -0
- data/modules/mruby/mrblib/mrblib.rake +18 -0
- data/modules/mruby/mrblib/numeric.rb +101 -0
- data/modules/mruby/mrblib/print.rb +18 -0
- data/modules/mruby/mrblib/range.rb +40 -0
- data/modules/mruby/mrblib/string.rb +145 -0
- data/modules/mruby/src/array.c +1150 -0
- data/modules/mruby/src/backtrace.c +73 -0
- data/modules/mruby/src/class.c +1942 -0
- data/modules/mruby/src/codegen.c +2864 -0
- data/modules/mruby/src/compar.c +13 -0
- data/modules/mruby/src/crc.c +38 -0
- data/modules/mruby/src/dump.c +542 -0
- data/modules/mruby/src/enum.c +14 -0
- data/modules/mruby/src/error.c +454 -0
- data/modules/mruby/src/error.h +18 -0
- data/modules/mruby/src/etc.c +204 -0
- data/modules/mruby/src/gc.c +1542 -0
- data/modules/mruby/src/hash.c +1261 -0
- data/modules/mruby/src/init.c +62 -0
- data/modules/mruby/src/kernel.c +1105 -0
- data/modules/mruby/src/keywords +50 -0
- data/modules/mruby/src/lex.def +212 -0
- data/modules/mruby/src/load.c +629 -0
- data/modules/mruby/src/mruby_core.rake +28 -0
- data/modules/mruby/src/node.h +117 -0
- data/modules/mruby/src/numeric.c +1418 -0
- data/modules/mruby/src/object.c +593 -0
- data/modules/mruby/src/opcode.h +160 -0
- data/modules/mruby/src/parse.y +6050 -0
- data/modules/mruby/src/pool.c +190 -0
- data/modules/mruby/src/print.c +71 -0
- data/modules/mruby/src/proc.c +209 -0
- data/modules/mruby/src/range.c +442 -0
- data/modules/mruby/src/re.h +13 -0
- data/modules/mruby/src/state.c +200 -0
- data/modules/mruby/src/string.c +2580 -0
- data/modules/mruby/src/symbol.c +456 -0
- data/modules/mruby/src/value_array.h +27 -0
- data/modules/mruby/src/variable.c +1147 -0
- data/modules/mruby/src/vm.c +2129 -0
- data/modules/mruby/tasks/libmruby.rake +18 -0
- data/modules/mruby/tasks/mrbgem_spec.rake +297 -0
- data/modules/mruby/tasks/mrbgems.rake +85 -0
- data/modules/mruby/tasks/mrbgems_test.rake +88 -0
- data/modules/mruby/tasks/mruby_build.rake +211 -0
- data/modules/mruby/tasks/mruby_build_commands.rake +287 -0
- data/modules/mruby/tasks/mruby_build_gem.rake +67 -0
- data/modules/mruby/tasks/ruby_ext.rake +70 -0
- data/modules/mruby/tasks/toolchains/androideabi.rake +126 -0
- data/modules/mruby/tasks/toolchains/clang.rake +8 -0
- data/modules/mruby/tasks/toolchains/gcc.rake +21 -0
- data/modules/mruby/tasks/toolchains/vs2010.rake +3 -0
- data/modules/mruby/tasks/toolchains/vs2012.rake +44 -0
- data/modules/mruby/test/README.md +7 -0
- data/modules/mruby/test/assert.rb +238 -0
- data/modules/mruby/test/driver.c +118 -0
- data/modules/mruby/test/init_mrbtest.c +24 -0
- data/modules/mruby/test/mrbtest.rake +47 -0
- data/modules/mruby/test/report.rb +4 -0
- data/modules/mruby/test/t/argumenterror.rb +21 -0
- data/modules/mruby/test/t/array.rb +309 -0
- data/modules/mruby/test/t/basicobject.rb +11 -0
- data/modules/mruby/test/t/bs_block.rb +489 -0
- data/modules/mruby/test/t/bs_literal.rb +38 -0
- data/modules/mruby/test/t/class.rb +219 -0
- data/modules/mruby/test/t/comparable.rb +72 -0
- data/modules/mruby/test/t/enumerable.rb +108 -0
- data/modules/mruby/test/t/exception.rb +337 -0
- data/modules/mruby/test/t/false.rb +33 -0
- data/modules/mruby/test/t/float.rb +145 -0
- data/modules/mruby/test/t/gc.rb +45 -0
- data/modules/mruby/test/t/hash.rb +310 -0
- data/modules/mruby/test/t/indexerror.rb +10 -0
- data/modules/mruby/test/t/integer.rb +222 -0
- data/modules/mruby/test/t/kernel.rb +425 -0
- data/modules/mruby/test/t/literals.rb +287 -0
- data/modules/mruby/test/t/localjumperror.rb +13 -0
- data/modules/mruby/test/t/methods.rb +109 -0
- data/modules/mruby/test/t/module.rb +344 -0
- data/modules/mruby/test/t/nameerror.rb +32 -0
- data/modules/mruby/test/t/nil.rb +29 -0
- data/modules/mruby/test/t/nomethoderror.rb +13 -0
- data/modules/mruby/test/t/numeric.rb +29 -0
- data/modules/mruby/test/t/object.rb +11 -0
- data/modules/mruby/test/t/proc.rb +56 -0
- data/modules/mruby/test/t/range.rb +82 -0
- data/modules/mruby/test/t/rangeerror.rb +10 -0
- data/modules/mruby/test/t/regexperror.rb +4 -0
- data/modules/mruby/test/t/runtimeerror.rb +6 -0
- data/modules/mruby/test/t/standarderror.rb +10 -0
- data/modules/mruby/test/t/string.rb +483 -0
- data/modules/mruby/test/t/symbol.rb +27 -0
- data/modules/mruby/test/t/syntax.rb +67 -0
- data/modules/mruby/test/t/true.rb +33 -0
- data/modules/mruby/test/t/typeerror.rb +11 -0
- data/modules/mruby/tools/mrbc/mrbc.c +318 -0
- data/modules/mruby/tools/mrbc/mrbc.rake +14 -0
- data/modules/mruby/travis_config.rb +6 -0
- data/modules/mrubymix/LICENSE +21 -0
- data/modules/mrubymix/README.md +6 -0
- data/modules/mrubymix/bin/mrubymix +29 -0
- data/modules/mrubymix/lib/mrubymix.rb +93 -0
- data/modules/mrubymix/mrubymix.gemspec +13 -0
- data/scripts/gen_gems_config.rb +185 -0
- data/scripts/gen_post.rb +104 -0
- data/templates/minimal/Rakefile +36 -0
- data/templates/minimal/app/app.rb +3 -0
- metadata +1408 -0
|
@@ -0,0 +1,3440 @@
|
|
|
1
|
+
//==============================================================================
|
|
2
|
+
// Optimizer tool. This is meant to be run after the emscripten compiler has
|
|
3
|
+
// finished generating code. These optimizations are done on the generated
|
|
4
|
+
// code to further improve it. Some of the modifications also work in
|
|
5
|
+
// conjunction with closure compiler.
|
|
6
|
+
//
|
|
7
|
+
// TODO: Optimize traverse to modify a node we want to replace, in-place,
|
|
8
|
+
// instead of returning it to the previous call frame where we check?
|
|
9
|
+
// TODO: Share EMPTY_NODE instead of emptyNode that constructs?
|
|
10
|
+
//==============================================================================
|
|
11
|
+
|
|
12
|
+
// *** Environment setup code ***
|
|
13
|
+
var arguments_ = [];
|
|
14
|
+
var debug = false;
|
|
15
|
+
|
|
16
|
+
var ENVIRONMENT_IS_NODE = typeof process === 'object';
|
|
17
|
+
var ENVIRONMENT_IS_WEB = typeof window === 'object';
|
|
18
|
+
var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
|
|
19
|
+
var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
|
|
20
|
+
|
|
21
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
22
|
+
// Expose functionality in the same simple way that the shells work
|
|
23
|
+
// Note that we pollute the global namespace here, otherwise we break in node
|
|
24
|
+
print = function(x) {
|
|
25
|
+
process['stdout'].write(x + '\n');
|
|
26
|
+
};
|
|
27
|
+
printErr = function(x) {
|
|
28
|
+
process['stderr'].write(x + '\n');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
var nodeFS = require('fs');
|
|
32
|
+
var nodePath = require('path');
|
|
33
|
+
|
|
34
|
+
if (!nodeFS.existsSync) {
|
|
35
|
+
nodeFS.existsSync = function(path) {
|
|
36
|
+
try {
|
|
37
|
+
return !!nodeFS.readFileSync(path);
|
|
38
|
+
} catch(e) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function find(filename) {
|
|
45
|
+
var prefixes = [nodePath.join(__dirname, '..', 'src'), process.cwd()];
|
|
46
|
+
for (var i = 0; i < prefixes.length; ++i) {
|
|
47
|
+
var combined = nodePath.join(prefixes[i], filename);
|
|
48
|
+
if (nodeFS.existsSync(combined)) {
|
|
49
|
+
return combined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return filename;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
read = function(filename) {
|
|
56
|
+
var absolute = find(filename);
|
|
57
|
+
return nodeFS['readFileSync'](absolute).toString();
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
load = function(f) {
|
|
61
|
+
globalEval(read(f));
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
arguments_ = process['argv'].slice(2);
|
|
65
|
+
|
|
66
|
+
} else if (ENVIRONMENT_IS_SHELL) {
|
|
67
|
+
// Polyfill over SpiderMonkey/V8 differences
|
|
68
|
+
if (!this['read']) {
|
|
69
|
+
this['read'] = function(f) { snarf(f) };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (typeof scriptArgs != 'undefined') {
|
|
73
|
+
arguments_ = scriptArgs;
|
|
74
|
+
} else if (typeof arguments != 'undefined') {
|
|
75
|
+
arguments_ = arguments;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
} else if (ENVIRONMENT_IS_WEB) {
|
|
79
|
+
this['print'] = printErr = function(x) {
|
|
80
|
+
console.log(x);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
this['read'] = function(url) {
|
|
84
|
+
var xhr = new XMLHttpRequest();
|
|
85
|
+
xhr.open('GET', url, false);
|
|
86
|
+
xhr.send(null);
|
|
87
|
+
return xhr.responseText;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (this['arguments']) {
|
|
91
|
+
arguments_ = arguments;
|
|
92
|
+
}
|
|
93
|
+
} else if (ENVIRONMENT_IS_WORKER) {
|
|
94
|
+
// We can do very little here...
|
|
95
|
+
|
|
96
|
+
this['load'] = importScripts;
|
|
97
|
+
|
|
98
|
+
} else {
|
|
99
|
+
throw 'Unknown runtime environment. Where are we?';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function globalEval(x) {
|
|
103
|
+
eval.call(null, x);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof load === 'undefined' && typeof read != 'undefined') {
|
|
107
|
+
this['load'] = function(f) {
|
|
108
|
+
globalEval(read(f));
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (typeof printErr === 'undefined') {
|
|
113
|
+
this['printErr'] = function(){};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (typeof print === 'undefined') {
|
|
117
|
+
this['print'] = printErr;
|
|
118
|
+
}
|
|
119
|
+
// *** Environment setup code ***
|
|
120
|
+
|
|
121
|
+
var uglify = require('../tools/eliminator/node_modules/uglify-js');
|
|
122
|
+
var fs = require('fs');
|
|
123
|
+
var path = require('path');
|
|
124
|
+
|
|
125
|
+
// Load some modules
|
|
126
|
+
|
|
127
|
+
load('utility.js');
|
|
128
|
+
|
|
129
|
+
// Utilities
|
|
130
|
+
|
|
131
|
+
var FUNCTION = set('defun', 'function');
|
|
132
|
+
var LOOP = set('do', 'while', 'for');
|
|
133
|
+
var LOOP_FLOW = set('break', 'continue');
|
|
134
|
+
var ASSIGN_OR_ALTER = set('assign', 'unary-postfix', 'unary-prefix');
|
|
135
|
+
var CONTROL_FLOW = set('do', 'while', 'for', 'if', 'switch');
|
|
136
|
+
var NAME_OR_NUM = set('name', 'num');
|
|
137
|
+
var ASSOCIATIVE_BINARIES = set('+', '*', '|', '&', '^');
|
|
138
|
+
|
|
139
|
+
var BREAK_CAPTURERS = set('do', 'while', 'for', 'switch');
|
|
140
|
+
var CONTINUE_CAPTURERS = LOOP;
|
|
141
|
+
|
|
142
|
+
var NULL_NODE = ['name', 'null'];
|
|
143
|
+
var UNDEFINED_NODE = ['unary-prefix', 'void', ['num', 0]];
|
|
144
|
+
var TRUE_NODE = ['unary-prefix', '!', ['num', 0]];
|
|
145
|
+
var FALSE_NODE = ['unary-prefix', '!', ['num', 1]];
|
|
146
|
+
|
|
147
|
+
var GENERATED_FUNCTIONS_MARKER = '// EMSCRIPTEN_GENERATED_FUNCTIONS';
|
|
148
|
+
var generatedFunctions = false; // whether we have received only generated functions
|
|
149
|
+
|
|
150
|
+
var extraInfo = null;
|
|
151
|
+
|
|
152
|
+
function srcToAst(src) {
|
|
153
|
+
return uglify.parser.parse(src, false, debug);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function astToSrc(ast, minifyWhitespace) {
|
|
157
|
+
return uglify.uglify.gen_code(ast, {
|
|
158
|
+
debug: debug,
|
|
159
|
+
ascii_only: true,
|
|
160
|
+
beautify: !minifyWhitespace,
|
|
161
|
+
indent_level: 1
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Traverses the children of a node. If the traverse function returns an object,
|
|
166
|
+
// replaces the child. If it returns true, stop the traversal and return true.
|
|
167
|
+
function traverseChildren(node, traverse, pre, post, stack) {
|
|
168
|
+
for (var i = 0; i < node.length; i++) {
|
|
169
|
+
var subnode = node[i];
|
|
170
|
+
if (Array.isArray(subnode)) {
|
|
171
|
+
var subresult = traverse(subnode, pre, post, stack);
|
|
172
|
+
if (subresult === true) return true;
|
|
173
|
+
if (subresult !== null && typeof subresult === 'object') node[i] = subresult;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Traverses a JavaScript syntax tree rooted at the given node calling the given
|
|
179
|
+
// callback for each node.
|
|
180
|
+
// @arg node: The root of the AST.
|
|
181
|
+
// @arg pre: The pre to call for each node. This will be called with
|
|
182
|
+
// the node as the first argument and its type as the second. If true is
|
|
183
|
+
// returned, the traversal is stopped. If an object is returned,
|
|
184
|
+
// it replaces the passed node in the tree. If null is returned, we stop
|
|
185
|
+
// traversing the subelements (but continue otherwise).
|
|
186
|
+
// @arg post: A callback to call after traversing all children.
|
|
187
|
+
// @arg stack: If true, a stack will be implemented: If pre does not push on
|
|
188
|
+
// the stack, we push a 0. We pop when we leave the node. The
|
|
189
|
+
// stack is passed as a third parameter to the callbacks.
|
|
190
|
+
// @returns: If the root node was replaced, the new root node. If the traversal
|
|
191
|
+
// was stopped, true. Otherwise undefined.
|
|
192
|
+
function traverse(node, pre, post, stack) {
|
|
193
|
+
var type = node[0], result, len;
|
|
194
|
+
var relevant = typeof type === 'string';
|
|
195
|
+
if (relevant) {
|
|
196
|
+
if (stack) len = stack.length;
|
|
197
|
+
var result = pre(node, type, stack);
|
|
198
|
+
if (result === true) return true;
|
|
199
|
+
if (result && result !== null) node = result; // Continue processing on this node
|
|
200
|
+
if (stack && len === stack.length) stack.push(0);
|
|
201
|
+
}
|
|
202
|
+
if (result !== null) {
|
|
203
|
+
if (traverseChildren(node, traverse, pre, post, stack) === true) return true;
|
|
204
|
+
}
|
|
205
|
+
if (relevant) {
|
|
206
|
+
if (post) {
|
|
207
|
+
var postResult = post(node, type, stack);
|
|
208
|
+
result = result || postResult;
|
|
209
|
+
}
|
|
210
|
+
if (stack) stack.pop();
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Only walk through the generated functions
|
|
216
|
+
function traverseGenerated(ast, pre, post, stack) {
|
|
217
|
+
assert(generatedFunctions);
|
|
218
|
+
traverse(ast, function(node) {
|
|
219
|
+
if (node[0] === 'defun') {
|
|
220
|
+
traverse(node, pre, post, stack);
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function traverseGeneratedFunctions(ast, callback) {
|
|
227
|
+
assert(generatedFunctions);
|
|
228
|
+
if (ast[0] === 'toplevel') {
|
|
229
|
+
var stats = ast[1];
|
|
230
|
+
for (var i = 0; i < stats.length; i++) {
|
|
231
|
+
var curr = stats[i];
|
|
232
|
+
if (curr[0] === 'defun') callback(curr);
|
|
233
|
+
}
|
|
234
|
+
} else if (ast[0] === 'defun') {
|
|
235
|
+
callback(ast);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Walk the ast in a simple way, with an understanding of which JS variables are defined)
|
|
240
|
+
function traverseWithVariables(ast, callback) {
|
|
241
|
+
traverse(ast, function(node, type, stack) {
|
|
242
|
+
if (type in FUNCTION) {
|
|
243
|
+
stack.push({ type: 'function', vars: node[2] });
|
|
244
|
+
} else if (type === 'var') {
|
|
245
|
+
// Find our function, add our vars
|
|
246
|
+
var func = stack[stack.length-1];
|
|
247
|
+
if (func) {
|
|
248
|
+
func.vars = func.vars.concat(node[1].map(function(varItem) { return varItem[0] }));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}, function(node, type, stack) {
|
|
252
|
+
if (type === 'toplevel' || type in FUNCTION) {
|
|
253
|
+
// We know all of the variables that are seen here, proceed to do relevant replacements
|
|
254
|
+
var allVars = stack.map(function(item) { return item ? item.vars : [] }).reduce(concatenator, []); // FIXME dictionary for speed?
|
|
255
|
+
traverse(node, function(node2, type2, stack2) {
|
|
256
|
+
// Be careful not to look into our inner functions. They have already been processed.
|
|
257
|
+
if (sum(stack2) > 1 || (type === 'toplevel' && sum(stack2) === 1)) return;
|
|
258
|
+
if (type2 in FUNCTION) stack2.push(1);
|
|
259
|
+
return callback(node2, type2, allVars);
|
|
260
|
+
}, null, []);
|
|
261
|
+
}
|
|
262
|
+
}, []);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function emptyNode() { // XXX do we need to create new nodes here? can't we reuse?
|
|
266
|
+
return ['toplevel', []]
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function isEmptyNode(node) {
|
|
270
|
+
return node.length === 2 && node[0] === 'toplevel' && node[1].length === 0;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Passes
|
|
274
|
+
|
|
275
|
+
// Dump the AST. Useful for debugging. For example,
|
|
276
|
+
// node tools/js-optimizer.js ABSOLUTE_PATH_TO_FILE dumpAst
|
|
277
|
+
function dumpAst(ast) {
|
|
278
|
+
printErr(JSON.stringify(ast, null, ' '));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function dumpSrc(ast) {
|
|
282
|
+
printErr(astToSrc(ast));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Undos closure's creation of global variables with values true, false,
|
|
286
|
+
// undefined, null. These cut down on size, but do not affect gzip size
|
|
287
|
+
// and make JS engine's lives slightly harder (?)
|
|
288
|
+
function unGlobalize(ast) {
|
|
289
|
+
|
|
290
|
+
throw 'this is deprecated!'; // and does not work with parallel compilation
|
|
291
|
+
|
|
292
|
+
assert(ast[0] === 'toplevel');
|
|
293
|
+
var values = {};
|
|
294
|
+
// Find global renamings of the relevant values
|
|
295
|
+
ast[1].forEach(function(node, i) {
|
|
296
|
+
if (node[0] != 'var') return;
|
|
297
|
+
node[1] = node[1].filter(function(varItem, j) {
|
|
298
|
+
var ident = varItem[0];
|
|
299
|
+
var value = varItem[1];
|
|
300
|
+
if (!value) return true;
|
|
301
|
+
var possible = false;
|
|
302
|
+
if (jsonCompare(value, NULL_NODE) ||
|
|
303
|
+
jsonCompare(value, UNDEFINED_NODE) ||
|
|
304
|
+
jsonCompare(value, TRUE_NODE) ||
|
|
305
|
+
jsonCompare(value, FALSE_NODE)) {
|
|
306
|
+
possible = true;
|
|
307
|
+
}
|
|
308
|
+
if (!possible) return true;
|
|
309
|
+
// Make sure there are no assignments to this variable. (This isn't fast, we traverse many times..)
|
|
310
|
+
ast[1][i][1][j] = emptyNode();
|
|
311
|
+
var assigned = false;
|
|
312
|
+
traverseWithVariables(ast, function(node, type, allVars) {
|
|
313
|
+
if (type === 'assign' && node[2][0] === 'name' && node[2][1] === ident) assigned = true;
|
|
314
|
+
});
|
|
315
|
+
ast[1][i][1][j] = [ident, value];
|
|
316
|
+
if (!assigned) {
|
|
317
|
+
values[ident] = value;
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (node[1].length === 0) {
|
|
324
|
+
ast[1][i] = emptyNode();
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
traverseWithVariables(ast, function(node, type, allVars) {
|
|
328
|
+
if (type === 'name') {
|
|
329
|
+
var ident = node[1];
|
|
330
|
+
if (ident in values && allVars.indexOf(ident) < 0) {
|
|
331
|
+
return copy(values[ident]);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Closure compiler, when inlining, will insert assignments to
|
|
338
|
+
// undefined for the shared variables. However, in compiled code
|
|
339
|
+
// - and in library/shell code too! - we should never rely on
|
|
340
|
+
// undefined being assigned. So we can simply remove those assignments.
|
|
341
|
+
//
|
|
342
|
+
// Note: An inlined function that kept a large value referenced, may
|
|
343
|
+
// keep that references when inlined, if we remove the setting to
|
|
344
|
+
// undefined. This is not dangerous in compiled code, but might be
|
|
345
|
+
// in supporting code (for example, holding on to the HEAP when copying).
|
|
346
|
+
//
|
|
347
|
+
// This pass assumes that unGlobalize has been run, so undefined
|
|
348
|
+
// is now explicit.
|
|
349
|
+
function removeAssignsToUndefined(ast) {
|
|
350
|
+
traverse(ast, function(node, type) {
|
|
351
|
+
if (type === 'assign' && jsonCompare(node[3], ['unary-prefix', 'void', ['num', 0]])) {
|
|
352
|
+
return emptyNode();
|
|
353
|
+
} else if (type === 'var') {
|
|
354
|
+
node[1] = node[1].map(function(varItem, j) {
|
|
355
|
+
var ident = varItem[0];
|
|
356
|
+
var value = varItem[1];
|
|
357
|
+
if (jsonCompare(value, UNDEFINED_NODE)) return [ident];
|
|
358
|
+
return [ident, value];
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
// cleanup (|x = y = void 0| leaves |x = ;| right now)
|
|
363
|
+
var modified = true;
|
|
364
|
+
while (modified) {
|
|
365
|
+
modified = false;
|
|
366
|
+
traverse(ast, function(node, type) {
|
|
367
|
+
if (type === 'assign' && jsonCompare(node[3], emptyNode())) {
|
|
368
|
+
modified = true;
|
|
369
|
+
return emptyNode();
|
|
370
|
+
} else if (type === 'var') {
|
|
371
|
+
node[1] = node[1].map(function(varItem, j) {
|
|
372
|
+
var ident = varItem[0];
|
|
373
|
+
var value = varItem[1];
|
|
374
|
+
if (value && jsonCompare(value, emptyNode())) return [ident];
|
|
375
|
+
return [ident, value];
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// XXX This is an invalid optimization
|
|
383
|
+
// We sometimes leave some settings to label that are not needed, if later in
|
|
384
|
+
// the relooper we realize that we have a single entry, so no checks on label
|
|
385
|
+
// are actually necessary. It's easy to clean those up now.
|
|
386
|
+
function removeUnneededLabelSettings(ast) {
|
|
387
|
+
traverse(ast, function(node, type) {
|
|
388
|
+
if (type === 'defun') { // all of our compiled code is in defun nodes
|
|
389
|
+
// Find all checks
|
|
390
|
+
var checked = {};
|
|
391
|
+
traverse(node, function(node, type) {
|
|
392
|
+
if (type === 'binary' && node[1] === '==' && node[2][0] === 'name' && node[2][1] === 'label') {
|
|
393
|
+
assert(node[3][0] === 'num');
|
|
394
|
+
checked[node[3][1]] = 1;
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
// Remove unneeded sets
|
|
398
|
+
traverse(node, function(node, type) {
|
|
399
|
+
if (type === 'assign' && node[2][0] === 'name' && node[2][1] === 'label') {
|
|
400
|
+
assert(node[3][0] === 'num');
|
|
401
|
+
if (!(node[3][1] in checked)) return emptyNode();
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Various expression simplifications. Pre run before closure (where we still have metadata), Post run after.
|
|
409
|
+
|
|
410
|
+
var USEFUL_BINARY_OPS = set('<<', '>>', '|', '&', '^');
|
|
411
|
+
var COMPARE_OPS = set('<', '<=', '>', '>=', '==', '===', '!=', '!==');
|
|
412
|
+
|
|
413
|
+
function simplifyExpressionsPre(ast) {
|
|
414
|
+
// Simplify common expressions used to perform integer conversion operations
|
|
415
|
+
// in cases where no conversion is needed.
|
|
416
|
+
function simplifyIntegerConversions(ast) {
|
|
417
|
+
traverse(ast, function(node, type) {
|
|
418
|
+
if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
|
|
419
|
+
node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' && node[3][1] === node[2][3][1]) {
|
|
420
|
+
// Transform (x&A)<<B>>B to X&A.
|
|
421
|
+
var innerNode = node[2][2];
|
|
422
|
+
var shifts = node[3][1];
|
|
423
|
+
if (innerNode[0] === 'binary' && innerNode[1] === '&' && innerNode[3][0] === 'num') {
|
|
424
|
+
var mask = innerNode[3][1];
|
|
425
|
+
if (mask << shifts >> shifts === mask) {
|
|
426
|
+
return innerNode;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
} else if (type === 'binary' && node[1] === '&' && node[3][0] === 'num') {
|
|
430
|
+
// Rewrite (X < Y) & 1 to (X < Y)|0. (Subsequent passes will eliminate
|
|
431
|
+
// the |0 if possible.)
|
|
432
|
+
var input = node[2];
|
|
433
|
+
var amount = node[3][1];
|
|
434
|
+
if (input[0] === 'binary' && (input[1] in COMPARE_OPS) && amount == 1) {
|
|
435
|
+
node[1] = '|';
|
|
436
|
+
node[3][1] = 0;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// When there is a bunch of math like (((8+5)|0)+12)|0, only the external |0 is needed, one correction is enough.
|
|
443
|
+
// At each node, ((X|0)+Y)|0 can be transformed into (X+Y): The inner corrections are not needed
|
|
444
|
+
// TODO: Is the same is true for 0xff, 0xffff?
|
|
445
|
+
// Likewise, if we have |0 inside a block that will be >>'d, then the |0 is unnecessary because some
|
|
446
|
+
// 'useful' mathops already |0 anyhow.
|
|
447
|
+
|
|
448
|
+
function simplifyBitops(ast) {
|
|
449
|
+
var SAFE_BINARY_OPS;
|
|
450
|
+
if (asm) {
|
|
451
|
+
SAFE_BINARY_OPS = set('+', '-'); // division is unsafe as it creates non-ints in JS; mod is unsafe as signs matter so we can't remove |0's; mul does not nest with +,- in asm
|
|
452
|
+
} else {
|
|
453
|
+
SAFE_BINARY_OPS = set('+', '-', '*');
|
|
454
|
+
}
|
|
455
|
+
var COERCION_REQUIRING_OPS = set('sub', 'unary-prefix'); // ops that in asm must be coerced right away
|
|
456
|
+
var COERCION_REQUIRING_BINARIES = set('*', '/', '%'); // binary ops that in asm must be coerced
|
|
457
|
+
var ZERO = ['num', 0];
|
|
458
|
+
|
|
459
|
+
function removeMultipleOrZero() {
|
|
460
|
+
var rerun = true;
|
|
461
|
+
while (rerun) {
|
|
462
|
+
rerun = false;
|
|
463
|
+
traverse(ast, function process(node, type, stack) {
|
|
464
|
+
if (type === 'binary' && node[1] === '|') {
|
|
465
|
+
if (node[2][0] === 'num' && node[3][0] === 'num') {
|
|
466
|
+
node[2][1] |= node[3][1];
|
|
467
|
+
return node[2];
|
|
468
|
+
}
|
|
469
|
+
var go = false;
|
|
470
|
+
if (jsonCompare(node[2], ZERO)) {
|
|
471
|
+
// canonicalize order
|
|
472
|
+
var temp = node[3];
|
|
473
|
+
node[3] = node[2];
|
|
474
|
+
node[2] = temp;
|
|
475
|
+
go = true;
|
|
476
|
+
} else if (jsonCompare(node[3], ZERO)) {
|
|
477
|
+
go = true;
|
|
478
|
+
}
|
|
479
|
+
if (!go) {
|
|
480
|
+
stack.push(1);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
// We might be able to remove this correction
|
|
484
|
+
for (var i = stack.length-1; i >= 0; i--) {
|
|
485
|
+
if (stack[i] >= 1) {
|
|
486
|
+
if (asm) {
|
|
487
|
+
if (stack[stack.length-1] < 2 && node[2][0] === 'call') break; // we can only remove multiple |0s on these
|
|
488
|
+
if (stack[stack.length-1] < 1 && (node[2][0] in COERCION_REQUIRING_OPS ||
|
|
489
|
+
(node[2][0] === 'binary' && node[2][1] in COERCION_REQUIRING_BINARIES))) break; // we can remove |0 or >>2
|
|
490
|
+
}
|
|
491
|
+
// we will replace ourselves with the non-zero side. Recursively process that node.
|
|
492
|
+
var result = jsonCompare(node[2], ZERO) ? node[3] : node[2], other;
|
|
493
|
+
// replace node in-place
|
|
494
|
+
node.length = result.length;
|
|
495
|
+
for (var j = 0; j < result.length; j++) {
|
|
496
|
+
node[j] = result[j];
|
|
497
|
+
}
|
|
498
|
+
rerun = true;
|
|
499
|
+
return process(result, result[0], stack);
|
|
500
|
+
} else if (stack[i] === -1) {
|
|
501
|
+
break; // Too bad, we can't
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
stack.push(2); // From here on up, no need for this kind of correction, it's done at the top
|
|
505
|
+
// (Add this at the end, so it is only added if we did not remove it)
|
|
506
|
+
} else if (type === 'binary' && node[1] in USEFUL_BINARY_OPS) {
|
|
507
|
+
stack.push(1);
|
|
508
|
+
} else if ((type === 'binary' && node[1] in SAFE_BINARY_OPS) || type === 'num' || type === 'name') {
|
|
509
|
+
stack.push(0); // This node is safe in that it does not interfere with this optimization
|
|
510
|
+
} else if (type === 'unary-prefix' && node[1] === '~') {
|
|
511
|
+
stack.push(1);
|
|
512
|
+
} else {
|
|
513
|
+
stack.push(-1); // This node is dangerous! Give up if you see this before you see '1'
|
|
514
|
+
}
|
|
515
|
+
}, null, []);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
removeMultipleOrZero();
|
|
520
|
+
|
|
521
|
+
// & and heap-related optimizations
|
|
522
|
+
|
|
523
|
+
var heapBits, heapUnsigned;
|
|
524
|
+
function parseHeap(name) {
|
|
525
|
+
if (name.substr(0, 4) != 'HEAP') return false;
|
|
526
|
+
heapUnsigned = name[4] === 'U';
|
|
527
|
+
heapBits = parseInt(name.substr(heapUnsigned ? 5 : 4));
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
var hasTempDoublePtr = false, rerunOrZeroPass = false;
|
|
532
|
+
|
|
533
|
+
traverse(ast, function(node, type) {
|
|
534
|
+
if (type === 'name') {
|
|
535
|
+
if (node[1] === 'tempDoublePtr') hasTempDoublePtr = true;
|
|
536
|
+
} else if (type === 'binary' && node[1] === '&' && node[3][0] === 'num') {
|
|
537
|
+
if (node[2][0] === 'num') return ['num', node[2][1] & node[3][1]];
|
|
538
|
+
var input = node[2];
|
|
539
|
+
var amount = node[3][1];
|
|
540
|
+
if (input[0] === 'binary' && input[1] === '&' && input[3][0] === 'num') {
|
|
541
|
+
// Collapse X & 255 & 1
|
|
542
|
+
node[3][1] = amount & input[3][1];
|
|
543
|
+
node[2] = input[2];
|
|
544
|
+
} else if (input[0] === 'sub' && input[1][0] === 'name') {
|
|
545
|
+
// HEAP8[..] & 255 => HEAPU8[..]
|
|
546
|
+
var name = input[1][1];
|
|
547
|
+
if (parseHeap(name)) {
|
|
548
|
+
if (amount === Math.pow(2, heapBits)-1) {
|
|
549
|
+
if (!heapUnsigned) {
|
|
550
|
+
input[1][1] = 'HEAPU' + heapBits; // make unsigned
|
|
551
|
+
}
|
|
552
|
+
if (asm) {
|
|
553
|
+
// we cannot return HEAPU8 without a coercion, but at least we do HEAP8 & 255 => HEAPU8 | 0
|
|
554
|
+
node[1] = '|';
|
|
555
|
+
node[3][1] = 0;
|
|
556
|
+
return node;
|
|
557
|
+
}
|
|
558
|
+
return input;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
} else if (type === 'binary' && node[1] === '^') {
|
|
563
|
+
// LLVM represents bitwise not as xor with -1. Translate it back to an actual bitwise not.
|
|
564
|
+
if (node[3][0] === 'unary-prefix' && node[3][1] === '-' && node[3][2][0] === 'num' &&
|
|
565
|
+
node[3][2][1] === 1 &&
|
|
566
|
+
!(node[2][0] == 'unary-prefix' && node[2][1] == '~')) { // avoid creating ~~~ which is confusing for asm given the role of ~~
|
|
567
|
+
return ['unary-prefix', '~', node[2]];
|
|
568
|
+
}
|
|
569
|
+
} else if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
|
|
570
|
+
node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' &&
|
|
571
|
+
node[2][2][0] === 'sub' && node[2][2][1][0] === 'name') {
|
|
572
|
+
// collapse HEAPU?8[..] << 24 >> 24 etc. into HEAP8[..] | 0
|
|
573
|
+
var amount = node[3][1];
|
|
574
|
+
var name = node[2][2][1][1];
|
|
575
|
+
if (amount === node[2][3][1] && parseHeap(name)) {
|
|
576
|
+
if (heapBits === 32 - amount) {
|
|
577
|
+
node[2][2][1][1] = 'HEAP' + heapBits;
|
|
578
|
+
node[1] = '|';
|
|
579
|
+
node[2] = node[2][2];
|
|
580
|
+
node[3][1] = 0;
|
|
581
|
+
rerunOrZeroPass = true;
|
|
582
|
+
return node;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
} else if (type === 'assign') {
|
|
586
|
+
// optimizations for assigning into HEAP32 specifically
|
|
587
|
+
if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name' && node[2][1][1] === 'HEAP32') {
|
|
588
|
+
// HEAP32[..] = x | 0 does not need the | 0 (unless it is a mandatory |0 of a call)
|
|
589
|
+
if (node[3][0] === 'binary' && node[3][1] === '|') {
|
|
590
|
+
if (node[3][2][0] === 'num' && node[3][2][1] === 0 && node[3][3][0] != 'call') {
|
|
591
|
+
node[3] = node[3][3];
|
|
592
|
+
} else if (node[3][3][0] === 'num' && node[3][3][1] === 0 && node[3][2][0] != 'call') {
|
|
593
|
+
node[3] = node[3][2];
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
var value = node[3];
|
|
598
|
+
if (value[0] === 'binary' && value[1] === '|') {
|
|
599
|
+
// canonicalize order of |0 to end
|
|
600
|
+
if (value[2][0] === 'num' && value[2][1] === 0) {
|
|
601
|
+
var temp = value[2];
|
|
602
|
+
value[2] = value[3];
|
|
603
|
+
value[3] = temp;
|
|
604
|
+
}
|
|
605
|
+
// if a seq ends in an |0, remove an external |0
|
|
606
|
+
// note that it is only safe to do this in assigns, like we are doing here (return (x, y|0); is not valid)
|
|
607
|
+
if (value[2][0] === 'seq' && value[2][2][0] === 'binary' && value[2][2][1] in USEFUL_BINARY_OPS) {
|
|
608
|
+
node[3] = value[2];
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
} else if (type == 'sub' && node[1][0] == 'name' && /^FUNCTION_TABLE.*/.exec(node[1][1])) {
|
|
612
|
+
return null; // do not traverse subchildren here, we should not collapse 55 & 126. TODO: optimize this into a nonvirtual call (also because we lose some other opts here)!
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
if (rerunOrZeroPass) removeMultipleOrZero();
|
|
617
|
+
|
|
618
|
+
if (asm) {
|
|
619
|
+
if (hasTempDoublePtr) {
|
|
620
|
+
traverse(ast, function(node, type) {
|
|
621
|
+
if (type === 'assign') {
|
|
622
|
+
if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name' && node[2][1][1] === 'HEAP32') {
|
|
623
|
+
// remove bitcasts that are now obviously pointless, e.g.
|
|
624
|
+
// HEAP32[$45 >> 2] = HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0;
|
|
625
|
+
var value = node[3];
|
|
626
|
+
if (value[0] === 'seq' && value[1][0] === 'assign' && value[1][2][0] === 'sub' && value[1][2][1][0] === 'name' && value[1][2][1][1] === 'HEAPF32' &&
|
|
627
|
+
value[1][2][2][0] === 'binary' && value[1][2][2][2][0] === 'name' && value[1][2][2][2][1] === 'tempDoublePtr') {
|
|
628
|
+
// transform to HEAPF32[$45 >> 2] = ($14 < $28 ? $14 : $28) - $42;
|
|
629
|
+
node[2][1][1] = 'HEAPF32';
|
|
630
|
+
node[3] = value[1][3];
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
} else if (type === 'seq') {
|
|
634
|
+
// (HEAP32[tempDoublePtr >> 2] = HEAP32[$37 >> 2], +HEAPF32[tempDoublePtr >> 2])
|
|
635
|
+
// ==>
|
|
636
|
+
// +HEAPF32[$37 >> 2]
|
|
637
|
+
if (node[0] === 'seq' && node[1][0] === 'assign' && node[1][2][0] === 'sub' && node[1][2][1][0] === 'name' &&
|
|
638
|
+
(node[1][2][1][1] === 'HEAP32' || node[1][2][1][1] === 'HEAPF32') &&
|
|
639
|
+
node[1][2][2][0] === 'binary' && node[1][2][2][2][0] === 'name' && node[1][2][2][2][1] === 'tempDoublePtr' &&
|
|
640
|
+
node[1][3][0] === 'sub' && node[1][3][1][0] === 'name' && (node[1][3][1][1] === 'HEAP32' || node[1][3][1][1] === 'HEAPF32') &&
|
|
641
|
+
node[2][0] !== 'seq') { // avoid (x, y, z) which can be used for tempDoublePtr on doubles for alignment fixes
|
|
642
|
+
if (node[1][2][1][1] === 'HEAP32') {
|
|
643
|
+
node[1][3][1][1] = 'HEAPF32';
|
|
644
|
+
return ['unary-prefix', '+', node[1][3]];
|
|
645
|
+
} else {
|
|
646
|
+
node[1][3][1][1] = 'HEAP32';
|
|
647
|
+
return ['binary', '|', node[1][3], ['num', 0]];
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// finally, wipe out remaining ones by finding cases where all assignments to X are bitcasts, and all uses are writes to
|
|
654
|
+
// the other heap type, then eliminate the bitcast
|
|
655
|
+
var bitcastVars = {};
|
|
656
|
+
traverse(ast, function(node, type) {
|
|
657
|
+
if (type === 'assign' && node[1] === true && node[2][0] === 'name') {
|
|
658
|
+
var value = node[3];
|
|
659
|
+
if (value[0] === 'seq' && value[1][0] === 'assign' && value[1][2][0] === 'sub' && value[1][2][1][0] === 'name' &&
|
|
660
|
+
(value[1][2][1][1] === 'HEAP32' || value[1][2][1][1] === 'HEAPF32') &&
|
|
661
|
+
value[1][2][2][0] === 'binary' && value[1][2][2][2][0] === 'name' && value[1][2][2][2][1] === 'tempDoublePtr') {
|
|
662
|
+
var name = node[2][1];
|
|
663
|
+
if (!bitcastVars[name]) bitcastVars[name] = {
|
|
664
|
+
define_HEAP32: 0, define_HEAPF32: 0, use_HEAP32: 0, use_HEAPF32: 0, bad: false, namings: 0, defines: [], uses: []
|
|
665
|
+
};
|
|
666
|
+
bitcastVars[name]['define_' + value[1][2][1][1]]++;
|
|
667
|
+
bitcastVars[name].defines.push(node);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
traverse(ast, function(node, type) {
|
|
672
|
+
if (type === 'name' && bitcastVars[node[1]]) {
|
|
673
|
+
bitcastVars[node[1]].namings++;
|
|
674
|
+
} else if (type === 'assign' && node[1] === true) {
|
|
675
|
+
var value = node[3];
|
|
676
|
+
if (value[0] === 'name') {
|
|
677
|
+
var name = value[1];
|
|
678
|
+
if (bitcastVars[name]) {
|
|
679
|
+
var target = node[2];
|
|
680
|
+
if (target[0] === 'sub' && target[1][0] === 'name' && (target[1][1] === 'HEAP32' || target[1][1] === 'HEAPF32')) {
|
|
681
|
+
bitcastVars[name]['use_' + target[1][1]]++;
|
|
682
|
+
bitcastVars[name].uses.push(node);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
var asmData = normalizeAsm(ast);
|
|
689
|
+
for (var v in bitcastVars) {
|
|
690
|
+
var info = bitcastVars[v];
|
|
691
|
+
// good variables define only one type, use only one type, have definitions and uses, and define as a different type than they use
|
|
692
|
+
if (info.define_HEAP32*info.define_HEAPF32 === 0 && info.use_HEAP32*info.use_HEAPF32 === 0 &&
|
|
693
|
+
info.define_HEAP32+info.define_HEAPF32 > 0 && info.use_HEAP32+info.use_HEAPF32 > 0 &&
|
|
694
|
+
info.define_HEAP32*info.use_HEAP32 === 0 && info.define_HEAPF32*info.use_HEAPF32 === 0 &&
|
|
695
|
+
v in asmData.vars && info.namings === info.define_HEAP32+info.define_HEAPF32+info.use_HEAP32+info.use_HEAPF32) {
|
|
696
|
+
var correct = info.use_HEAP32 ? 'HEAPF32' : 'HEAP32';
|
|
697
|
+
info.defines.forEach(function(define) {
|
|
698
|
+
define[3] = define[3][1][3];
|
|
699
|
+
if (correct === 'HEAP32') {
|
|
700
|
+
define[3] = ['binary', '|', define[3], ['num', 0]];
|
|
701
|
+
} else {
|
|
702
|
+
define[3] = ['unary-prefix', '+', define[3]];
|
|
703
|
+
}
|
|
704
|
+
// do we want a simplifybitops on the new values here?
|
|
705
|
+
});
|
|
706
|
+
info.uses.forEach(function(use) {
|
|
707
|
+
use[2][1][1] = correct;
|
|
708
|
+
});
|
|
709
|
+
asmData.vars[v] = 1 - asmData.vars[v];
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
denormalizeAsm(ast, asmData);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// optimize num >> num, in asm we need this here since we do not run optimizeShifts
|
|
716
|
+
traverse(ast, function(node, type) {
|
|
717
|
+
if (type === 'binary' && node[1] === '>>' && node[2][0] === 'num' && node[3][0] === 'num') {
|
|
718
|
+
node[0] = 'num';
|
|
719
|
+
node[1] = node[2][1] >> node[3][1];
|
|
720
|
+
node.length = 2;
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// The most common mathop is addition, e.g. in getelementptr done repeatedly. We can join all of those,
|
|
727
|
+
// by doing (num+num) ==> newnum, and (name+num)+num = name+newnum
|
|
728
|
+
function joinAdditions(ast) {
|
|
729
|
+
var rerun = true;
|
|
730
|
+
while (rerun) {
|
|
731
|
+
rerun = false;
|
|
732
|
+
traverse(ast, function(node, type) {
|
|
733
|
+
if (type === 'binary' && node[1] === '+') {
|
|
734
|
+
if (node[2][0] === 'num' && node[3][0] === 'num') {
|
|
735
|
+
rerun = true;
|
|
736
|
+
node[2][1] += node[3][1];
|
|
737
|
+
return node[2];
|
|
738
|
+
}
|
|
739
|
+
for (var i = 2; i <= 3; i++) {
|
|
740
|
+
var ii = 5-i;
|
|
741
|
+
for (var j = 2; j <= 3; j++) {
|
|
742
|
+
if (node[i][0] === 'num' && node[ii][0] === 'binary' && node[ii][1] === '+' && node[ii][j][0] === 'num') {
|
|
743
|
+
rerun = true;
|
|
744
|
+
node[ii][j][1] += node[i][1];
|
|
745
|
+
return node[ii];
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// if (x === 0) can be if (!x), etc.
|
|
755
|
+
function simplifyZeroComp(ast) {
|
|
756
|
+
traverse(ast, function(node, type) {
|
|
757
|
+
var binary;
|
|
758
|
+
if (type === 'if' && (binary = node[1])[0] === 'binary') {
|
|
759
|
+
if ((binary[1] === '!=' || binary[1] === '!==') && binary[3][0] === 'num' && binary[3][1] === 0) {
|
|
760
|
+
node[1] = binary[2];
|
|
761
|
+
return node;
|
|
762
|
+
} else if ((binary[1] === '==' || binary[1] === '===') && binary[3][0] === 'num' && binary[3][1] === 0) {
|
|
763
|
+
node[1] = ['unary-prefix', '!', binary[2]];
|
|
764
|
+
return node;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function asmOpts(fun) {
|
|
771
|
+
// Add final returns when necessary
|
|
772
|
+
var returnType = null;
|
|
773
|
+
traverse(fun, function(node, type) {
|
|
774
|
+
if (type === 'return' && node[1]) {
|
|
775
|
+
returnType = detectAsmCoercion(node[1]);
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
// Add a final return if one is missing.
|
|
779
|
+
if (returnType !== null) {
|
|
780
|
+
var stats = getStatements(fun);
|
|
781
|
+
var last = stats[stats.length-1];
|
|
782
|
+
if (last[0] != 'return') {
|
|
783
|
+
var returnValue = ['num', 0];
|
|
784
|
+
if (returnType === ASM_DOUBLE) returnValue = ['unary-prefix', '+', returnValue];
|
|
785
|
+
stats.push(['return', returnValue]);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
traverseGeneratedFunctions(ast, function(func) {
|
|
791
|
+
simplifyIntegerConversions(func);
|
|
792
|
+
simplifyBitops(func);
|
|
793
|
+
joinAdditions(func);
|
|
794
|
+
// simplifyZeroComp(func); TODO: investigate performance
|
|
795
|
+
if (asm) asmOpts(func);
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// In typed arrays mode 2, we can have
|
|
800
|
+
// HEAP[x >> 2]
|
|
801
|
+
// very often. We can in some cases do the shift on the variable itself when it is set,
|
|
802
|
+
// to greatly reduce the number of shift operations.
|
|
803
|
+
// TODO: when shifting a variable, if there are other uses, keep an unshifted version too, to prevent slowdowns?
|
|
804
|
+
function optimizeShiftsInternal(ast, conservative) {
|
|
805
|
+
var MAX_SHIFTS = 3;
|
|
806
|
+
traverseGeneratedFunctions(ast, function(fun) {
|
|
807
|
+
var funMore = true;
|
|
808
|
+
var funFinished = {};
|
|
809
|
+
while (funMore) {
|
|
810
|
+
funMore = false;
|
|
811
|
+
// Recognize variables and parameters
|
|
812
|
+
var vars = {};
|
|
813
|
+
function newVar(name, param, addUse) {
|
|
814
|
+
if (!vars[name]) {
|
|
815
|
+
vars[name] = {
|
|
816
|
+
param: param,
|
|
817
|
+
defs: addUse ? 1 : 0,
|
|
818
|
+
uses: 0,
|
|
819
|
+
timesShifted: [0, 0, 0, 0], // zero shifts of size 0, 1, 2, 3
|
|
820
|
+
benefit: 0,
|
|
821
|
+
primaryShift: -1
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
// params
|
|
826
|
+
if (fun[2]) {
|
|
827
|
+
fun[2].forEach(function(arg) {
|
|
828
|
+
newVar(arg, true, true);
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
// vars
|
|
832
|
+
// XXX if var has >>=, ignore it here? That means a previous pass already optimized it
|
|
833
|
+
var hasSwitch = traverse(fun, function(node, type) {
|
|
834
|
+
if (type === 'var') {
|
|
835
|
+
node[1].forEach(function(arg) {
|
|
836
|
+
newVar(arg[0], false, arg[1]);
|
|
837
|
+
});
|
|
838
|
+
} else if (type === 'switch') {
|
|
839
|
+
// The relooper can't always optimize functions, and we currently don't work with
|
|
840
|
+
// switch statements when optimizing shifts. Bail.
|
|
841
|
+
return true;
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
if (hasSwitch) {
|
|
845
|
+
break;
|
|
846
|
+
}
|
|
847
|
+
// uses and defs TODO: weight uses by being inside a loop (powers). without that, we
|
|
848
|
+
// optimize for code size, not speed.
|
|
849
|
+
traverse(fun, function(node, type, stack) {
|
|
850
|
+
stack.push(node);
|
|
851
|
+
if (type === 'name' && vars[node[1]] && stack[stack.length-2][0] != 'assign') {
|
|
852
|
+
vars[node[1]].uses++;
|
|
853
|
+
} else if (type === 'assign' && node[2][0] === 'name' && vars[node[2][1]]) {
|
|
854
|
+
vars[node[2][1]].defs++;
|
|
855
|
+
}
|
|
856
|
+
}, null, []);
|
|
857
|
+
// First, break up elements inside a shift. This lets us see clearly what to do next.
|
|
858
|
+
traverse(fun, function(node, type) {
|
|
859
|
+
if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num') {
|
|
860
|
+
var shifts = node[3][1];
|
|
861
|
+
if (shifts <= MAX_SHIFTS) {
|
|
862
|
+
// Push the >> inside the value elements
|
|
863
|
+
function addShift(subNode) {
|
|
864
|
+
if (subNode[0] === 'binary' && subNode[1] === '+') {
|
|
865
|
+
subNode[2] = addShift(subNode[2]);
|
|
866
|
+
subNode[3] = addShift(subNode[3]);
|
|
867
|
+
return subNode;
|
|
868
|
+
}
|
|
869
|
+
if (subNode[0] === 'name' && !subNode[2]) { // names are returned with a shift, but we also note their being shifted
|
|
870
|
+
var name = subNode[1];
|
|
871
|
+
if (vars[name]) {
|
|
872
|
+
vars[name].timesShifted[shifts]++;
|
|
873
|
+
subNode[2] = true;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return ['binary', '>>', subNode, ['num', shifts]];
|
|
877
|
+
}
|
|
878
|
+
return addShift(node[2]);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
traverse(fun, function(node, type) {
|
|
883
|
+
if (node[0] === 'name' && node[2]) {
|
|
884
|
+
return node.slice(0, 2); // clean up our notes
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
// At this point, shifted expressions are split up, and we know who the vars are and their info, so we can decide
|
|
888
|
+
// TODO: vars that depend on other vars
|
|
889
|
+
for (var name in vars) {
|
|
890
|
+
var data = vars[name];
|
|
891
|
+
var totalTimesShifted = sum(data.timesShifted);
|
|
892
|
+
if (totalTimesShifted === 0) {
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
if (totalTimesShifted != Math.max.apply(null, data.timesShifted)) {
|
|
896
|
+
// TODO: Handle multiple different shifts
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (funFinished[name]) continue;
|
|
900
|
+
// We have one shift size (and possible unshifted uses). Consider replacing this variable with a shifted clone. If
|
|
901
|
+
// the estimated benefit is >0, we will do it
|
|
902
|
+
if (data.defs === 1) {
|
|
903
|
+
data.benefit = totalTimesShifted - 2*(data.defs + (data.param ? 1 : 0));
|
|
904
|
+
}
|
|
905
|
+
if (conservative) data.benefit = 0;
|
|
906
|
+
if (data.benefit > 0) {
|
|
907
|
+
funMore = true; // We will reprocess this function
|
|
908
|
+
for (var i = 0; i < 4; i++) {
|
|
909
|
+
if (data.timesShifted[i]) {
|
|
910
|
+
data.primaryShift = i;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
//printErr(JSON.stringify(vars));
|
|
916
|
+
function cleanNotes() { // We need to mark 'name' nodes as 'processed' in some passes here; this cleans the notes up
|
|
917
|
+
traverse(fun, function(node, type) {
|
|
918
|
+
if (node[0] === 'name' && node[2]) {
|
|
919
|
+
return node.slice(0, 2);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
cleanNotes();
|
|
924
|
+
// Apply changes
|
|
925
|
+
function needsShift(name) {
|
|
926
|
+
return vars[name] && vars[name].primaryShift >= 0;
|
|
927
|
+
}
|
|
928
|
+
for (var name in vars) { // add shifts for params and var's for all new variables
|
|
929
|
+
var data = vars[name];
|
|
930
|
+
if (needsShift(name)) {
|
|
931
|
+
if (data.param) {
|
|
932
|
+
fun[3].unshift(['var', [[name + '$s' + data.primaryShift, ['binary', '>>', ['name', name], ['num', data.primaryShift]]]]]);
|
|
933
|
+
} else {
|
|
934
|
+
fun[3].unshift(['var', [[name + '$s' + data.primaryShift]]]);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
traverse(fun, function(node, type, stack) { // add shift to assignments
|
|
939
|
+
stack.push(node);
|
|
940
|
+
if (node[0] === 'assign' && node[1] === true && node[2][0] === 'name' && needsShift(node[2][1]) && !node[2][2]) {
|
|
941
|
+
var name = node[2][1];
|
|
942
|
+
var data = vars[name];
|
|
943
|
+
var parent = stack[stack.length-3];
|
|
944
|
+
var statements = getStatements(parent);
|
|
945
|
+
assert(statements, 'Invalid parent for assign-shift: ' + dump(parent));
|
|
946
|
+
var i = statements.indexOf(stack[stack.length-2]);
|
|
947
|
+
statements.splice(i+1, 0, ['stat', ['assign', true, ['name', name + '$s' + data.primaryShift], ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]]);
|
|
948
|
+
} else if (node[0] === 'var') {
|
|
949
|
+
var args = node[1];
|
|
950
|
+
for (var i = 0; i < args.length; i++) {
|
|
951
|
+
var arg = args[i];
|
|
952
|
+
var name = arg[0];
|
|
953
|
+
var data = vars[name];
|
|
954
|
+
if (arg[1] && needsShift(name)) {
|
|
955
|
+
args.splice(i+1, 0, [name + '$s' + data.primaryShift, ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return node;
|
|
959
|
+
}
|
|
960
|
+
}, null, []);
|
|
961
|
+
cleanNotes();
|
|
962
|
+
traverse(fun, function(node, type, stack) { // replace shifted name with new variable
|
|
963
|
+
stack.push(node);
|
|
964
|
+
if (node[0] === 'binary' && node[1] === '>>' && node[2][0] === 'name' && needsShift(node[2][1]) && node[3][0] === 'num') {
|
|
965
|
+
var name = node[2][1];
|
|
966
|
+
var data = vars[name];
|
|
967
|
+
var parent = stack[stack.length-2];
|
|
968
|
+
// Don't modify in |x$sN = x >> 2|, in normal assigns and in var assigns
|
|
969
|
+
if (parent[0] === 'assign' && parent[2][0] === 'name' && parent[2][1] === name + '$s' + data.primaryShift) return;
|
|
970
|
+
if (parent[0] === name + '$s' + data.primaryShift) return;
|
|
971
|
+
if (node[3][1] === data.primaryShift) {
|
|
972
|
+
return ['name', name + '$s' + data.primaryShift];
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}, null, []);
|
|
976
|
+
cleanNotes();
|
|
977
|
+
var SIMPLE_SHIFTS = set('<<', '>>');
|
|
978
|
+
var more = true;
|
|
979
|
+
while (more) { // combine shifts in the same direction as an optimization
|
|
980
|
+
more = false;
|
|
981
|
+
traverse(fun, function(node, type) {
|
|
982
|
+
if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] === 'binary' && node[2][1] === node[1] &&
|
|
983
|
+
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
|
|
984
|
+
more = true;
|
|
985
|
+
return ['binary', node[1], node[2][2], ['num', node[3][1] + node[2][3][1]]];
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
// Before recombining, do some additional optimizations
|
|
990
|
+
traverse(fun, function(node, type) {
|
|
991
|
+
// Apply constant shifts onto constants
|
|
992
|
+
if (type === 'binary' && node[1] === '>>' && node[2][0] === 'num' && node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) {
|
|
993
|
+
var subNode = node[2];
|
|
994
|
+
var shifts = node[3][1];
|
|
995
|
+
var result = subNode[1] / Math.pow(2, shifts);
|
|
996
|
+
if (result % 1 === 0) {
|
|
997
|
+
subNode[1] = result;
|
|
998
|
+
return subNode;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
// Optimize the case of ($a*80)>>2 into ($a*20)|0
|
|
1002
|
+
if (type === 'binary' && node[1] in SIMPLE_SHIFTS &&
|
|
1003
|
+
node[2][0] === 'binary' && node[2][1] === '*') {
|
|
1004
|
+
var mulNode = node[2];
|
|
1005
|
+
if (mulNode[2][0] === 'num') {
|
|
1006
|
+
var temp = mulNode[2];
|
|
1007
|
+
mulNode[2] = mulNode[3];
|
|
1008
|
+
mulNode[3] = temp;
|
|
1009
|
+
}
|
|
1010
|
+
if (mulNode[3][0] === 'num') {
|
|
1011
|
+
if (node[1] === '<<') {
|
|
1012
|
+
mulNode[3][1] *= Math.pow(2, node[3][1]);
|
|
1013
|
+
node[1] = '|';
|
|
1014
|
+
node[3][1] = 0;
|
|
1015
|
+
return node;
|
|
1016
|
+
} else {
|
|
1017
|
+
if (mulNode[3][1] % Math.pow(2, node[3][1]) === 0) {
|
|
1018
|
+
mulNode[3][1] /= Math.pow(2, node[3][1]);
|
|
1019
|
+
node[1] = '|';
|
|
1020
|
+
node[3][1] = 0;
|
|
1021
|
+
return node;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
/* XXX - theoretically useful optimization(s), but commented out as not helpful in practice
|
|
1027
|
+
// Transform (x << 2) >> 2 into x & mask or something even simpler
|
|
1028
|
+
if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
|
|
1029
|
+
node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' && node[3][1] === node[2][3][1]) {
|
|
1030
|
+
var subNode = node[2];
|
|
1031
|
+
var shifts = node[3][1];
|
|
1032
|
+
var mask = ((0xffffffff << shifts) >>> shifts) | 0;
|
|
1033
|
+
return ['binary', '&', subNode[2], ['num', mask]];
|
|
1034
|
+
//return ['binary', '|', subNode[2], ['num', 0]];
|
|
1035
|
+
//return subNode[2];
|
|
1036
|
+
}
|
|
1037
|
+
*/
|
|
1038
|
+
});
|
|
1039
|
+
// Re-combine remaining shifts, to undo the breaking up we did before. may require reordering inside +'s
|
|
1040
|
+
traverse(fun, function(node, type, stack) {
|
|
1041
|
+
stack.push(node);
|
|
1042
|
+
if (type === 'binary' && node[1] === '+' && (stack[stack.length-2][0] != 'binary' || stack[stack.length-2][1] !== '+')) {
|
|
1043
|
+
// 'Flatten' added items
|
|
1044
|
+
var addedItems = [];
|
|
1045
|
+
function flatten(node) {
|
|
1046
|
+
if (node[0] === 'binary' && node[1] === '+') {
|
|
1047
|
+
flatten(node[2]);
|
|
1048
|
+
flatten(node[3]);
|
|
1049
|
+
} else {
|
|
1050
|
+
addedItems.push(node);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
flatten(node);
|
|
1054
|
+
var originalOrder = addedItems.slice();
|
|
1055
|
+
function key(node) { // a unique value for all relevant shifts for recombining, non-unique for stuff we don't need to bother with
|
|
1056
|
+
function originalOrderKey(item) {
|
|
1057
|
+
return -originalOrder.indexOf(item);
|
|
1058
|
+
}
|
|
1059
|
+
if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS) {
|
|
1060
|
+
if (node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) return 2*node[3][1] + (node[1] === '>>' ? 100 : 0); // 0-106
|
|
1061
|
+
return (node[1] === '>>' ? 20000 : 10000) + originalOrderKey(node);
|
|
1062
|
+
}
|
|
1063
|
+
if (node[0] === 'num') return -20000 + node[1];
|
|
1064
|
+
return -10000 + originalOrderKey(node); // Don't modify the original order if we don't modify anything
|
|
1065
|
+
}
|
|
1066
|
+
for (var i = 0; i < addedItems.length; i++) {
|
|
1067
|
+
if (addedItems[i][0] === 'string') return; // this node is not relevant for us
|
|
1068
|
+
}
|
|
1069
|
+
addedItems.sort(function(node1, node2) {
|
|
1070
|
+
return key(node1) - key(node2);
|
|
1071
|
+
});
|
|
1072
|
+
// Regenerate items, now sorted
|
|
1073
|
+
var i = 0;
|
|
1074
|
+
while (i < addedItems.length-1) { // re-combine inside addedItems
|
|
1075
|
+
var k = key(addedItems[i]), k1 = key(addedItems[i+1]);
|
|
1076
|
+
if (k === k1 && k >= 0 && k1 <= 106) {
|
|
1077
|
+
addedItems[i] = ['binary', addedItems[i][1], ['binary', '+', addedItems[i][2], addedItems[i+1][2]], addedItems[i][3]];
|
|
1078
|
+
addedItems.splice(i+1, 1);
|
|
1079
|
+
} else {
|
|
1080
|
+
i++;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
var num = 0;
|
|
1084
|
+
for (i = 0; i < addedItems.length; i++) { // combine all numbers into one
|
|
1085
|
+
if (addedItems[i][0] === 'num') {
|
|
1086
|
+
num += addedItems[i][1];
|
|
1087
|
+
addedItems.splice(i, 1);
|
|
1088
|
+
i--;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (num != 0) { // add the numbers into an existing shift, we
|
|
1092
|
+
// prefer (x+5)>>7 over (x>>7)+5 , since >>'s result is known to be 32-bit and is more easily optimized.
|
|
1093
|
+
// Also, in the former we can avoid the parentheses, which saves a little space (the number will be bigger,
|
|
1094
|
+
// so it might take more space, but normally at most one more digit).
|
|
1095
|
+
var added = false;
|
|
1096
|
+
for (i = 0; i < addedItems.length; i++) {
|
|
1097
|
+
if (addedItems[i][0] === 'binary' && addedItems[i][1] === '>>' && addedItems[i][3][0] === 'num' && addedItems[i][3][1] <= MAX_SHIFTS) {
|
|
1098
|
+
addedItems[i] = ['binary', '>>', ['binary', '+', addedItems[i][2], ['num', num << addedItems[i][3][1]]], addedItems[i][3]];
|
|
1099
|
+
added = true;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
if (!added) {
|
|
1103
|
+
addedItems.unshift(['num', num]);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
var ret = addedItems.pop();
|
|
1107
|
+
while (addedItems.length > 0) { // re-create AST from addedItems
|
|
1108
|
+
ret = ['binary', '+', ret, addedItems.pop()];
|
|
1109
|
+
}
|
|
1110
|
+
return ret;
|
|
1111
|
+
}
|
|
1112
|
+
}, null, []);
|
|
1113
|
+
// Note finished variables
|
|
1114
|
+
for (var name in vars) {
|
|
1115
|
+
funFinished[name] = true;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
function optimizeShiftsConservative(ast) {
|
|
1122
|
+
optimizeShiftsInternal(ast, true);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function optimizeShiftsAggressive(ast) {
|
|
1126
|
+
optimizeShiftsInternal(ast, false);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// We often have branchings that are simplified so one end vanishes, and
|
|
1130
|
+
// we then get
|
|
1131
|
+
// if (!(x < 5))
|
|
1132
|
+
// or such. Simplifying these saves space and time.
|
|
1133
|
+
function simplifyNotCompsDirect(node) {
|
|
1134
|
+
if (node[0] === 'unary-prefix' && node[1] === '!') {
|
|
1135
|
+
if (node[2][0] === 'binary') {
|
|
1136
|
+
switch(node[2][1]) {
|
|
1137
|
+
case '<': return ['binary', '>=', node[2][2], node[2][3]];
|
|
1138
|
+
case '>': return ['binary', '<=', node[2][2], node[2][3]];
|
|
1139
|
+
case '<=': return ['binary', '>', node[2][2], node[2][3]];
|
|
1140
|
+
case '>=': return ['binary', '<', node[2][2], node[2][3]];
|
|
1141
|
+
case '==': return ['binary', '!=', node[2][2], node[2][3]];
|
|
1142
|
+
case '!=': return ['binary', '==', node[2][2], node[2][3]];
|
|
1143
|
+
case '===': return ['binary', '!==', node[2][2], node[2][3]];
|
|
1144
|
+
case '!==': return ['binary', '===', node[2][2], node[2][3]];
|
|
1145
|
+
}
|
|
1146
|
+
} else if (node[2][0] === 'unary-prefix' && node[2][1] === '!') {
|
|
1147
|
+
return node[2][2];
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
if (!simplifyNotCompsPass) return node;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
var simplifyNotCompsPass = false;
|
|
1154
|
+
|
|
1155
|
+
function simplifyNotComps(ast) {
|
|
1156
|
+
simplifyNotCompsPass = true;
|
|
1157
|
+
traverse(ast, simplifyNotCompsDirect);
|
|
1158
|
+
simplifyNotCompsPass = false;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
function simplifyExpressionsPost(ast) {
|
|
1162
|
+
simplifyNotComps(ast);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
var NO_SIDE_EFFECTS = set('num', 'name');
|
|
1166
|
+
|
|
1167
|
+
function hasSideEffects(node) { // this is 99% incomplete!
|
|
1168
|
+
if (node[0] in NO_SIDE_EFFECTS) return false;
|
|
1169
|
+
if (node[0] === 'unary-prefix') return hasSideEffects(node[2]);
|
|
1170
|
+
if (node[0] === 'binary') return hasSideEffects(node[2]) || hasSideEffects(node[3]);
|
|
1171
|
+
return true;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// Clear out empty ifs and blocks, and redundant blocks/stats and so forth
|
|
1175
|
+
// Operates on generated functions only
|
|
1176
|
+
function vacuum(ast) {
|
|
1177
|
+
function isEmpty(node) {
|
|
1178
|
+
if (!node) return true;
|
|
1179
|
+
if (node[0] === 'toplevel' && (!node[1] || node[1].length === 0)) return true;
|
|
1180
|
+
if (node[0] === 'block' && (!node[1] || (typeof node[1] != 'object') || node[1].length === 0 || (node[1].length === 1 && isEmpty(node[1])))) return true;
|
|
1181
|
+
return false;
|
|
1182
|
+
}
|
|
1183
|
+
function simplifyList(node, si) {
|
|
1184
|
+
var changed = false;
|
|
1185
|
+
// Merge block items into this list, thus removing unneeded |{ .. }|'s
|
|
1186
|
+
var statements = node[si];
|
|
1187
|
+
var i = 0;
|
|
1188
|
+
while (i < statements.length) {
|
|
1189
|
+
var subNode = statements[i];
|
|
1190
|
+
if (subNode[0] === 'block') {
|
|
1191
|
+
statements.splice.apply(statements, [i, 1].concat(subNode[1] || []));
|
|
1192
|
+
changed = true;
|
|
1193
|
+
} else {
|
|
1194
|
+
i++;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
// Remove empty items
|
|
1198
|
+
var pre = node[si].length;
|
|
1199
|
+
node[si] = node[si].filter(function(node) { return !isEmpty(node) });
|
|
1200
|
+
if (node[si].length < pre) changed = true;
|
|
1201
|
+
if (changed) {
|
|
1202
|
+
return node;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
function vacuumInternal(node) {
|
|
1206
|
+
traverseChildren(node, vacuumInternal);
|
|
1207
|
+
var ret;
|
|
1208
|
+
switch(node[0]) {
|
|
1209
|
+
case 'block': {
|
|
1210
|
+
if (node[1] && node[1].length === 1 && node[1][0][0] === 'block') {
|
|
1211
|
+
return node[1][0];
|
|
1212
|
+
} else if (typeof node[1] === 'object') {
|
|
1213
|
+
ret = simplifyList(node, 1);
|
|
1214
|
+
if (ret) return ret;
|
|
1215
|
+
}
|
|
1216
|
+
} break;
|
|
1217
|
+
case 'stat': {
|
|
1218
|
+
if (node[1][0] === 'block') {
|
|
1219
|
+
return node[1];
|
|
1220
|
+
}
|
|
1221
|
+
} break;
|
|
1222
|
+
case 'defun': {
|
|
1223
|
+
if (node[3].length === 1 && node[3][0][0] === 'block') {
|
|
1224
|
+
node[3] = node[3][0][1];
|
|
1225
|
+
return node;
|
|
1226
|
+
} else {
|
|
1227
|
+
ret = simplifyList(node, 3);
|
|
1228
|
+
if (ret) return ret;
|
|
1229
|
+
}
|
|
1230
|
+
} break;
|
|
1231
|
+
case 'do': {
|
|
1232
|
+
if (node[1][0] === 'num' && node[2][0] === 'toplevel' && (!node[2][1] || node[2][1].length === 0)) {
|
|
1233
|
+
return emptyNode();
|
|
1234
|
+
} else if (isEmpty(node[2]) && !hasSideEffects(node[1])) {
|
|
1235
|
+
return emptyNode();
|
|
1236
|
+
}
|
|
1237
|
+
} break;
|
|
1238
|
+
case 'label': {
|
|
1239
|
+
if (node[2][0] === 'toplevel' && (!node[2][1] || node[2][1].length === 0)) {
|
|
1240
|
+
return emptyNode();
|
|
1241
|
+
}
|
|
1242
|
+
} break;
|
|
1243
|
+
case 'if': {
|
|
1244
|
+
var empty2 = isEmpty(node[2]), empty3 = isEmpty(node[3]), has3 = node.length === 4;
|
|
1245
|
+
if (!empty2 && empty3 && has3) { // empty else clauses
|
|
1246
|
+
return node.slice(0, 3);
|
|
1247
|
+
} else if (empty2 && !empty3) { // empty if blocks
|
|
1248
|
+
return ['if', ['unary-prefix', '!', node[1]], node[3]];
|
|
1249
|
+
} else if (empty2 && empty3) {
|
|
1250
|
+
if (hasSideEffects(node[1])) {
|
|
1251
|
+
return ['stat', node[1]];
|
|
1252
|
+
} else {
|
|
1253
|
+
return emptyNode();
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
} break;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
traverseGeneratedFunctions(ast, function(node) {
|
|
1260
|
+
vacuumInternal(node);
|
|
1261
|
+
simplifyNotComps(node);
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
function getStatements(node) {
|
|
1266
|
+
if (node[0] === 'defun') {
|
|
1267
|
+
return node[3];
|
|
1268
|
+
} else if (node[0] === 'block') {
|
|
1269
|
+
return node[1];
|
|
1270
|
+
} else {
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// Multiple blocks from the relooper are, in general, implemented by
|
|
1276
|
+
// if (label === x) { } else if ..
|
|
1277
|
+
// and branching into them by
|
|
1278
|
+
// if (condition) { label === x } else ..
|
|
1279
|
+
// We can hoist the multiple block into the condition, thus removing code and one 'if' check
|
|
1280
|
+
function hoistMultiples(ast) {
|
|
1281
|
+
traverseGeneratedFunctions(ast, function(node) {
|
|
1282
|
+
traverse(node, function(node, type) {
|
|
1283
|
+
var statements = getStatements(node);
|
|
1284
|
+
if (!statements) return;
|
|
1285
|
+
var modified = false;
|
|
1286
|
+
for (var i = 0; i < statements.length-1; i++) {
|
|
1287
|
+
var modifiedI = false;
|
|
1288
|
+
var pre = statements[i];
|
|
1289
|
+
if (pre[0] != 'if') continue;
|
|
1290
|
+
var post = statements[i+1];
|
|
1291
|
+
// Look into some block types. shell() will then recreate the shell that we looked into
|
|
1292
|
+
var postInner = post;
|
|
1293
|
+
var shellLabel = false, shellDo = false;
|
|
1294
|
+
while (true) {
|
|
1295
|
+
if (postInner[0] === 'label') {
|
|
1296
|
+
shellLabel = postInner[1];
|
|
1297
|
+
postInner = postInner[2];
|
|
1298
|
+
} else if (postInner[0] === 'do') {
|
|
1299
|
+
shellDo = postInner[1];
|
|
1300
|
+
postInner = postInner[2][1][0];
|
|
1301
|
+
} else {
|
|
1302
|
+
break; // give up
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
if (postInner[0] != 'if') continue;
|
|
1306
|
+
// Look into this if, and its elseifs
|
|
1307
|
+
while (postInner && postInner[0] === 'if') {
|
|
1308
|
+
var cond = postInner[1];
|
|
1309
|
+
if (cond[0] === 'binary' && cond[1] === '==' && cond[2][0] === 'name' && cond[2][1] === 'label') {
|
|
1310
|
+
assert(cond[3][0] === 'num');
|
|
1311
|
+
// We have a valid Multiple check here. Try to hoist it, look for the source in |pre| and its else's
|
|
1312
|
+
var labelNum = cond[3][1];
|
|
1313
|
+
var labelBlock = postInner[2];
|
|
1314
|
+
assert(labelBlock[0] === 'block');
|
|
1315
|
+
var found = false;
|
|
1316
|
+
traverse(pre, function(preNode, preType) {
|
|
1317
|
+
if (!found && preType === 'assign' && preNode[2][0] === 'name' && preNode[2][1] === 'label') {
|
|
1318
|
+
assert(preNode[3][0] === 'num');
|
|
1319
|
+
if (preNode[3][1] === labelNum) {
|
|
1320
|
+
// That's it! Hoist away. We can also throw away the label setting as its goal has already been achieved
|
|
1321
|
+
found = true;
|
|
1322
|
+
modifiedI = true;
|
|
1323
|
+
postInner[2] = ['block', []];
|
|
1324
|
+
return labelBlock;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
postInner = postInner[3]; // Proceed to look in the else clause
|
|
1330
|
+
}
|
|
1331
|
+
if (modifiedI) {
|
|
1332
|
+
if (shellDo) {
|
|
1333
|
+
statements[i] = ['do', shellDo, ['block', [statements[i]]]];
|
|
1334
|
+
}
|
|
1335
|
+
if (shellLabel) {
|
|
1336
|
+
statements[i] = ['label', shellLabel, statements[i]];
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
if (modified) return node;
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
// After hoisting in this function, it is safe to remove { label = x; } blocks, because
|
|
1344
|
+
// if they were leading to the next code right after them, they would be hoisted, and if they
|
|
1345
|
+
// are going to some other place entirely, they would break or continue. The only risky
|
|
1346
|
+
// situation is if the code after us is a multiple, in which case we might be checking for
|
|
1347
|
+
// this label inside it (or in a later multiple, even)
|
|
1348
|
+
function tryEliminate(node) {
|
|
1349
|
+
if (node[0] === 'if') {
|
|
1350
|
+
var replaced;
|
|
1351
|
+
if (replaced = tryEliminate(node[2])) node[2] = replaced;
|
|
1352
|
+
if (node[3] && (replaced = tryEliminate(node[3]))) node[3] = replaced;
|
|
1353
|
+
} else {
|
|
1354
|
+
if (node[0] === 'block' && node[1] && node[1].length > 0) {
|
|
1355
|
+
var subNode = node[1][node[1].length-1];
|
|
1356
|
+
if (subNode[0] === 'stat' && subNode[1][0] === 'assign' && subNode[1][2][0] === 'name' &&
|
|
1357
|
+
subNode[1][2][1] === 'label' && subNode[1][3][0] === 'num') {
|
|
1358
|
+
if (node[1].length === 1) {
|
|
1359
|
+
return emptyNode();
|
|
1360
|
+
} else {
|
|
1361
|
+
node[1].splice(node[1].length-1, 1);
|
|
1362
|
+
return node;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
function getActualStatement(node) { // find the actual active statement, ignoring a label and one-time do loop
|
|
1370
|
+
if (node[0] === 'label') node = node[2];
|
|
1371
|
+
if (node[0] === 'do') node = node[2];
|
|
1372
|
+
if (node[0] === 'block' && node[1].length === 1) node = node[1][0];
|
|
1373
|
+
return node;
|
|
1374
|
+
}
|
|
1375
|
+
vacuum(node);
|
|
1376
|
+
traverse(node, function(node, type) {
|
|
1377
|
+
var statements = getStatements(node);
|
|
1378
|
+
if (!statements) return;
|
|
1379
|
+
for (var i = 0; i < statements.length-1; i++) {
|
|
1380
|
+
var curr = getActualStatement(statements[i]);
|
|
1381
|
+
var next = statements[i+1];
|
|
1382
|
+
if (curr[0] === 'if' && next[0] != 'if' && next[0] != 'label' && next[0] != 'do' && next[0] != 'while') {
|
|
1383
|
+
tryEliminate(curr);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
vacuum(ast);
|
|
1390
|
+
|
|
1391
|
+
// Afterpass: Reduce
|
|
1392
|
+
// if (..) { .. break|continue } else { .. }
|
|
1393
|
+
// to
|
|
1394
|
+
// if (..) { .. break|continue } ..
|
|
1395
|
+
traverseGenerated(ast, function(container, type) {
|
|
1396
|
+
var statements = getStatements(container);
|
|
1397
|
+
if (!statements) return;
|
|
1398
|
+
for (var i = 0; i < statements.length; i++) {
|
|
1399
|
+
var node = statements[i];
|
|
1400
|
+
if (node[0] === 'if' && node[2][0] === 'block' && node[3] && node[3][0] === 'block') {
|
|
1401
|
+
var stat1 = node[2][1], stat2 = node[3][1];
|
|
1402
|
+
// If break|continue in the latter and not the former, reverse them
|
|
1403
|
+
if (!(stat1[stat1.length-1][0] in LOOP_FLOW) && (stat2[stat2.length-1][0] in LOOP_FLOW)) {
|
|
1404
|
+
var temp = node[3];
|
|
1405
|
+
node[3] = node[2];
|
|
1406
|
+
node[2] = temp;
|
|
1407
|
+
node[1] = simplifyNotCompsDirect(['unary-prefix', '!', node[1]]);
|
|
1408
|
+
stat1 = node[2][1];
|
|
1409
|
+
stat2 = node[3][1];
|
|
1410
|
+
}
|
|
1411
|
+
if (stat1[stat1.length-1][0] in LOOP_FLOW) {
|
|
1412
|
+
statements.splice.apply(statements, [i+1, 0].concat(stat2));
|
|
1413
|
+
node[3] = null;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// Simplifies loops
|
|
1421
|
+
// WARNING: This assumes all loops and breaks/continues are labelled
|
|
1422
|
+
function loopOptimizer(ast) {
|
|
1423
|
+
// Remove unneeded labels and one-time (do while(0)) loops. It is convenient to do these both at once.
|
|
1424
|
+
function passTwo(ast) {
|
|
1425
|
+
var neededDos = [];
|
|
1426
|
+
// Find unneeded labels
|
|
1427
|
+
traverseGenerated(ast, function(node, type, stack) {
|
|
1428
|
+
if (type === 'label' && node[2][0] in LOOP) {
|
|
1429
|
+
// this is a labelled loop. we don't know if it's needed yet. Mark its label for removal for now now.
|
|
1430
|
+
stack.push(node);
|
|
1431
|
+
node[1] = '+' + node[1];
|
|
1432
|
+
} else if (type in LOOP) {
|
|
1433
|
+
stack.push(node);
|
|
1434
|
+
} else if (type in LOOP_FLOW) {
|
|
1435
|
+
// Find topmost loop, and its label if there is one
|
|
1436
|
+
var lastLabel = null, lastLoop = null, i = stack.length-1;
|
|
1437
|
+
while (i >= 0 && !lastLoop) {
|
|
1438
|
+
if (stack[i][0] in LOOP) lastLoop = stack[i];
|
|
1439
|
+
i--;
|
|
1440
|
+
}
|
|
1441
|
+
assert(lastLoop, 'Cannot break/continue without a Label');
|
|
1442
|
+
while (i >= 0 && !lastLabel) {
|
|
1443
|
+
if (stack[i][0] in LOOP) break; // another loop in the middle - no label for lastLoop
|
|
1444
|
+
if (stack[i][0] === 'label') lastLabel = stack[i];
|
|
1445
|
+
i--;
|
|
1446
|
+
}
|
|
1447
|
+
var ident = node[1]; // there may not be a label ident if this is a simple break; or continue;
|
|
1448
|
+
var plus = '+' + ident;
|
|
1449
|
+
if (lastLabel && ident && (ident === lastLabel[1] || plus === lastLabel[1])) {
|
|
1450
|
+
// If this is a 'do' loop, this break means we actually need it.
|
|
1451
|
+
neededDos.push(lastLoop);
|
|
1452
|
+
// We don't need the control flow command to have a label - it's referring to the current loop
|
|
1453
|
+
return [node[0]];
|
|
1454
|
+
} else {
|
|
1455
|
+
if (!ident) {
|
|
1456
|
+
// No label on the break/continue, so keep the last loop alive (no need for its label though)
|
|
1457
|
+
neededDos.push(lastLoop);
|
|
1458
|
+
} else {
|
|
1459
|
+
// Find the label node that needs to stay alive
|
|
1460
|
+
stack.forEach(function(label) {
|
|
1461
|
+
if (!label) return;
|
|
1462
|
+
if (label[1] === plus) label[1] = label[1].substr(1); // Remove '+', marking it as needed
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
}, null, []);
|
|
1468
|
+
// We return whether another pass is necessary
|
|
1469
|
+
var more = false;
|
|
1470
|
+
// Remove unneeded labels
|
|
1471
|
+
traverseGenerated(ast, function(node, type) {
|
|
1472
|
+
if (type === 'label' && node[1][0] === '+') {
|
|
1473
|
+
more = true;
|
|
1474
|
+
var ident = node[1].substr(1);
|
|
1475
|
+
// Remove label from loop flow commands
|
|
1476
|
+
traverse(node[2], function(node2, type) {
|
|
1477
|
+
if (type in LOOP_FLOW && node2[1] === ident) {
|
|
1478
|
+
return [node2[0]];
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
return node[2]; // Remove the label itself on the loop
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
// Remove unneeded one-time loops. We need such loops if (1) they have a label, or (2) they have a direct break so they are in neededDos.
|
|
1485
|
+
// First, add all labeled loops of this nature to neededDos
|
|
1486
|
+
traverseGenerated(ast, function(node, type) {
|
|
1487
|
+
if (type === 'label' && node[2][0] === 'do') {
|
|
1488
|
+
neededDos.push(node[2]);
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
// Remove unneeded dos, we know who they are now
|
|
1492
|
+
traverseGenerated(ast, function(node, type) {
|
|
1493
|
+
if (type === 'do' && neededDos.indexOf(node) < 0) {
|
|
1494
|
+
assert(jsonCompare(node[1], ['num', 0]), 'Trying to remove a one-time do loop that is not one of our generated ones.;');
|
|
1495
|
+
more = true;
|
|
1496
|
+
return node[2];
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
return more;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// Go
|
|
1503
|
+
|
|
1504
|
+
// TODO: pass 1: Removal of unneeded continues, breaks if they get us to where we are already going. That will
|
|
1505
|
+
// help the next pass.
|
|
1506
|
+
|
|
1507
|
+
// Multiple pass two runs may be needed, as we remove one-time loops and so forth
|
|
1508
|
+
do {
|
|
1509
|
+
var more = passTwo(ast);
|
|
1510
|
+
vacuum(ast);
|
|
1511
|
+
} while (more);
|
|
1512
|
+
|
|
1513
|
+
vacuum(ast);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
function unVarify(vars, ret) { // transform var x=1, y=2 etc. into (x=1, y=2), i.e., the same assigns, but without a var definition
|
|
1517
|
+
ret = ret || [];
|
|
1518
|
+
ret[0] = 'stat';
|
|
1519
|
+
if (vars.length === 1) {
|
|
1520
|
+
ret[1] = ['assign', true, ['name', vars[0][0]], vars[0][1]];
|
|
1521
|
+
} else {
|
|
1522
|
+
ret[1] = [];
|
|
1523
|
+
var curr = ret[1];
|
|
1524
|
+
for (var i = 0; i < vars.length-1; i++) {
|
|
1525
|
+
curr[0] = 'seq';
|
|
1526
|
+
curr[1] = ['assign', true, ['name', vars[i][0]], vars[i][1]];
|
|
1527
|
+
if (i != vars.length-2) curr = curr[2] = [];
|
|
1528
|
+
}
|
|
1529
|
+
curr[2] = ['assign', true, ['name', vars[vars.length-1][0]], vars[vars.length-1][1]];
|
|
1530
|
+
}
|
|
1531
|
+
return ret;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// asm.js support code - normalize (convert asm.js code to 'normal' JS, without
|
|
1535
|
+
// annotations, plus explicit metadata) and denormalize (vice versa)
|
|
1536
|
+
var ASM_INT = 0;
|
|
1537
|
+
var ASM_DOUBLE = 1;
|
|
1538
|
+
|
|
1539
|
+
function detectAsmCoercion(node, asmInfo) {
|
|
1540
|
+
// for params, +x vs x|0, for vars, 0.0 vs 0
|
|
1541
|
+
if (node[0] === 'num' && node[1].toString().indexOf('.') >= 0) return ASM_DOUBLE;
|
|
1542
|
+
if (node[0] === 'unary-prefix') return ASM_DOUBLE;
|
|
1543
|
+
if (asmInfo && node[0] == 'name') {
|
|
1544
|
+
if (node[1] in asmInfo.vars) return asmInfo.vars[node[1]];
|
|
1545
|
+
if (node[1] in asmInfo.params) return asmInfo.params[node[1]];
|
|
1546
|
+
}
|
|
1547
|
+
return ASM_INT;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
function makeAsmParamCoercion(param, type) {
|
|
1551
|
+
return type === ASM_INT ? ['binary', '|', ['name', param], ['num', 0]] : ['unary-prefix', '+', ['name', param]];
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
function makeAsmVarDef(v, type) {
|
|
1555
|
+
return [v, type === ASM_INT ? ['num', 0] : ['unary-prefix', '+', ['num', 0]]];
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
function getAsmType(asmInfo, name) {
|
|
1559
|
+
if (name in asmInfo.vars) return asmInfo.vars[name];
|
|
1560
|
+
return asmInfo.params[name];
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
function normalizeAsm(func) {
|
|
1564
|
+
//printErr('pre-normalize \n\n' + astToSrc(func) + '\n\n');
|
|
1565
|
+
var data = {
|
|
1566
|
+
params: {}, // ident => ASM_* type
|
|
1567
|
+
vars: {}, // ident => ASM_* type
|
|
1568
|
+
};
|
|
1569
|
+
// process initial params
|
|
1570
|
+
var stats = func[3];
|
|
1571
|
+
var i = 0;
|
|
1572
|
+
while (i < stats.length) {
|
|
1573
|
+
var node = stats[i];
|
|
1574
|
+
if (node[0] != 'stat' || node[1][0] != 'assign' || node[1][2][0] != 'name') break;
|
|
1575
|
+
node = node[1];
|
|
1576
|
+
var name = node[2][1];
|
|
1577
|
+
if (func[2] && func[2].indexOf(name) < 0) break; // not an assign into a parameter, but a global
|
|
1578
|
+
data.params[name] = detectAsmCoercion(node[3]);
|
|
1579
|
+
stats[i] = emptyNode();
|
|
1580
|
+
i++;
|
|
1581
|
+
}
|
|
1582
|
+
// process initial variable definitions
|
|
1583
|
+
outer:
|
|
1584
|
+
while (i < stats.length) {
|
|
1585
|
+
var node = stats[i];
|
|
1586
|
+
if (node[0] != 'var') break;
|
|
1587
|
+
for (var j = 0; j < node[1].length; j++) {
|
|
1588
|
+
var v = node[1][j];
|
|
1589
|
+
var name = v[0];
|
|
1590
|
+
var value = v[1];
|
|
1591
|
+
if (!(name in data.vars)) {
|
|
1592
|
+
assert(value[0] === 'num' || (value[0] === 'unary-prefix' && value[2][0] === 'num')); // must be valid coercion no-op
|
|
1593
|
+
data.vars[name] = detectAsmCoercion(value);
|
|
1594
|
+
v.length = 1; // make an un-assigning var
|
|
1595
|
+
} else {
|
|
1596
|
+
break outer;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
i++;
|
|
1600
|
+
}
|
|
1601
|
+
// finally, look for other var definitions and collect them
|
|
1602
|
+
while (i < stats.length) {
|
|
1603
|
+
traverse(stats[i], function(node, type) {
|
|
1604
|
+
if (type === 'var') {
|
|
1605
|
+
for (var j = 0; j < node[1].length; j++) {
|
|
1606
|
+
var v = node[1][j];
|
|
1607
|
+
var name = v[0];
|
|
1608
|
+
var value = v[1];
|
|
1609
|
+
if (!(name in data.vars)) {
|
|
1610
|
+
if (value[0] != 'name') {
|
|
1611
|
+
data.vars[name] = detectAsmCoercion(value); // detect by coercion
|
|
1612
|
+
} else {
|
|
1613
|
+
var origin = value[1];
|
|
1614
|
+
data.vars[name] = data.vars[origin] || ASM_INT; // detect by origin variable, or assume int for non-locals
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
unVarify(node[1], node);
|
|
1619
|
+
} else if (type === 'dot') {
|
|
1620
|
+
if (node[1][0] === 'name' && node[1][1] === 'Math') {
|
|
1621
|
+
// transform Math.max to Math_max; we forward in the latter version
|
|
1622
|
+
node[0] = 'name';
|
|
1623
|
+
node[1] = 'Math_' + node[2];
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
});
|
|
1627
|
+
i++;
|
|
1628
|
+
}
|
|
1629
|
+
//printErr('normalized \n\n' + astToSrc(func) + '\n\nwith: ' + JSON.stringify(data));
|
|
1630
|
+
return data;
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
function denormalizeAsm(func, data) {
|
|
1634
|
+
//printErr('pre-denormalize \n\n' + astToSrc(func) + '\n\nwith: ' + JSON.stringify(data));
|
|
1635
|
+
var stats = func[3];
|
|
1636
|
+
// Remove var definitions, if any
|
|
1637
|
+
for (var i = 0; i < stats.length; i++) {
|
|
1638
|
+
if (stats[i][0] === 'var') {
|
|
1639
|
+
stats[i] = emptyNode();
|
|
1640
|
+
} else {
|
|
1641
|
+
if (!isEmptyNode(stats[i])) break;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
// each param needs a line; reuse emptyNodes as much as we can
|
|
1645
|
+
var numParams = 0;
|
|
1646
|
+
for (var i in data.params) numParams++;
|
|
1647
|
+
var emptyNodes = 0;
|
|
1648
|
+
while (emptyNodes < stats.length) {
|
|
1649
|
+
if (!isEmptyNode(stats[emptyNodes])) break;
|
|
1650
|
+
emptyNodes++;
|
|
1651
|
+
}
|
|
1652
|
+
var neededEmptyNodes = numParams + 1; // params plus one big var
|
|
1653
|
+
if (neededEmptyNodes > emptyNodes) {
|
|
1654
|
+
var args = [0, 0];
|
|
1655
|
+
for (var i = 0; i < neededEmptyNodes - emptyNodes; i++) args[i+2] = 0;
|
|
1656
|
+
stats.splice.apply(stats, args);
|
|
1657
|
+
}
|
|
1658
|
+
// add param coercions
|
|
1659
|
+
var next = 0;
|
|
1660
|
+
func[2].forEach(function(param) {
|
|
1661
|
+
stats[next++] = ['stat', ['assign', true, ['name', param], makeAsmParamCoercion(param, data.params[param])]];
|
|
1662
|
+
});
|
|
1663
|
+
// add variable definitions
|
|
1664
|
+
var varDefs = [];
|
|
1665
|
+
for (var v in data.vars) {
|
|
1666
|
+
varDefs.push(makeAsmVarDef(v, data.vars[v]));
|
|
1667
|
+
}
|
|
1668
|
+
if (varDefs.length) {
|
|
1669
|
+
stats[next] = ['var', varDefs];
|
|
1670
|
+
} else {
|
|
1671
|
+
stats[next] = emptyNode();
|
|
1672
|
+
}
|
|
1673
|
+
//printErr('denormalized \n\n' + astToSrc(func) + '\n\n');
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// Very simple 'registerization', coalescing of variables into a smaller number,
|
|
1677
|
+
// as part of minification. Globals-level minification began in a previous pass,
|
|
1678
|
+
// we receive extraInfo which tells us how to rename globals. (Only in asm.js.)
|
|
1679
|
+
//
|
|
1680
|
+
// We do not optimize when there are switches, so this pass only makes sense with
|
|
1681
|
+
// relooping.
|
|
1682
|
+
// TODO: Consider how this fits in with the rest of the optimization toolchain. Do
|
|
1683
|
+
// we still need the eliminator? Closure? And in what order? Perhaps just
|
|
1684
|
+
// closure simple?
|
|
1685
|
+
function registerize(ast) {
|
|
1686
|
+
traverseGeneratedFunctions(ast, function(fun) {
|
|
1687
|
+
if (asm) var asmData = normalizeAsm(fun);
|
|
1688
|
+
// Add parameters as a first (fake) var (with assignment), so they get taken into consideration
|
|
1689
|
+
var params = {}; // note: params are special, they can never share a register between them (see later)
|
|
1690
|
+
if (fun[2] && fun[2].length) {
|
|
1691
|
+
var assign = ['num', 0];
|
|
1692
|
+
fun[3].unshift(['var', fun[2].map(function(param) {
|
|
1693
|
+
params[param] = 1;
|
|
1694
|
+
return [param, assign];
|
|
1695
|
+
})]);
|
|
1696
|
+
}
|
|
1697
|
+
if (asm) {
|
|
1698
|
+
// copy params into vars
|
|
1699
|
+
for (var p in asmData.params) asmData.vars[p] = asmData.params[p];
|
|
1700
|
+
//printErr('fake params: \n\n' + astToSrc(fun) + '\n\n');
|
|
1701
|
+
}
|
|
1702
|
+
// Replace all var definitions with assignments; we will add var definitions at the top after we registerize
|
|
1703
|
+
// We also mark local variables - i.e., having a var definition
|
|
1704
|
+
var localVars = {};
|
|
1705
|
+
var hasSwitch = false; // we cannot optimize variables if there is a switch, unless in asm mode
|
|
1706
|
+
traverse(fun, function(node, type) {
|
|
1707
|
+
if (type === 'var') {
|
|
1708
|
+
node[1].forEach(function(defined) { localVars[defined[0]] = 1 });
|
|
1709
|
+
var vars = node[1].filter(function(varr) { return varr[1] });
|
|
1710
|
+
if (vars.length >= 1) {
|
|
1711
|
+
return unVarify(vars);
|
|
1712
|
+
} else {
|
|
1713
|
+
return emptyNode();
|
|
1714
|
+
}
|
|
1715
|
+
} else if (type === 'switch') {
|
|
1716
|
+
hasSwitch = true;
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
vacuum(fun);
|
|
1720
|
+
if (extraInfo) {
|
|
1721
|
+
assert(asm);
|
|
1722
|
+
var usedGlobals = {};
|
|
1723
|
+
var nextLocal = 0;
|
|
1724
|
+
// Minify globals using the mapping we were given
|
|
1725
|
+
traverse(fun, function(node, type) {
|
|
1726
|
+
if (type === 'name') {
|
|
1727
|
+
var name = node[1];
|
|
1728
|
+
var minified = extraInfo.globals[name];
|
|
1729
|
+
if (minified) {
|
|
1730
|
+
assert(!localVars[name], name); // locals must not shadow globals, or else we don't know which is which
|
|
1731
|
+
if (localVars[minified]) {
|
|
1732
|
+
// trying to minify a global into a name used locally. rename all the locals
|
|
1733
|
+
var newName = '$_newLocal_' + (nextLocal++);
|
|
1734
|
+
assert(!localVars[newName]);
|
|
1735
|
+
if (params[minified]) {
|
|
1736
|
+
params[newName] = 1;
|
|
1737
|
+
delete params[minified];
|
|
1738
|
+
}
|
|
1739
|
+
localVars[newName] = 1;
|
|
1740
|
+
delete localVars[minified];
|
|
1741
|
+
asmData.vars[newName] = asmData.vars[minified];
|
|
1742
|
+
delete asmData.vars[minified];
|
|
1743
|
+
asmData.params[newName] = asmData.params[minified];
|
|
1744
|
+
delete asmData.params[minified];
|
|
1745
|
+
traverse(fun, function(node, type) {
|
|
1746
|
+
if (type === 'name' && node[1] === minified) {
|
|
1747
|
+
node[1] = newName;
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
if (fun[2]) {
|
|
1751
|
+
for (var i = 0; i < fun[2].length; i++) {
|
|
1752
|
+
if (fun[2][i] === minified) fun[2][i] = newName;
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
node[1] = minified;
|
|
1757
|
+
usedGlobals[minified] = 1;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
});
|
|
1761
|
+
assert(fun[1] in extraInfo.globals, fun[1]);
|
|
1762
|
+
fun[1] = extraInfo.globals[fun[1]];
|
|
1763
|
+
assert(fun[1]);
|
|
1764
|
+
var nextRegName = 0;
|
|
1765
|
+
}
|
|
1766
|
+
var regTypes = {};
|
|
1767
|
+
function getNewRegName(num, name) {
|
|
1768
|
+
if (!asm) return 'r' + num;
|
|
1769
|
+
var type = asmData.vars[name];
|
|
1770
|
+
if (!extraInfo) {
|
|
1771
|
+
var ret = (type ? 'd' : 'i') + num;
|
|
1772
|
+
regTypes[ret] = type;
|
|
1773
|
+
return ret;
|
|
1774
|
+
}
|
|
1775
|
+
// find the next free minified name that is not used by a global that shows up in this function
|
|
1776
|
+
while (nextRegName < extraInfo.names.length) {
|
|
1777
|
+
var ret = extraInfo.names[nextRegName++];
|
|
1778
|
+
if (!usedGlobals[ret]) {
|
|
1779
|
+
regTypes[ret] = type;
|
|
1780
|
+
return ret;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
assert('ran out of names');
|
|
1784
|
+
}
|
|
1785
|
+
// Find the # of uses of each variable.
|
|
1786
|
+
// While doing so, check if all a variable's uses are dominated in a simple
|
|
1787
|
+
// way by a simple assign, if so, then we can assign its register to it
|
|
1788
|
+
// just for its definition to its last use, and not to the entire toplevel loop,
|
|
1789
|
+
// we call such variables "optimizable"
|
|
1790
|
+
var varUses = {};
|
|
1791
|
+
var level = 1;
|
|
1792
|
+
var levelDominations = {};
|
|
1793
|
+
var varLevels = {};
|
|
1794
|
+
var possibles = {};
|
|
1795
|
+
var unoptimizables = {};
|
|
1796
|
+
function purgeLevel() {
|
|
1797
|
+
// Invalidate all dominating on this level, further users make it unoptimizable
|
|
1798
|
+
for (var name in levelDominations[level]) {
|
|
1799
|
+
varLevels[name] = 0;
|
|
1800
|
+
}
|
|
1801
|
+
levelDominations[level] = null;
|
|
1802
|
+
level--;
|
|
1803
|
+
}
|
|
1804
|
+
traverse(fun, function possibilifier(node, type) {
|
|
1805
|
+
if (type === 'name') {
|
|
1806
|
+
var name = node[1];
|
|
1807
|
+
if (localVars[name]) {
|
|
1808
|
+
if (!varUses[name]) varUses[name] = 0;
|
|
1809
|
+
varUses[name]++;
|
|
1810
|
+
if (possibles[name] && !varLevels[name]) unoptimizables[name] = 1; // used outside of simple domination
|
|
1811
|
+
}
|
|
1812
|
+
} else if (type === 'assign' && typeof node[1] != 'string') {
|
|
1813
|
+
if (node[2] && node[2][0] === 'name') {
|
|
1814
|
+
var name = node[2][1];
|
|
1815
|
+
// if local and not yet used, this might be optimizable if we dominate
|
|
1816
|
+
// all other uses
|
|
1817
|
+
if (localVars[name] && !varUses[name] && !varLevels[name]) {
|
|
1818
|
+
possibles[name] = 1;
|
|
1819
|
+
varLevels[name] = level;
|
|
1820
|
+
if (!levelDominations[level]) levelDominations[level] = {};
|
|
1821
|
+
levelDominations[level][name] = 1;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
} else if (type in CONTROL_FLOW) {
|
|
1825
|
+
// recurse children, in the context of a loop
|
|
1826
|
+
switch(type) {
|
|
1827
|
+
case 'while': case 'do': {
|
|
1828
|
+
traverse(node[1], possibilifier);
|
|
1829
|
+
level++;
|
|
1830
|
+
traverse(node[2], possibilifier);
|
|
1831
|
+
purgeLevel();
|
|
1832
|
+
break;
|
|
1833
|
+
}
|
|
1834
|
+
case 'for': {
|
|
1835
|
+
traverse(node[1], possibilifier);
|
|
1836
|
+
for (var i = 2; i <= 4; i++) {
|
|
1837
|
+
level++;
|
|
1838
|
+
traverse(node[i], possibilifier);
|
|
1839
|
+
purgeLevel();
|
|
1840
|
+
}
|
|
1841
|
+
break;
|
|
1842
|
+
}
|
|
1843
|
+
case 'if': {
|
|
1844
|
+
traverse(node[1], possibilifier);
|
|
1845
|
+
level++;
|
|
1846
|
+
traverse(node[2], possibilifier);
|
|
1847
|
+
purgeLevel();
|
|
1848
|
+
if (node[3]) {
|
|
1849
|
+
level++;
|
|
1850
|
+
traverse(node[3], possibilifier);
|
|
1851
|
+
purgeLevel();
|
|
1852
|
+
}
|
|
1853
|
+
break;
|
|
1854
|
+
}
|
|
1855
|
+
case 'switch': {
|
|
1856
|
+
traverse(node[1], possibilifier);
|
|
1857
|
+
var cases = node[2];
|
|
1858
|
+
for (var i = 0; i < cases.length; i++) {
|
|
1859
|
+
level++;
|
|
1860
|
+
traverse(cases[i][1], possibilifier);
|
|
1861
|
+
purgeLevel();
|
|
1862
|
+
}
|
|
1863
|
+
break;
|
|
1864
|
+
}
|
|
1865
|
+
default: throw dumpAst(node);
|
|
1866
|
+
}
|
|
1867
|
+
return null; // prevent recursion into children, which we already did
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
var optimizables = {};
|
|
1871
|
+
if (!hasSwitch || asm) {
|
|
1872
|
+
for (var possible in possibles) {
|
|
1873
|
+
if (!unoptimizables[possible]) optimizables[possible] = 1;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
//printErr('optimizables: ' + JSON.stringify(optimizables));
|
|
1878
|
+
//printErr('unoptimizables: ' + JSON.stringify(unoptimizables));
|
|
1879
|
+
|
|
1880
|
+
// Go through the function's code, assigning 'registers'.
|
|
1881
|
+
// The only tricky bit is to keep variables locked on a register through loops,
|
|
1882
|
+
// since they can potentially be returned to. Optimizable variables lock onto
|
|
1883
|
+
// loops that they enter, unoptimizable variables lock in a conservative way
|
|
1884
|
+
// into the topmost loop.
|
|
1885
|
+
// Note that we cannot lock onto a variable in a loop if it was used and free'd
|
|
1886
|
+
// before! (then they could overwrite us in the early part of the loop). For now
|
|
1887
|
+
// we just use a fresh register to make sure we avoid this, but it could be
|
|
1888
|
+
// optimized to check for safe registers (free, and not used in this loop level).
|
|
1889
|
+
var varRegs = {}; // maps variables to the register they will use all their life
|
|
1890
|
+
var freeRegsClasses = asm ? [[], []] : []; // two classes for asm, one otherwise
|
|
1891
|
+
var nextReg = 1;
|
|
1892
|
+
var fullNames = {};
|
|
1893
|
+
var loopRegs = {}; // for each loop nesting level, the list of bound variables
|
|
1894
|
+
var loops = 0; // 0 is toplevel, 1 is first loop, etc
|
|
1895
|
+
var saved = 0;
|
|
1896
|
+
var activeOptimizables = {};
|
|
1897
|
+
var optimizableLoops = {};
|
|
1898
|
+
var paramRegs = {}; // true if the register is used by a parameter (and so needs no def at start of function; also cannot
|
|
1899
|
+
// be shared with another param, each needs its own)
|
|
1900
|
+
function decUse(name) {
|
|
1901
|
+
if (!varUses[name]) return false; // no uses left, or not a relevant variable
|
|
1902
|
+
if (optimizables[name]) activeOptimizables[name] = 1;
|
|
1903
|
+
var reg = varRegs[name];
|
|
1904
|
+
if (asm) assert(name in asmData.vars, name);
|
|
1905
|
+
var freeRegs = asm ? freeRegsClasses[asmData.vars[name]] : freeRegsClasses;
|
|
1906
|
+
if (!reg) {
|
|
1907
|
+
// acquire register
|
|
1908
|
+
if (optimizables[name] && freeRegs.length > 0 &&
|
|
1909
|
+
!(params[name] && paramRegs[freeRegs[freeRegs.length-1]])) { // do not share registers between parameters
|
|
1910
|
+
reg = freeRegs.pop();
|
|
1911
|
+
saved++;
|
|
1912
|
+
} else {
|
|
1913
|
+
reg = nextReg++;
|
|
1914
|
+
fullNames[reg] = getNewRegName(reg, name);
|
|
1915
|
+
if (params[name]) paramRegs[reg] = 1;
|
|
1916
|
+
}
|
|
1917
|
+
varRegs[name] = reg;
|
|
1918
|
+
}
|
|
1919
|
+
varUses[name]--;
|
|
1920
|
+
assert(varUses[name] >= 0);
|
|
1921
|
+
if (varUses[name] === 0) {
|
|
1922
|
+
if (optimizables[name]) delete activeOptimizables[name];
|
|
1923
|
+
// If we are not in a loop, or we are optimizable and not bound to a loop
|
|
1924
|
+
// (we might have been in one but left it), we can free the register now.
|
|
1925
|
+
if (loops === 0 || (optimizables[name] && !optimizableLoops[name])) {
|
|
1926
|
+
// free register
|
|
1927
|
+
freeRegs.push(reg);
|
|
1928
|
+
} else {
|
|
1929
|
+
// when the relevant loop is exited, we will free the register
|
|
1930
|
+
var releventLoop = optimizables[name] ? (optimizableLoops[name] || 1) : 1;
|
|
1931
|
+
if (!loopRegs[releventLoop]) loopRegs[releventLoop] = [];
|
|
1932
|
+
loopRegs[releventLoop].push(reg);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
return true;
|
|
1936
|
+
}
|
|
1937
|
+
traverse(fun, function(node, type) { // XXX we rely on traversal order being the same as execution order here
|
|
1938
|
+
if (type === 'name') {
|
|
1939
|
+
var name = node[1];
|
|
1940
|
+
if (decUse(name)) {
|
|
1941
|
+
node[1] = fullNames[varRegs[name]];
|
|
1942
|
+
}
|
|
1943
|
+
} else if (type in LOOP) {
|
|
1944
|
+
loops++;
|
|
1945
|
+
// Active optimizables lock onto this loop, if not locked onto one that encloses this one
|
|
1946
|
+
for (var name in activeOptimizables) {
|
|
1947
|
+
if (!optimizableLoops[name]) {
|
|
1948
|
+
optimizableLoops[name] = loops;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
}, function(node, type) {
|
|
1953
|
+
if (type in LOOP) {
|
|
1954
|
+
// Free registers that were locked to this loop
|
|
1955
|
+
if (loopRegs[loops]) {
|
|
1956
|
+
if (asm) {
|
|
1957
|
+
loopRegs[loops].forEach(function(loopReg) {
|
|
1958
|
+
freeRegsClasses[regTypes[fullNames[loopReg]]].push(loopReg);
|
|
1959
|
+
});
|
|
1960
|
+
} else {
|
|
1961
|
+
freeRegsClasses = freeRegsClasses.concat(loopRegs[loops]);
|
|
1962
|
+
}
|
|
1963
|
+
loopRegs[loops].length = 0;
|
|
1964
|
+
}
|
|
1965
|
+
loops--;
|
|
1966
|
+
}
|
|
1967
|
+
});
|
|
1968
|
+
if (fun[2] && fun[2].length) {
|
|
1969
|
+
fun[2].length = 0; // clear params, we will fill with registers
|
|
1970
|
+
fun[3].shift(); // remove fake initial var
|
|
1971
|
+
}
|
|
1972
|
+
//printErr('var regs: ' + JSON.stringify(varRegs) + '\n\nparam regs: ' + JSON.stringify(paramRegs));
|
|
1973
|
+
if (!asm) {
|
|
1974
|
+
if (nextReg > 1) {
|
|
1975
|
+
var vars = [];
|
|
1976
|
+
for (var i = 1; i < nextReg; i++) {
|
|
1977
|
+
var reg = fullNames[i];
|
|
1978
|
+
if (!paramRegs[i]) {
|
|
1979
|
+
vars.push([reg]);
|
|
1980
|
+
} else {
|
|
1981
|
+
fun[2].push(reg);
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
if (vars.length > 0) getStatements(fun).unshift(['var', vars]);
|
|
1985
|
+
}
|
|
1986
|
+
} else {
|
|
1987
|
+
//printErr('unfake params: \n\n' + astToSrc(fun) + '\n\n');
|
|
1988
|
+
var finalAsmData = {
|
|
1989
|
+
params: {},
|
|
1990
|
+
vars: {},
|
|
1991
|
+
};
|
|
1992
|
+
for (var i = 1; i < nextReg; i++) {
|
|
1993
|
+
var reg = fullNames[i];
|
|
1994
|
+
var type = regTypes[reg];
|
|
1995
|
+
if (!paramRegs[i]) {
|
|
1996
|
+
finalAsmData.vars[reg] = type;
|
|
1997
|
+
} else {
|
|
1998
|
+
finalAsmData.params[reg] = type;
|
|
1999
|
+
fun[2].push(reg);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
denormalizeAsm(fun, finalAsmData);
|
|
2003
|
+
}
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// Eliminator aka Expressionizer
|
|
2008
|
+
//
|
|
2009
|
+
// The goal of this pass is to eliminate unneeded variables (which represent one of the infinite registers in the LLVM
|
|
2010
|
+
// model) and thus to generate complex expressions where possible, for example
|
|
2011
|
+
//
|
|
2012
|
+
// var x = a(10);
|
|
2013
|
+
// var y = HEAP[20];
|
|
2014
|
+
// print(x+y);
|
|
2015
|
+
//
|
|
2016
|
+
// can be transformed into
|
|
2017
|
+
//
|
|
2018
|
+
// print(a(10)+HEAP[20]);
|
|
2019
|
+
//
|
|
2020
|
+
// The basic principle is to scan along the code in the order of parsing/execution, and keep a list of tracked
|
|
2021
|
+
// variables that are current contenders for elimination. We must untrack when we see something that we cannot
|
|
2022
|
+
// cross, for example, a write to memory means we must invalidate variables that depend on reading from
|
|
2023
|
+
// memory, since if we change the order then we do not preserve the computation.
|
|
2024
|
+
//
|
|
2025
|
+
// We rely on some assumptions about emscripten-generated code here, which means we can do a lot more than
|
|
2026
|
+
// a general JS optimization can. For example, we assume that 'sub' nodes (indexing like HEAP[..]) are
|
|
2027
|
+
// memory accesses or FUNCTION_TABLE accesses, and in both cases that the symbol cannot be replaced although
|
|
2028
|
+
// the contents can. So we assume FUNCTION_TABLE might have its contents changed but not be pointed to
|
|
2029
|
+
// a different object, which allows
|
|
2030
|
+
//
|
|
2031
|
+
// var x = f();
|
|
2032
|
+
// FUNCTION_TABLE[x]();
|
|
2033
|
+
//
|
|
2034
|
+
// to be optimized (f could replace FUNCTION_TABLE, so in general JS eliminating x is not valid).
|
|
2035
|
+
//
|
|
2036
|
+
// In memSafe mode, we are more careful and assume functions can replace HEAP and FUNCTION_TABLE, which
|
|
2037
|
+
// can happen in ALLOW_MEMORY_GROWTH mode
|
|
2038
|
+
|
|
2039
|
+
var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch'); // do is checked carefully, however
|
|
2040
|
+
var NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS = set('name', 'num', 'string', 'binary', 'sub', 'unary-prefix');
|
|
2041
|
+
var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break', 'continue', 'dot'); // dot can only be STRING_TABLE.*
|
|
2042
|
+
var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body)
|
|
2043
|
+
|
|
2044
|
+
function isTempDoublePtrAccess(node) { // these are used in bitcasts; they are not really affecting memory, and should cause no invalidation
|
|
2045
|
+
assert(node[0] === 'sub');
|
|
2046
|
+
return (node[2][0] === 'name' && node[2][1] === 'tempDoublePtr') ||
|
|
2047
|
+
(node[2][0] === 'binary' && ((node[2][2][0] === 'name' && node[2][2][1] === 'tempDoublePtr') ||
|
|
2048
|
+
(node[2][3][0] === 'name' && node[2][3][1] === 'tempDoublePtr')));
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
function eliminate(ast, memSafe) {
|
|
2052
|
+
// Find variables that have a single use, and if they can be eliminated, do so
|
|
2053
|
+
traverseGeneratedFunctions(ast, function(func, type) {
|
|
2054
|
+
if (asm) var asmData = normalizeAsm(func);
|
|
2055
|
+
//printErr('eliminate in ' + func[1]);
|
|
2056
|
+
|
|
2057
|
+
// First, find the potentially eliminatable functions: that have one definition and one use
|
|
2058
|
+
var definitions = {};
|
|
2059
|
+
var uses = {};
|
|
2060
|
+
var namings = {};
|
|
2061
|
+
var values = {};
|
|
2062
|
+
var locals = {};
|
|
2063
|
+
var varsToRemove = {}; // variables being removed, that we can eliminate all 'var x;' of (this refers to 'var' nodes we should remove)
|
|
2064
|
+
// 1 means we should remove it, 2 means we successfully removed it
|
|
2065
|
+
var varsToTryToRemove = {}; // variables that have 0 uses, but have side effects - when we scan we can try to remove them
|
|
2066
|
+
// add arguments as locals
|
|
2067
|
+
if (func[2]) {
|
|
2068
|
+
for (var i = 0; i < func[2].length; i++) {
|
|
2069
|
+
locals[func[2][i]] = true;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
// examine body and note locals
|
|
2073
|
+
var hasSwitch = false;
|
|
2074
|
+
traverse(func, function(node, type) {
|
|
2075
|
+
if (type === 'var') {
|
|
2076
|
+
var node1 = node[1];
|
|
2077
|
+
for (var i = 0; i < node1.length; i++) {
|
|
2078
|
+
var node1i = node1[i];
|
|
2079
|
+
var name = node1i[0];
|
|
2080
|
+
var value = node1i[1];
|
|
2081
|
+
if (value) {
|
|
2082
|
+
if (!(name in definitions)) definitions[name] = 0;
|
|
2083
|
+
definitions[name]++;
|
|
2084
|
+
if (!values[name]) values[name] = value;
|
|
2085
|
+
}
|
|
2086
|
+
if (!uses[name]) uses[name] = 0;
|
|
2087
|
+
locals[name] = true;
|
|
2088
|
+
}
|
|
2089
|
+
} else if (type === 'name') {
|
|
2090
|
+
var name = node[1];
|
|
2091
|
+
if (!uses[name]) uses[name] = 0;
|
|
2092
|
+
uses[name]++;
|
|
2093
|
+
} else if (type === 'assign') {
|
|
2094
|
+
var target = node[2];
|
|
2095
|
+
if (target[0] === 'name') {
|
|
2096
|
+
var name = target[1];
|
|
2097
|
+
if (!(name in definitions)) definitions[name] = 0;
|
|
2098
|
+
definitions[name]++;
|
|
2099
|
+
if (!uses[name]) uses[name] = 0;
|
|
2100
|
+
if (!values[name]) values[name] = node[3];
|
|
2101
|
+
if (node[1] === true) { // not +=, -= etc., just =
|
|
2102
|
+
uses[name]--; // because the name node will show up by itself in the previous case
|
|
2103
|
+
if (!namings[name]) namings[name] = 0;
|
|
2104
|
+
namings[name]++; // offset it here, this tracks the total times we are named
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
} else if (type === 'switch') {
|
|
2108
|
+
hasSwitch = true;
|
|
2109
|
+
}
|
|
2110
|
+
});
|
|
2111
|
+
|
|
2112
|
+
for (var used in uses) {
|
|
2113
|
+
namings[used] = (namings[used] || 0) + uses[used];
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// we cannot eliminate variables if there is a switch
|
|
2117
|
+
if (hasSwitch && !asm) return;
|
|
2118
|
+
|
|
2119
|
+
var potentials = {}; // local variables with 1 definition and 1 use
|
|
2120
|
+
var sideEffectFree = {}; // whether a local variable has no side effects in its definition. Only relevant when there are no uses
|
|
2121
|
+
|
|
2122
|
+
function unprocessVariable(name) {
|
|
2123
|
+
if (name in potentials) delete potentials[name];
|
|
2124
|
+
if (name in varsToRemove) delete varsToRemove[name];
|
|
2125
|
+
if (name in sideEffectFree) delete sideEffectFree[name];
|
|
2126
|
+
if (name in varsToTryToRemove) delete varsToTryToRemove[name];
|
|
2127
|
+
}
|
|
2128
|
+
function processVariable(name) {
|
|
2129
|
+
if (definitions[name] === 1 && uses[name] === 1) {
|
|
2130
|
+
potentials[name] = 1;
|
|
2131
|
+
} else if (uses[name] === 0 && (!definitions[name] || definitions[name] <= 1)) { // no uses, no def or 1 def (cannot operate on phis, and the llvm optimizer will remove unneeded phis anyhow) (no definition means it is a function parameter, or a local with just |var x;| but no defining assignment)
|
|
2132
|
+
var hasSideEffects = false;
|
|
2133
|
+
var value = values[name];
|
|
2134
|
+
if (value) {
|
|
2135
|
+
// TODO: merge with other side effect code
|
|
2136
|
+
// First, pattern-match
|
|
2137
|
+
// (HEAP32[((tempDoublePtr)>>2)]=((HEAP32[(($_sroa_0_0__idx1)>>2)])|0),HEAP32[(((tempDoublePtr)+(4))>>2)]=((HEAP32[((($_sroa_0_0__idx1)+(4))>>2)])|0),(+(HEAPF64[(tempDoublePtr)>>3])))
|
|
2138
|
+
// which has no side effects and is the special form of converting double to i64.
|
|
2139
|
+
if (!(value[0] === 'seq' && value[1][0] === 'assign' && value[1][2][0] === 'sub' && value[1][2][2][0] === 'binary' && value[1][2][2][1] === '>>' &&
|
|
2140
|
+
value[1][2][2][2][0] === 'name' && value[1][2][2][2][1] === 'tempDoublePtr')) {
|
|
2141
|
+
// If not that, then traverse and scan normally.
|
|
2142
|
+
traverse(value, function(node, type) {
|
|
2143
|
+
if (!(type in NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS)) {
|
|
2144
|
+
hasSideEffects = true; // cannot remove this unused variable, constructing it has side effects
|
|
2145
|
+
return true;
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
if (!hasSideEffects) {
|
|
2151
|
+
varsToRemove[name] = !definitions[name] ? 2 : 1; // remove it normally
|
|
2152
|
+
sideEffectFree[name] = true;
|
|
2153
|
+
// Each time we remove a variable with 0 uses, if its value has no
|
|
2154
|
+
// side effects and vanishes too, then we can remove a use from variables
|
|
2155
|
+
// appearing in it, and possibly eliminate again
|
|
2156
|
+
if (value) {
|
|
2157
|
+
traverse(value, function(node, type) {
|
|
2158
|
+
if (type === 'name') {
|
|
2159
|
+
var name = node[1];
|
|
2160
|
+
node[1] = ''; // we can remove this - it will never be shown, and should not be left to confuse us as we traverse
|
|
2161
|
+
if (name in locals) {
|
|
2162
|
+
uses[name]--; // cannot be infinite recursion since we descend an energy function
|
|
2163
|
+
assert(uses[name] >= 0);
|
|
2164
|
+
unprocessVariable(name);
|
|
2165
|
+
processVariable(name);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
2170
|
+
} else {
|
|
2171
|
+
varsToTryToRemove[name] = 1; // try to remove it later during scanning
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
for (var name in locals) {
|
|
2176
|
+
processVariable(name);
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
//printErr('defs: ' + JSON.stringify(definitions));
|
|
2180
|
+
//printErr('uses: ' + JSON.stringify(uses));
|
|
2181
|
+
//printErr('values: ' + JSON.stringify(values));
|
|
2182
|
+
//printErr('locals: ' + JSON.stringify(locals));
|
|
2183
|
+
//printErr('varsToRemove: ' + JSON.stringify(varsToRemove));
|
|
2184
|
+
//printErr('varsToTryToRemove: ' + JSON.stringify(varsToTryToRemove));
|
|
2185
|
+
values = null;
|
|
2186
|
+
//printErr('potentials: ' + JSON.stringify(potentials));
|
|
2187
|
+
// We can now proceed through the function. In each list of statements, we try to eliminate
|
|
2188
|
+
var tracked = {};
|
|
2189
|
+
var globalsInvalidated = false; // do not repeat invalidations, until we track something new
|
|
2190
|
+
var memoryInvalidated = false;
|
|
2191
|
+
var callsInvalidated = false;
|
|
2192
|
+
function track(name, value, defNode) { // add a potential that has just been defined to the tracked list, we hope to eliminate it
|
|
2193
|
+
var usesGlobals = false, usesMemory = false, deps = {}, doesCall = false;
|
|
2194
|
+
var ignoreName = false; // one-time ignorings of names, as first op in sub and call
|
|
2195
|
+
traverse(value, function(node, type) {
|
|
2196
|
+
if (type === 'name') {
|
|
2197
|
+
if (!ignoreName) {
|
|
2198
|
+
var name = node[1];
|
|
2199
|
+
if (!(name in locals)) {
|
|
2200
|
+
usesGlobals = true;
|
|
2201
|
+
}
|
|
2202
|
+
if (!(name in potentials)) { // deps do not matter for potentials - they are defined once, so no complexity
|
|
2203
|
+
deps[name] = 1;
|
|
2204
|
+
}
|
|
2205
|
+
} else {
|
|
2206
|
+
ignoreName = false;
|
|
2207
|
+
}
|
|
2208
|
+
} else if (type === 'sub') {
|
|
2209
|
+
usesMemory = true;
|
|
2210
|
+
ignoreName = true;
|
|
2211
|
+
} else if (type === 'call') {
|
|
2212
|
+
usesGlobals = true;
|
|
2213
|
+
usesMemory = true;
|
|
2214
|
+
doesCall = true;
|
|
2215
|
+
ignoreName = true;
|
|
2216
|
+
} else {
|
|
2217
|
+
ignoreName = false;
|
|
2218
|
+
}
|
|
2219
|
+
});
|
|
2220
|
+
tracked[name] = {
|
|
2221
|
+
usesGlobals: usesGlobals,
|
|
2222
|
+
usesMemory: usesMemory,
|
|
2223
|
+
defNode: defNode,
|
|
2224
|
+
deps: deps,
|
|
2225
|
+
doesCall: doesCall
|
|
2226
|
+
};
|
|
2227
|
+
globalsInvalidated = false;
|
|
2228
|
+
memoryInvalidated = false;
|
|
2229
|
+
callsInvalidated = false;
|
|
2230
|
+
//printErr('track ' + [name, JSON.stringify(tracked[name])]);
|
|
2231
|
+
}
|
|
2232
|
+
var temp = [];
|
|
2233
|
+
// TODO: invalidate using a sequence number for each type (if you were tracked before the last invalidation, you are cancelled). remove for.in loops
|
|
2234
|
+
function invalidateGlobals() {
|
|
2235
|
+
//printErr('invalidate globals');
|
|
2236
|
+
temp.length = 0;
|
|
2237
|
+
for (var name in tracked) {
|
|
2238
|
+
var info = tracked[name];
|
|
2239
|
+
if (info.usesGlobals) {
|
|
2240
|
+
temp.push(name);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
for (var i = 0; i < temp.length; i++) {
|
|
2244
|
+
delete tracked[temp[i]];
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
function invalidateMemory() {
|
|
2248
|
+
//printErr('invalidate memory');
|
|
2249
|
+
temp.length = 0;
|
|
2250
|
+
for (var name in tracked) {
|
|
2251
|
+
var info = tracked[name];
|
|
2252
|
+
if (info.usesMemory) {
|
|
2253
|
+
temp.push(name);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
for (var i = 0; i < temp.length; i++) {
|
|
2257
|
+
delete tracked[temp[i]];
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
function invalidateByDep(dep) {
|
|
2261
|
+
//printErr('invalidate by dep ' + dep);
|
|
2262
|
+
temp.length = 0;
|
|
2263
|
+
for (var name in tracked) {
|
|
2264
|
+
var info = tracked[name];
|
|
2265
|
+
if (info.deps[dep]) {
|
|
2266
|
+
temp.push(name);
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
for (var i = 0; i < temp.length; i++) {
|
|
2270
|
+
delete tracked[temp[i]];
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
function invalidateCalls() {
|
|
2274
|
+
//printErr('invalidate calls');
|
|
2275
|
+
temp.length = 0;
|
|
2276
|
+
for (var name in tracked) {
|
|
2277
|
+
var info = tracked[name];
|
|
2278
|
+
if (info.doesCall) {
|
|
2279
|
+
temp.push(name);
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
for (var i = 0; i < temp.length; i++) {
|
|
2283
|
+
delete tracked[temp[i]];
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
// Generate the sequence of execution. This determines what is executed before what, so we know what can be reordered. Using
|
|
2288
|
+
// that, performs invalidations and eliminations
|
|
2289
|
+
function scan(node) {
|
|
2290
|
+
//printErr('scan: ' + JSON.stringify(node).substr(0, 50) + ' : ' + keys(tracked));
|
|
2291
|
+
var abort = false;
|
|
2292
|
+
var allowTracking = true; // false inside an if; also prevents recursing in an if
|
|
2293
|
+
//var nesting = 1; // printErr-related
|
|
2294
|
+
function traverseInOrder(node, ignoreSub, ignoreName) {
|
|
2295
|
+
if (abort) return;
|
|
2296
|
+
//nesting++; // printErr-related
|
|
2297
|
+
//printErr(spaces(2*(nesting+1)) + 'trav: ' + JSON.stringify(node).substr(0, 50) + ' : ' + keys(tracked) + ' : ' + [allowTracking, ignoreSub, ignoreName]);
|
|
2298
|
+
var type = node[0];
|
|
2299
|
+
if (type === 'assign') {
|
|
2300
|
+
var target = node[2];
|
|
2301
|
+
var value = node[3];
|
|
2302
|
+
var nameTarget = target[0] === 'name';
|
|
2303
|
+
traverseInOrder(target, true, nameTarget); // evaluate left
|
|
2304
|
+
traverseInOrder(value); // evaluate right
|
|
2305
|
+
// do the actual assignment
|
|
2306
|
+
if (nameTarget) {
|
|
2307
|
+
var name = target[1];
|
|
2308
|
+
if (!(name in potentials)) {
|
|
2309
|
+
if (!(name in varsToTryToRemove)) {
|
|
2310
|
+
// expensive check for invalidating specific tracked vars. This list is generally quite short though, because of
|
|
2311
|
+
// how we just eliminate in short spans and abort when control flow happens TODO: history numbers instead
|
|
2312
|
+
invalidateByDep(name); // can happen more than once per dep..
|
|
2313
|
+
if (!(name in locals) && !globalsInvalidated) {
|
|
2314
|
+
invalidateGlobals();
|
|
2315
|
+
globalsInvalidated = true;
|
|
2316
|
+
}
|
|
2317
|
+
// if we can track this name (that we assign into), and it has 0 uses and we want to remove its 'var'
|
|
2318
|
+
// definition - then remove it right now, there is no later chance
|
|
2319
|
+
if (allowTracking && (name in varsToRemove) && uses[name] === 0) {
|
|
2320
|
+
track(name, node[3], node);
|
|
2321
|
+
doEliminate(name, node);
|
|
2322
|
+
}
|
|
2323
|
+
} else {
|
|
2324
|
+
// replace it in-place
|
|
2325
|
+
node.length = value.length;
|
|
2326
|
+
for (var i = 0; i < value.length; i++) {
|
|
2327
|
+
node[i] = value[i];
|
|
2328
|
+
}
|
|
2329
|
+
varsToRemove[name] = 2;
|
|
2330
|
+
}
|
|
2331
|
+
} else {
|
|
2332
|
+
if (allowTracking) track(name, node[3], node);
|
|
2333
|
+
}
|
|
2334
|
+
} else if (target[0] === 'sub') {
|
|
2335
|
+
if (!isTempDoublePtrAccess(target) && !memoryInvalidated) {
|
|
2336
|
+
invalidateMemory();
|
|
2337
|
+
memoryInvalidated = true;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
} else if (type === 'sub') {
|
|
2341
|
+
traverseInOrder(node[1], false, !memSafe); // evaluate inner
|
|
2342
|
+
traverseInOrder(node[2]); // evaluate outer
|
|
2343
|
+
// ignoreSub means we are a write (happening later), not a read
|
|
2344
|
+
if (!ignoreSub && !isTempDoublePtrAccess(node)) {
|
|
2345
|
+
// do the memory access
|
|
2346
|
+
if (!callsInvalidated) {
|
|
2347
|
+
invalidateCalls();
|
|
2348
|
+
callsInvalidated = true;
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
} else if (type === 'var') {
|
|
2352
|
+
var vars = node[1];
|
|
2353
|
+
for (var i = 0; i < vars.length; i++) {
|
|
2354
|
+
var name = vars[i][0];
|
|
2355
|
+
var value = vars[i][1];
|
|
2356
|
+
if (value) {
|
|
2357
|
+
traverseInOrder(value);
|
|
2358
|
+
if (name in potentials && allowTracking) {
|
|
2359
|
+
track(name, value, node);
|
|
2360
|
+
} else {
|
|
2361
|
+
invalidateByDep(name);
|
|
2362
|
+
}
|
|
2363
|
+
if (vars.length === 1 && name in varsToTryToRemove && value) {
|
|
2364
|
+
// replace it in-place
|
|
2365
|
+
value = ['stat', value];
|
|
2366
|
+
node.length = value.length;
|
|
2367
|
+
for (var i = 0; i < value.length; i++) {
|
|
2368
|
+
node[i] = value[i];
|
|
2369
|
+
}
|
|
2370
|
+
varsToRemove[name] = 2;
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
} else if (type === 'binary') {
|
|
2375
|
+
var flipped = false;
|
|
2376
|
+
if (node[1] in ASSOCIATIVE_BINARIES && !(node[2][0] in NAME_OR_NUM) && node[3][0] in NAME_OR_NUM) { // TODO recurse here?
|
|
2377
|
+
// associatives like + and * can be reordered in the simple case of one of the sides being a name, since we assume they are all just numbers
|
|
2378
|
+
var temp = node[2];
|
|
2379
|
+
node[2] = node[3];
|
|
2380
|
+
node[3] = temp;
|
|
2381
|
+
flipped = true;
|
|
2382
|
+
}
|
|
2383
|
+
traverseInOrder(node[2]);
|
|
2384
|
+
traverseInOrder(node[3]);
|
|
2385
|
+
if (flipped && node[2][0] in NAME_OR_NUM) { // dunno if we optimized, but safe to flip back - and keeps the code closer to the original and more readable
|
|
2386
|
+
var temp = node[2];
|
|
2387
|
+
node[2] = node[3];
|
|
2388
|
+
node[3] = temp;
|
|
2389
|
+
}
|
|
2390
|
+
} else if (type === 'name') {
|
|
2391
|
+
if (!ignoreName) { // ignoreName means we are the name of something like a call or a sub - irrelevant for us
|
|
2392
|
+
var name = node[1];
|
|
2393
|
+
if (name in tracked) {
|
|
2394
|
+
doEliminate(name, node);
|
|
2395
|
+
} else if (!(name in locals) && !callsInvalidated) {
|
|
2396
|
+
invalidateCalls();
|
|
2397
|
+
callsInvalidated = true;
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
} else if (type === 'unary-prefix' || type === 'unary-postfix') {
|
|
2401
|
+
traverseInOrder(node[2]);
|
|
2402
|
+
} else if (type in IGNORABLE_ELIMINATOR_SCAN_NODES) {
|
|
2403
|
+
} else if (type === 'call') {
|
|
2404
|
+
traverseInOrder(node[1], false, true);
|
|
2405
|
+
var args = node[2];
|
|
2406
|
+
for (var i = 0; i < args.length; i++) {
|
|
2407
|
+
traverseInOrder(args[i]);
|
|
2408
|
+
}
|
|
2409
|
+
// these two invalidations will also invalidate calls
|
|
2410
|
+
if (!globalsInvalidated) {
|
|
2411
|
+
invalidateGlobals();
|
|
2412
|
+
globalsInvalidated = true;
|
|
2413
|
+
}
|
|
2414
|
+
if (!memoryInvalidated) {
|
|
2415
|
+
invalidateMemory();
|
|
2416
|
+
memoryInvalidated = true;
|
|
2417
|
+
}
|
|
2418
|
+
} else if (type === 'if') {
|
|
2419
|
+
if (allowTracking) {
|
|
2420
|
+
traverseInOrder(node[1]); // can eliminate into condition, but nowhere else
|
|
2421
|
+
if (!callsInvalidated) { // invalidate calls, since we cannot eliminate them into an if that may not execute!
|
|
2422
|
+
invalidateCalls();
|
|
2423
|
+
callsInvalidated = true;
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
allowTracking = false;
|
|
2427
|
+
traverseInOrder(node[2]); // 2 and 3 could be 'parallel', really..
|
|
2428
|
+
if (node[3]) traverseInOrder(node[3]);
|
|
2429
|
+
allowTracking = true;
|
|
2430
|
+
|
|
2431
|
+
} else {
|
|
2432
|
+
tracked = {};
|
|
2433
|
+
}
|
|
2434
|
+
} else if (type === 'block') {
|
|
2435
|
+
var stats = node[1];
|
|
2436
|
+
if (stats) {
|
|
2437
|
+
for (var i = 0; i < stats.length; i++) {
|
|
2438
|
+
traverseInOrder(stats[i]);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
} else if (type === 'stat') {
|
|
2442
|
+
traverseInOrder(node[1]);
|
|
2443
|
+
} else if (type === 'label') {
|
|
2444
|
+
traverseInOrder(node[2]);
|
|
2445
|
+
} else if (type === 'seq') {
|
|
2446
|
+
traverseInOrder(node[1]);
|
|
2447
|
+
traverseInOrder(node[2]);
|
|
2448
|
+
} else if (type === 'do') {
|
|
2449
|
+
if (node[1][0] === 'num' && node[1][1] === 0) { // one-time loop
|
|
2450
|
+
traverseInOrder(node[2]);
|
|
2451
|
+
} else {
|
|
2452
|
+
tracked = {};
|
|
2453
|
+
}
|
|
2454
|
+
} else if (type === 'return') {
|
|
2455
|
+
if (node[1]) traverseInOrder(node[1]);
|
|
2456
|
+
} else if (type === 'conditional') {
|
|
2457
|
+
traverseInOrder(node[1]);
|
|
2458
|
+
traverseInOrder(node[2]);
|
|
2459
|
+
traverseInOrder(node[3]);
|
|
2460
|
+
} else if (type === 'switch') {
|
|
2461
|
+
traverseInOrder(node[1]);
|
|
2462
|
+
var cases = node[2];
|
|
2463
|
+
for (var i = 0; i < cases.length; i++) {
|
|
2464
|
+
var c = cases[i];
|
|
2465
|
+
assert(c[0] === null || c[0][0] === 'num' || (c[0][0] === 'unary-prefix' && c[0][2][0] === 'num'));
|
|
2466
|
+
var stats = c[1];
|
|
2467
|
+
for (var j = 0; j < stats.length; j++) {
|
|
2468
|
+
traverseInOrder(stats[j]);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
} else {
|
|
2472
|
+
if (!(type in ABORTING_ELIMINATOR_SCAN_NODES)) {
|
|
2473
|
+
printErr('unfamiliar eliminator scan node: ' + JSON.stringify(node));
|
|
2474
|
+
}
|
|
2475
|
+
tracked = {};
|
|
2476
|
+
abort = true;
|
|
2477
|
+
}
|
|
2478
|
+
//nesting--; // printErr-related
|
|
2479
|
+
}
|
|
2480
|
+
traverseInOrder(node);
|
|
2481
|
+
}
|
|
2482
|
+
//var eliminationLimit = 0; // used to debugging purposes
|
|
2483
|
+
function doEliminate(name, node) {
|
|
2484
|
+
//if (eliminationLimit === 0) return;
|
|
2485
|
+
//eliminationLimit--;
|
|
2486
|
+
//printErr('elim!!!!! ' + name);
|
|
2487
|
+
// yes, eliminate!
|
|
2488
|
+
varsToRemove[name] = 2; // both assign and var definitions can have other vars we must clean up
|
|
2489
|
+
var info = tracked[name];
|
|
2490
|
+
delete tracked[name];
|
|
2491
|
+
var defNode = info.defNode;
|
|
2492
|
+
if (!sideEffectFree[name]) {
|
|
2493
|
+
if (defNode[0] === 'var') {
|
|
2494
|
+
defNode[1].forEach(function(pair) {
|
|
2495
|
+
if (pair[0] === name) {
|
|
2496
|
+
value = pair[1];
|
|
2497
|
+
}
|
|
2498
|
+
});
|
|
2499
|
+
assert(value);
|
|
2500
|
+
} else { // assign
|
|
2501
|
+
value = defNode[3];
|
|
2502
|
+
// wipe out the assign
|
|
2503
|
+
defNode[0] = 'toplevel';
|
|
2504
|
+
defNode[1] = [];
|
|
2505
|
+
defNode.length = 2;
|
|
2506
|
+
}
|
|
2507
|
+
// replace this node in-place
|
|
2508
|
+
node.length = 0;
|
|
2509
|
+
for (var i = 0; i < value.length; i++) {
|
|
2510
|
+
node[i] = value[i];
|
|
2511
|
+
}
|
|
2512
|
+
} else {
|
|
2513
|
+
// This has no side effects and no uses, empty it out in-place
|
|
2514
|
+
node.length = 0;
|
|
2515
|
+
node[0] = 'toplevel';
|
|
2516
|
+
node[1] = [];
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
traverse(func, function(block) {
|
|
2520
|
+
// Look for statements, including while-switch pattern
|
|
2521
|
+
var stats = getStatements(block) || (block[0] === 'while' && block[2][0] === 'switch' ? [block[2]] : stats);
|
|
2522
|
+
if (!stats) return;
|
|
2523
|
+
//printErr('Stats: ' + JSON.stringify(stats).substr(0,100));
|
|
2524
|
+
tracked = {};
|
|
2525
|
+
//printErr('new StatBlock');
|
|
2526
|
+
for (var i = 0; i < stats.length; i++) {
|
|
2527
|
+
var node = stats[i];
|
|
2528
|
+
//printErr('StatBlock[' + i + '] => ' + JSON.stringify(node).substr(0,100));
|
|
2529
|
+
var type = node[0];
|
|
2530
|
+
if (type === 'stat') {
|
|
2531
|
+
node = node[1];
|
|
2532
|
+
type = node[0];
|
|
2533
|
+
} else if (type == 'return' && i < stats.length-1) {
|
|
2534
|
+
stats.length = i+1; // remove any code after a return
|
|
2535
|
+
}
|
|
2536
|
+
// Check for things that affect elimination
|
|
2537
|
+
if (type in ELIMINATION_SAFE_NODES) {
|
|
2538
|
+
scan(node);
|
|
2539
|
+
} else {
|
|
2540
|
+
tracked = {}; // not a var or assign, break all potential elimination so far
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
//printErr('delete StatBlock');
|
|
2544
|
+
});
|
|
2545
|
+
|
|
2546
|
+
var seenUses = {}, helperReplacements = {}; // for looper-helper optimization
|
|
2547
|
+
|
|
2548
|
+
// clean up vars, and loop variable elimination
|
|
2549
|
+
traverse(func, function(node, type) {
|
|
2550
|
+
// pre
|
|
2551
|
+
if (type === 'var') {
|
|
2552
|
+
node[1] = node[1].filter(function(pair) { return !varsToRemove[pair[0]] });
|
|
2553
|
+
if (node[1].length === 0) {
|
|
2554
|
+
// wipe out an empty |var;|
|
|
2555
|
+
node[0] = 'toplevel';
|
|
2556
|
+
node[1] = [];
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
}, function(node, type) {
|
|
2560
|
+
// post
|
|
2561
|
+
if (type === 'name') {
|
|
2562
|
+
var name = node[1];
|
|
2563
|
+
if (name in helperReplacements) {
|
|
2564
|
+
node[1] = helperReplacements[name];
|
|
2565
|
+
return; // no need to track this anymore, we can't loop-optimize more than once
|
|
2566
|
+
}
|
|
2567
|
+
// track how many uses we saw. we need to know when a variable is no longer used (hence we run this in the post)
|
|
2568
|
+
if (!(name in seenUses)) {
|
|
2569
|
+
seenUses[name] = 1;
|
|
2570
|
+
} else {
|
|
2571
|
+
seenUses[name]++;
|
|
2572
|
+
}
|
|
2573
|
+
} else if (type === 'while') {
|
|
2574
|
+
// try to remove loop helper variables specifically
|
|
2575
|
+
var stats = node[2][1];
|
|
2576
|
+
var last = stats[stats.length-1];
|
|
2577
|
+
if (last && last[0] === 'if' && last[2][0] === 'block' && last[3] && last[3][0] === 'block') {
|
|
2578
|
+
var ifTrue = last[2];
|
|
2579
|
+
var ifFalse = last[3];
|
|
2580
|
+
var flip = false;
|
|
2581
|
+
if (ifFalse[1][0] && ifFalse[1][0][0] === 'break') { // canonicalize break in the if
|
|
2582
|
+
var temp = ifFalse;
|
|
2583
|
+
ifFalse = ifTrue;
|
|
2584
|
+
ifTrue = temp;
|
|
2585
|
+
flip = true;
|
|
2586
|
+
}
|
|
2587
|
+
if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') {
|
|
2588
|
+
var assigns = ifFalse[1];
|
|
2589
|
+
var loopers = [], helpers = [];
|
|
2590
|
+
for (var i = 0; i < assigns.length; i++) {
|
|
2591
|
+
if (assigns[i][0] === 'stat' && assigns[i][1][0] === 'assign') {
|
|
2592
|
+
var assign = assigns[i][1];
|
|
2593
|
+
if (assign[1] === true && assign[2][0] === 'name' && assign[3][0] === 'name') {
|
|
2594
|
+
var looper = assign[2][1];
|
|
2595
|
+
var helper = assign[3][1];
|
|
2596
|
+
if (definitions[helper] === 1 && seenUses[looper] === namings[looper] &&
|
|
2597
|
+
!helperReplacements[helper] && !helperReplacements[looper]) {
|
|
2598
|
+
loopers.push(looper);
|
|
2599
|
+
helpers.push(helper);
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
if (loopers.length < assigns.length) return; // TODO: handle the case where can can just eliminate one. (we can't optimize the break, but we can remove the var at least)
|
|
2605
|
+
for (var l = 0; l < loopers.length; l++) {
|
|
2606
|
+
var looper = loopers[l];
|
|
2607
|
+
var helper = helpers[l];
|
|
2608
|
+
// the remaining issue is whether loopers are used after the assignment to helper and before the last line (where we assign to it)
|
|
2609
|
+
var found = -1;
|
|
2610
|
+
for (var i = stats.length-2; i >= 0; i--) {
|
|
2611
|
+
var curr = stats[i];
|
|
2612
|
+
if (curr[0] === 'stat' && curr[1][0] === 'assign') {
|
|
2613
|
+
var currAssign = curr[1];
|
|
2614
|
+
if (currAssign[1] === true && currAssign[2][0] === 'name') {
|
|
2615
|
+
var to = currAssign[2][1];
|
|
2616
|
+
if (to === helper) {
|
|
2617
|
+
found = i;
|
|
2618
|
+
break;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
if (found < 0) return;
|
|
2624
|
+
var looperUsed = false;
|
|
2625
|
+
for (var i = found+1; i < stats.length && !looperUsed; i++) {
|
|
2626
|
+
var curr = i < stats.length-1 ? stats[i] : last[1]; // on the last line, just look in the condition
|
|
2627
|
+
traverse(curr, function(node, type) {
|
|
2628
|
+
if (type === 'name' && node[1] === looper) {
|
|
2629
|
+
looperUsed = true;
|
|
2630
|
+
return true;
|
|
2631
|
+
}
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
if (looperUsed) return;
|
|
2635
|
+
}
|
|
2636
|
+
for (var l = 0; l < helpers.length; l++) {
|
|
2637
|
+
for (var k = 0; k < helpers.length; k++) {
|
|
2638
|
+
if (l != k && helpers[l] === helpers[k]) return; // it is complicated to handle a shared helper, abort
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
// hurrah! this is safe to do
|
|
2642
|
+
//printErr("ELIM LOOP VAR " + JSON.stringify(loopers) + ' :: ' + JSON.stringify(helpers));
|
|
2643
|
+
for (var l = 0; l < loopers.length; l++) {
|
|
2644
|
+
var looper = loopers[l];
|
|
2645
|
+
var helper = helpers[l];
|
|
2646
|
+
varsToRemove[helper] = 2;
|
|
2647
|
+
traverse(node, function(node, type) { // replace all appearances of helper with looper
|
|
2648
|
+
if (type === 'name' && node[1] === helper) node[1] = looper;
|
|
2649
|
+
});
|
|
2650
|
+
helperReplacements[helper] = looper; // replace all future appearances of helper with looper
|
|
2651
|
+
helperReplacements[looper] = looper; // avoid any further attempts to optimize looper in this manner (seenUses is wrong anyhow, too)
|
|
2652
|
+
}
|
|
2653
|
+
// simplify the if. we remove the if branch, leaving only the else
|
|
2654
|
+
if (flip) {
|
|
2655
|
+
last[1] = simplifyNotCompsDirect(['unary-prefix', '!', last[1]]);
|
|
2656
|
+
last[2] = last[3];
|
|
2657
|
+
}
|
|
2658
|
+
last.pop();
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
});
|
|
2663
|
+
|
|
2664
|
+
if (asm) {
|
|
2665
|
+
for (var v in varsToRemove) {
|
|
2666
|
+
if (varsToRemove[v] === 2) delete asmData.vars[v];
|
|
2667
|
+
}
|
|
2668
|
+
denormalizeAsm(func, asmData);
|
|
2669
|
+
}
|
|
2670
|
+
});
|
|
2671
|
+
|
|
2672
|
+
if (!asm) { // TODO: deprecate in non-asm too
|
|
2673
|
+
// A class for optimizing expressions. We know that it is legitimate to collapse
|
|
2674
|
+
// 5+7 in the generated code, as it will always be numerical, for example. XXX do we need this? here?
|
|
2675
|
+
function ExpressionOptimizer(node) {
|
|
2676
|
+
this.node = node;
|
|
2677
|
+
|
|
2678
|
+
this.run = function() {
|
|
2679
|
+
traverse(this.node, function(node, type) {
|
|
2680
|
+
if (type === 'binary' && node[1] === '+') {
|
|
2681
|
+
var names = [];
|
|
2682
|
+
var num = 0;
|
|
2683
|
+
var has_num = false;
|
|
2684
|
+
var fail = false;
|
|
2685
|
+
traverse(node, function(subNode, subType) {
|
|
2686
|
+
if (subType === 'binary') {
|
|
2687
|
+
if (subNode[1] !== '+') {
|
|
2688
|
+
fail = true;
|
|
2689
|
+
return false;
|
|
2690
|
+
}
|
|
2691
|
+
} else if (subType === 'name') {
|
|
2692
|
+
names.push(subNode[1]);
|
|
2693
|
+
return;
|
|
2694
|
+
} else if (subType === 'num') {
|
|
2695
|
+
num += subNode[1];
|
|
2696
|
+
has_num = true;
|
|
2697
|
+
return;
|
|
2698
|
+
} else {
|
|
2699
|
+
fail = true;
|
|
2700
|
+
return false;
|
|
2701
|
+
}
|
|
2702
|
+
});
|
|
2703
|
+
if (!fail && has_num) {
|
|
2704
|
+
var ret = ['num', num];
|
|
2705
|
+
for (var i = 0; i < names.length; i++) {
|
|
2706
|
+
ret = ['binary', '+', ['name', names[i]], ret];
|
|
2707
|
+
}
|
|
2708
|
+
return ret;
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
});
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
new ExpressionOptimizer(ast).run();
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
function eliminateMemSafe(ast) {
|
|
2719
|
+
eliminate(ast, true);
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
function minifyGlobals(ast) {
|
|
2723
|
+
var minified = {};
|
|
2724
|
+
var next = 0;
|
|
2725
|
+
var first = true; // do not minify initial 'var asm ='
|
|
2726
|
+
// find the globals
|
|
2727
|
+
traverse(ast, function(node, type) {
|
|
2728
|
+
if (type === 'var') {
|
|
2729
|
+
if (first) {
|
|
2730
|
+
first = false;
|
|
2731
|
+
return;
|
|
2732
|
+
}
|
|
2733
|
+
var vars = node[1];
|
|
2734
|
+
for (var i = 0; i < vars.length; i++) {
|
|
2735
|
+
var name = vars[i][0];
|
|
2736
|
+
assert(next < extraInfo.names.length);
|
|
2737
|
+
vars[i][0] = minified[name] = extraInfo.names[next++];
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
});
|
|
2741
|
+
// add all globals in function chunks, i.e. not here but passed to us
|
|
2742
|
+
for (var i = 0; i < extraInfo.globals.length; i++) {
|
|
2743
|
+
name = extraInfo.globals[i];
|
|
2744
|
+
assert(next < extraInfo.names.length);
|
|
2745
|
+
minified[name] = extraInfo.names[next++];
|
|
2746
|
+
}
|
|
2747
|
+
// apply minification
|
|
2748
|
+
traverse(ast, function(node, type) {
|
|
2749
|
+
if (type === 'name') {
|
|
2750
|
+
var name = node[1];
|
|
2751
|
+
if (name in minified) {
|
|
2752
|
+
node[1] = minified[name];
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
});
|
|
2756
|
+
suffix = '// EXTRA_INFO:' + JSON.stringify(minified);
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
// Relocation pass for a shared module (for the functions part of the module)
|
|
2760
|
+
//
|
|
2761
|
+
// 1. Replace function names with alternate names as defined (to avoid colliding with
|
|
2762
|
+
// names in the main module we are being linked to)
|
|
2763
|
+
// 2. Hardcode function table offsets from F_BASE+x to const+x if x is a variable, or
|
|
2764
|
+
// the constant sum of the base + offset
|
|
2765
|
+
// 3. Hardcode heap offsets from H_BASE as well
|
|
2766
|
+
function relocate(ast) {
|
|
2767
|
+
assert(asm); // we also assume we are normalized
|
|
2768
|
+
|
|
2769
|
+
var replacements = extraInfo.replacements;
|
|
2770
|
+
var fBases = extraInfo.fBases;
|
|
2771
|
+
var hBase = extraInfo.hBase;
|
|
2772
|
+
var m;
|
|
2773
|
+
|
|
2774
|
+
traverse(ast, function(node, type) {
|
|
2775
|
+
switch(type) {
|
|
2776
|
+
case 'name': case 'defun': {
|
|
2777
|
+
var rep = replacements[node[1]];
|
|
2778
|
+
if (rep) node[1] = rep;
|
|
2779
|
+
break;
|
|
2780
|
+
}
|
|
2781
|
+
case 'binary': {
|
|
2782
|
+
if (node[1] == '+' && node[2][0] == 'name') {
|
|
2783
|
+
var base = null;
|
|
2784
|
+
if (node[2][1] == 'H_BASE') {
|
|
2785
|
+
base = hBase;
|
|
2786
|
+
} else if (m = /^F_BASE_(\w+)$/.exec(node[2][1])) {
|
|
2787
|
+
base = fBases[m[1]] || 0; // 0 if the parent has no function table for this, but the child does. so no relocation needed
|
|
2788
|
+
}
|
|
2789
|
+
if (base !== null) {
|
|
2790
|
+
var other = node[3];
|
|
2791
|
+
if (base === 0) return other;
|
|
2792
|
+
if (other[0] == 'num') {
|
|
2793
|
+
other[1] += base;
|
|
2794
|
+
return other;
|
|
2795
|
+
} else {
|
|
2796
|
+
node[2] = ['num', base];
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
break;
|
|
2801
|
+
}
|
|
2802
|
+
case 'var': {
|
|
2803
|
+
var vars = node[1];
|
|
2804
|
+
for (var i = 0; i < vars.length; i++) {
|
|
2805
|
+
var name = vars[i][0];
|
|
2806
|
+
assert(!(name in replacements)); // cannot shadow functions we are replacing TODO: fix that
|
|
2807
|
+
}
|
|
2808
|
+
break;
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
});
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// Break up very large functions
|
|
2815
|
+
|
|
2816
|
+
var NODES_WITHOUT_ELIMINATION_SENSITIVITY = set('name', 'num', 'binary', 'unary-prefix');
|
|
2817
|
+
var FAST_ELIMINATION_BINARIES = setUnion(setUnion(USEFUL_BINARY_OPS, COMPARE_OPS), set('+'));
|
|
2818
|
+
|
|
2819
|
+
function outline(ast) {
|
|
2820
|
+
function measureSize(ast) {
|
|
2821
|
+
var size = 0;
|
|
2822
|
+
traverse(ast, function() {
|
|
2823
|
+
size++;
|
|
2824
|
+
});
|
|
2825
|
+
return size;
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
function aggressiveVariableElimination(func, asmData) {
|
|
2829
|
+
// This removes as many variables as possible. This is often not the best thing because it increases
|
|
2830
|
+
// code size, but it is far preferable to the risk of split functions needing to do more spilling. Specifically,
|
|
2831
|
+
// it finds 'trivial' variables: ones with 1 definition, and that definition is not sensitive to any changes: it
|
|
2832
|
+
// only depends on constants and local variables that are themselves trivial. We can unquestionably eliminate
|
|
2833
|
+
// such variables in a trivial manner.
|
|
2834
|
+
|
|
2835
|
+
var assignments = {};
|
|
2836
|
+
var appearances = {};
|
|
2837
|
+
var defs = {};
|
|
2838
|
+
var considered = {};
|
|
2839
|
+
|
|
2840
|
+
traverse(func, function(node, type) {
|
|
2841
|
+
if (type == 'assign' && node[2][0] == 'name') {
|
|
2842
|
+
var name = node[2][1];
|
|
2843
|
+
if (name in asmData.vars) {
|
|
2844
|
+
assignments[name] = (assignments[name] || 0) + 1;
|
|
2845
|
+
appearances[name] = (appearances[name] || 0) - 1; // this appearance is a definition, offset the counting later
|
|
2846
|
+
defs[name] = node;
|
|
2847
|
+
} else {
|
|
2848
|
+
if (name in asmData.params) {
|
|
2849
|
+
considered[name] = true; // this parameter is not ssa, it must be in a hand-optimized function, so it is not trivial
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
} else if (type == 'name') {
|
|
2853
|
+
var name = node[1];
|
|
2854
|
+
if (name in asmData.vars) {
|
|
2855
|
+
appearances[name] = (appearances[name] || 0) + 1;
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
});
|
|
2859
|
+
|
|
2860
|
+
var allTrivials = {}; // key of a trivial var => size of its (expanded) value, at least 1
|
|
2861
|
+
|
|
2862
|
+
// three levels of variables:
|
|
2863
|
+
// 1. trivial: 1 def (or less), uses nothing sensitive, can be eliminated
|
|
2864
|
+
// 2. safe: 1 def (or less), can be used in a trivial, but cannot itself be eliminated
|
|
2865
|
+
// 3. sensitive: uses a global or memory or something else that prevents trivial elimination.
|
|
2866
|
+
|
|
2867
|
+
function assessTriviality(name) {
|
|
2868
|
+
// only care about vars with 0-1 assignments of (0 for parameters), and can ignore label (which is not explicitly initialized, but cannot be eliminated ever anyhow)
|
|
2869
|
+
if (assignments[name] > 1 || (!(name in asmData.vars) && !(name in asmData.params)) || name == 'label') return false;
|
|
2870
|
+
if (considered[name]) return allTrivials[name];
|
|
2871
|
+
considered[name] = true;
|
|
2872
|
+
var sensitive = false;
|
|
2873
|
+
var size = 0, originalSize = 0;
|
|
2874
|
+
var def = defs[name];
|
|
2875
|
+
if (def) {
|
|
2876
|
+
var value = def[3];
|
|
2877
|
+
originalSize = measureSize(value);
|
|
2878
|
+
if (value) {
|
|
2879
|
+
traverse(value, function recurseValue(node, type) {
|
|
2880
|
+
var one = node[1];
|
|
2881
|
+
if (!(type in NODES_WITHOUT_ELIMINATION_SENSITIVITY)) { // || (type == 'binary' && !(one in FAST_ELIMINATION_BINARIES))) {
|
|
2882
|
+
sensitive = true;
|
|
2883
|
+
return true;
|
|
2884
|
+
}
|
|
2885
|
+
if (type == 'name' && !assessTriviality(one)) {
|
|
2886
|
+
if (assignments[one] > 1 || (!(one in asmData.vars) && !(one in asmData.params))) {
|
|
2887
|
+
sensitive = true; // directly using something sensitive
|
|
2888
|
+
return true;
|
|
2889
|
+
} // otherwise, not trivial, but at least safe.
|
|
2890
|
+
}
|
|
2891
|
+
// if this is a name, it must be a trivial variable (or a safe one) and we know its size
|
|
2892
|
+
size += ((type == 'name') ? allTrivials[one] : 1) || 1;
|
|
2893
|
+
});
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
if (!sensitive) {
|
|
2897
|
+
size = size || 1;
|
|
2898
|
+
originalSize = originalSize || 1;
|
|
2899
|
+
var factor = ((appearances[name] - 1) || 0) * (size - originalSize); // If no size change or just one appearance, always ok to trivially eliminate. otherwise, tradeoff
|
|
2900
|
+
if (factor <= 12) {
|
|
2901
|
+
allTrivials[name] = size; // trivial!
|
|
2902
|
+
return true;
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
return false;
|
|
2906
|
+
}
|
|
2907
|
+
for (var name in asmData.vars) {
|
|
2908
|
+
assessTriviality(name);
|
|
2909
|
+
}
|
|
2910
|
+
var trivials = {};
|
|
2911
|
+
|
|
2912
|
+
for (var name in allTrivials) { // from now on, ignore parameters
|
|
2913
|
+
if (name in asmData.vars) trivials[name] = true;
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
allTrivials = {};
|
|
2917
|
+
|
|
2918
|
+
var values = {};
|
|
2919
|
+
|
|
2920
|
+
function evaluate(name) {
|
|
2921
|
+
var node = values[name];
|
|
2922
|
+
if (node) return node;
|
|
2923
|
+
values[node] = null; // prevent infinite recursion
|
|
2924
|
+
var def = defs[name];
|
|
2925
|
+
if (def) {
|
|
2926
|
+
node = def[3];
|
|
2927
|
+
if (node[0] == 'name') {
|
|
2928
|
+
var name2 = node[1];
|
|
2929
|
+
if (name2 in trivials) {
|
|
2930
|
+
node = evaluate(name2);
|
|
2931
|
+
}
|
|
2932
|
+
} else {
|
|
2933
|
+
traverse(node, function(node, type) {
|
|
2934
|
+
if (type == 'name') {
|
|
2935
|
+
var name2 = node[1];
|
|
2936
|
+
if (name2 in trivials) {
|
|
2937
|
+
return evaluate(name2);
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
values[name] = node;
|
|
2943
|
+
}
|
|
2944
|
+
return node;
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
for (var name in trivials) {
|
|
2948
|
+
evaluate(name);
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
for (var name in trivials) {
|
|
2952
|
+
var def = defs[name];
|
|
2953
|
+
if (def) {
|
|
2954
|
+
def.length = 0;
|
|
2955
|
+
def[0] = 'toplevel';
|
|
2956
|
+
def[1] = [];
|
|
2957
|
+
}
|
|
2958
|
+
delete asmData.vars[name];
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
// Perform replacements TODO: save list of uses objects before, replace directly, avoid extra traverse
|
|
2962
|
+
traverse(func, function(node, type) {
|
|
2963
|
+
if (type == 'name') {
|
|
2964
|
+
var name = node[1];
|
|
2965
|
+
if (name in trivials) {
|
|
2966
|
+
var value = values[name];
|
|
2967
|
+
if (!value) throw 'missing value: ' + [func[1], name, values[name]] + ' - faulty reliance on asm zero-init?';
|
|
2968
|
+
return copy(value); // must copy, or else the same object can be used multiple times
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
// Prepares information for spilling of local variables
|
|
2975
|
+
function analyzeFunction(func, asmData) {
|
|
2976
|
+
var stack = []; // list of variables, each gets 8 bytes
|
|
2977
|
+
for (var name in asmData.params) {
|
|
2978
|
+
stack.push(name);
|
|
2979
|
+
}
|
|
2980
|
+
for (var name in asmData.vars) {
|
|
2981
|
+
stack.push(name);
|
|
2982
|
+
}
|
|
2983
|
+
asmData.stackPos = {};
|
|
2984
|
+
for (var i = 0; i < stack.length; i++) {
|
|
2985
|
+
asmData.stackPos[stack[i]] = i*8;
|
|
2986
|
+
}
|
|
2987
|
+
// Reserve an extra two spots: one for control flow var, the other for control flow data
|
|
2988
|
+
asmData.stackSize = (stack.length + 2)*8;
|
|
2989
|
+
asmData.controlStackPos = asmData.stackSize - 16;
|
|
2990
|
+
asmData.controlDataStackPos = asmData.stackSize - 8;
|
|
2991
|
+
asmData.splitCounter = 0;
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
// Analyze uses - reads and writes - of variables in part of the AST of a function
|
|
2995
|
+
function analyzeCode(func, asmData, ast) {
|
|
2996
|
+
var labels = {};
|
|
2997
|
+
var labelCounter = 1; // 0 means no label
|
|
2998
|
+
|
|
2999
|
+
traverse(ast, function(node, type) {
|
|
3000
|
+
if ((type == 'label' || type in LOOP_FLOW) && node[1] && !(node[1] in labels)) {
|
|
3001
|
+
labels[node[1]] = labelCounter++;
|
|
3002
|
+
}
|
|
3003
|
+
});
|
|
3004
|
+
|
|
3005
|
+
var writes = {};
|
|
3006
|
+
var appearances = {};
|
|
3007
|
+
var hasReturn = false, hasBreak = false, hasContinue = false;
|
|
3008
|
+
var breaks = {}; // set of labels we break or continue
|
|
3009
|
+
var continues = {}; // to. '0' is an unlabeled one
|
|
3010
|
+
var breakCapturers = 0;
|
|
3011
|
+
var continueCapturers = 0;
|
|
3012
|
+
|
|
3013
|
+
traverse(ast, function(node, type) {
|
|
3014
|
+
if (type == 'assign' && node[2][0] == 'name') {
|
|
3015
|
+
var name = node[2][1];
|
|
3016
|
+
if (name in asmData.vars || name in asmData.params) {
|
|
3017
|
+
writes[name] = 0;
|
|
3018
|
+
appearances[name] = (appearances[name] || 0) - 1; // this appearance is a definition, offset the counting later
|
|
3019
|
+
}
|
|
3020
|
+
} else if (type == 'name') {
|
|
3021
|
+
var name = node[1];
|
|
3022
|
+
if (name in asmData.vars || name in asmData.params) {
|
|
3023
|
+
appearances[name] = (appearances[name] || 0) + 1;
|
|
3024
|
+
}
|
|
3025
|
+
} else if (type == 'return') {
|
|
3026
|
+
hasReturn = true;
|
|
3027
|
+
} else if (type == 'break') {
|
|
3028
|
+
var label = node[1] || 0;
|
|
3029
|
+
if (!label && breakCapturers > 0) return; // no label, and captured
|
|
3030
|
+
if (label && (label in labels)) return; // label, and defined in this code, so captured
|
|
3031
|
+
breaks[label || 0] = 0;
|
|
3032
|
+
hasBreak = true;
|
|
3033
|
+
} else if (type == 'continue') {
|
|
3034
|
+
var label = node[1] || 0;
|
|
3035
|
+
if (!label && continueCapturers > 0) return; // no label, and captured
|
|
3036
|
+
if (label && (label in labels)) return; // label, and defined in this code, so captured
|
|
3037
|
+
continues[label || 0] = 0;
|
|
3038
|
+
hasContinue = true;
|
|
3039
|
+
} else {
|
|
3040
|
+
if (type in BREAK_CAPTURERS) {
|
|
3041
|
+
breakCapturers++;
|
|
3042
|
+
}
|
|
3043
|
+
if (type in CONTINUE_CAPTURERS) {
|
|
3044
|
+
continueCapturers++;
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
}, function(node, type) {
|
|
3048
|
+
if (type in BREAK_CAPTURERS) {
|
|
3049
|
+
breakCapturers--;
|
|
3050
|
+
}
|
|
3051
|
+
if (type in CONTINUE_CAPTURERS) {
|
|
3052
|
+
continueCapturers--;
|
|
3053
|
+
}
|
|
3054
|
+
});
|
|
3055
|
+
|
|
3056
|
+
var reads = {};
|
|
3057
|
+
|
|
3058
|
+
for (var name in appearances) {
|
|
3059
|
+
if (appearances[name] > 0) reads[name] = 0;
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
return { writes: writes, reads: reads, hasReturn: hasReturn, breaks: breaks, continues: continues, labels: labels };
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
function makeAssign(dst, src) {
|
|
3066
|
+
return ['assign', true, dst, src];
|
|
3067
|
+
}
|
|
3068
|
+
function makeStackAccess(type, pos) { // TODO: float64, not 32
|
|
3069
|
+
return ['sub', ['name', type == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', pos]], ['num', '2']]];
|
|
3070
|
+
}
|
|
3071
|
+
function makeIf(cond, then, else_) {
|
|
3072
|
+
var ret = ['if', cond, ['block', then]];
|
|
3073
|
+
if (else_) ret.push(['block', else_]);
|
|
3074
|
+
return ret;
|
|
3075
|
+
}
|
|
3076
|
+
function makeComparison(left, comp, right) {
|
|
3077
|
+
return ['binary', comp, left, right];
|
|
3078
|
+
}
|
|
3079
|
+
|
|
3080
|
+
var CONTROL_BREAK = 1, CONTROL_BREAK_LABEL = 2, CONTROL_CONTINUE = 3, CONTROL_CONTINUE_LABEL = 4, CONTROL_RETURN_VOID = 5, CONTROL_RETURN_INT = 6, CONTROL_RETURN_DOUBLE = 7;
|
|
3081
|
+
|
|
3082
|
+
var sizeToOutline = extraInfo.sizeToOutline;
|
|
3083
|
+
var level = 0;
|
|
3084
|
+
|
|
3085
|
+
function doOutline(func, asmData, stats, start, end) {
|
|
3086
|
+
printErr(' do outline ' + [func[1], level, 'range:', start, end, 'of', stats.length]);
|
|
3087
|
+
var code = stats.slice(start, end+1);
|
|
3088
|
+
var newIdent = func[1] + '$' + (asmData.splitCounter++);
|
|
3089
|
+
// add spills and reads before and after the call to the outlined code, and in the outlined code itself
|
|
3090
|
+
var codeInfo = analyzeCode(func, asmData, code);
|
|
3091
|
+
var reps = [];
|
|
3092
|
+
for (var v in codeInfo.reads) {
|
|
3093
|
+
if (v != 'sp') {
|
|
3094
|
+
reps.push(['stat', ['assign', true, ['sub', ['name', getAsmType(asmData, v) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
|
|
3095
|
+
code.unshift(['stat', ['assign', true, ['name', v], ['sub', ['name', getAsmType(asmData, v) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]]]]);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
reps.push(['stat', ['call', ['name', newIdent], [['name', 'sp']]]]);
|
|
3099
|
+
for (var v in codeInfo.writes) {
|
|
3100
|
+
reps.push(['stat', ['assign', true, ['name', v], ['sub', ['name', getAsmType(asmData, v) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]]]]);
|
|
3101
|
+
code.push(['stat', ['assign', true, ['sub', ['name', getAsmType(asmData, v) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
|
|
3102
|
+
}
|
|
3103
|
+
// Generate new function
|
|
3104
|
+
if (codeInfo.hasReturn || codeInfo.hasBreak || codeInfo.hasContinue) {
|
|
3105
|
+
// we need to capture all control flow using a top-level labeled one-time loop in the outlined function
|
|
3106
|
+
code = [['label', 'OL', ['do', ['num', 0], ['block', code]]]];
|
|
3107
|
+
var breakCapturers = 0;
|
|
3108
|
+
var continueCapturers = 0;
|
|
3109
|
+
traverse(code, function(node, type) {
|
|
3110
|
+
// replace all break/continue/returns with code to break out of the main one-time loop, and set the control data
|
|
3111
|
+
if (type == 'return') {
|
|
3112
|
+
var ret = ['break', 'OL'];
|
|
3113
|
+
if (!node[1]) {
|
|
3114
|
+
ret = ['seq', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', CONTROL_RETURN_VOID]), ret];
|
|
3115
|
+
} else {
|
|
3116
|
+
var type = detectAsmCoercion(node[1], asmData);
|
|
3117
|
+
ret = ['seq', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', type == ASM_INT ? CONTROL_RETURN_INT : CONTROL_RETURN_DOUBLE]), ret];
|
|
3118
|
+
ret = ['seq', makeAssign(makeStackAccess(type, asmData.controlDataStackPos), node[1]), ret];
|
|
3119
|
+
}
|
|
3120
|
+
return ret;
|
|
3121
|
+
} else if (type == 'break') {
|
|
3122
|
+
var label = node[1] || 0;
|
|
3123
|
+
if (label == 'OL') return; // this was just added before us, it is new replacement code
|
|
3124
|
+
if (!label && breakCapturers > 0) return; // no label, and captured
|
|
3125
|
+
if (label && (label in codeInfo.labels)) return; // label, and defined in this code, so captured
|
|
3126
|
+
var ret = ['break', 'OL'];
|
|
3127
|
+
ret = ['seq', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', label ? CONTROL_BREAK_LABEL : CONTROL_BREAK]), ret];
|
|
3128
|
+
if (label) {
|
|
3129
|
+
assert(label in codeInfo.labels, label + ' in ' + keys(codeInfo.labels));
|
|
3130
|
+
ret = ['seq', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ['num', codeInfo.labels[label]]), ret];
|
|
3131
|
+
}
|
|
3132
|
+
return ret;
|
|
3133
|
+
} else if (type == 'continue') {
|
|
3134
|
+
var label = node[1] || 0;
|
|
3135
|
+
if (!label && continueCapturers > 0) return; // no label, and captured
|
|
3136
|
+
if (label && (label in codeInfo.labels)) return; // label, and defined in this code, so captured
|
|
3137
|
+
var ret = ['break', 'OL'];
|
|
3138
|
+
ret = ['seq', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', label ? CONTROL_CONTINUE_LABEL : CONTROL_CONTINUE]), ret];
|
|
3139
|
+
if (label) {
|
|
3140
|
+
ret = ['seq', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ['num', codeInfo.labels[label]]), ret];
|
|
3141
|
+
}
|
|
3142
|
+
return ret;
|
|
3143
|
+
} else {
|
|
3144
|
+
if (type in BREAK_CAPTURERS) {
|
|
3145
|
+
breakCapturers++;
|
|
3146
|
+
}
|
|
3147
|
+
if (type in CONTINUE_CAPTURERS) {
|
|
3148
|
+
continueCapturers++;
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
}, function(node, type) {
|
|
3152
|
+
if (type in BREAK_CAPTURERS) {
|
|
3153
|
+
breakCapturers--;
|
|
3154
|
+
}
|
|
3155
|
+
if (type in CONTINUE_CAPTURERS) {
|
|
3156
|
+
continueCapturers--;
|
|
3157
|
+
}
|
|
3158
|
+
});
|
|
3159
|
+
// read the control data at the callsite to the outlined function
|
|
3160
|
+
if (codeInfo.hasReturn) {
|
|
3161
|
+
reps.push(makeIf(
|
|
3162
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_RETURN_VOID]),
|
|
3163
|
+
[['stat', ['return']]]
|
|
3164
|
+
));
|
|
3165
|
+
reps.push(makeIf(
|
|
3166
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_RETURN_INT]),
|
|
3167
|
+
[['stat', ['return', makeStackAccess(ASM_INT, asmData.controlDataStackPos)]]]
|
|
3168
|
+
));
|
|
3169
|
+
reps.push(makeIf(
|
|
3170
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_RETURN_DOUBLE]),
|
|
3171
|
+
[['stat', ['return', makeStackAccess(ASM_DOUBLE, asmData.controlDataStackPos)]]]
|
|
3172
|
+
));
|
|
3173
|
+
}
|
|
3174
|
+
if (codeInfo.hasBreak) {
|
|
3175
|
+
reps.push(makeIf(
|
|
3176
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_BREAK]),
|
|
3177
|
+
['stat', ['break']]
|
|
3178
|
+
));
|
|
3179
|
+
reps.push(makeIf(
|
|
3180
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_BREAK_LABEL]),
|
|
3181
|
+
['stat', ['break', makeStackAccess(ASM_INT, asmData.controlDataStackPos)]] // XXX here and below, need a switch overall possible labels
|
|
3182
|
+
));
|
|
3183
|
+
}
|
|
3184
|
+
if (codeInfo.hasContinue) {
|
|
3185
|
+
reps.push(makeIf(
|
|
3186
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_CONTINUE]),
|
|
3187
|
+
['stat', ['break']]
|
|
3188
|
+
));
|
|
3189
|
+
reps.push(makeIf(
|
|
3190
|
+
makeComparison(makeStackAccess(ASM_INT, asmData.controlStackPos), '==', ['num', CONTROL_CONTINUE_LABEL]),
|
|
3191
|
+
['stat', ['continue', makeStackAccess(ASM_INT, asmData.controlDataStackPos)]] // XXX
|
|
3192
|
+
));
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
var newFunc = ['defun', newIdent, ['sp'], code];
|
|
3196
|
+
var newAsmData = { params: { sp: ASM_INT }, vars: {} };
|
|
3197
|
+
for (var v in codeInfo.reads) {
|
|
3198
|
+
newAsmData.vars[v] = getAsmType(asmData, v);
|
|
3199
|
+
}
|
|
3200
|
+
for (var v in codeInfo.writes) {
|
|
3201
|
+
newAsmData.vars[v] = getAsmType(asmData, v);
|
|
3202
|
+
}
|
|
3203
|
+
denormalizeAsm(newFunc, newAsmData);
|
|
3204
|
+
// replace in stats
|
|
3205
|
+
stats.splice.apply(stats, [start, end-start+1].concat(reps));
|
|
3206
|
+
return [newFunc];
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
function outlineStatements(func, asmData, stats, maxSize) {
|
|
3210
|
+
level++;
|
|
3211
|
+
if (measureSize(stats) < sizeToOutline) return;
|
|
3212
|
+
var ret = [];
|
|
3213
|
+
var sizeSeen = 0;
|
|
3214
|
+
var end = stats.length-1;
|
|
3215
|
+
var i = stats.length;
|
|
3216
|
+
while (--i >= 0) {
|
|
3217
|
+
var stat = stats[i];
|
|
3218
|
+
var size = measureSize(stat);
|
|
3219
|
+
//printErr(level + ' size ' + [i, size]);
|
|
3220
|
+
if (size >= sizeToOutline) {
|
|
3221
|
+
// this by itself is big enough to inline, recurse into it and find statements to split on
|
|
3222
|
+
var subStatements = null;
|
|
3223
|
+
traverse(stat, function(node, type) {
|
|
3224
|
+
if (type == 'block') {
|
|
3225
|
+
if (measureSize(node) >= sizeToOutline) {
|
|
3226
|
+
var subRet = outlineStatements(func, asmData, node[1], maxSize);
|
|
3227
|
+
if (subRet && subRet.length > 0) ret.push.apply(ret, subRet);
|
|
3228
|
+
}
|
|
3229
|
+
return null; // do not recurse into children, outlineStatements will do so if necessary
|
|
3230
|
+
}
|
|
3231
|
+
});
|
|
3232
|
+
sizeSeen = 0;
|
|
3233
|
+
continue;
|
|
3234
|
+
}
|
|
3235
|
+
sizeSeen += size;
|
|
3236
|
+
// If this is big enough to outline, but no too big (if very close to the size of the full function,
|
|
3237
|
+
// outlining is pointless; remove stats from the end to try to achieve the good case), then outline.
|
|
3238
|
+
// Also, try to reduce the size if it is much larger than the hoped-for size
|
|
3239
|
+
while ((sizeSeen > maxSize || sizeSeen > 2*sizeToOutline) && i < end) {
|
|
3240
|
+
sizeSeen -= measureSize(stats[end]);
|
|
3241
|
+
if (sizeSeen >= sizeToOutline) {
|
|
3242
|
+
end--;
|
|
3243
|
+
} else {
|
|
3244
|
+
sizeSeen += measureSize(stats[end]); // abort, this took away too much
|
|
3245
|
+
break;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
if (sizeSeen >= sizeToOutline && sizeSeen <= maxSize) {
|
|
3249
|
+
ret.push.apply(ret, doOutline(func, asmData, stats, i, end)); // outline [i, .. ,end] inclusive
|
|
3250
|
+
sizeSeen = 0;
|
|
3251
|
+
end = i-1;
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
level--;
|
|
3255
|
+
return ret;
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
//
|
|
3259
|
+
|
|
3260
|
+
if (ast[0] !== 'toplevel') {
|
|
3261
|
+
assert(ast[0] == 'defun');
|
|
3262
|
+
ast = ['toplevel', [ast]];
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
var funcs = ast[1];
|
|
3266
|
+
|
|
3267
|
+
var more = true;
|
|
3268
|
+
while (more) {
|
|
3269
|
+
more = false;
|
|
3270
|
+
|
|
3271
|
+
var newFuncs = [];
|
|
3272
|
+
|
|
3273
|
+
funcs.forEach(function(func) {
|
|
3274
|
+
var asmData = normalizeAsm(func);
|
|
3275
|
+
var size = measureSize(func);
|
|
3276
|
+
if (size >= sizeToOutline) {
|
|
3277
|
+
aggressiveVariableElimination(func, asmData);
|
|
3278
|
+
analyzeFunction(func, asmData);
|
|
3279
|
+
var ret = outlineStatements(func, asmData, getStatements(func), 0.5*size);
|
|
3280
|
+
if (ret && ret.length > 0) newFuncs.push.apply(newFuncs, ret);
|
|
3281
|
+
}
|
|
3282
|
+
denormalizeAsm(func, asmData);
|
|
3283
|
+
});
|
|
3284
|
+
|
|
3285
|
+
// TODO: control flow: route returns and breaks. outlined code should have all breaks/continues/returns break into the outermost scope,
|
|
3286
|
+
// after setting a state variable, etc.
|
|
3287
|
+
|
|
3288
|
+
if (newFuncs.length > 0) {
|
|
3289
|
+
// We have outlined. Add stack support: header in which we allocate enough stack space TODO
|
|
3290
|
+
// If sp was not present before, add it and before each return, pop the stack. also a final pop if not ending with a return TODO
|
|
3291
|
+
// (none of this should be done in inner functions, of course, just the original)
|
|
3292
|
+
|
|
3293
|
+
// add new functions to the toplevel, or create a toplevel if there isn't one
|
|
3294
|
+
ast[1].push.apply(ast[1], newFuncs);
|
|
3295
|
+
|
|
3296
|
+
funcs = newFuncs;
|
|
3297
|
+
more = true;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
// Last pass utilities
|
|
3303
|
+
|
|
3304
|
+
// Change +5 to DOT$ZERO(5). We then textually change 5 to 5.0 (uglify's ast cannot differentiate between 5 and 5.0 directly)
|
|
3305
|
+
function prepDotZero(ast) {
|
|
3306
|
+
traverse(ast, function(node, type) {
|
|
3307
|
+
if (type === 'unary-prefix' && node[1] === '+') {
|
|
3308
|
+
if (node[2][0] === 'num' ||
|
|
3309
|
+
(node[2][0] === 'unary-prefix' && node[2][1] === '-' && node[2][2][0] === 'num')) {
|
|
3310
|
+
return ['call', ['name', 'DOT$ZERO'], [node[2]]];
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
});
|
|
3314
|
+
}
|
|
3315
|
+
function fixDotZero(js) {
|
|
3316
|
+
return js.replace(/DOT\$ZERO\(([-+]?(0x)?[0-9a-f]*\.?[0-9]+([eE][-+]?[0-9]+)?)\)/g, function(m, num) {
|
|
3317
|
+
if (num.substr(0, 2) === '0x' || num.substr(0, 3) === '-0x') {
|
|
3318
|
+
return eval(num) + '.0';
|
|
3319
|
+
}
|
|
3320
|
+
if (num.indexOf('.') >= 0) return num;
|
|
3321
|
+
var e = num.indexOf('e');
|
|
3322
|
+
if (e < 0) return num + '.0';
|
|
3323
|
+
return num.substr(0, e) + '.0' + num.substr(e);
|
|
3324
|
+
});
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
function asmLastOpts(ast) {
|
|
3328
|
+
traverseGeneratedFunctions(ast, function(fun) {
|
|
3329
|
+
traverse(fun, function(node, type) {
|
|
3330
|
+
if (type === 'while' && node[1][0] === 'num' && node[1][1] === 1 && node[2][0] === 'block') {
|
|
3331
|
+
// This is at the end of the pipeline, we can assume all other optimizations are done, and we modify loops
|
|
3332
|
+
// into shapes that might confuse other passes
|
|
3333
|
+
|
|
3334
|
+
// while (1) { .. if (..) { break } } ==> do { .. } while(..)
|
|
3335
|
+
var stats = node[2][1];
|
|
3336
|
+
var last = stats[stats.length-1];
|
|
3337
|
+
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]) {
|
|
3338
|
+
var abort = false;
|
|
3339
|
+
var stack = 0;
|
|
3340
|
+
traverse(stats, function(node, type) {
|
|
3341
|
+
if (type == 'continue') {
|
|
3342
|
+
if (stack == 0 || node[1]) { // abort if labeled (we do not analyze labels here yet), or a continue directly on us
|
|
3343
|
+
abort = true;
|
|
3344
|
+
return true;
|
|
3345
|
+
}
|
|
3346
|
+
} else if (type in LOOP) {
|
|
3347
|
+
stack++;
|
|
3348
|
+
}
|
|
3349
|
+
}, function(node, type) {
|
|
3350
|
+
if (type in LOOP) {
|
|
3351
|
+
stack--;
|
|
3352
|
+
}
|
|
3353
|
+
});
|
|
3354
|
+
if (abort) return;
|
|
3355
|
+
var conditionToBreak = last[1];
|
|
3356
|
+
stats.pop();
|
|
3357
|
+
node[0] = 'do';
|
|
3358
|
+
node[1] = simplifyNotCompsDirect(['unary-prefix', '!', conditionToBreak]);
|
|
3359
|
+
return node;
|
|
3360
|
+
}
|
|
3361
|
+
} else if (type == 'binary' && node[1] == '&' && node[3][0] == 'unary-prefix' && node[3][1] == '-' && node[3][2][0] == 'num' && node[3][2][1] == 1) {
|
|
3362
|
+
// Change &-1 into |0, at this point the hint is no longer needed
|
|
3363
|
+
node[1] = '|';
|
|
3364
|
+
node[3] = node[3][2];
|
|
3365
|
+
node[3][1] = 0;
|
|
3366
|
+
}
|
|
3367
|
+
});
|
|
3368
|
+
});
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
// Passes table
|
|
3372
|
+
|
|
3373
|
+
var minifyWhitespace = false, printMetadata = true, asm = false, last = false;
|
|
3374
|
+
|
|
3375
|
+
var passes = {
|
|
3376
|
+
dumpAst: dumpAst,
|
|
3377
|
+
dumpSrc: dumpSrc,
|
|
3378
|
+
unGlobalize: unGlobalize,
|
|
3379
|
+
removeAssignsToUndefined: removeAssignsToUndefined,
|
|
3380
|
+
//removeUnneededLabelSettings: removeUnneededLabelSettings,
|
|
3381
|
+
simplifyExpressionsPre: simplifyExpressionsPre,
|
|
3382
|
+
optimizeShiftsConservative: optimizeShiftsConservative,
|
|
3383
|
+
optimizeShiftsAggressive: optimizeShiftsAggressive,
|
|
3384
|
+
simplifyExpressionsPost: simplifyExpressionsPost,
|
|
3385
|
+
hoistMultiples: hoistMultiples,
|
|
3386
|
+
loopOptimizer: loopOptimizer,
|
|
3387
|
+
registerize: registerize,
|
|
3388
|
+
eliminate: eliminate,
|
|
3389
|
+
eliminateMemSafe: eliminateMemSafe,
|
|
3390
|
+
minifyGlobals: minifyGlobals,
|
|
3391
|
+
relocate: relocate,
|
|
3392
|
+
outline: outline,
|
|
3393
|
+
minifyWhitespace: function() { minifyWhitespace = true },
|
|
3394
|
+
noPrintMetadata: function() { printMetadata = false },
|
|
3395
|
+
asm: function() { asm = true },
|
|
3396
|
+
last: function() { last = true },
|
|
3397
|
+
};
|
|
3398
|
+
|
|
3399
|
+
// Main
|
|
3400
|
+
|
|
3401
|
+
var suffix = '';
|
|
3402
|
+
|
|
3403
|
+
arguments_ = arguments_.filter(function (arg) {
|
|
3404
|
+
if (!/^--/.test(arg)) return true;
|
|
3405
|
+
|
|
3406
|
+
if (arg === '--debug') debug = true;
|
|
3407
|
+
else throw new Error('Unrecognized flag: ' + arg);
|
|
3408
|
+
});
|
|
3409
|
+
|
|
3410
|
+
|
|
3411
|
+
var src = read(arguments_[0]);
|
|
3412
|
+
var ast = srcToAst(src);
|
|
3413
|
+
//printErr(JSON.stringify(ast)); throw 1;
|
|
3414
|
+
generatedFunctions = src.indexOf(GENERATED_FUNCTIONS_MARKER) >= 0;
|
|
3415
|
+
var extraInfoStart = src.indexOf('// EXTRA_INFO:')
|
|
3416
|
+
if (extraInfoStart > 0) extraInfo = JSON.parse(src.substr(extraInfoStart + 14));
|
|
3417
|
+
//printErr(JSON.stringify(extraInfo));
|
|
3418
|
+
|
|
3419
|
+
|
|
3420
|
+
arguments_.slice(1).forEach(function(arg) {
|
|
3421
|
+
passes[arg](ast);
|
|
3422
|
+
});
|
|
3423
|
+
if (asm && last) {
|
|
3424
|
+
asmLastOpts(ast); // TODO: move out of last, to make last faster when done later (as in side modules)
|
|
3425
|
+
prepDotZero(ast);
|
|
3426
|
+
}
|
|
3427
|
+
var js = astToSrc(ast, minifyWhitespace), old;
|
|
3428
|
+
if (asm && last) {
|
|
3429
|
+
js = fixDotZero(js);
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
// remove unneeded newlines+spaces, and print
|
|
3433
|
+
do {
|
|
3434
|
+
old = js;
|
|
3435
|
+
js = js.replace(/\n *\n/g, '\n');
|
|
3436
|
+
} while (js != old);
|
|
3437
|
+
print(js);
|
|
3438
|
+
print('\n');
|
|
3439
|
+
print(suffix);
|
|
3440
|
+
|