diff --git a/AUTHORS b/AUTHORS
index 8a8f7c663731b..5121103af4eb9 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -253,3 +253,6 @@ a license to everyone to use it as detailed in LICENSE.)
 * Aiden Koss <madd0131@umn.edu>
 * Dustin VanLerberghe <good_ol_dv@hotmail.com>
 * Philip Bielby <pmb45-github@srcf.ucam.org> (copyright owned by Jagex Ltd.)
+* Régis Fénéon <regis.feneon@gmail.com>
+* Dominic Chen <d.c.ddcc@gmail.com> (copyright owned by Google, Inc.)
+* Junji Hashimoto <junji.hashimoto@gmail.com>
diff --git a/embuilder.py b/embuilder.py
index e11b89b60b5af..6674ccd255799 100755
--- a/embuilder.py
+++ b/embuilder.py
@@ -63,10 +63,11 @@
 temp_files = shared.configuration.get_temp_files()
 
 def build(src, result_libs, args=[]):
-  temp = temp_files.get('.cpp').name
-  open(temp, 'w').write(src)
-  temp_js = temp_files.get('.js').name
-  shared.Building.emcc(temp, args, output_filename=temp_js)
+  with temp_files.get_file('.cpp') as temp:
+    open(temp, 'w').write(src)
+    temp_js = temp_files.get('.js').name
+    shared.Building.emcc(temp, args, output_filename=temp_js)
+
   assert os.path.exists(temp_js), 'failed to build file'
   if result_libs:
     for lib in result_libs:
diff --git a/emcc.py b/emcc.py
index 5cf9ee59d7995..cd9f825d101a1 100755
--- a/emcc.py
+++ b/emcc.py
@@ -436,6 +436,7 @@ def log_time(name):
     default_object_extension = '.o'
     valid_abspaths = []
     separate_asm = False
+    cfi = False
 
     def is_valid_abspath(path_name):
       # Any path that is underneath the emscripten repository root must be ok.
@@ -724,6 +725,8 @@ def detect_fixed_language_mode(args):
         newargs.append('-D__SSSE3__=1')
         newargs.append('-D__SSE4_1__=1')
         newargs[i] = ''
+      elif newargs[i].startswith("-fsanitize=cfi"):
+        cfi = True
 
     if should_exit:
       sys.exit(0)
@@ -907,7 +910,7 @@ def detect_fixed_language_mode(args):
               break
           if found: break
         if found: break
-      if not found and lib not in ['GL', 'GLU', 'glut', 'm', 'c', 'SDL', 'stdc++']: # whitelist our default libraries
+      if not found and lib not in ['GL', 'GLU', 'glut', 'm', 'c', 'SDL', 'stdc++', 'pthread']: # whitelist our default libraries
         logging.warning('emcc: cannot find library "%s"', lib)
 
     # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so
@@ -1105,9 +1108,6 @@ def check(input_file):
     if proxy_to_worker or use_preload_plugins:
       shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$Browser']
 
-    if js_opts:
-      shared.Settings.RUNNING_JS_OPTS = 1
-
     if not shared.Settings.NO_FILESYSTEM and not shared.Settings.ONLY_MY_CODE:
       shared.Settings.EXPORTED_FUNCTIONS += ['___errno_location'] # so FS can report errno back to C
       if not shared.Settings.NO_EXIT_RUNTIME:
@@ -1124,9 +1124,6 @@ def check(input_file):
       js_libraries.append(shared.path_from_root('src', 'library_pthread_stub.js'))
 
     if shared.Settings.USE_PTHREADS:
-      if shared.Settings.PROXY_TO_WORKER:
-        logging.error('-s PROXY_TO_WORKER=1 is not yet supported with -s USE_PTHREADS=1!')
-        exit(1)
       if shared.Settings.LINKABLE:
         logging.error('-s LINKABLE=1 is not supported with -s USE_PTHREADS=1!')
         exit(1)
@@ -1138,6 +1135,7 @@ def check(input_file):
         exit(1)
 
     if shared.Settings.WASM_BACKEND:
+      js_opts = None
       shared.Settings.BINARYEN = 1
       # Static linking is tricky with LLVM, since e.g. memset might not be used from libc,
       # but be used as an intrinsic, and codegen will generate a libc call from that intrinsic
@@ -1148,12 +1146,24 @@ def check(input_file):
       # to bootstrap struct_info, we need binaryen
       os.environ['EMCC_WASM_BACKEND_BINARYEN'] = '1'
 
+    if js_opts:
+      shared.Settings.RUNNING_JS_OPTS = 1
+
     if shared.Settings.BINARYEN:
       debug_level = max(1, debug_level) # keep whitespace readable, for asm.js parser simplicity
       shared.Settings.GLOBAL_BASE = 1024 # leave some room for mapping global vars
       assert not shared.Settings.SPLIT_MEMORY, 'WebAssembly does not support split memory'
       if not shared.Settings.BINARYEN_METHOD:
         shared.Settings.BINARYEN_METHOD = 'native-wasm,interpret-binary'
+      assert not shared.Settings.INCLUDE_FULL_LIBRARY, 'The WebAssembly libc overlaps with JS libs, so INCLUDE_FULL_LIBRARY does not just work (FIXME)'
+      # if root was not specified in -s, it might be fixed in ~/.emscripten, copy from there
+      if not shared.Settings.BINARYEN_ROOT:
+        try:
+          shared.Settings.BINARYEN_ROOT = shared.BINARYEN_ROOT
+        except:
+          pass
+      if use_closure_compiler:
+        logging.warning('closure compiler is known to have issues with binaryen (FIXME)')
 
     if shared.Settings.CYBERDWARF:
       newargs.append('-g')
@@ -1437,6 +1447,11 @@ def save_intermediate(name=None, suffix='js'):
         # At minimum remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it)
         link_opts += shared.Building.get_safe_internalize() + ['-globaldce']
 
+      if cfi:
+        if use_cxx:
+           link_opts.append("-wholeprogramdevirt")
+        link_opts.append("-lowertypetests")
+
       if AUTODEBUG:
         # let llvm opt directly emit ll, to skip writing and reading all the bitcode
         link_opts += ['-S']
@@ -1621,9 +1636,7 @@ class JSOptimizer:
       def flush(title='js_opts'):
         JSOptimizer.queue = filter(lambda p: p not in JSOptimizer.blacklist, JSOptimizer.queue)
 
-        if shared.Settings.WASM_BACKEND:
-          logging.debug('ignoring js-optimizer passes since emitting pure wasm: ' + ' '.join(JSOptimizer.queue))
-          return
+        assert not shared.Settings.WASM_BACKEND, 'JSOptimizer should not run with pure wasm output'
 
         if JSOptimizer.extra_info is not None and len(JSOptimizer.extra_info) == 0:
           JSOptimizer.extra_info = None
@@ -1877,9 +1890,9 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati
     # Separate out the asm.js code, if asked. Or, if necessary for another option
     if (separate_asm or shared.Settings.BINARYEN) and not shared.Settings.WASM_BACKEND:
       logging.debug('separating asm')
-      temp_target = misc_temp_files.get(suffix='.js').name
-      subprocess.check_call([shared.PYTHON, shared.path_from_root('tools', 'separate_asm.py'), js_target, asm_target, temp_target])
-      shutil.move(temp_target, js_target)
+      with misc_temp_files.get_file(suffix='.js') as temp_target:
+        subprocess.check_call([shared.PYTHON, shared.path_from_root('tools', 'separate_asm.py'), js_target, asm_target, temp_target])
+        shutil.move(temp_target, js_target)
 
       # extra only-my-code logic
       if shared.Settings.ONLY_MY_CODE:
diff --git a/emscripten-version.txt b/emscripten-version.txt
index 71be8e725dcda..29eea1738741e 100644
--- a/emscripten-version.txt
+++ b/emscripten-version.txt
@@ -1,2 +1,2 @@
-"1.36.5"
+"1.36.6"
 
diff --git a/emscripten.py b/emscripten.py
index 7575cdf7ab291..943f535d556eb 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -97,54 +97,54 @@ def emscript(infile, settings, outfile, libraries=None, compiler_engine=None,
       shared.try_delete(outfile.name) # remove partial output
 
 def get_and_parse_backend(infile, settings, temp_files, DEBUG):
-    temp_js = temp_files.get('.4.js').name
-    backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc')
-    backend_args = [backend_compiler, infile, '-march=js', '-filetype=asm', '-o', temp_js]
-    if settings['PRECISE_F32']:
-      backend_args += ['-emscripten-precise-f32']
-    if settings['USE_PTHREADS']:
-      backend_args += ['-emscripten-enable-pthreads']
-    if settings['WARN_UNALIGNED']:
-      backend_args += ['-emscripten-warn-unaligned']
-    if settings['RESERVED_FUNCTION_POINTERS'] > 0:
-      backend_args += ['-emscripten-reserved-function-pointers=%d' % settings['RESERVED_FUNCTION_POINTERS']]
-    if settings['ASSERTIONS'] > 0:
-      backend_args += ['-emscripten-assertions=%d' % settings['ASSERTIONS']]
-    if settings['ALIASING_FUNCTION_POINTERS'] == 0:
-      backend_args += ['-emscripten-no-aliasing-function-pointers']
-    if settings['EMULATED_FUNCTION_POINTERS']:
-      backend_args += ['-emscripten-emulated-function-pointers']
-    if settings['RELOCATABLE']:
-      backend_args += ['-emscripten-relocatable']
-      backend_args += ['-emscripten-global-base=0']
-    elif settings['GLOBAL_BASE'] >= 0:
-      backend_args += ['-emscripten-global-base=%d' % settings['GLOBAL_BASE']]
-    backend_args += ['-O' + str(settings['OPT_LEVEL'])]
-    if settings['DISABLE_EXCEPTION_CATCHING'] != 1:
-      backend_args += ['-enable-emscripten-cxx-exceptions']
-      if settings['DISABLE_EXCEPTION_CATCHING'] == 2:
-        backend_args += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(settings['EXCEPTION_CATCHING_WHITELIST'] or ['fake'])]
-    if settings['ASYNCIFY']:
-      backend_args += ['-emscripten-asyncify']
-      backend_args += ['-emscripten-asyncify-functions=' + ','.join(settings['ASYNCIFY_FUNCTIONS'])]
-      backend_args += ['-emscripten-asyncify-whitelist=' + ','.join(settings['ASYNCIFY_WHITELIST'])]
-    if settings['NO_EXIT_RUNTIME']:
-      backend_args += ['-emscripten-no-exit-runtime']
-    if settings['BINARYEN']:
-      backend_args += ['-emscripten-wasm']
-    if settings['CYBERDWARF']:
-      backend_args += ['-enable-cyberdwarf']
-
-    if DEBUG:
-      logging.debug('emscript: llvm backend: ' + ' '.join(backend_args))
-      t = time.time()
-    shared.jsrun.timeout_run(subprocess.Popen(backend_args, stdout=subprocess.PIPE))
-    if DEBUG:
-      logging.debug('  emscript: llvm backend took %s seconds' % (time.time() - t))
-
-    # Split up output
-    backend_output = open(temp_js).read()
-    #if DEBUG: print >> sys.stderr, backend_output
+    with temp_files.get_file('.4.js') as temp_js:
+      backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc')
+      backend_args = [backend_compiler, infile, '-march=js', '-filetype=asm', '-o', temp_js]
+      if settings['PRECISE_F32']:
+        backend_args += ['-emscripten-precise-f32']
+      if settings['USE_PTHREADS']:
+        backend_args += ['-emscripten-enable-pthreads']
+      if settings['WARN_UNALIGNED']:
+        backend_args += ['-emscripten-warn-unaligned']
+      if settings['RESERVED_FUNCTION_POINTERS'] > 0:
+        backend_args += ['-emscripten-reserved-function-pointers=%d' % settings['RESERVED_FUNCTION_POINTERS']]
+      if settings['ASSERTIONS'] > 0:
+        backend_args += ['-emscripten-assertions=%d' % settings['ASSERTIONS']]
+      if settings['ALIASING_FUNCTION_POINTERS'] == 0:
+        backend_args += ['-emscripten-no-aliasing-function-pointers']
+      if settings['EMULATED_FUNCTION_POINTERS']:
+        backend_args += ['-emscripten-emulated-function-pointers']
+      if settings['RELOCATABLE']:
+        backend_args += ['-emscripten-relocatable']
+        backend_args += ['-emscripten-global-base=0']
+      elif settings['GLOBAL_BASE'] >= 0:
+        backend_args += ['-emscripten-global-base=%d' % settings['GLOBAL_BASE']]
+      backend_args += ['-O' + str(settings['OPT_LEVEL'])]
+      if settings['DISABLE_EXCEPTION_CATCHING'] != 1:
+        backend_args += ['-enable-emscripten-cxx-exceptions']
+        if settings['DISABLE_EXCEPTION_CATCHING'] == 2:
+          backend_args += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(settings['EXCEPTION_CATCHING_WHITELIST'] or ['fake'])]
+      if settings['ASYNCIFY']:
+        backend_args += ['-emscripten-asyncify']
+        backend_args += ['-emscripten-asyncify-functions=' + ','.join(settings['ASYNCIFY_FUNCTIONS'])]
+        backend_args += ['-emscripten-asyncify-whitelist=' + ','.join(settings['ASYNCIFY_WHITELIST'])]
+      if settings['NO_EXIT_RUNTIME']:
+        backend_args += ['-emscripten-no-exit-runtime']
+      if settings['BINARYEN']:
+        backend_args += ['-emscripten-wasm']
+      if settings['CYBERDWARF']:
+        backend_args += ['-enable-cyberdwarf']
+
+      if DEBUG:
+        logging.debug('emscript: llvm backend: ' + ' '.join(backend_args))
+        t = time.time()
+      shared.jsrun.timeout_run(subprocess.Popen(backend_args, stdout=subprocess.PIPE))
+      if DEBUG:
+        logging.debug('  emscript: llvm backend took %s seconds' % (time.time() - t))
+
+      # Split up output
+      backend_output = open(temp_js).read()
+      #if DEBUG: print >> sys.stderr, backend_output
 
     start_funcs_marker = '// EMSCRIPTEN_START_FUNCTIONS'
     end_funcs_marker = '// EMSCRIPTEN_END_FUNCTIONS'
@@ -267,19 +267,19 @@ def is_int(x):
     assert not (metadata['simd'] and settings['SPLIT_MEMORY']), 'SIMD is used, but not supported in SPLIT_MEMORY'
 
     # Save settings to a file to work around v8 issue 1579
-    settings_file = temp_files.get('.txt').name
-    def save_settings():
-      global settings_text
-      settings_text = json.dumps(settings, sort_keys=True)
-      s = open(settings_file, 'w')
-      s.write(settings_text)
-      s.close()
-    save_settings()
-
-    # Call js compiler
-    out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine,
-                       [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
-                       cwd=path_from_root('src'), error_limit=300)
+    with temp_files.get_file('.txt') as settings_file:
+      def save_settings():
+        global settings_text
+        settings_text = json.dumps(settings, sort_keys=True)
+        s = open(settings_file, 'w')
+        s.write(settings_text)
+        s.close()
+      save_settings()
+
+      # Call js compiler
+      out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine,
+                         [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
+                         cwd=path_from_root('src'), error_limit=300)
     assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?'
     glue, forwarded_data = out.split('//FORWARDED_DATA:')
 
@@ -1305,38 +1305,39 @@ def emscript_wasm_backend(infile, settings, outfile, libraries=None, compiler_en
 
   if libraries is None: libraries = []
 
-  temp_s = temp_files.get('.wb.s').name
-  backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc')
-  backend_args = [backend_compiler, infile, '-march=wasm32', '-filetype=asm',
-                  '-asm-verbose=false',
-                  '-o', temp_s]
-  backend_args += ['-thread-model=single'] # no threads support in backend, tell llc to not emit atomics
-  # disable slow and relatively unimportant optimization passes
-  backend_args += ['-combiner-alias-analysis=false', '-combiner-global-alias-analysis=false']
-  if DEBUG:
-    logging.debug('emscript: llvm wasm backend: ' + ' '.join(backend_args))
-    t = time.time()
-  shared.check_call(backend_args)
-  if DEBUG:
-    logging.debug('  emscript: llvm wasm backend took %s seconds' % (time.time() - t))
-    t = time.time()
-    import shutil
-    shutil.copyfile(temp_s, os.path.join(shared.CANONICAL_TEMP_DIR, 'emcc-llvm-backend-output.s'))
-
-  assert shared.Settings.BINARYEN_ROOT, 'need BINARYEN_ROOT config set so we can use Binaryen s2wasm on the backend output'
-  wasm = outfile.name[:-3] + '.wast'
-  s2wasm_args = [os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 's2wasm'), temp_s]
-  s2wasm_args += ['--emscripten-glue']
-  s2wasm_args += ['--global-base=%d' % shared.Settings.GLOBAL_BASE]
-  s2wasm_args += ['--initial-memory=%d' % shared.Settings.TOTAL_MEMORY]
-  def compiler_rt_fail(): raise Exception('Expected wasm_compiler_rt.a to already be built')
-  compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', lambda: compiler_rt_fail(), 'a')
-  s2wasm_args += ['-l', compiler_rt_lib]
-  if DEBUG:
-    logging.debug('emscript: binaryen s2wasm: ' + ' '.join(s2wasm_args))
-    t = time.time()
-    #s2wasm_args += ['--debug']
-  shared.check_call(s2wasm_args, stdout=open(wasm, 'w'))
+  with temp_files.get_file('.wb.s') as temp_s:
+    backend_compiler = os.path.join(shared.LLVM_ROOT, 'llc')
+    backend_args = [backend_compiler, infile, '-march=wasm32', '-filetype=asm',
+                    '-asm-verbose=false',
+                    '-o', temp_s]
+    backend_args += ['-thread-model=single'] # no threads support in backend, tell llc to not emit atomics
+    # disable slow and relatively unimportant optimization passes
+    backend_args += ['-combiner-alias-analysis=false', '-combiner-global-alias-analysis=false']
+    if DEBUG:
+      logging.debug('emscript: llvm wasm backend: ' + ' '.join(backend_args))
+      t = time.time()
+    shared.check_call(backend_args)
+    if DEBUG:
+      logging.debug('  emscript: llvm wasm backend took %s seconds' % (time.time() - t))
+      t = time.time()
+      import shutil
+      shutil.copyfile(temp_s, os.path.join(shared.CANONICAL_TEMP_DIR, 'emcc-llvm-backend-output.s'))
+
+    assert shared.Settings.BINARYEN_ROOT, 'need BINARYEN_ROOT config set so we can use Binaryen s2wasm on the backend output'
+    wasm = outfile.name[:-3] + '.wast'
+    s2wasm_args = [os.path.join(shared.Settings.BINARYEN_ROOT, 'bin', 's2wasm'), temp_s]
+    s2wasm_args += ['--emscripten-glue']
+    s2wasm_args += ['--global-base=%d' % shared.Settings.GLOBAL_BASE]
+    s2wasm_args += ['--initial-memory=%d' % shared.Settings.TOTAL_MEMORY]
+    def compiler_rt_fail(): raise Exception('Expected wasm_compiler_rt.a to already be built')
+    compiler_rt_lib = shared.Cache.get('wasm_compiler_rt.a', lambda: compiler_rt_fail(), 'a')
+    s2wasm_args += ['-l', compiler_rt_lib]
+    if DEBUG:
+      logging.debug('emscript: binaryen s2wasm: ' + ' '.join(s2wasm_args))
+      t = time.time()
+      #s2wasm_args += ['--debug']
+    shared.check_call(s2wasm_args, stdout=open(wasm, 'w'))
+
   if DEBUG:
     logging.debug('  emscript: binaryen s2wasm took %s seconds' % (time.time() - t))
     t = time.time()
@@ -1416,20 +1417,20 @@ def asmjs_mangle(name):
   settings['IMPLEMENTED_FUNCTIONS'] = metadata['implementedFunctions']
 
   # Save settings to a file to work around v8 issue 1579
-  settings_file = temp_files.get('.txt').name
-  def save_settings():
-    global settings_text
-    settings_text = json.dumps(settings, sort_keys=True)
-    s = open(settings_file, 'w')
-    s.write(settings_text)
-    s.close()
-  save_settings()
-
-  # Call js compiler
-  if DEBUG: t = time.time()
-  out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine,
-                     [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
-                     cwd=path_from_root('src'), error_limit=300)
+  with temp_files.get_file('.txt') as settings_file:
+    def save_settings():
+      global settings_text
+      settings_text = json.dumps(settings, sort_keys=True)
+      s = open(settings_file, 'w')
+      s.write(settings_text)
+      s.close()
+    save_settings()
+
+    # Call js compiler
+    if DEBUG: t = time.time()
+    out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine,
+                       [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
+                       cwd=path_from_root('src'), error_limit=300)
   assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?'
   glue, forwarded_data = out.split('//FORWARDED_DATA:')
 
diff --git a/site/build/text/docs/api_reference/emscripten.h.txt b/site/build/text/docs/api_reference/emscripten.h.txt
deleted file mode 100644
index 1df8e81c3acda..0000000000000
--- a/site/build/text/docs/api_reference/emscripten.h.txt
+++ /dev/null
@@ -1,1911 +0,0 @@
-
-emscripten.h
-************
-
-This page documents the public C++ APIs provided by emscripten.h.
-
-Emscripten uses existing/familiar APIs where possible (for example:
-*SDL*). This API provides C++ support for capabilities that are
-specific to JavaScript or the browser environment, or for which there
-is no existing API.
-
-
-Table of Contents
-^^^^^^^^^^^^^^^^^
-
-* Inline assembly/JavaScript
-
-* Calling JavaScript From C/C++
-
-* Browser Execution Environment
-
-* Emscripten Asynchronous File System API
-
-* Emscripten Asynchronous IndexedDB API
-
-* Compiling
-
-* Worker API
-
-* Logging utilities
-
-* Socket event registration
-
-* Unaligned types
-
-* Emterpreter-Async functions
-
-* Asyncify functions
-
-
-Inline assembly/JavaScript
-==========================
-
-Guide material for the following APIs can be found in Calling
-JavaScript from C/C++.
-
-
-Defines
--------
-
-EM_ASM(...)
-
-   Convenient syntax for inline assembly/JavaScript.
-
-   This allows you to declare JavaScript in your C code "inline",
-   which is then executed when your compiled code is run in the
-   browser. For example, the following C code would display two alerts
-   if it was compiled with Emscripten and run in the browser:
-
-      EM_ASM( alert(‘hai’));
-      alert(‘bai’)); )
-
-   Note: * Double-quotes (") cannot be used in the inline
-
-       assembly/JavaScript. Single-quotes (‘) can be used, as shown
-       above.
-
-     * Newlines (\n, \r etc.) are supported in the inline
-       JavaScript. Note that any platform-specific issues with line
-       endings in normal JavaScript also apply to inline JavaScript
-       declared using "EM_ASM".
-
-     * You can’t access C variables with "EM_ASM", nor receive a
-       value back. Instead use "EM_ASM_ARGS", "EM_ASM_INT", or
-       "EM_ASM_DOUBLE".
-
-     * As of "1.30.4", "EM_ASM" contents appear as normal JS,
-       outside of the compiled code. Previously we had them as a
-       string that was "eval``ed. The newer approach avoids the
-       overhead of ``eval", and also allows for better optimization of
-       "EM_ASM" contents by things like closure compiler, as their
-       contents are now visible. Note that this means that closure
-       compiler will optimize them as if they were written together
-       with the rest of the codebase, which is a change from before -
-       you may need to use safety quotes in some places ("a['b']"
-       instead of "a.b").
-
-EM_ASM_(code, ...)
-EM_ASM_ARGS(code, ...)
-EM_ASM_INT(code, ...)
-EM_ASM_DOUBLE(code, ...)
-EM_ASM_INT_V(code)
-EM_ASM_DOUBLE_V(code)
-
-   Input-output versions of EM_ASM.
-
-   "EM_ASM_" (an extra "_" is added) or "EM_ASM_ARGS" allow values
-   ("int" or "double") to be sent into the code.
-
-   If you also want a return value, "EM_ASM_INT" receives arguments
-   (of "int" or "double" type) and returns an "int"; "EM_ASM_DOUBLE"
-   does the same and returns a "double".
-
-   Arguments arrive as "$0", "$1" etc. The output value should be
-   returned:
-
-      int x = EM_ASM_INT({
-        console.log('I received: ' + [$0, $1]);
-        return $0 + $1;
-      }, calc(), otherCalc());
-
-   Note the "{" and "}".
-
-   If you just want to receive an output value ("int" or "double") but
-   not pass any values, you can use "EM_ASM_INT_V" or
-   "EM_ASM_DOUBLE_V", respectively.
-
-
-Calling JavaScript From C/C++
-=============================
-
-Guide material for the following APIs can be found in Calling
-JavaScript from C/C++.
-
-
-Function pointer types for callbacks
-------------------------------------
-
-The following types are used to define function callback signatures
-used in a number of functions in this file.
-
-em_callback_func
-
-   General function pointer type for use in callbacks with no
-   parameters.
-
-   Defined as:
-
-      typedef void (*em_callback_func)(void)
-
-em_arg_callback_func
-
-   Generic function pointer type for use in callbacks with a single
-   "void*" parameter.
-
-   This type is used to define function callbacks that need to pass
-   arbitrary data. For example, "emscripten_set_main_loop_arg()" sets
-   user-defined data, and passes it to a callback of this type on
-   completion.
-
-   Defined as:
-
-      typedef void (*em_arg_callback_func)(void*)
-
-em_str_callback_func
-
-   General function pointer type for use in callbacks with a C string
-   ("const char *") parameter.
-
-   This type is used for function callbacks that need to be passed a C
-   string. For example, it is used in "emscripten_async_wget()" to
-   pass the name of a file that has been asynchronously loaded.
-
-   Defined as:
-
-      typedef void (*em_str_callback_func)(const char *)
-
-
-Functions
----------
-
-void emscripten_run_script(const char *script)
-
-   Interface to the underlying JavaScript engine. This function will
-   "eval()" the given script.
-
-   Parameters:
-      * **script** (*const char**) -- The script to evaluate.
-
-   Return type:
-      void
-
-int emscripten_run_script_int(const char *script)
-
-   Interface to the underlying JavaScript engine. This function will
-   "eval()" the given script.
-
-   Parameters:
-      * **script** (*const char**) -- The script to evaluate.
-
-   Returns:
-      The result of the evaluation, as an integer.
-
-   Return type:
-      int
-
-char *emscripten_run_script_string(const char *script)
-
-   Interface to the underlying JavaScript engine. This function will
-   "eval()" the given script. Note that this overload uses a single
-   buffer shared between calls.
-
-   Parameters:
-      * **script** (*const char**) -- The script to evaluate.
-
-   Returns:
-      The result of the evaluation, as a string.
-
-   Return type:
-      char*
-
-void emscripten_async_run_script(const char *script, int millis)
-
-   Asynchronously run a script, after a specified amount of time.
-
-   Parameters:
-      * **script** (*const char**) -- The script to evaluate.
-
-      * **millis** (*int*) -- The amount of time before the script
-        is run, in milliseconds.
-
-   Return type:
-      void
-
-void emscripten_async_load_script(const char *script, em_callback_func onload, em_callback_func onerror)
-
-   Asynchronously loads a script from a URL.
-
-   This integrates with the run dependencies system, so your script
-   can call "addRunDependency" multiple times, prepare various
-   asynchronous tasks, and call "removeRunDependency" on them; when
-   all are complete (or if there were no run dependencies to begin
-   with), "onload" is called. An example use for this is to load an
-   asset module, that is, the output of the file packager.
-
-   Parameters:
-      * **script** (*const char**) -- The script to evaluate.
-
-      * **onload** (*em_callback_func*) -- A callback function, with
-        no parameters, that is executed when the script has fully
-        loaded.
-
-      * **onerror** (*em_callback_func*) -- A callback function,
-        with no parameters, that is executed if there is an error in
-        loading.
-
-   Return type:
-      void
-
-
-Browser Execution Environment
-=============================
-
-Guide material for the following APIs can be found in Emscripten
-Runtime Environment.
-
-
-Functions
----------
-
-void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop)
-
-   Set a C function as the main event loop.
-
-   If the main loop function needs to receive user-defined data, use
-   "emscripten_set_main_loop_arg()" instead.
-
-   The JavaScript environment will call that function at a specified
-   number of frames per second. Setting 0 or a negative value as the
-   "fps" will instead use the browser’s "requestAnimationFrame"
-   mechanism to call the main loop function. This is **HIGHLY**
-   recommended if you are doing rendering, as the browser’s
-   "requestAnimationFrame" will make sure you render at a proper
-   smooth rate that lines up properly with the browser and monitor. If
-   you do not render at all in your application, then you should pick
-   a specific frame rate that makes sense for your code.
-
-   If "simulate_infinite_loop" is true, the function will throw an
-   exception in order to stop execution of the caller. This will lead
-   to the main loop being entered instead of code after the call to
-   "emscripten_set_main_loop()" being run, which is the closest we can
-   get to simulating an infinite loop (we do something similar in
-   glutMainLoop in GLUT). If this parameter is "false", then the
-   behavior is the same as it was before this parameter was added to
-   the API, which is that execution continues normally. Note that in
-   both cases we do not run global destructors, "atexit", etc., since
-   we know the main loop will still be running, but if we do not
-   simulate an infinite loop then the stack will be unwound. That
-   means that if "simulate_infinite_loop" is "false", and you created
-   an object on the stack, it will be cleaned up before the main loop
-   is called for the first time.
-
-   Tip: There can be only *one* main loop function at a time. To
-     change the main loop function, first "cancel" the current loop,
-     and then call this function to set another.
-
-   Note: See "emscripten_set_main_loop_expected_blockers()",
-     "emscripten_pause_main_loop()", "emscripten_resume_main_loop()"
-     and "emscripten_cancel_main_loop()" for information about
-     blocking, pausing, and resuming the main loop.
-
-   Note: Calling this function overrides the effect of any previous
-     calls to "emscripten_set_main_loop_timing()" by applying the
-     timing mode specified by the parameter "fps". To specify a
-     different timing mode, call the function
-     "emscripten_set_main_loop_timing()" after setting up the main
-     loop.
-
-   Parameters:
-      * **func** (*em_callback_func*) -- C function to set as main
-        event loop.
-
-      * **fps** (*int*) -- Number of frames per second that the
-        JavaScript will call the function. Setting "int <=0"
-        (recommended) uses the browser’s "requestAnimationFrame"
-        mechanism to call the function.
-
-      * **simulate_infinite_loop** (*int*) -- If true, this function
-        will throw an exception in order to stop execution of the
-        caller.
-
-void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop)
-
-   Set a C function as the main event loop, passing it user-defined
-   data.
-
-   See also: The information in "emscripten_set_main_loop()" also
-     applies to this function.
-
-   Parameters:
-      * **func** (*em_arg_callback_func*) -- C function to set as
-        main event loop. The function signature must have a "void*"
-        parameter for passing the "arg" value.
-
-      * **arg** (*void**) -- User-defined data passed to the main
-        loop function, untouched by the API itself.
-
-      * **fps** (*int*) -- Number of frames per second at which the
-        JavaScript will call the function. Setting "int <=0"
-        (recommended) uses the browser’s "requestAnimationFrame"
-        mechanism to call the function.
-
-      * **simulate_infinite_loop** (*int*) -- If true, this function
-        will throw an exception in order to stop execution of the
-        caller.
-
-void emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg)
-void emscripten_push_uncounted_main_loop_blocker(em_arg_callback_func func, void *arg)
-
-   Add a function that **blocks** the main loop.
-
-   The function is added to the back of a queue of events to be
-   blocked; the main loop will not run until all blockers in the queue
-   complete.
-
-   In the "counted" version, blockers are counted (internally) and
-   "Module.setStatus" is called with some text to report progress
-   ("setStatus" is a general hook that a program can define in order
-   to show processing updates).
-
-   Note: * Main loop blockers block the main loop from running, and
-     can
-
-       be counted to show progress. In contrast,
-       "emscripten_async_calls" are not counted, do not block the main
-       loop, and can fire at specific time in the future.
-
-   Parameters:
-      * **func** (*em_arg_callback_func*) -- The main loop blocker
-        function. The function signature must have a "void*" parameter
-        for passing the "arg" value.
-
-      * **arg** (*void**) -- User-defined arguments to pass to the
-        blocker function.
-
-   Return type:
-      void
-
-void emscripten_pause_main_loop(void)
-void emscripten_resume_main_loop(void)
-
-   Pause and resume the main loop.
-
-   Pausing and resuming the main loop is useful if your app needs to
-   perform some synchronous operation, for example to load a file from
-   the network. It might be wrong to run the main loop before that
-   finishes (the original code assumes that), so you can break the
-   code up into asynchronous callbacks, but you must pause the main
-   loop until they complete.
-
-   Note: These are fairly low-level functions.
-     "emscripten_push_main_loop_blocker()" (and friends) provide more
-     convenient alternatives.
-
-void emscripten_cancel_main_loop(void)
-
-   Cancels the main event loop.
-
-   See also "emscripten_set_main_loop()" and
-   "emscripten_set_main_loop_arg()" for information about setting and
-   using the main loop.
-
-int emscripten_set_main_loop_timing(int mode, int value)
-
-      Specifies the scheduling mode that the current main loop tick
-      function will be called with.
-
-      This function can be used to interactively control the rate at
-      which Emscripten runtime drives the main loop specified by
-      calling the function "emscripten_set_main_loop()". In native
-      development, this corresponds with the "swap interval" or the
-      "presentation interval" for 3D rendering. The new tick interval
-      specified by this function takes effect immediately on the
-      existing main loop, and this function must be called only after
-      setting up a main loop via "emscripten_set_main_loop()".
-
-   Parameters:
-      * **mode** (*int*) --
-
-        The timing mode to use. Allowed values are
-        EM_TIMING_SETTIMEOUT, EM_TIMING_RAF and
-        EM_TIMING_SETIMMEDIATE.
-
-        param int value:
-           The timing value to activate for the main loop. This value
-           interpreted differently according to the "mode" parameter:
-
-           * If "mode" is EM_TIMING_SETTIMEOUT, then "value"
-             specifies the number of milliseconds to wait between
-             subsequent ticks to the main loop and updates occur
-             independent of the vsync rate of the display (vsync off).
-             This method uses the JavaScript "setTimeout" function to
-             drive the animation.
-
-           * If "mode" is EM_TIMING_RAF, then updates are performed
-             using the "requestAnimationFrame" function (with vsync
-             enabled), and this value is interpreted as a "swap
-             interval" rate for the main loop. The value of "1"
-             specifies the runtime that it should render at every
-             vsync (typically 60fps), whereas the value "2" means that
-             the main loop callback should be called only every second
-             vsync (30fps). As a general formula, the value "n" means
-             that the main loop is updated at every n'th vsync, or at
-             a rate of "60/n" for 60Hz displays, and "120/n" for 120Hz
-             displays.
-
-           * If "mode" is EM_TIMING_SETIMMEDIATE, then updates are
-             performed using the "setImmediate" function, or if not
-             available, emulated via "postMessage". See *setImmediate
-             on MDN <https://developer.mozilla.org/en-
-             US/docs/Web/API/Window/setImmediate>* for more
-             information. Note that this mode is **strongly not
-             recommended** to be used when deploying Emscripten output
-             to the web, since it depends on an unstable web extension
-             that is in draft status, browsers other than IE do not
-             currently support it, and its implementation has been
-             considered controversial in review.
-
-        rtype:
-           int
-
-        return:
-           The value 0 is returned on success, and a nonzero value is
-           returned on failure. A failure occurs if there is no main
-           loop active before calling this function.
-
-        Note: Browsers heavily optimize towards using
-          "requestAnimationFrame" for animation instead of the other
-          provided modes. Because of that, for best experience across
-          browsers, calling this function with "mode=EM_TIMING_RAF"
-          and "value=1" will yield best results. Using the JavaScript
-          "setTimeout" function is known to cause stutter and
-          generally worse experience than using the
-          "requestAnimationFrame" function.
-
-        Note: There is a functional difference between "setTimeout"
-          and "requestAnimationFrame": If the user minimizes the
-          browser window or hides your application tab, browsers will
-          typically stop calling "requestAnimationFrame" callbacks,
-          but "setTimeout"-based main loop will continue to be run,
-          although with heavily throttled intervals. See *setTimeout
-          on MDN <https://developer.mozilla.org/en-
-          US/docs/Web/API/WindowTimers.setTimeout#Inactive_tabs>* for
-          more information.
-
-void emscripten_get_main_loop_timing(int *mode, int *value)
-
-      Returns the current main loop timing mode that is in effect. For
-      interpretation of the values, see the documentation of the
-      function "emscripten_set_main_loop_timing()". The timing mode is
-      controlled by calling the functions
-      "emscripten_set_main_loop_timing()" and
-      "emscripten_set_main_loop()".
-
-   Parameters:
-      * **mode** (*int**) -- If not null, the used timing mode is
-        returned here.
-
-      * **value** (*int**) -- If not null, the used timing value is
-        returned here.
-
-void emscripten_set_main_loop_expected_blockers(int num)
-
-   Sets the number of blockers that are about to be pushed.
-
-   The number is used for reporting the *relative progress* through a
-   set of blockers, after which the main loop will continue.
-
-   For example, a game might have to run 10 blockers before starting a
-   new level. The operation would first set this value as '10' and
-   then push the 10 blockers. When the 3^rd blocker (say) completes,
-   progress is displayed as 3/10.
-
-   Parameters:
-      * **num** (*int*) -- The number of blockers that are about to
-        be pushed.
-
-void emscripten_async_call(em_arg_callback_func func, void *arg, int millis)
-
-   Call a C function asynchronously, that is, after returning control
-   to the JavaScript event loop.
-
-   This is done by a "setTimeout".
-
-   When building natively this becomes a simple direct call, after
-   "SDL_Delay" (you must include **SDL.h** for that).
-
-   If "millis" is negative, the browser's "requestAnimationFrame"
-   mechanism is used.
-
-   Parameters:
-      * **func** (*em_arg_callback_func*) -- The C function to call
-        asynchronously. The function signature must have a "void*"
-        parameter for passing the "arg" value.
-
-      * **arg** (*void**) -- User-defined argument to pass to the C
-        function.
-
-      * **millis** (*int*) -- Timeout before function is called.
-
-void emscripten_exit_with_live_runtime(void)
-
-   Exits the program immediately, but leaves the runtime alive so that
-   you can continue to run code later (so global destructors etc., are
-   not run). Note that the runtime is kept alive automatically when
-   you do an asynchronous operation like "emscripten_async_call()", so
-   you don't need to call this function for those cases.
-
-void emscripten_force_exit(int status)
-
-   Shuts down the runtime and exits (terminates) the program, as if
-   you called "exit()".
-
-   The difference is that "emscripten_force_exit" will shut down the
-   runtime even if you previously called
-   "emscripten_exit_with_live_runtime()" or otherwise kept the runtime
-   alive. In other words, this method gives you the option to
-   completely shut down the runtime after it was kept alive beyond the
-   completion of "main()".
-
-   Parameters:
-      * **status** (*int*) -- The same as for the *libc* function
-        exit().
-
-double emscripten_get_device_pixel_ratio(void)
-
-   Returns the value of "window.devicePixelRatio".
-
-   Return type:
-      double
-
-   Returns:
-      The pixel ratio or 1.0 if not supported.
-
-void emscripten_set_canvas_size(int width, int height)
-
-   Resizes the pixel width and height of the "<canvas>" element on the
-   Emscripten web page.
-
-   Parameters:
-      * **width** (*int*) -- New pixel width of canvas element.
-
-      * **height** (*int*) -- New pixel height of canvas element.
-
-void emscripten_get_canvas_size(int * width, int * height, int * isFullscreen)
-
-   Gets the current pixel width and height of the "<canvas>" element
-   as well as whether the canvas is fullscreen or not.
-
-   Parameters:
-      * **width** (*int**) -- Pixel width of canvas element.
-
-      * **height** (*int**) -- New pixel height of canvas element.
-
-      * **isFullscreen** (*int**) -- If True ("*int > 0"),
-        "<canvas>" is full screen.
-
-double emscripten_get_now(void)
-
-   Returns the highest-precision representation of the current time
-   that the browser provides.
-
-   This uses either "Date.now" or "performance.now". The result is not
-   an absolute time, and is only meaningful in comparison to other
-   calls to this function.
-
-   Return type:
-      double
-
-   Returns:
-      The current time, in milliseconds (ms).
-
-float emscripten_random(void)
-
-   Generates a random number in the range 0-1. This maps to
-   "Math.random()".
-
-   Return type:
-      float
-
-   Returns:
-      A random number.
-
-
-Emscripten Asynchronous File System API
-=======================================
-
-
-Typedefs
---------
-
-em_async_wget_onload_func
-
-   Function pointer type for the "onload" callback of
-   "emscripten_async_wget_data()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_wget_onload_func)(void*, void*, int)
-
-em_async_wget2_onload_func
-
-   Function pointer type for the "onload" callback of
-   "emscripten_async_wget2()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_wget2_onload_func)(void*, const char*)
-
-em_async_wget2_onstatus_func
-
-   Function pointer type for the "onerror" and "onprogress" callbacks
-   of "emscripten_async_wget2()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_wget2_onstatus_func)(void*, int)
-
-em_async_wget2_data_onload_func
-
-   Function pointer type for the "onload" callback of
-   "emscripten_async_wget2_data()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_wget2_data_onload_func)(void*, void *, unsigned*)
-
-em_async_wget2_data_onerror_func
-
-   Function pointer type for the "onerror" callback of
-   "emscripten_async_wget2_data()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_wget2_data_onerror_func)(void*, int, const char*)
-
-em_async_wget2_data_onprogress_func
-
-   Function pointer type for the "onprogress" callback of
-   "emscripten_async_wget2_data()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_wget2_data_onprogress_func)(void*, int, int)
-
-em_async_prepare_data_onload_func
-
-   Function pointer type for the "onload" callback of
-   "emscripten_async_prepare_data()" (specific values of the
-   parameters documented in that method).
-
-   Defined as:
-
-      typedef void (*em_async_prepare_data_onload_func)(void*, const char*)
-
-
-Functions
----------
-
-void emscripten_wget(const char* url, const char* file)
-
-   Load file from url in *synchronously*. For the asynchronous
-   version, see the "emscripten_async_wget()".
-
-   In addition to fetching the URL from the network, the contents are
-   prepared so that the data is usable in "IMG_Load" and so forth (we
-   synchronously do the work to make the browser decode the image or
-   audio etc.).
-
-   This function is blocking; it won't return until all operations are
-   finished. You can then open and read the file if it succeeded.
-
-   To use this function, you will need to compile your application
-   with the linker flag "-s ASYNCIFY=1"
-
-   Parameters:
-      * **char* url** (*const*) -- The URL to load.
-
-      * **char* file** (*const*) -- The name of the file created and
-        loaded from the URL. If the file already exists it will be
-        overwritten.
-
-void emscripten_async_wget(const char* url, const char* file, em_str_callback_func onload, em_str_callback_func onerror)
-
-   Loads a file from a URL asynchronously.
-
-   In addition to fetching the URL from the network, the contents are
-   prepared so that the data is usable in "IMG_Load" and so forth (we
-   asynchronously do the work to make the browser decode the image or
-   audio etc.).
-
-   When the file is ready the "onload" callback will be called. If any
-   error occurs "onerror" will be called. The callbacks are called
-   with the file as their argument.
-
-   Parameters:
-      * **char* url** (*const*) -- The URL to load.
-
-      * **char* file** (*const*) -- The name of the file created and
-        loaded from the URL. If the file already exists it will be
-        overwritten.
-
-      * **onload** (*em_str_callback_func*) --
-
-        Callback on successful load of the file. The callback function
-        parameter value is:
-
-        * *(const char*)* : The name of the "file" that was loaded
-          from the URL.
-
-      * **onerror** (*em_str_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter value is:
-
-        * *(const char*)* : The name of the "file" that failed to
-          load from the URL.
-
-void emscripten_async_wget_data(const char* url, void *arg, em_async_wget_onload_func onload, em_arg_callback_func onerror)
-
-   Loads a buffer from a URL asynchronously.
-
-   This is the "data" version of "emscripten_async_wget()".
-
-   Instead of writing to a file, this function writes to a buffer
-   directly in memory. This avoids the overhead of using the emulated
-   file system; note however that since files are not used, it cannot
-   do the 'prepare' stage to set things up for "IMG_Load" and so forth
-   ("IMG_Load" etc. work on files).
-
-   When the file is ready then the "onload" callback will be called.
-   If any error occurred "onerror" will be called.
-
-   Parameters:
-      * **url** (*const char**) -- The URL of the file to load.
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **onload** (*em_async_wget_onload_func*) --
-
-        Callback on successful load of the URL into the buffer. The
-        callback function parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(void*)* : A pointer to a buffer with the data. Note
-          that, as with the worker API, the data buffer only lives
-          during the callback; it must be used or copied during that
-          time.
-
-        * *(int)* : The size of the buffer, in bytes.
-
-      * **onerror** (*em_arg_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-int emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, em_async_wget2_onload_func onload, em_async_wget2_onstatus_func onerror, em_async_wget2_onstatus_func onprogress)
-
-   Loads a file from a URL asynchronously.
-
-   This is an **experimental** "more feature-complete" version of
-   "emscripten_async_wget()".
-
-   In addition to fetching the URL from the network, the contents are
-   prepared so that the data is usable in "IMG_Load" and so forth (we
-   asynchronously do the work to make the browser decode the image,
-   audio, etc.).
-
-   When the file is ready the "onload" callback will be called with
-   the object pointers given in "arg" and "file". During the download
-   the "onprogress" callback is called.
-
-   Parameters:
-      * **url** (*const char**) -- The URL of the file to load.
-
-      * **file** (*const char**) -- The name of the file created and
-        loaded from the URL. If the file already exists it will be
-        overwritten.
-
-      * **requesttype** (*const char**) -- 'GET' or 'POST'.
-
-      * **param** (*const char**) -- Request parameters for POST
-        requests (see "requesttype"). The parameters are specified in
-        the same way as they would be in the URL for an equivalent GET
-        request: e.g. "key=value&key2=value2".
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **onload** (*em_async_wget2_onload_func*) --
-
-        Callback on successful load of the file. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(const char*)* : The "file" passed to the original call.
-
-      * **onerror** (*em_async_wget2_onstatus_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(int)* : The HTTP status code.
-
-      * **onprogress** (*em_async_wget2_onstatus_func*) --
-
-        Callback during load of the file. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(int)* : The progress (percentage completed).
-
-   Returns:
-      A handle to request ("int") that can be used to "abort" the
-      request.
-
-int emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress)
-
-   Loads a buffer from a URL asynchronously.
-
-   This is the "data" version of "emscripten_async_wget2()". It is an
-   **experimental** "more feature complete" version of
-   "emscripten_async_wget_data()".
-
-   Instead of writing to a file, this function writes to a buffer
-   directly in memory. This avoids the overhead of using the emulated
-   file system; note however that since files are not used, it cannot
-   do the 'prepare' stage to set things up for "IMG_Load" and so forth
-   ("IMG_Load" etc. work on files).
-
-   In addition to fetching the URL from the network, the contents are
-   prepared so that the data is usable in "IMG_Load" and so forth (we
-   asynchronously do the work to make the browser decode the image or
-   audio etc.).
-
-   When the file is ready the "onload" callback will be called with
-   the object pointers given in "arg", a pointer to the buffer in
-   memory, and an unsigned integer containing the size of the buffer.
-   During the download the "onprogress" callback is called with
-   progress information. If an error occurs, "onerror" will be called
-   with the HTTP status code and a string containing the status
-   description.
-
-   Parameters:
-      * **url** (*const char**) -- The URL of the file to load.
-
-      * **requesttype** (*const char**) -- 'GET' or 'POST'.
-
-      * **param** (*const char**) -- Request parameters for POST
-        requests (see "requesttype"). The parameters are specified in
-        the same way as they would be in the URL for an equivalent GET
-        request: e.g. "key=value&key2=value2".
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **free** (*int*) -- Tells the runtime whether to free
-        the returned buffer after "onload" is complete. If "false"
-        freeing the buffer is the receiver's responsibility.
-
-      * **onload** (*em_async_wget2_data_onload_func*) --
-
-        Callback on successful load of the file. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(void*)* : A pointer to the buffer in memory.
-
-        * *(unsigned)* : The size of the buffer (in bytes).
-
-      * **onerror** (*em_async_wget2_data_onerror_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(int)* : The HTTP error code.
-
-        * *(const char*)* : A string with the status description.
-
-      * **onprogress** (*em_async_wget2_data_onprogress_func*) --
-
-        Callback called (regularly) during load of the file to update
-        progress. The callback function parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(int)* : The number of bytes loaded.
-
-        * *(int)* : The total size of the data in bytes, or zero if
-          the size is unavailable.
-
-   Returns:
-      A handle to request ("int") that can be used to "abort" the
-      request.
-
-emscripten_async_wget2_abort(int handle)
-
-   Abort an asynchronous request raised using
-   "emscripten_async_wget2()" or "emscripten_async_wget2_data()".
-
-   Parameters:
-      * **handle** (*int*) -- A handle to request to be aborted.
-
-void emscripten_async_prepare_data(char* data, int size, const char *suffix, void *arg, em_async_prepare_data_onload_func onload, em_arg_callback_func onerror)
-
-   Prepares a buffer of data asynchronously. This is a "data" version
-   of "emscripten_async_prepare()", which receives raw data as input
-   instead of a filename (this can prevent the need to write data to a
-   file first).
-
-   When file is loaded then the "onload" callback will be called. If
-   any error occurs "onerror" will be called.
-
-   "onload" also receives a second parameter, which is a 'fake'
-   filename which you can pass into "IMG_Load" (it is not an actual
-   file, but it identifies this image for "IMG_Load" to be able to
-   process it). Note that the user of this API is responsible for
-   "free()" ing the memory allocated for the fake filename.
-
-   Parameters:
-      * **data** (*char**) -- The buffer of data to prepare.
-
-      * **suffix** (*const char**) -- The file suffix, e.g. 'png' or
-        'jpg'.
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **onload** (*em_async_prepare_data_onload_func*) --
-
-        Callback on successful preparation of the file. The callback
-        function parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(const char*)* : A 'fake' filename which you can pass
-          into "IMG_Load". See above for more information.
-
-      * **onerror** (*em_arg_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter value is:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-
-Emscripten Asynchronous IndexedDB API
-=====================================
-
-   IndexedDB is a browser API that lets you store data persistently,
-   that is, you can save data there and load it later when the user
-   re-visits the web page. IDBFS provides one way to use IndexedDB,
-   through the Emscripten filesystem layer. The "emscripten_idb_*"
-   methods listed here provide an alternative API, directly to
-   IndexedDB, thereby avoiding the overhead of the filesystem layer.
-
-void emscripten_idb_async_load(const char *db_name, const char *file_id, void* arg, em_async_wget_onload_func onload, em_arg_callback_func onerror)
-
-   Loads data from local IndexedDB storage asynchronously. This allows
-   use of persistent data, without the overhead of the filesystem
-   layer.
-
-   When the data is ready then the "onload" callback will be called.
-   If any error occurred "onerror" will be called.
-
-   Parameters:
-      * **db_name** -- The IndexedDB database from which to load.
-
-      * **file_id** -- The identifier of the data to load.
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **onload** (*em_async_wget_onload_func*) --
-
-        Callback on successful load of the URL into the buffer. The
-        callback function parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *(void*)* : A pointer to a buffer with the data. Note
-          that, as with the worker API, the data buffer only lives
-          during the callback; it must be used or copied during that
-          time.
-
-        * *(int)* : The size of the buffer, in bytes.
-
-      * **onerror** (*em_arg_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-void emscripten_idb_async_store(const char *db_name, const char *file_id, void* ptr, int num, void* arg, em_arg_callback_func onstore, em_arg_callback_func onerror);
-
-   Stores data to local IndexedDB storage asynchronously. This allows
-   use of persistent data, without the overhead of the filesystem
-   layer.
-
-   When the data has been stored then the "onstore" callback will be
-   called. If any error occurred "onerror" will be called.
-
-   Parameters:
-      * **db_name** -- The IndexedDB database from which to load.
-
-      * **file_id** -- The identifier of the data to load.
-
-      * **ptr** -- A pointer to the data to store.
-
-      * **num** -- How many bytes to store.
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **onload** (*em_arg_callback_func*) --
-
-        Callback on successful load of the URL into the buffer. The
-        callback function parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-      * **onerror** (*em_arg_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-void emscripten_idb_async_delete(const char *db_name, const char *file_id, void* arg, em_arg_callback_func ondelete, em_arg_callback_func onerror)
-
-   Deletes data from local IndexedDB storage asynchronously.
-
-   When the data has been deleted then the "ondelete" callback will be
-   called. If any error occurred "onerror" will be called.
-
-   Parameters:
-      * **db_name** -- The IndexedDB database.
-
-      * **file_id** -- The identifier of the data.
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **ondelete** (*em_arg_callback_func*) --
-
-        Callback on successful delete
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-      * **onerror** (*em_arg_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-void emscripten_idb_async_exists(const char *db_name, const char *file_id, void* arg, em_idb_exists_func oncheck, em_arg_callback_func onerror)
-
-   Checks if data with a certain ID exists in the local IndexedDB
-   storage asynchronously.
-
-   When the data has been checked then the "oncheck" callback will be
-   called. If any error occurred "onerror" will be called.
-
-   Parameters:
-      * **db_name** -- The IndexedDB database.
-
-      * **file_id** -- The identifier of the data.
-
-      * **arg** (*void**) -- User-defined data that is passed to the
-        callbacks, untouched by the API itself. This may be used by a
-        callback to identify the associated call.
-
-      * **oncheck** (*em_idb_exists_func*) --
-
-        Callback on successful check, with arguments
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-        * *int* : Whether the file exists or not.
-
-      * **onerror** (*em_arg_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter values are:
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-int emscripten_async_prepare(const char* file, em_str_callback_func onload, em_str_callback_func onerror)
-
-   Prepares a file asynchronously.
-
-   This does just the preparation part of "emscripten_async_wget()".
-   That is, it works on file data already present and performs any
-   required asynchronous operations (for example, decoding images for
-   use in "IMG_Load", decoding audio for use in "Mix_LoadWAV", etc.).
-
-   Once the operations are complete (the file is prepared), the
-   "onload" callback will be called. If any error occurs "onerror"
-   will be called. The callbacks are called with the file as their
-   argument.
-
-   Parameters:
-      * **file** (*const char**) -- The name of the file to prepare.
-
-      * **onload** (*em_str_callback_func*) --
-
-        Callback on successful preparation of the file. The callback
-        function parameter value is:
-
-        * *(const char*)* : The name of the "file" that was
-          prepared.
-
-      * **onerror** (*em_str_callback_func*) --
-
-        Callback in the event of failure. The callback function
-        parameter value is:
-
-        * *(const char*)* : The name of the "file" for which the
-          prepare failed.
-
-   Returns:
-      0 if successful, -1 if the file does not exist
-
-   Return type:
-      int
-
-
-Compiling
-=========
-
-EMSCRIPTEN_KEEPALIVE
-
-   Forces LLVM to not dead-code-eliminate a function.
-
-   This also exports the function, as if you added it to
-   EXPORTED_FUNCTIONS.
-
-   For example:
-
-      void EMSCRIPTEN_KEEPALIVE my_function() { printf("I am being kept alive\n"); }
-
-
-Worker API
-==========
-
-
-Typedefs
---------
-
-int worker_handle
-
-   A wrapper around web workers that lets you create workers and
-   communicate with them.
-
-   Note that the current API is mainly focused on a main thread that
-   sends jobs to workers and waits for responses, i.e., in an
-   asymmetrical manner, there is no current API to send a message
-   without being asked for it from a worker to the main thread.
-
-em_worker_callback_func
-
-   Function pointer type for the callback from
-   "emscripten_call_worker()" (specific values of the parameters
-   documented in that method).
-
-   Defined as:
-
-      typedef void (*em_worker_callback_func)(char*, int, void*)
-
-
-Functions
----------
-
-worker_handle emscripten_create_worker(const char * url)
-
-   Creates a worker.
-
-   A worker must be compiled separately from the main program, and
-   with the "BUILD_AS_WORKER" flag set to 1.
-
-   Parameters:
-      * **url** (*const char**) -- The URL of the worker script.
-
-   Returns:
-      A handle to the newly created worker.
-
-   Return type:
-      worker_handle
-
-void emscripten_destroy_worker(worker_handle worker)
-
-   Destroys a worker. See "emscripten_create_worker()"
-
-   Parameters:
-      * **worker** (*worker_handle*) -- A handle to the worker to be
-        destroyed.
-
-void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, em_worker_callback_func callback, void *arg)
-
-   Asynchronously calls a worker.
-
-   The worker function will be called with two parameters: a data
-   pointer, and a size. The data block defined by the pointer and size
-   exists only during the callback: **it cannot be relied upon
-   afterwards**. If you need to keep some of that information outside
-   the callback, then it needs to be copied to a safe location.
-
-   The called worker function can return data, by calling
-   "emscripten_worker_respond()". When the worker is called, if a
-   callback was given it will be called with three arguments: a data
-   pointer, a size, and an argument that was provided when calling
-   "emscripten_call_worker()" (to more easily associate callbacks to
-   calls). The data block defined by the data pointer and size behave
-   like the data block in the worker function — it exists only during
-   the callback.
-
-   Parameters:
-      * **worker** (*worker_handle*) -- A handle to the worker to be
-        called.
-
-      * **funcname** (*const char**) -- The name of the function in
-        the worker. The function must be a C function (so no C++ name
-        mangling), and must be exported (EXPORTED_FUNCTIONS).
-
-      * **data** (*char**) -- The address of a block of memory to
-        copy over.
-
-      * **size** (*int*) -- The size of the block of memory.
-
-      * **callback** (*em_worker_callback_func*) --
-
-        Worker callback with the response. This can be "null". The
-        callback function parameter values are:
-
-        * *(char*)* : The "data" pointer provided in
-          "emscripten_call_worker()".
-
-        * *(int)* : The "size" of the block of data.
-
-        * *(void*)* : Equal to "arg" (user defined data).
-
-      * **arg** (*void**) -- An argument (user data) to be passed to
-        the callback
-
-void emscripten_worker_respond(char *data, int size)
-void emscripten_worker_respond_provisionally(char *data, int size)
-
-   Sends a response when in a worker call (that is, when called by the
-   main thread using "emscripten_call_worker()").
-
-   Both functions post a message back to the thread which called the
-   worker. The "emscripten_worker_respond_provisionally()" variant can
-   be invoked multiple times, which will queue up messages to be
-   posted to the worker’s creator. Eventually, the _respond variant
-   must be invoked, which will disallow further messages and free
-   framework resources previously allocated for this worker call.
-
-   Note: Calling the provisional version is optional, but you must
-     call the non-provisional version to avoid leaks.
-
-   Parameters:
-      * **data** (*char**) -- The message to be posted.
-
-      * **size** (*int*) -- The size of the message, in bytes.
-
-int emscripten_get_worker_queue_size(worker_handle worker)
-
-   Checks how many responses are being waited for from a worker.
-
-   This only counts calls to "emscripten_call_worker()" that had a
-   callback (calls with null callbacks are ignored), and where the
-   response has not yet been received. It is a simple way to check on
-   the status of the worker to see how busy it is, and do basic
-   decisions about throttling.
-
-   Parameters:
-      * **worker** (*worker_handle*) -- The handle to the relevant
-        worker.
-
-   Returns:
-      The number of responses waited on from a worker.
-
-   Return type:
-      int
-
-
-Logging utilities
-=================
-
-
-Defines
--------
-
-EM_LOG_CONSOLE
-
-   If specified, logs directly to the browser console/inspector
-   window. If not specified, logs via the application Module.
-
-EM_LOG_WARN
-
-   If specified, prints a warning message.
-
-EM_LOG_ERROR
-
-   If specified, prints an error message. If neither "EM_LOG_WARN" or
-   "EM_LOG_ERROR" is specified, an info message is printed.
-   "EM_LOG_WARN" and "EM_LOG_ERROR" are mutually exclusive.
-
-EM_LOG_C_STACK
-
-   If specified, prints a call stack that contains file names
-   referring to original C sources using source map information.
-
-EM_LOG_JS_STACK
-
-   If specified, prints a call stack that contains file names
-   referring to lines in the built .js/.html file along with the
-   message. The flags "EM_LOG_C_STACK" and "EM_LOG_JS_STACK" can be
-   combined to output both untranslated and translated file and line
-   information.
-
-EM_LOG_DEMANGLE
-
-   If specified, C/C++ function names are de-mangled before printing.
-   Otherwise, the mangled post-compilation JavaScript function names
-   are displayed.
-
-EM_LOG_NO_PATHS
-
-   If specified, the pathnames of the file information in the call
-   stack will be omitted.
-
-EM_LOG_FUNC_PARAMS
-
-   If specified, prints out the actual values of the parameters the
-   functions were invoked with.
-
-
-Functions
----------
-
-int emscripten_get_compiler_setting(const char *name)
-
-   Returns the value of a compiler setting.
-
-   For example, to return the integer representing the value of
-   "PRECISE_F32" during compilation:
-
-      emscripten_get_compiler_setting("PRECISE_F32")
-
-   For values containing anything other than an integer, a string is
-   returned (you will need to cast the "int" return value to a
-   "char*").
-
-   Some useful things this can do is provide the version of Emscripten
-   (“EMSCRIPTEN_VERSION”), the optimization level (“OPT_LEVEL”), debug
-   level (“DEBUG_LEVEL”), etc.
-
-   For this command to work, you must build with the following
-   compiler option (as we do not want to increase the build size with
-   this metadata):
-
-      -s RETAIN_COMPILER_SETTINGS=1
-
-   Parameters:
-      * **name** (*const char**) -- The compiler setting to return.
-
-   Returns:
-      The value of the specified setting. Note that for values other
-      than an integer, a string is returned (cast the "int" return
-      value to a "char*").
-
-   Return type:
-      int
-
-void emscripten_debugger()
-
-   Emits "debugger".
-
-   This is inline in the code, which tells the JavaScript engine to
-   invoke the debugger if it gets there.
-
-void emscripten_log(int flags, ...)
-
-   Prints out a message to the console, optionally with the callstack
-   information.
-
-   Parameters:
-      * **flags** (*int*) -- A binary OR of items from the list of
-        "EM_LOG_xxx" flags that specify printing options.
-
-      * **...** -- A "printf"-style "format, ..." parameter list
-        that is parsed according to the "printf" formatting rules.
-
-int emscripten_get_callstack(int flags, char *out, int maxbytes)
-
-   Programmatically obtains the current callstack.
-
-   To query the amount of bytes needed for a callstack without writing
-   it, pass 0 to "out" and "maxbytes", in which case the function will
-   return the number of bytes (including the terminating zero) that
-   will be needed to hold the full callstack. Note that this might be
-   fully accurate since subsequent calls will carry different line
-   numbers, so it is best to allocate a few bytes extra to be safe.
-
-   Parameters:
-      * **flags** (*int*) -- A binary OR of items from the list of
-        "EM_LOG_xxx" flags that specify printing options. The flags
-        "EM_LOG_CONSOLE", "EM_LOG_WARN" and "EM_LOG_ERROR" do not
-        apply in this function and are ignored.
-
-      * **out** (*char**) -- A pointer to a memory region where the
-        callstack string will be written to. The string outputted by
-        this function will always be null-terminated.
-
-      * **maxbytes** (*int*) -- The maximum number of bytes that
-        this function can write to the memory pointed to by "out". If
-        there is not enough space, the output will be truncated (but
-        always null-terminated).
-
-   Returns:
-      The number of bytes written (not number of characters, so this
-      will also include the terminating zero).
-
-   Return type:
-      int
-
-char *emscripten_get_preloaded_image_data(const char *path, int *w, int *h)
-
-   Gets preloaded image data and the size of the image.
-
-   The function returns pointer to loaded image or NULL — the pointer
-   should be "free()"'d. The width/height of the image are written to
-   the "w" and "h" parameters if the data is valid.
-
-   Parameters:
-      * **path** -- Full path/filename to the file containing the
-        preloaded image.
-
-      * **w** (*int**) -- Width of the image (if data is valid).
-
-      * **h** (*int**) -- Height of the image (if data is valid).
-
-   Type:
-      const char*
-
-   Returns:
-      A pointer to the preloaded image or NULL.
-
-   Return type:
-      char*
-
-char *emscripten_get_preloaded_image_data_from_FILE(FILE *file, int *w, int *h)
-
-   Gets preloaded image data from a C "FILE*".
-
-   Parameters:
-      * **file** (*FILE**) -- The "FILE" containing the preloaded
-        image.
-
-      * **w** (*int**) -- Width of the image (if data is valid).
-
-      * **h** (*int**) -- Height of the image (if data is valid).
-
-   Type:
-      const char*
-
-   Returns:
-      A pointer to the preloaded image or NULL.
-
-   Return type:
-      char*
-
-int emscripten_print_double(double x, char *to, signed max)
-
-   Prints a double as a string, including a null terminator. This is
-   useful because JS engines have good support for printing out a
-   double in a way that takes the least possible size, but preserves
-   all the information in the double, i.e., it can then be parsed back
-   in a perfectly reversible manner (snprintf etc. do not do so,
-   sadly).
-
-   Parameters:
-      * **x** (*double*) -- The double.
-
-      * **to** (*char**) -- A pre-allocated buffer of sufficient
-        size, or NULL if no output is requested (useful to get the
-        necessary size).
-
-      * **max** (*signed*) -- The maximum number of characters to
-        write
-
-   Return type:
-      The number of necessary bytes, not including the null terminator
-      (actually written, if "to" is not NULL).
-
-
-Socket event registration
-=========================
-
-The functions in this section register callback functions for
-receiving socket events. These events are analogous to WebSocket
-events but are emitted *after* the internal Emscripten socket
-processing has occurred. This means, for example, that the message
-callback will be triggered after the data has been added to the
-*recv_queue*, so that an application receiving this callback can
-simply read the data using the file descriptor passed as a parameter
-to the callback. All of the callbacks are passed a file descriptor
-("fd") representing the socket that the notified activity took place
-on. The error callback also takes an "int" representing the socket
-error number ("errno") and a "char*" that represents the error message
-("msg").
-
-Only a single callback function may be registered to handle any given
-event, so calling a given registration function more than once will
-cause the first callback to be replaced. Similarly, passing a "NULL"
-callback function to any "emscripten_set_socket_*_callback" call will
-de-register the callback registered for that event.
-
-The "userData" pointer allows arbitrary data specified during event
-registration to be passed to the callback, this is particularly useful
-for passing "this" pointers around in Object Oriented code.
-
-In addition to being able to register network callbacks from C it is
-also possible for native JavaScript code to directly use the
-underlying mechanism used to implement the callback registration. For
-example, the following code shows simple logging callbacks that are
-registered by default when "SOCKET_DEBUG" is enabled:
-
-   Module['websocket']['on']('error', function(error) {console.log('Socket error ' + error);});
-   Module['websocket']['on']('open', function(fd) {console.log('Socket open fd = ' + fd);});
-   Module['websocket']['on']('listen', function(fd) {console.log('Socket listen fd = ' + fd);});
-   Module['websocket']['on']('connection', function(fd) {console.log('Socket connection fd = ' + fd);});
-   Module['websocket']['on']('message', function(fd) {console.log('Socket message fd = ' + fd);});
-   Module['websocket']['on']('close', function(fd) {console.log('Socket close fd = ' + fd);});
-
-Most of the JavaScript callback functions above get passed the file
-descriptor of the socket that triggered the callback, the on error
-callback however gets passed an *array* that contains the file
-descriptor, the error code and an error message.
-
-Note: The underlying JavaScript implementation doesn't pass
-  "userData". This is mostly of use to C/C++ code and the
-  "emscripten_set_socket_*_callback" calls simply create a closure
-  containing the "userData" and pass that as the callback to the
-  underlying JavaScript event registration mechanism.
-
-
-Callback functions
-------------------
-
-em_socket_callback
-
-   Function pointer for "emscripten_set_socket_open_callback()", and
-   the other socket functions (except
-   "emscripten_set_socket_error_callback()"). This is defined as:
-
-      typedef void (*em_socket_callback)(int fd, void *userData);
-
-   Parameters:
-      * **fd** (*int*) -- The file descriptor of the socket that
-        triggered the callback.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the event registration function.
-
-em_socket_error_callback
-
-   Function pointer for the "emscripten_set_socket_error_callback()",
-   defined as:
-
-      typedef void (*em_socket_error_callback)(int fd, int err, const char* msg, void *userData);
-
-   Parameters:
-      * **fd** (*int*) -- The file descriptor of the socket that
-        triggered the callback.
-
-      * **err** (*int*) -- The code for the error that occurred.
-
-      * **msg** (*int*) -- The message for the error that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the event registration function.
-
-
-Functions
----------
-
-void emscripten_set_socket_error_callback(void *userData, em_socket_error_callback callback)
-
-   Triggered by a "WebSocket" error.
-
-   See Socket event registration for more information.
-
-   Parameters:
-      * **userData** (*void**) -- Arbitrary user data to be passed
-        to the callback.
-
-      * **callback** (*em_socket_error_callback*) -- Pointer to a
-        callback function. The callback returns a file descriptor,
-        error code and message, and the arbitrary "userData" passed to
-        this function.
-
-void emscripten_set_socket_open_callback(void *userData, em_socket_callback callback)
-
-   Triggered when the "WebSocket" has opened.
-
-   See Socket event registration for more information.
-
-   Parameters:
-      * **userData** (*void**) -- Arbitrary user data to be passed
-        to the callback.
-
-      * **callback** (*em_socket_callback*) -- Pointer to a callback
-        function. The callback returns a file descriptor and the
-        arbitrary "userData" passed to this function.
-
-void emscripten_set_socket_listen_callback(void *userData, em_socket_callback callback)
-
-   Triggered when "listen" has been called (synthetic event).
-
-   See Socket event registration for more information.
-
-   Parameters:
-      * **userData** (*void**) -- Arbitrary user data to be passed
-        to the callback.
-
-      * **callback** (*em_socket_callback*) -- Pointer to a callback
-        function. The callback returns a file descriptor and the
-        arbitrary "userData" passed to this function.
-
-void emscripten_set_socket_connection_callback(void *userData, em_socket_callback callback)
-
-   Triggered when the connection has been established.
-
-   See Socket event registration for more information.
-
-   Parameters:
-      * **userData** (*void**) -- Arbitrary user data to be passed
-        to the callback.
-
-      * **callback** (*em_socket_callback*) -- Pointer to a callback
-        function. The callback returns a file descriptor and the
-        arbitrary "userData" passed to this function.
-
-void emscripten_set_socket_message_callback(void *userData, em_socket_callback callback)
-
-   Triggered when data is available to be read from the socket.
-
-   See Socket event registration for more information.
-
-   Parameters:
-      * **userData** (*void**) -- Arbitrary user data to be passed
-        to the callback.
-
-      * **callback** (*em_socket_callback*) -- Pointer to a callback
-        function. The callback returns a file descriptor and the
-        arbitrary "userData" passed to this function.
-
-void emscripten_set_socket_close_callback(void *userData, em_socket_callback callback)
-
-   Triggered when the "WebSocket" has closed.
-
-   See Socket event registration for more information.
-
-   Parameters:
-      * **userData** (*void**) -- Arbitrary user data to be passed
-        to the callback.
-
-      * **callback** (*em_socket_callback*) -- Pointer to a callback
-        function. The callback returns a file descriptor and the
-        arbitrary "userData" passed to this function.
-
-
-Unaligned types
-===============
-
-
-Typedefs
---------
-
-emscripten_align1_short
-emscripten_align2_int
-emscripten_align1_int
-emscripten_align2_float
-emscripten_align1_float
-emscripten_align4_double
-emscripten_align2_double
-emscripten_align1_double
-
-   Unaligned types. These may be used to force LLVM to emit unaligned
-   loads/stores in places in your code where SAFE_HEAP found an
-   unaligned operation.
-
-   For usage examples see tests/core/test_set_align.c.
-
-   Note: It is better to avoid unaligned operations, but if you are
-     reading from a packed stream of bytes or such, these types may be
-     useful!
-
-
-Emterpreter-Async functions
-===========================
-
-Emterpreter-async functions are asynchronous functions that appear
-synchronously in C, the linker flags "-s EMTERPRETIFY -s
-EMTERPRETIFY_ASYNC=1" are required to use these functions. See
-Emterpreter for more details.
-
-
-Sleeping
---------
-
-void emscripten_sleep(unsigned int ms)
-
-   Sleep for *ms* milliseconds. This is a normal "synchronous" sleep,
-   which blocks all other operations while it runs. In other words, if
-   there are other async events waiting to happen, they will not
-   happen during this sleep, which makes sense as conceptually this
-   code is on the stack (that's how it looks in the C source code). If
-   you do want things to happen while sleeping, see
-   "emscripten_sleep_with_yield".
-
-void emscripten_sleep_with_yield(unsigned int ms)
-
-   Sleep for *ms* milliseconds, while allowing other asynchronous
-   operations, e.g. caused by "emscripten_async_call", to run
-   normally, during this sleep. Note that this method **does** still
-   block the main loop, as otherwise it could recurse, if you are
-   calling this method from it. Even so, you should use this method
-   carefully: the order of execution is potentially very confusing
-   this way.
-
-
-Network
--------
-
-void emscripten_wget_data(const char* url, void** pbuffer, int* pnum, int *perror);
-
-   Synchronously fetches data off the network, and stores it to a
-   buffer in memory, which is allocated for you. **You must free the
-   buffer, or it will leak!**
-
-   Parameters:
-      * **url** -- The URL to fetch from
-
-      * **pbuffer** -- An out parameter that will be filled with a
-        pointer to a buffer containing the data that is downloaded.
-        This space has been malloced for you, **and you must free it,
-        or it will leak!**
-
-      * **pnum** -- An out parameter that will be filled with the
-        size of the downloaded data.
-
-      * **perror** -- An out parameter that will be filled with a
-        non- zero value if an error occurred.
-
-
-IndexedDB
----------
-
-void emscripten_idb_load(const char *db_name, const char *file_id, void** pbuffer, int* pnum, int *perror);
-
-   Synchronously fetches data from IndexedDB, and stores it to a
-   buffer in memory, which is allocated for you. **You must free the
-   buffer, or it will leak!**
-
-   Parameters:
-      * **db_name** -- The name of the database to load from
-
-      * **file_id** -- The name of the file to load
-
-      * **pbuffer** -- An out parameter that will be filled with a
-        pointer to a buffer containing the data that is downloaded.
-        This space has been malloced for you, **and you must free it,
-        or it will leak!**
-
-      * **pnum** -- An out parameter that will be filled with the
-        size of the downloaded data.
-
-      * **perror** -- An out parameter that will be filled with a
-        non- zero value if an error occurred.
-
-void emscripten_idb_store(const char *db_name, const char *file_id, void* buffer, int num, int *perror);
-
-   Synchronously stores data to IndexedDB.
-
-   Parameters:
-      * **db_name** -- The name of the database to store to
-
-      * **file_id** -- The name of the file to store
-
-      * **buffer** -- A pointer to the data to store
-
-      * **num** -- How many bytes to store
-
-      * **perror** -- An out parameter that will be filled with a
-        non- zero value if an error occurred.
-
-void emscripten_idb_delete(const char *db_name, const char *file_id, int *perror);
-
-   Synchronously deletes data from IndexedDB.
-
-   Parameters:
-      * **db_name** -- The name of the database to delete from
-
-      * **file_id** -- The name of the file to delete
-
-      * **perror** -- An out parameter that will be filled with a
-        non- zero value if an error occurred.
-
-void emscripten_idb_exists(const char *db_name, const char *file_id, int* pexists, int *perror);
-
-   Synchronously checks if a file exists in IndexedDB.
-
-   Parameters:
-      * **db_name** -- The name of the database to check in
-
-      * **file_id** -- The name of the file to check
-
-      * **pexists** -- An out parameter that will be filled with a
-        non-zero value if the file exists in that database.
-
-      * **perror** -- An out parameter that will be filled with a
-        non- zero value if an error occurred.
-
-
-Asyncify functions
-==================
-
-Asyncify functions are asynchronous functions that appear
-synchronously in C, the linker flag *-s ASYNCIFY=1* is required to use
-these functions. See Asyncify for more details.
-
-
-Typedefs
---------
-
-emscripten_coroutine
-
-   A handle to the structure used by coroutine supporting functions.
-
-
-Functions
----------
diff --git a/site/build/text/docs/api_reference/html5.h.txt b/site/build/text/docs/api_reference/html5.h.txt
deleted file mode 100644
index 4707e163e051d..0000000000000
--- a/site/build/text/docs/api_reference/html5.h.txt
+++ /dev/null
@@ -1,2840 +0,0 @@
-
-html5.h
-*******
-
-The C++ APIs in html5.h define the Emscripten low-level glue bindings
-to interact with HTML5 events from native code.
-
-Tip: The C++ APIs map closely to their equivalent HTML5 JavaScript
-  APIs. The HTML5 specifications listed below provide additional
-  detailed reference "over and above" the information provided in this
-  document.In addition, the Test/Example code can be reviewed to see
-  how the code is used.
-
-The HTML5 specifications for APIs that are mapped by **html5.h**
-include:
-
-   * DOM Level 3 Events: Keyboard, Mouse, Mouse Wheel, Resize,
-     Scroll, Focus.
-
-   * Device Orientation Events for gyro and accelerometer.
-
-   * Screen Orientation Events for portrait/landscape handling.
-
-   * Fullscreen Events for browser canvas fullscreen modes
-     transitioning.
-
-   * Pointer Lock Events for relative-mode mouse motion control.
-
-   * Vibration API for mobile device haptic vibration feedback
-     control.
-
-   * Page Visibility Events for power management control.
-
-   * Touch Events.
-
-   * Gamepad API.
-
-   * Beforeunload event.
-
-   * WebGL context events
-
-
-Table of Contents
-^^^^^^^^^^^^^^^^^
-
-* How to use this API
-
-* General types
-
-* Function result values
-
-* Keys
-
-* Mouse
-
-* Wheel
-
-* UI
-
-* Focus
-
-* Device orientation
-
-* Device motion
-
-* Orientation
-
-* Fullscreen
-
-* Pointerlock
-
-* Visibility
-
-* Touch
-
-* Gamepad
-
-* Battery
-
-* Vibration
-
-* Page unload
-
-* WebGL context
-
-* CSS
-
-
-How to use this API
-===================
-
-Most of these APIs use an event-based architecture; functionality is
-accessed by registering a callback function that will be called when
-the event occurs.
-
-Note: The Gamepad API is currently an exception, as only a polling
-  API is available. For some APIs, both an event-based and a polling-
-  based model are exposed.
-
-
-Registration functions
-----------------------
-
-The typical format of registration functions is as follows (some
-methods may omit various parameters):
-
-      EMSCRIPTEN_RESULT emscripten_set_some_callback(
-              const char *target,     // ID of the target HTML element.
-              void *userData,         // User-defined data to be passed to the callback.
-              EM_BOOL useCapture,     // Whether or not to use capture.
-              em_someevent_callback_func callback     // Callback function.
-      );
-
-The "target" parameter is the ID of the HTML element to which the
-callback registration is to be applied. This field has the following
-special meanings:
-
-   * "0" or "NULL": A default element is chosen automatically based
-     on the event type, which should be reasonable most of the time.
-
-   * "#window": The event listener is applied to the JavaScript
-     "window" object.
-
-   * "#document": The event listener is applied to the JavaScript
-     "document" object.
-
-   * "#screen": The event listener is applied to the JavaScript
-     "window.screen" object.
-
-   * "#canvas": The event listener is applied to the Emscripten
-     default WebGL canvas element.
-
-   * Any other string without a leading hash "#" sign: The event
-     listener is applied to the element on the page with the given ID.
-
-The "userData" parameter is a user-defined value that is passed
-(unchanged) to the registered event callback. This can be used to, for
-example, pass a pointer to a C++ class or similarly to enclose the C
-API in a clean object-oriented manner.
-
-The "useCapture" parameter  maps to "useCapture" in
-EventTarget.addEventListener. It indicates whether or not to initiate
-*capture*: if "true" the callback will be invoked only for the DOM
-capture and target phases; if "false" the callback will be triggered
-during the target and bubbling phases. See DOM Level 3 Events for a
-more detailed explanation.
-
-Most functions return the result using the type "EMSCRIPTEN_RESULT".
-Non-zero and positive values denote success. Negative values signal
-failure. None of the functions fail or abort by throwing a JavaScript
-or C++ exception. If a particular browser does not support the given
-feature, the value "EMSCRIPTEN_RESULT_NOT_SUPPORTED" will be returned
-at the time the callback is registered.
-
-
-Callback functions
-------------------
-
-When the event occurs the callback is invoked with the relevant event
-"type" (for example "EMSCRIPTEN_EVENT_CLICK"), a "struct" containing
-the details of the event that occurred, and the "userData" that was
-originally passed to the registration function. The general format of
-the callback function is:
-
-   typedef EM_BOOL (*em_someevent_callback_func) // Callback function. Return true if event is "consumed".
-           (
-           int eventType, // The type of event.
-           const EmscriptenSomeEvent *someEvent, // Information about the event.
-           void *userData // User data passed from the registration function.
-           );
-
-Callback handlers that return an "EM_BOOL" may specify "true" to
-signal that the handler *consumed* the event (this suppresses the
-default action for that event by calling its ".preventDefault();"
-member). Returning "false" indicates that the event was not consumed —
-the default browser event action is carried out and the event is
-allowed to pass on/bubble up as normal.
-
-Calling a registration function with a "null" pointer for the callback
-causes a de-registration of that callback from the given "target"
-element. All event handlers are also automatically unregistered when
-the C "exit()" function is invoked during the "atexit" handler pass.
-Either use the function "emscripten_set_main_loop()" or set
-"Module.noExitRuntime = true;" to make sure that leaving "main()" will
-not immediately cause an "exit()" and clean up the event handlers.
-
-
-Functions affected by web security
-----------------------------------
-
-Some functions, including "emscripten_request_pointerlock()" and
-"emscripten_request_fullscreen()", are affected by web security.
-
-While the functions can be called anywhere, the actual "requests" can
-only be raised inside the handler for a user-generated event (for
-example a key, mouse or touch press/release).
-
-When porting code, it may be difficult to ensure that the functions
-are called inside appropriate event handlers (so that the requests are
-raised immediately). As a convenience, developers can set
-"deferUntilInEventHandler=true" to automatically defer insecure
-requests until the user next presses a keyboard or mouse button. This
-simplifies porting, but often results in a poorer user experience. For
-example, the user must click once on the canvas to hide the pointer or
-transition to full screen.
-
-Where possible, the functions should only be called inside appropriate
-event handlers. Setting "deferUntilInEventHandler=false" causes the
-functions to abort with an error if the request is refused due to a
-security restriction: this is a useful mechanism for discovering
-instances where the functions are called outside the handler for a
-user-generated event.
-
-
-Test/Example code
------------------
-
-The HTML5 test code demonstrates how to use this API:
-
-   * test_html5.c
-
-   * test_html5_fullscreen.c
-
-   * test_html5_mouse.c
-
-
-General types
-=============
-
-EM_BOOL
-
-   This is the Emscripten type for a "bool".
-
-EM_UTF8
-
-   This is the Emscripten type for a UTF8 string (maps to a "char").
-   This is used for node names, element ids, etc.
-
-
-Function result values
-======================
-
-Most functions in this API return a result of type
-"EMSCRIPTEN_RESULT". None of the functions fail or abort by throwing a
-JavaScript or C++ exception. If a particular browser does not support
-the given feature, the value "EMSCRIPTEN_RESULT_NOT_SUPPORTED" will be
-returned at the time the callback is registered.
-
-EMSCRIPTEN_RESULT
-
-   This type is used to return the result of most functions in this
-   API.  Positive values denote success, while zero and negative
-   values signal failure. Possible values are listed below.
-
-   EMSCRIPTEN_RESULT_SUCCESS
-
-      The operation succeeded.
-
-   EMSCRIPTEN_RESULT_DEFERRED
-
-      The requested operation cannot be completed now for web security
-      reasons, and has been deferred for completion in the next event
-      handler.
-
-   EMSCRIPTEN_RESULT_NOT_SUPPORTED
-
-      The given operation is not supported by this browser or the
-      target element.     This value will be returned at the time the
-      callback is registered if the operation is not supported.
-
-   EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED
-
-      The requested operation could not be completed now for web
-      security reasons. It failed because the user requested the
-      operation not be deferred.
-
-   EMSCRIPTEN_RESULT_INVALID_TARGET
-
-      The operation failed because the specified target element is
-      invalid.
-
-   EMSCRIPTEN_RESULT_UNKNOWN_TARGET
-
-      The operation failed because the specified target element was
-      not found.
-
-   EMSCRIPTEN_RESULT_INVALID_PARAM
-
-      The operation failed because an invalid parameter was passed to
-      the function.
-
-   EMSCRIPTEN_RESULT_FAILED
-
-      Generic failure result message, returned if no specific result
-      is available.
-
-   EMSCRIPTEN_RESULT_NO_DATA
-
-      The operation failed because no data is currently available.
-
-
-Keys
-====
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_KEYPRESS
-EMSCRIPTEN_EVENT_KEYDOWN
-EMSCRIPTEN_EVENT_KEYUP
-
-   Emscripten key events.
-
-DOM_KEY_LOCATION
-
-   The location of the key on the keyboard; one of the values below.
-
-   DOM_KEY_LOCATION_STANDARD
-   DOM_KEY_LOCATION_LEFT
-   DOM_KEY_LOCATION_RIGHT
-   DOM_KEY_LOCATION_NUMPAD
-
-      Locations of the key on the keyboard.
-
-
-Struct
-------
-
-EmscriptenKeyboardEvent
-
-   The event structure passed in keyboard events: "keypress",
-   "keydown" and "keyup".
-
-   Note that since the DOM Level 3 Events spec is very recent at the
-   time of writing (2014-03), uniform support for the different fields
-   in the spec is still in flux. Be sure to check the results in
-   multiple browsers. See the unmerged pull request #2222 for an
-   example of how to interpret the legacy key events.
-
-   EM_UTF8 key
-
-      The printed representation of the pressed key.
-
-      Maximum size 32 "char" (i.e. "EM_UTF8 key[32]").
-
-   EM_UTF8 code
-
-      A string that identifies the physical key being pressed. The
-      value is not affected by the current keyboard layout or modifier
-      state, so a particular key will always return the same value.
-
-      Maximum size 32 "char" (i.e. "EM_UTF8 code[32]").
-
-   unsigned long location
-
-      Indicates the location of the key on the keyboard. One of the
-      "DOM_KEY_LOCATION" values.
-
-   EM_BOOL ctrlKey
-   EM_BOOL shiftKey
-   EM_BOOL altKey
-   EM_BOOL metaKey
-
-      Specifies which modifiers were active during the key event.
-
-   EM_BOOL repeat
-
-      Specifies if this keyboard event represents a repeated press.
-
-   EM_UTF8 locale
-
-      A locale string indicating the configured keyboard locale. This
-      may be an empty string if the browser or device doesn't know the
-      keyboard's locale.
-
-      Maximum size 32 char (i.e. "EM_UTF8 locale[32]").
-
-   EM_UTF8 charValue
-
-      The following fields are values from previous versions of the
-      DOM key events specifications. See the character representation
-      of the key. This is the field "char" from the docs, but renamed
-      to "charValue" to avoid a C reserved word.
-
-      Maximum size 32 "char" (i.e. "EM_UTF8 charValue[32]").
-
-      Warning: This attribute has been dropped from DOM Level 3
-        events.
-
-   unsigned long charCode
-
-      The Unicode reference number of the key; this attribute is used
-      only by the keypress event. For keys whose "char" attribute
-      contains multiple characters, this is the Unicode value of the
-      first character in that attribute.
-
-      Warning: This attribute is deprecated, you should use the
-        field "key" instead, if available.
-
-   unsigned long keyCode
-
-      A system and implementation dependent numerical code identifying
-      the unmodified value of the pressed key.
-
-      Warning: This attribute is deprecated, you should use the
-        field "key" instead, if available.
-
-   unsigned long which
-
-      A system and implementation dependent numeric code identifying
-      the unmodified value of the pressed key; this is usually the
-      same as "keyCode".
-
-      Warning: This attribute is deprecated, you should use the
-        field "key" instead, if available. Note thought that while
-        this field is deprecated, the cross-browser support for
-        "which" may be better than for the other fields, so
-        experimentation is recommended. Read issue
-        https://github.com/kripken/emscripten/issues/2817 for more
-        information.
-
-
-Callback functions
-------------------
-
-em_key_callback_func
-
-   Function pointer for the "keypress callback functions", defined as:
-
-      typedef EM_BOOL (*em_key_callback_func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of "key event".
-
-      * **keyEvent** (*const EmscriptenKeyboardEvent**) --
-        Information about the key event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_keypress_callback(const char *target, void *userData, EM_BOOL useCapture, em_key_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_keydown_callback(const char *target, void *userData, EM_BOOL useCapture, em_key_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_keyup_callback(const char *target, void *userData, EM_BOOL useCapture, em_key_callback_func callback)
-
-   Registers a callback function for receiving browser-generated
-   keyboard input events.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_key_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-   See also:
-      * https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent
-
-      * http://www.javascriptkit.com/jsref/eventkeyboardmouse.shtml
-
-
-Mouse
-=====
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_CLICK
-EMSCRIPTEN_EVENT_MOUSEDOWN
-EMSCRIPTEN_EVENT_MOUSEUP
-EMSCRIPTEN_EVENT_DBLCLICK
-EMSCRIPTEN_EVENT_MOUSEMOVE
-EMSCRIPTEN_EVENT_MOUSEENTER
-EMSCRIPTEN_EVENT_MOUSELEAVE
-
-   Emscripten mouse events.
-
-
-Struct
-------
-
-EmscriptenMouseEvent
-
-   The event structure passed in mouse events: click, mousedown,
-   mouseup, dblclick, mousemove, mouseenter and mouseleave.
-
-   double timestamp;
-
-      A timestamp of when this data was generated by the browser. This
-      is an absolute wallclock time in milliseconds.
-
-   long screenX
-   long screenY
-
-      The coordinates relative to the browser screen coordinate
-      system.
-
-   long clientX
-   long clientY
-
-      The coordinates relative to the viewport associated with the
-      event.
-
-   EM_BOOL ctrlKey
-   EM_BOOL shiftKey
-   EM_BOOL altKey
-   EM_BOOL metaKey
-
-      Specifies which modifiers were active during the mouse event.
-
-   unsigned short button
-
-      Identifies which pointer device button changed state (see
-      MouseEvent.button):
-
-         * 0 : Left button
-
-         * 1 : Middle button (if present)
-
-         * 2 : Right button
-
-   unsigned short buttons
-
-      A bitmask that indicates which combinations of mouse buttons
-      were being held down at the time of the event.
-
-   long movementX
-   long movementY;
-
-      If pointer lock is active, these two extra fields give relative
-      mouse movement since the last event.
-
-   long targetX
-   long targetY
-
-      These fields give the mouse coordinates mapped relative to the
-      coordinate space of the target DOM element receiving the input
-      events (Emscripten-specific extension).
-
-   long canvasX
-   long canvasY
-
-      These fields give the mouse coordinates mapped to the Emscripten
-      canvas client area (Emscripten-specific extension).
-
-   long padding
-
-      Internal, and can be ignored.
-
-      Note: Implementers only: pad this struct to multiple of 8
-        bytes to make "WheelEvent" unambiguously align to 8 bytes.
-
-
-Callback functions
-------------------
-
-em_mouse_callback_func
-
-   Function pointer for the "mouse event callback functions", defined
-   as:
-
-      typedef EM_BOOL (*em_mouse_callback_func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of "mouse event".
-
-      * **mouseEvent** (*const EmscriptenMouseEvent**) --
-        Information about the mouse event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_click_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_mousedown_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_mouseup_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_dblclick_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_mousemove_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_mouseenter_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_mouseleave_callback(const char *target, void *userData, EM_BOOL useCapture, em_mouse_callback_func callback)
-
-   Registers a callback function for receiving browser-generated mouse
-   input events.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_mouse_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_mouse_status(EmscriptenMouseEvent *mouseState)
-
-   Returns the most recently received mouse event state.
-
-   Note that for this function call to succeed,
-   "emscripten_set_xxx_callback" must have first been called with one
-   of the mouse event types and a non-zero callback function pointer
-   to enable the Mouse state capture.
-
-   Parameters:
-      * **mouseState** (*EmscriptenMouseEvent**) -- The most
-        recently received mouse event state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Wheel
-=====
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_WHEEL
-
-   Emscripten wheel event.
-
-DOM_DELTA_PIXEL
-
-   The units of measurement for the delta must be pixels (from spec).
-
-DOM_DELTA_LINE
-
-   The units of measurement for the delta must be individual lines of
-   text (from spec).
-
-DOM_DELTA_PAGE
-
-   The units of measurement for the delta must be pages, either
-   defined as a single screen or as a demarcated page (from spec).
-
-
-Struct
-------
-
-EmscriptenWheelEvent
-
-   The event structure passed in mousewheel events.
-
-   EmscriptenMouseEvent mouse
-
-      Specifies general mouse information related to this event.
-
-   double deltaX
-   double deltaY
-   double deltaZ
-
-      Movement of the wheel on each of the axis. Note that these
-      values may be fractional, so you should avoid simply casting
-      them to integer, or it might result in scroll values of 0. The
-      positive Y scroll direction is when scrolling the page downwards
-      (page CSS pixel +Y direction), which corresponds to scrolling
-      the mouse wheel downwards (away from the screen) on Windows,
-      Linux, and also on OSX when the 'natural scroll' option is
-      disabled.
-
-   unsigned long deltaMode
-
-      One of the "DOM_DELTA_" values that indicates the units of
-      measurement for the delta values.
-
-
-Callback functions
-------------------
-
-em_wheel_callback_func
-
-   Function pointer for the "wheel event callback functions", defined
-   as:
-
-      typedef EM_BOOL (*em_wheel_callback_func)(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of wheel event
-        ("EMSCRIPTEN_EVENT_WHEEL").
-
-      * **wheelEvent** (*const EmscriptenWheelEvent**) --
-        Information about the wheel event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_wheel_callback(const char *target, void *userData, EM_BOOL useCapture, em_wheel_callback_func callback)
-
-   Registers a callback function for receiving browser-generated
-   mousewheel events.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_wheel_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-UI
-==
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_RESIZE
-EMSCRIPTEN_EVENT_SCROLL
-
-   Emscripten UI events.
-
-
-Struct
-------
-
-EmscriptenUiEvent
-
-   The event structure passed in DOM element UIEvent events: resize
-   and scroll.
-
-   long detail
-
-      Specifies additional detail/information about this event.
-
-   int documentBodyClientWidth
-   int documentBodyClientHeight
-
-      The clientWidth/clientHeight of the "document.body" element.
-
-   int windowInnerWidth
-   int windowInnerHeight
-
-      The innerWidth/innerHeight of the browser window.
-
-   int windowOuterWidth
-   int windowOuterHeight;
-
-      The outerWidth/outerHeight of the browser window.
-
-   int scrollTop
-   int scrollLeft
-
-      The page scroll position.
-
-
-Callback functions
-------------------
-
-em_ui_callback_func
-
-   Function pointer for the "UI event callback functions", defined as:
-
-      typedef EM_BOOL (*em_ui_callback_func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of UI event
-        ("EMSCRIPTEN_EVENT_RESIZE").
-
-      * **uiEvent** (*const EmscriptenUiEvent**) -- Information
-        about the UI event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, EM_BOOL useCapture, em_ui_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, EM_BOOL useCapture, em_ui_callback_func callback)
-
-   Registers a callback function for receiving DOM element resize and
-   scroll events.
-
-   Note: * For the "resize" callback, pass in target = 0 to get
-     "resize"
-
-       events from the "Window" object.
-
-     * The DOM3 Events specification only requires that the "Window"
-       object sends resize events. It is valid to register a "resize"
-       callback on other DOM elements, but the browser is not required
-       to fire "resize" events for these.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_ui_callback_func*) -- A callback function.
-        The function is called with the type of event, information
-        about the event, and user data passed from this registration
-        function. The callback should return "true" if the event is
-        consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Focus
-=====
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_BLUR
-EMSCRIPTEN_EVENT_FOCUS
-EMSCRIPTEN_EVENT_FOCUSIN
-EMSCRIPTEN_EVENT_FOCUSOUT
-
-   Emscripten focus events.
-
-
-Struct
-------
-
-EmscriptenFocusEvent
-
-   The event structure passed in DOM element blur, focus, focusin and
-   focusout events.
-
-   EM_UTF8 nodeName
-
-      The nodeName of the target HTML Element.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 nodeName[128]").
-
-   EM_UTF8 id
-
-      The ID of the target element.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 id[128]").
-
-
-Callback functions
-------------------
-
-em_focus_callback_func
-
-   Function pointer for the "focus event callback functions", defined
-   as:
-
-      typedef EM_BOOL (*em_focus_callback_func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of focus event
-        ("EMSCRIPTEN_EVENT_BLUR").
-
-      * **focusEvent** (*const EmscriptenFocusEvent**) --
-        Information about the focus event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_blur_callback(const char *target, void *userData, EM_BOOL useCapture, em_focus_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_focus_callback(const char *target, void *userData, EM_BOOL useCapture, em_focus_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_focusin_callback(const char *target, void *userData, EM_BOOL useCapture, em_focus_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_focusout_callback(const char *target, void *userData, EM_BOOL useCapture, em_focus_callback_func callback)
-
-   Registers a callback function for receiving DOM element blur,
-   focus, focusin and focusout events.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_focus_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Device orientation
-==================
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_DEVICEORIENTATION
-
-   Emscripten "deviceorientation" events.
-
-
-Struct
-------
-
-EmscriptenDeviceOrientationEvent
-
-   The event structure passed in the deviceorientation event.
-
-   double timestamp
-
-      Absolute wallclock time when the event occurred (in
-      milliseconds).
-
-   double alpha
-   double beta
-   double gamma
-
-      The orientation of the device in terms of the transformation
-      from a coordinate frame fixed on the Earth to a coordinate frame
-      fixed in the device.
-
-      The image (source: dev.opera.com) and definitions below
-      illustrate the co-ordinate frame:
-
-         * "alpha": the rotation of the device around the Z axis.
-
-         * "beta": the rotation of the device around the X axis.
-
-         * "gamma": the rotation of the device around the Y axis.
-
-      [image: Image of device showing X, Y, Z axes][image]
-
-   EM_BOOL absolute
-
-      If "false", the orientation is only relative to some other base
-      orientation, not to the fixed coordinate frame.
-
-
-Callback functions
-------------------
-
-em_deviceorientation_callback_func
-
-   Function pointer for the "orientation event callback functions",
-   defined as:
-
-      typedef EM_BOOL (*em_deviceorientation_callback_func)(int eventType, const EmscriptenDeviceOrientationEvent *deviceOrientationEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of orientation event
-        ("EMSCRIPTEN_EVENT_DEVICEORIENTATION").
-
-      * **deviceOrientationEvent** (*const
-        EmscriptenDeviceOrientationEvent**) -- Information about the
-        orientation event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_deviceorientation_callback(void *userData, EM_BOOL useCapture, em_deviceorientation_callback_func callback)
-
-   Registers a callback function for receiving the deviceorientation
-   event.
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_deviceorientation_callback_func*) -- A
-        callback function. The function is called with the type of
-        event, information about the event, and user data passed from
-        this registration function. The callback should return "true"
-        if the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_deviceorientation_status(EmscriptenDeviceOrientationEvent *orientationState)
-
-   Returns the most recently received "deviceorientation" event state.
-
-   Note that for this function call to succeed,
-   "emscripten_set_deviceorientation_callback()" must have first been
-   called with one of the mouse event types and a non-zero callback
-   function pointer to enable the "deviceorientation" state capture.
-
-   Parameters:
-      * **orientationState** (*EmscriptenDeviceOrientationEvent**)
-        -- The most recently received "deviceorientation" event state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Device motion
-=============
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_DEVICEMOTION
-
-   Emscripten devicemotion event.
-
-
-Struct
-------
-
-EmscriptenDeviceMotionEvent
-
-   The event structure passed in the devicemotion event.
-
-   double timestamp
-
-      Absolute wallclock time when the event occurred (milliseconds).
-
-   double accelerationX
-   double accelerationY
-   double accelerationZ
-
-      Acceleration of the device excluding gravity.
-
-   double accelerationIncludingGravityX
-   double accelerationIncludingGravityY
-   double accelerationIncludingGravityZ
-
-      Acceleration of the device including gravity.
-
-   double rotationRateAlpha
-   double rotationRateBeta
-   double rotationRateGamma
-
-      The rotational delta of the device.
-
-
-Callback functions
-------------------
-
-em_devicemotion_callback_func
-
-   Function pointer for the "devicemotion event callback functions",
-   defined as:
-
-      typedef EM_BOOL (*em_devicemotion_callback_func)(int eventType, const EmscriptenDeviceMotionEvent *deviceMotionEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of devicemotion event
-        ("EMSCRIPTEN_EVENT_DEVICEMOTION").
-
-      * **deviceMotionEvent** (*const EmscriptenDeviceMotionEvent**)
-        -- Information about the devicemotion event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_devicemotion_callback(void *userData, EM_BOOL useCapture, em_devicemotion_callback_func callback)
-
-   Registers a callback function for receiving the devicemotion event.
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_devicemotion_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_devicemotion_status(EmscriptenDeviceMotionEvent *motionState)
-
-   Returns the most recently received devicemotion event state.
-
-   Note that for this function call to succeed,
-   "emscripten_set_devicemotion_callback()" must have first been
-   called with one of the mouse event types and a non-zero callback
-   function pointer to enable the "devicemotion" state capture.
-
-   Parameters:
-      * **motionState** (*EmscriptenDeviceMotionEvent**) -- The most
-        recently received "devicemotion" event state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Orientation
-===========
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_ORIENTATIONCHANGE
-
-   Emscripten orientationchange event.
-
-EMSCRIPTEN_ORIENTATION_PORTRAIT_PRIMARY
-
-   Primary portrait mode orientation.
-
-EMSCRIPTEN_ORIENTATION_PORTRAIT_SECONDARY
-
-   Secondary portrait mode orientation.
-
-EMSCRIPTEN_ORIENTATION_LANDSCAPE_PRIMARY
-
-   Primary landscape mode orientation.
-
-EMSCRIPTEN_ORIENTATION_LANDSCAPE_SECONDARY
-
-   Secondary landscape mode orientation.
-
-
-Struct
-------
-
-EmscriptenOrientationChangeEvent
-
-   The event structure passed in the orientationchange event.
-
-   int orientationIndex
-
-      One of the "EM_ORIENTATION_PORTRAIT_xxx" fields, or -1 if
-      unknown.
-
-   int orientationAngle
-
-      Emscripten-specific extension: Some browsers refer to
-      "window.orientation", so report that as well.
-
-      Orientation angle in degrees. 0: "default orientation", i.e.
-      default upright orientation to hold the mobile device in. Could
-      be either landscape or portrait.
-
-
-Callback functions
-------------------
-
-em_orientationchange_callback_func
-
-   Function pointer for the "orientationchange event callback
-   functions", defined as:
-
-      typedef EM_BOOL (*em_orientationchange_callback_func)(int eventType, const EmscriptenOrientationChangeEvent *orientationChangeEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of orientationchange event
-        ("EMSCRIPTEN_EVENT_ORIENTATIONCHANGE").
-
-      * **orientationChangeEvent** (*const
-        EmscriptenOrientationChangeEvent**) -- Information about the
-        orientationchange event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_orientationchange_callback(void *userData, EM_BOOL useCapture, em_orientationchange_callback_func callback)
-
-   Registers a callback function for receiving the orientationchange
-   event.
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_orientationchange_callback_func*) -- A
-        callback function. The function is called with the type of
-        event, information about the event, and user data passed from
-        this registration function. The callback should return "true"
-        if the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_orientation_status(EmscriptenOrientationChangeEvent *orientationStatus)
-
-   Returns the current device orientation state.
-
-   Parameters:
-      * **orientationStatus** (*EmscriptenOrientationChangeEvent**)
-        -- The most recently received orientation state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_lock_orientation(int allowedOrientations)
-
-   Locks the screen orientation to the given set of "allowed
-   orientations".
-
-   Parameters:
-      * **allowedOrientations** (*int*) -- A bitfield set of
-        "EMSCRIPTEN_ORIENTATION_xxx" flags.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_unlock_orientation(void)
-
-   Removes the orientation lock so the screen can turn to any
-   orientation.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Fullscreen
-==========
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_FULLSCREENCHANGE
-
-   Emscripten fullscreenchange event.
-
-EMSCRIPTEN_FULLSCREEN_SCALE
-
-   An enum-like type which specifies how the Emscripten runtime should
-   treat the CSS size of the target element when displaying it in
-   fullscreen mode via calls to functions
-   "emscripten_request_fullscreen_strategy()" and
-   "emscripten_enter_soft_fullscreen()".
-
-EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT
-
-   Specifies that the DOM element should not be resized by Emscripten
-   runtime when transitioning between fullscreen and windowed modes.
-   The browser will be responsible for scaling the DOM element to the
-   fullscreen size. The proper browser behavior in this mode is to
-   stretch the element to fit the full display ignoring aspect ratio,
-   but at the time of writing, browsers implement different behavior
-   here. See the discussion at
-   https://github.com/kripken/emscripten/issues/2556 for more
-   information.
-
-EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH
-
-   Specifies that the Emscripten runtime should explicitly stretch the
-   CSS size of the target element to cover the whole screen when
-   transitioning to fullscreen mode. This will change the aspect ratio
-   of the displayed content.
-
-EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT
-
-   Specifies that the Emscripten runtime should explicitly scale the
-   CSS size of the target element to cover the whole screen, while
-   adding either vertical or horizontal black letterbox padding to
-   preserve the aspect ratio of the content. The aspect ratio that is
-   used here is the render target size of the canvas element. To
-   change the desired aspect ratio, call
-   "emscripten_set_canvas_size()" before entering fullscreen mode.
-
-EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE
-
-   An enum-like type which specifies how the Emscripten runtime should
-   treat the pixel size (render target resolution) of the target
-   canvas element when displaying it in fullscreen mode via calls to
-   functions "emscripten_request_fullscreen_strategy()" and
-   "emscripten_enter_soft_fullscreen()". To better understand the
-   underlying distinction between the CSS size of a canvas element
-   versus the render target size of a canvas element, see
-   https://www.khronos.org/webgl/wiki/HandlingHighDPI.
-
-EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE
-
-   Specifies that the Emscripten runtime should not do any changes to
-   the render target resolution of the target canvas element that is
-   displayed in fullscreen mode. Use this mode when your application
-   is set up to render to a single fixed resolution that cannot be
-   changed under any condition.
-
-EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF
-
-   Specifies that the Emscripten runtime should resize the render
-   target of the canvas element to match 1:1 with the CSS size of the
-   element in fullscreen mode. On high DPI displays
-   (*window.devicePixelRatio* > 1), the CSS size is not the same as
-   the physical screen resolution of the device. Call
-   "emscripten_get_device_pixel_ratio()" to obtain the pixel ratio
-   between CSS pixels and actual device pixels of the screen. Use this
-   mode when you want to render to a pixel resolution that is DPI-
-   independent.
-
-EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF
-
-   Specifies that the Emscripten runtime should resize the canvas
-   render target size to match 1:1 with the physical screen resolution
-   on the device. This corresponds to high definition displays on
-   retina iOS and other mobile and desktop devices with high DPI. Use
-   this mode to match and render 1:1 to the native display resolution.
-
-EMSCRIPTEN_FULLSCREEN_FILTERING
-
-   An enum-like type that specifies what kind of image filtering
-   algorithm to apply to the element when it is presented in
-   fullscreen mode.
-
-EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT
-
-   Specifies that the image filtering mode should not be changed from
-   the existing setting in the CSS style.
-
-EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST
-
-   Applies a CSS style to the element that displays the content using
-   a nearest-neighbor image filtering algorithm in fullscreen mode.
-
-EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR
-
-   Applies a CSS style to the element that displays the content using
-   a bilinear image filtering algorithm in fullscreen mode. This is
-   the default browser behavior.
-
-
-Struct
-------
-
-EmscriptenFullscreenChangeEvent
-
-   The event structure passed in the fullscreenchange event.
-
-   EM_BOOL isFullscreen
-
-      Specifies whether an element on the browser page is currently
-      fullscreen.
-
-   EM_BOOL fullscreenEnabled
-
-      Specifies if the current page has the ability to display
-      elements fullscreen.
-
-   EM_UTF8 nodeName
-
-      The nodeName of the target HTML Element that is in full screen
-      mode.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 nodeName[128]").
-
-      If "isFullscreen" is "false", then "nodeName", "id" and
-      "elementWidth" and "ElementHeight" specify information about the
-      element that just exited fullscreen mode.
-
-   EM_UTF8 id
-
-      The ID of the target HTML element that is in full screen mode.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 id[128]").
-
-   int elementWidth
-   int elementHeight
-
-      The new pixel size of the element that changed fullscreen
-      status.
-
-   int screenWidth
-   int screenHeight
-
-      The size of the whole screen, in pixels.
-
-EmscriptenFullscreenStrategy
-
-   The options structure that is passed in to functions
-   "emscripten_request_fullscreen_strategy()" and
-   "emscripten_enter_soft_fullscreen()" to configure how the target
-   element should be displayed in fullscreen mode.
-
-   EMSCRIPTEN_FULLSCREEN_SCALE scaleMode
-
-      Specifies the rule how the CSS size (the displayed size) of the
-      target element is resized when displayed in fullscreen mode.
-
-   EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE canvasResolutionScaleMode
-
-      Specifies how the render target size (the pixel resolution) of
-      the target element is adjusted when displayed in fullscreen
-      mode.
-
-   EMSCRIPTEN_FULLSCREEN_FILTERING filteringMode
-
-      Specifies the image filtering algorithm to apply to the element
-      in fullscreen mode.
-
-   em_canvasresized_callback_func canvasResizedCallback
-
-      If nonzero, points to a user-provided callback function which
-      will be called whenever either the CSS or the canvas render
-      target size changes. Use this callback to reliably obtain
-      information about canvas resize events.
-
-   void *canvasResizedCallbackUserData
-
-      Stores a custom data field which will be passed to all calls to
-      the user-provided callback function.
-
-
-Callback functions
-------------------
-
-em_fullscreenchange_callback_func
-
-   Function pointer for the "fullscreen event callback functions",
-   defined as:
-
-      typedef EM_BOOL (*em_fullscreenchange_callback_func)(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of fullscreen event
-        ("EMSCRIPTEN_EVENT_FULLSCREENCHANGE").
-
-      * **fullscreenChangeEvent** (*const
-        EmscriptenFullscreenChangeEvent**) -- Information about the
-        fullscreen event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_fullscreenchange_callback(const char *target, void *userData, EM_BOOL useCapture, em_fullscreenchange_callback_func callback)
-
-   Registers a callback function for receiving the fullscreenchange
-   event.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_fullscreenchange_callback_func*) -- A
-        callback function. The function is called with the type of
-        event, information about the event, and user data passed from
-        this registration function. The callback should return "true"
-        if the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_fullscreen_status(EmscriptenFullscreenChangeEvent *fullscreenStatus)
-
-   Returns the current page fullscreen state.
-
-   Parameters:
-      * **fullscreenStatus** (*EmscriptenFullscreenChangeEvent**) --
-        The most recently received fullscreen state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_request_fullscreen(const char *target, EM_BOOL deferUntilInEventHandler)
-
-   Requests the given target element to transition to full screen
-   mode.
-
-   Note: This function can be called anywhere, but for web security
-     reasons its associated *request* can only be raised inside the
-     event handler for a user-generated event (for example a key,
-     mouse or touch press/release). This has implications for porting
-     and the value of "deferUntilInEventHandler"  — see Functions
-     affected by web security for more information.
-
-   Note: This function only performs a fullscreen request without
-     changing any parameters of the DOM element that is to be
-     displayed in fullscreen mode. At the time of writing, there are
-     differences in how browsers present elements in fullscreen mode.
-     For more information, read the discussion at
-     https://github.com/kripken/emscripten/issues/2556. To display an
-     element in fullscreen mode in a way that is consistent across
-     browsers, prefer calling the function
-     "emscripten_request_fullscreen_strategy()" instead. This function
-     is best called only in scenarios where the preconfigured presets
-     defined by "emscripten_request_fullscreen_strategy()" conflict
-     with the developer's use case in some way.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **deferUntilInEventHandler** (*EM_BOOL*) -- If "true"
-        requests made outside of a user-generated event handler are
-        automatically deferred until the user next presses a keyboard
-        or mouse button. If "false" the request will fail if called
-        outside of a user-generated event handler.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      **EMSCRIPTEN_RESULT**
-
-EMSCRIPTEN_RESULT emscripten_request_fullscreen_strategy(const char *target, EM_BOOL deferUntilInEventHandler, const EmscriptenFullscreenStrategy *fullscreenStrategy)
-
-   Requests the given target element to transition to full screen
-   mode, using a custom presentation mode for the element. This
-   function is otherwise the same as
-   "emscripten_request_fullscreen()", but this function adds options
-   to control how resizing and aspect ratio, and ensures that the
-   behavior is consistent across browsers.
-
-   Note: This function makes changes to the DOM to satisfy
-     consistent presentation across browsers. These changes have been
-     designed to intrude as little as possible, and the changes are
-     cleared once windowed browsing is restored. If any of these
-     changes are conflicting, see the function
-     "emscripten_request_fullscreen()" instead, which performs a bare
-     fullscreen request without any modifications to the DOM.
-
-   Parameters:
-      * **fullscreenStrategy** (*const
-        EmscriptenFullscreenStrategy**) -- [in] Points to a
-        configuration structure filled by the caller which specifies
-        display options for the fullscreen mode.
-
-EMSCRIPTEN_RESULT emscripten_exit_fullscreen(void)
-
-   Returns back to windowed browsing mode from a proper fullscreen
-   mode.
-
-   Do not call this function to attempt to return to windowed browsing
-   mode from a soft fullscreen mode, or vice versa.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_enter_soft_fullscreen(const char *target, const EmscriptenFullscreenStrategy *fullscreenStrategy)
-
-   Enters a "soft" fullscreen mode, where the given target element is
-   displayed in the whole client area of the page and all other
-   elements are hidden, but does not actually request fullscreen mode
-   for the browser. This function is useful in cases where the actual
-   Fullscreen API is not desirable or needed, for example in packaged
-   apps for Firefox OS, where applications essentially already cover
-   the whole screen.
-
-   Pressing the esc button does not automatically exit the soft
-   fullscreen mode. To return to windowed presentation mode, manually
-   call the function "emscripten_exit_soft_fullscreen()".
-
-EMSCRIPTEN_RESULT emscripten_exit_soft_fullscreen()
-
-   Returns back to windowed browsing mode from a soft fullscreen mode.
-   Do not call this function to attempt to return to windowed browsing
-   mode from a real fullscreen mode, or vice versa.
-
-
-Pointerlock
-===========
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_POINTERLOCKCHANGE
-
-   Emscripten pointerlockchange events.
-
-
-Struct
-------
-
-EmscriptenPointerlockChangeEvent
-
-   The event structure passed in the pointerlockchange event.
-
-   EM_BOOL isActive
-
-      Specifies whether an element on the browser page currently has
-      pointer lock enabled.
-
-   EM_UTF8 nodeName
-
-      The nodeName of the target HTML Element that has the pointer
-      lock active.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 nodeName[128]").
-
-   EM_UTF8 id
-
-      The ID of the target HTML element that has the pointer lock
-      active.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 id[128]").
-
-
-Callback functions
-------------------
-
-em_pointerlockchange_callback_func
-
-   Function pointer for the "pointerlockchange event callback
-   functions", defined as:
-
-      typedef EM_BOOL (*em_pointerlockchange_callback_func)(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of pointerlockchange event
-        ("EMSCRIPTEN_EVENT_POINTERLOCKCHANGE").
-
-      * **pointerlockChangeEvent** (*const
-        EmscriptenPointerlockChangeEvent**) -- Information about the
-        pointerlockchange event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(const char *target, void *userData, EM_BOOL useCapture, em_pointerlockchange_callback_func callback)
-
-   Registers a callback function for receiving the pointerlockchange
-   event.
-
-   Pointer lock hides the mouse cursor and exclusively gives the
-   target element relative mouse movement events via the mousemove
-   event.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_pointerlockchange_callback_func*) -- A
-        callback function. The function is called with the type of
-        event, information about the event, and user data passed from
-        this registration function. The callback should return "true"
-        if the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(EmscriptenPointerlockChangeEvent *pointerlockStatus)
-
-   Returns the current page pointerlock state.
-
-   Parameters:
-      * **pointerlockStatus** (*EmscriptenPointerlockChangeEvent**)
-        -- The most recently received pointerlock state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_request_pointerlock(const char *target, EM_BOOL deferUntilInEventHandler)
-
-   Requests the given target element to grab pointerlock.
-
-   Note: This function can be called anywhere, but for web security
-     reasons its associated *request* can only be raised inside the
-     event handler for a user-generated event (for example a key,
-     mouse or touch press/release). This has implications for porting
-     and the value of "deferUntilInEventHandler"  — see Functions
-     affected by web security for more information.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **deferUntilInEventHandler** (*EM_BOOL*) -- If "true"
-        requests made outside of a user-generated event handler are
-        automatically deferred until the user next presses a keyboard
-        or mouse button. If "false" the request will fail if called
-        outside of a user-generated event handler.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_exit_pointerlock(void)
-
-   Exits pointer lock state and restores the mouse cursor to be
-   visible again.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Visibility
-==========
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_VISIBILITYCHANGE
-
-   Emscripten visibilitychange event.
-
-EMSCRIPTEN_VISIBILITY_HIDDEN
-
-   The document is hidden (not visible).
-
-EMSCRIPTEN_VISIBILITY_VISIBLE
-
-   The document is at least partially visible.
-
-EMSCRIPTEN_VISIBILITY_PRERENDER
-
-   The document is loaded off screen and not visible (prerender).
-
-EMSCRIPTEN_VISIBILITY_UNLOADED
-
-   The document is to be unloaded.
-
-
-Struct
-------
-
-EmscriptenVisibilityChangeEvent
-
-   The event structure passed in the visibilitychange event.
-
-   EM_BOOL hidden
-
-      If true, the current browser page is now hidden.
-
-   int visibilityState
-
-      Specifies a more fine-grained state of the current page
-      visibility status. One of the "EMSCRIPTEN_VISIBILITY_" values.
-
-
-Callback functions
-------------------
-
-em_visibilitychange_callback_func
-
-   Function pointer for the "visibilitychange event callback
-   functions", defined as:
-
-      typedef EM_BOOL (*em_visibilitychange_callback_func)(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of "visibilitychange"
-        event ("EMSCRIPTEN_VISIBILITY_HIDDEN").
-
-      * **visibilityChangeEvent** (*const
-        EmscriptenVisibilityChangeEvent**) -- Information about the
-        "visibilitychange" event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, EM_BOOL useCapture, em_visibilitychange_callback_func callback)
-
-   Registers a callback function for receiving the visibilitychange
-   event.
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_visibilitychange_callback_func*) -- A
-        callback function. The function is called with the type of
-        event, information about the event, and user data passed from
-        this registration function. The callback should return "true"
-        if the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_visibility_status(EmscriptenVisibilityChangeEvent *visibilityStatus)
-
-   Returns the current page visibility state.
-
-   Parameters:
-      * **visibilityStatus** (*EmscriptenVisibilityChangeEvent**) --
-        The most recently received page visibility state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Touch
-=====
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_TOUCHSTART
-EMSCRIPTEN_EVENT_TOUCHEND
-EMSCRIPTEN_EVENT_TOUCHMOVE
-EMSCRIPTEN_EVENT_TOUCHCANCEL
-
-   Emscripten touch events.
-
-
-Struct
-------
-
-EmscriptenTouchPoint
-
-   Specifies the status of a single touch point on the page.
-
-   long identifier
-
-      An identification number for each touch point.
-
-   long screenX
-   long screenY
-
-      The touch coordinate relative to the whole screen origin, in
-      pixels.
-
-   long clientX
-   long clientY
-
-      The touch coordinate relative to the viewport, in pixels.
-
-   long pageX
-   long pageY
-
-      The touch coordinate relative to the viewport, in pixels, and
-      including any scroll offset.
-
-   EM_BOOL isChanged
-
-      Specifies whether the touch point changed during this event.
-
-   EM_BOOL onTarget
-
-      Specifies whether this touch point is still above the original
-      target on which it was initially pressed.
-
-   long targetX
-   long targetY
-
-      These fields give the touch coordinates mapped relative to the
-      coordinate space of the target DOM element receiving the input
-      events (Emscripten-specific extension).
-
-   long canvasX
-   long canvasY
-
-      The touch coordinates mapped to the Emscripten canvas client
-      area, in pixels (Emscripten-specific extension).
-
-EmscriptenTouchEvent
-
-   Specifies the data of a single touchevent.
-
-   int numTouches
-
-      The number of valid elements in the touches array.
-
-   EM_BOOL ctrlKey
-   EM_BOOL shiftKey
-   EM_BOOL altKey
-   EM_BOOL metaKey
-
-      Specifies which modifiers were active during the touch event.
-
-   EmscriptenTouchPoint touches[32]
-
-      An array of currently active touches, one for each finger.
-
-
-Callback functions
-------------------
-
-em_touch_callback_func
-
-   Function pointer for the "touch event callback functions", defined
-   as:
-
-      typedef EM_BOOL (*em_touch_callback_func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of touch event
-        ("EMSCRIPTEN_EVENT_TOUCHSTART").
-
-      * **touchEvent** (*const EmscriptenTouchEvent**) --
-        Information about the touch event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_touchstart_callback(const char *target, void *userData, EM_BOOL useCapture, em_touch_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_touchend_callback(const char *target, void *userData, EM_BOOL useCapture, em_touch_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_touchmove_callback(const char *target, void *userData, EM_BOOL useCapture, em_touch_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_touchcancel_callback(const char *target, void *userData, EM_BOOL useCapture, em_touch_callback_func callback)
-
-   Registers a callback function for receiving touch events :
-   touchstart, touchend, touchmove and touchcancel.
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_touch_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Gamepad
-=======
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_GAMEPADCONNECTED
-EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED
-
-   Emscripten gamepad events.
-
-
-Struct
-------
-
-EmscriptenGamepadEvent
-
-   Represents the current snapshot state of a gamepad.
-
-   double timestamp
-
-      Absolute wallclock time when the data was recorded
-      (milliseconds).
-
-   int numAxes
-
-      The number of valid axis entries in the "axis" array.
-
-   int numButtons
-
-      The number of valid button entries in the analogButton and
-      digitalButton arrays.
-
-   double axis[64]
-
-      The analog state of the gamepad axes, in the range [-1, 1].
-
-   double analogButton[64]
-
-      The analog state of the gamepad buttons, in the range [0, 1].
-
-   EM_BOOL digitalButton[64]
-
-      The digital state of the gamepad buttons, either 0 or 1.
-
-   EM_BOOL connected
-
-      Specifies whether this gamepad is connected to the browser page.
-
-   long index
-
-      An ordinal associated with this gamepad, zero-based.
-
-   EM_UTF8 id
-
-      An ID for the brand or style of the connected gamepad device.
-      Typically, this will include the USB vendor and a product ID.
-
-      Maximum size 64 "char" (i.e. "EM_UTF8 id[128]").
-
-   EM_UTF8 mapping
-
-      A string that identifies the layout or control mapping of this
-      device.
-
-      Maximum size 128 "char" (i.e. "EM_UTF8 mapping[128]").
-
-
-Callback functions
-------------------
-
-em_gamepad_callback_func
-
-   Function pointer for the "gamepad event callback functions",
-   defined as:
-
-      typedef EM_BOOL (*em_gamepad_callback_func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
-
-   Parameters:
-      * **eventType** (*int*) -- The type of gamepad event
-        ("EMSCRIPTEN_EVENT_GAMEPADCONNECTED").
-
-      * **gamepadEvent** (*const EmscriptenGamepadEvent**) --
-        Information about the gamepad event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_gamepadconnected_callback(void *userData, EM_BOOL useCapture, em_gamepad_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_gamepaddisconnected_callback(void *userData, EM_BOOL useCapture, em_gamepad_callback_func callback)
-
-   Registers a callback function for receiving the gamepad events:
-   gamepadconnected and gamepaddisconnected.
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_gamepad_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-int emscripten_get_num_gamepads(void)
-
-   Returns the number of gamepads connected to the system or
-   "EMSCRIPTEN_RESULT_NOT_SUPPORTED" if the current browser does not
-   support gamepads.
-
-   Note: A gamepad does not show up as connected until a button on
-     it is pressed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      int
-
-EMSCRIPTEN_RESULT emscripten_get_gamepad_status(int index, EmscriptenGamepadEvent *gamepadState)
-
-   Returns a snapshot of the current gamepad state.
-
-   Parameters:
-      * **index** (*int*) -- The index of the gamepad to check (in
-        the array of connected gamepads).
-
-      * **gamepadState** (*EmscriptenGamepadEvent**) -- The most
-        recently received gamepad state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Battery
-=======
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE
-EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE
-
-   Emscripten batterymanager events.
-
-
-Struct
-------
-
-EmscriptenBatteryEvent
-
-   The event structure passed in the batterymanager events:
-   "chargingchange" and "levelchange".
-
-   double chargingTime
-
-      Time remaining until the battery is fully charged (seconds).
-
-   double dischargingTime
-
-      Time remaining until the battery is empty and the system will be
-      suspended (seconds).
-
-   double level
-
-      Current battery level, on a scale of 0 to 1.0.
-
-   EM_BOOL charging;
-
-      "true" if the battery is charging, "false" otherwise.
-
-
-Callback functions
-------------------
-
-em_battery_callback_func
-
-   Function pointer for the "batterymanager event callback functions",
-   defined as:
-
-      typedef EM_BOOL (*em_battery_callback_func)(int eventType, const EmscriptenBatteryEvent *batteryEvent, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of "batterymanager" event
-        ("EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE").
-
-      * **batteryEvent** (*const EmscriptenBatteryEvent**) --
-        Information about the "batterymanager" event that occurred.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_batterychargingchange_callback(void *userData, em_battery_callback_func callback)
-EMSCRIPTEN_RESULT emscripten_set_batterylevelchange_callback(void *userData, em_battery_callback_func callback)
-
-   Registers a callback function for receiving the batterymanager
-   events: "chargingchange" and "levelchange".
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_battery_callback_func*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_battery_status(EmscriptenBatteryEvent *batteryState)
-
-   Returns the current battery status.
-
-   Parameters:
-      * **batteryState** (*EmscriptenBatteryEvent**) -- The most
-        recently received battery state.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Vibration
-=========
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_vibrate(int msecs)
-
-   Produces a vibration for the specified time, in milliseconds.
-
-   Parameters:
-      * **msecs** (*int*) -- The amount of time for which the
-        vibration is required (milliseconds).
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_vibrate_pattern(int *msecsArray, int numEntries)
-
-   Produces a complex vibration feedback pattern.
-
-   Parameters:
-      * **msecsArray** (*int**) -- An array of timing entries [on,
-        off, on, off, on, off, ...] where every second one specifies a
-        duration of vibration, and every other one specifies a
-        duration of silence.
-
-      * **numEntries** (*int*) -- The number of integers in the
-        array "msecsArray".
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-Page unload
-===========
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_BEFOREUNLOAD
-
-   Emscripten beforeunload event.
-
-
-Callback functions
-------------------
-
-em_beforeunload_callback
-
-   Function pointer for the "beforeunload event callback functions",
-   defined as:
-
-      typedef const char *(*em_beforeunload_callback)(int eventType, const void *reserved, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of "beforeunload" event
-        ("EMSCRIPTEN_EVENT_BEFOREUNLOAD").
-
-      * **reserved** (*const void**) -- Reserved for future use;
-        pass in 0.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      Return a string to be displayed to the user.
-
-   Return type:
-      char*
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_beforeunload_callback(void *userData, em_beforeunload_callback callback)
-
-   Registers a callback function for receiving the page beforeunload
-   event.
-
-   Hook into this event to perform actions immediately prior to page
-   close (for example, to display a notification to ask if the user
-   really wants to leave the page).
-
-   Parameters:
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **callback** (*em_beforeunload_callback*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-
-WebGL context
-=============
-
-
-Defines
--------
-
-EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST
-EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED
-
-   Emscripten WebGL context events.
-
-EMSCRIPTEN_WEBGL_CONTEXT_HANDLE
-
-   Represents a handle to an Emscripten WebGL context object. The
-   value 0 denotes an invalid/no context (this is a typedef to an
-   "int").
-
-
-Struct
-------
-
-EmscriptenWebGLContextAttributes
-
-   Specifies WebGL context creation parameters.
-
-   EM_BOOL alpha
-
-      If "true", request an alpha channel for the context. If you
-      create an alpha channel, you can blend the canvas rendering with
-      the underlying web page contents. Default value: "true".
-
-   EM_BOOL depth
-
-      If "true", request a depth buffer of at least 16 bits. If
-      "false", no depth buffer will be initialized. Default value:
-      "true".
-
-   EM_BOOL stencil
-
-      If "true", request a stencil buffer of at least 8 bits. If
-      "false", no stencil buffer will be initialized. Default value:
-      "false".
-
-   EM_BOOL antialias
-
-      If "true", antialiasing will be initialized with a browser-
-      specified algorithm and quality level. If "false", antialiasing
-      is disabled. Default value: "true".
-
-   EM_BOOL premultipliedAlpha
-
-      If "true", the alpha channel of the rendering context will be
-      treated as representing premultiplied alpha values. If "false",
-      the alpha channel represents non-premultiplied alpha. Default
-      value: "true".
-
-   EM_BOOL preserveDrawingBuffer
-
-      If "true", the contents of the drawing buffer are preserved
-      between consecutive "requestAnimationFrame()" calls. If "false",
-      color, depth and stencil are cleared at the beginning of each
-      "requestAnimationFrame()". Generally setting this to "false"
-      gives better performance. Default value: "false".
-
-   EM_BOOL preferLowPowerToHighPerformance
-
-      If "true", hints the browser to initialize a low-power GPU
-      rendering context. If "false", prefers to initialize a high-
-      performance rendering context. Default value: "false".
-
-   EM_BOOL failIfMajorPerformanceCaveat
-
-      If "true", requests context creation to abort if the browser is
-      only able to create a context that does not give good hardware-
-      accelerated performance. Default value: "false".
-
-   int majorVersion
-   int minorVersion
-
-      Emscripten-specific extensions which specify the WebGL context
-      version to initialize.
-
-      For example, pass in "majorVersion=1", "minorVersion=0" to
-      request a WebGL 1.0 context, and "majorVersion=2",
-      "minorVersion=0" to request a WebGL 2.0 context.
-
-      Default value: "majorVersion=1", "minorVersion=0"
-
-   EM_BOOL enableExtensionsByDefault
-
-      If "true", all GLES2-compatible non-performance-impacting WebGL
-      extensions will automatically be enabled for you after the
-      context has been created. If "false", no extensions are enabled
-      by default, and you need to manually call
-      "emscripten_webgl_enable_extension()" to enable each extension
-      that you want to use. Default value: "true".
-
-
-Callback functions
-------------------
-
-em_webgl_context_callback
-
-   Function pointer for the "WebGL Context event callback functions",
-   defined as:
-
-      typedef EM_BOOL (*em_webgl_context_callback)(int eventType, const void *reserved, void *userData);
-
-   Parameters:
-      * **eventType** (*int*) -- The type of "WebGL context event".
-
-      * **reserved** (*const void**) -- Reserved for future use;
-        pass in 0.
-
-      * **userData** (*void**) -- The "userData" originally passed
-        to the registration function.
-
-   Returns:
-      "true" (non zero) to indicate that the event was consumed by the
-      callback handler.
-
-   Return type:
-      "EM_BOOL"
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_webglcontextlost_callback(const char *target, void *userData, EM_BOOL useCapture, em_webgl_context_callback callback)
-EMSCRIPTEN_RESULT emscripten_set_webglcontextrestored_callback(const char *target, void *userData, EM_BOOL useCapture, em_webgl_context_callback callback)
-
-   Registers a callback function for the canvas WebGL context events:
-   "webglcontextlost" and "webglcontextrestored".
-
-   Parameters:
-      * **target** (*const char**) -- Target HTML element id.
-
-      * **userData** (*void**) -- User-defined data to be passed to
-        the callback (opaque to the API).
-
-      * **useCapture** (*EM_BOOL*) -- Set "true" to use capture.
-
-      * **callback** (*em_webgl_context_callback*) -- A callback
-        function. The function is called with the type of event,
-        information about the event, and user data passed from this
-        registration function. The callback should return "true" if
-        the event is consumed.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EM_BOOL emscripten_is_webgl_context_lost(const char *target)
-
-   Queries the given canvas element for whether its WebGL context is
-   in a lost state.
-
-   Parameters:
-      * **target** (*const char**) -- Reserved for future use, pass
-        in 0.
-
-   Returns:
-      "true" if the WebGL context is in a lost state.
-
-   Return type:
-      "EM_BOOL"
-
-void emscripten_webgl_init_context_attributes(EmscriptenWebGLContextAttributes *attributes)
-
-   Populates all fields of the given
-   "EmscriptenWebGLContextAttributes" structure to their default
-   values for use with WebGL 1.0.
-
-   Call this function as a forward-compatible way to ensure that if
-   there are new fields added to the
-   "EmscriptenWebGLContextAttributes" structure in the future, that
-   they also will get default-initialized without having to change any
-   code.
-
-   Parameters:
-      * **attributes** (*EmscriptenWebGLContextAttributes**) -- The
-        structure to be populated.
-
-EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_create_context(const char *target, const EmscriptenWebGLContextAttributes *attributes)
-
-   Creates and returns a new WebGL context.
-
-   Note: * A successful call to this function will not immediately
-     make
-
-       that rendering context active. Call
-       "emscripten_webgl_make_context_current()" after creating a
-       context to activate it.
-
-     * This function will try to initialize the context version that
-       was *exactly* requested. It will not e.g. initialize a newer
-       backwards-compatible version or similar.
-
-   Parameters:
-      * **target** (*const char**) -- The DOM canvas element in
-        which to initialize the WebGL context. If 0 is passed, the
-        element specified by "Module.canvas" will be used.
-
-      * **attributes** (*const EmscriptenWebGLContextAttributes**) -- The
-        attributes of the requested context version.
-
-   Returns:
-      On success, a strictly positive value that represents a handle
-      to the created context. On failure, a negative number that can
-      be cast to an "EMSCRIPTEN_RESULT" field to get the reason why
-      the context creation failed.
-
-   Return type:
-      "EMSCRIPTEN_WEBGL_CONTEXT_HANDLE"
-
-EMSCRIPTEN_RESULT emscripten_webgl_make_context_current(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context)
-
-   Activates the given WebGL context for rendering. After calling this
-   function, all OpenGL functions ("glBindBuffer()", "glDrawArrays()",
-   etc.) can be applied to the given GL context.
-
-   Parameters:
-      * **context** (*EMSCRIPTEN_WEBGL_CONTEXT_HANDLE*) -- The WebGL
-        context to activate.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_get_current_context()
-
-   Returns the currently active WebGL rendering context, or 0 if no
-   context is active. Calling any WebGL functions when there is no
-   active rendering context is undefined and may throw a JavaScript
-   exception.
-
-   Returns:
-      The currently active WebGL rendering context, or 0 if no context
-      is active.
-
-   Return type:
-      "EMSCRIPTEN_WEBGL_CONTEXT_HANDLE"
-
-EMSCRIPTEN_RESULT emscripten_webgl_destroy_context(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context)
-
-   Deletes the given WebGL context. If that context was active, then
-   the no context is set to active.
-
-   Parameters:
-      * **context** (*EMSCRIPTEN_WEBGL_CONTEXT_HANDLE*) -- The WebGL
-        context to delete.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EM_BOOL emscripten_webgl_enable_extension(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context, const char *extension)
-
-   Enables the given extension on the given context.
-
-   Parameters:
-      * **context** (*EMSCRIPTEN_WEBGL_CONTEXT_HANDLE*) -- The WebGL
-        context on which the extension is to be enabled.
-
-      * **extension** (*const char**) -- A string identifying the
-        WebGL extension. For example "OES_texture_float".
-
-   Returns:
-      EM_TRUE if the given extension is supported by the context, and
-      EM_FALSE if the extension was not available.
-
-   Return type:
-      "EM_BOOL"
-
-
-CSS
-===
-
-
-Functions
----------
-
-EMSCRIPTEN_RESULT emscripten_set_element_css_size(const char * target, double width, double height)
-
-   Resizes the css width and height of the element specified by
-   "target" on the Emscripten web page.
-
-   Parameters:
-      * **target** (*const char**) -- Element to resize. If 0 is
-        passed, the element specified by "Module.canvas" will be used.
-
-      * **width** (*double*) -- New width of the element.
-
-      * **height** (*double*) -- New height of the element.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
-
-EMSCRIPTEN_RESULT emscripten_get_element_css_size(const char * target, double * width, double * height)
-
-   Gets the current css width and height of the element specified by
-   "target".
-
-   Parameters:
-      * **target** (*const char**) -- Element to get size of. If 0
-        is passed, the element specified by "Module.canvas" will be
-        used.
-
-      * **width** (*double**) -- Width of the element.
-
-      * **height** (*double**) -- Height of the element.
-
-   Returns:
-      "EMSCRIPTEN_RESULT_SUCCESS", or one of the other result values.
-
-   Return type:
-      "EMSCRIPTEN_RESULT"
diff --git a/site/build/text/docs/api_reference/preamble.js.txt b/site/build/text/docs/api_reference/preamble.js.txt
deleted file mode 100644
index bb446710811e3..0000000000000
--- a/site/build/text/docs/api_reference/preamble.js.txt
+++ /dev/null
@@ -1,517 +0,0 @@
-
-preamble.js
-***********
-
-The JavaScript APIs in preamble.js provide programmatic access for
-interacting with the compiled C code, including: calling compiled C
-functions, accessing memory, converting pointers to JavaScript
-"Strings" and "Strings" to pointers (with different
-encodings/formats), and other convenience functions.
-
-Note: All functions should be called though the Module object (for
-  example: "Module.functionName"). At optimisation "-O2" (and higher)
-  function names are minified by the closure compiler, and calling
-  them directly will fail.
-
-
-Table of Contents
-^^^^^^^^^^^^^^^^^
-
-* Calling compiled C functions from JavaScript
-
-* Accessing memory
-
-* Conversion functions — strings, pointers and arrays
-
-* Run dependencies
-
-* Stack trace
-
-* Type accessors for the memory model
-
-
-Calling compiled C functions from JavaScript
-============================================
-
-ccall(ident, returnType, argTypes, args, opts)
-
-   Call a compiled C function from JavaScript.
-
-   The function executes a compiled C function from JavaScript and
-   returns the result. C++ name mangling means that "normal" C++
-   functions cannot be called; the function must either be defined in
-   a **.c** file or be a C++ function defined with "extern "C"".
-
-      // Call C from JavaScript
-      var result = Module.ccall('c_add', // name of C function
-              'number', // return type
-              ['number', 'number'], // argument types
-              [10, 20]); // arguments
-
-      // result is 30
-
-   Note: * "ccall" uses the C stack for temporary values. If you
-     pass a
-
-       string then it is only "alive" until the call is complete. If
-       the code being called saves the pointer to be used later, it
-       may point to invalid data.
-
-     * If you need a string to live forever, you can create it, for
-       example, using "_malloc" and "writeStringToMemory()". However,
-       you must later delete it manually!
-
-     * LLVM optimizations can inline and remove functions, after
-       which you will not be able to call them. Similarly, function
-       names minified by the *Closure Compiler* are inaccessible. In
-       either case, the solution is to add the functions to the
-       "EXPORTED_FUNCTIONS" list when you invoke *emcc* :
-
-             -s EXPORTED_FUNCTIONS="['_main', '_myfunc']"
-
-          Exported functions can be called as normal:
-
-             a_result = Module.ccall('myfunc', 'number', ['number'], 10)
-
-   Arguments:
-      * **ident** -- The name of the C function to be called.
-
-      * **returnType** -- The return type of the function. This can
-        be ""number"", ""string"" or ""array"", which correspond to
-        the appropriate JavaScript types (use ""number"" for any C
-        pointer, and ""array"" for JavaScript arrays and typed arrays;
-        note that arrays are 8-bit), or for a void function it can be
-        "null" (note: the JavaScript "null" value, not a string
-        containing the word "null").
-
-   Note: 64-bit integers become two 32-bit parameters, for the low
-     and high bits (since 64-bit integers cannot be represented in
-     JavaScript numbers).
-
-   Arguments:
-      * **argTypes** -- An array of the types of arguments for the
-        function (if there are no arguments, this can be omitted).
-        Types are as in "returnType", except that "array" is not
-        supported as there is no way for us to know the length of the
-        array).
-
-      * **args** -- An array of the arguments to the function, as
-        native JavaScript values (as in "returnType"). Note that
-        string arguments will be stored on the stack (the JavaScript
-        string will become a C string on the stack).
-
-   Returns:
-      The result of the function call as a native JavaScript value (as
-      in "returnType").
-
-   Opts:
-      An optional options object. It can contain the following
-      properties:
-
-      * "async": Implies that the ccall will perform an async
-        operation. This assumes you are using the Emterpreter-Async
-        option for your code. When using this option, the ccalled
-        function cannot return a value (it can't be received
-        synchronously anyhow).
-
-cwrap(ident, returnType, argTypes)
-
-   Returns a native JavaScript wrapper for a C function.
-
-   This is similar to "ccall()", but returns a JavaScript function
-   that can be reused as many time as needed. The C function can be
-   defined in a C file, or be a C-compatible C++ function defined
-   using "extern "C"" (to prevent name mangling).
-
-      // Call C from JavaScript
-      var c_javascript_add = Module.cwrap('c_add', // name of C function
-              'number', // return type
-              ['number', 'number']); // argument types
-
-      // Call c_javascript_add normally
-      console.log(c_javascript_add(10, 20)); // 30
-      console.log(c_javascript_add(20, 30)); // 50
-
-   Note: * "cwrap" uses the C stack for temporary values. If you
-     pass a
-
-       string then it is only "alive" until the call is complete. If
-       the code being called saves the pointer to be used later, it
-       may point to invalid data.
-
-     * If you need a string to live forever, you can create it, for
-       example, using "_malloc" and "writeStringToMemory()". However,
-       you must later delete it manually!
-
-     * LLVM optimizations can inline and remove functions, after
-       which you will not be able to "wrap" them. Similarly, function
-       names minified by the *Closure Compiler* are inaccessible. In
-       either case, the solution is to add the functions to the
-       "EXPORTED_FUNCTIONS" list when you invoke *emcc* :
-
-             -s EXPORTED_FUNCTIONS="['_main', '_myfunc']"
-
-          Exported functions can be called as normal:
-
-             my_func = Module.cwrap('myfunc', 'number', ['number'])
-             my_func(12)
-
-   Arguments:
-      * **ident** -- The name of the C function to be called.
-
-      * **returnType** -- The return type of the function. This will
-        be one of the JavaScript types "number", "string" or "array"
-        (use "number" for any C pointer, and "array" for JavaScript
-        arrays and typed arrays; note that arrays are 8-bit).
-
-      * **argTypes** -- An array of the types of arguments for the
-        function (if there are no arguments, this can be omitted).
-        Types are as in "returnType", except that "array" is not
-        supported as there is no way for us to know the length of the
-        array).
-
-   Returns:
-      A JavaScript function that can be used for running the C
-      function.
-
-
-Accessing memory
-================
-
-setValue(ptr, value, type[, noSafe])
-
-   Sets a value at a specific memory address at run-time.
-
-   Note: * "setValue()" and "getValue()" only do *aligned* writes
-     and
-
-       reads.
-
-     * The "type" is an LLVM IR type (one of "i8", "i16", "i32",
-       "i64", "float", "double", or a pointer type like "i8*" or just
-       "*"), not JavaScript types as used in "ccall()" or "cwrap()".
-       This is a lower-level operation, and we do need to care what
-       specific type is being used.
-
-   Arguments:
-      * **ptr** -- A pointer (number) representing the memory
-        address.
-
-      * **value** -- The value to be stored
-
-      * **type** -- An LLVM IR type as a string (see "note" above).
-
-      * **noSafe** (*bool*) -- Developers should ignore this
-        variable. It is only used in "SAFE_HEAP" compilation mode,
-        where it can help avoid infinite recursion in some specialist
-        use cases.
-
-getValue(ptr, type[, noSafe])
-
-   Gets a value at a specific memory address at run-time.
-
-   Note: * "setValue()" and "getValue()" only do *aligned* writes
-     and
-
-       reads!
-
-     * The "type" is an LLVM IR type (one of "i8", "i16", "i32",
-       "i64", "float", "double", or a pointer type like "i8*" or just
-       "*"), not JavaScript types as used in "ccall()" or "cwrap()".
-       This is a lower-level operation, and we do need to care what
-       specific type is being used.
-
-   Arguments:
-      * **ptr** -- A pointer (number) representing the memory
-        address.
-
-      * **type** -- An LLVM IR type as a string (see "note" above).
-
-      * **noSafe** (*bool*) -- Developers should ignore this
-        variable. It is only used in "SAFE_HEAP" compilation mode,
-        where it can help avoid infinite recursion in some specialist
-        use cases.
-
-   Returns:
-      The value stored at the specified memory address.
-
-
-Conversion functions — strings, pointers and arrays
-===================================================
-
-Pointer_stringify(ptr[, length])
-
-   Returns a JavaScript String from a pointer, for use in compiled
-   code.
-
-   Arguments:
-      * **ptr** -- The pointer to be converted to a "String".
-
-      * **length** -- The length of the data in the pointer
-        (optional).
-
-   Returns:
-      A JavaScript "String" containing the data from "ptr".
-
-   Return type:
-      String
-
-UTF8ToString(ptr)
-
-   Given a pointer "ptr" to a null-terminated UTF8-encoded string in
-   the Emscripten HEAP, returns a copy of that string as a JavaScript
-   "String" object.
-
-   Arguments:
-      * **ptr** -- A pointer to a null-terminated UTF8-encoded
-        string in the Emscripten HEAP.
-
-   Returns:
-      A JavaScript "String" object
-
-stringToUTF8(str, outPtr[, maxBytesToWrite])
-
-   Copies the given JavaScript "String" object "str" to the Emscripten
-   HEAP at address "outPtr", null-terminated and encoded in UTF8 form.
-
-   Arguments:
-      * **str** (*String*) -- A JavaScript "String" object.
-
-      * **outPtr** -- Pointer to data copied from "str", encoded in
-        UTF8 format and null-terminated.
-
-      * **maxBytesToWrite** -- A limit on the number of bytes to
-        write out.
-
-UTF16ToString(ptr)
-
-   Given a pointer "ptr" to a null-terminated UTF16LE-encoded string
-   in the Emscripten HEAP, returns a copy of that string as a
-   JavaScript "String" object.
-
-   Arguments:
-      * **ptr** -- A pointer to a null-terminated UTF16LE-encoded
-        string in the Emscripten HEAP.
-
-   Returns:
-      A JavaScript "String" object
-
-stringToUTF16(str, outPtr[, maxBytesToWrite])
-
-   Copies the given JavaScript "String" object "str" to the Emscripten
-   HEAP at address "outPtr", null-terminated and encoded in UTF16LE
-   form.
-
-   The copy will require at most "(str.length*2+1)*2" bytes of space
-   in the HEAP.
-
-   Arguments:
-      * **str** (*String*) -- A JavaScript "String" object.
-
-      * **outPtr** -- Pointer to data copied from "str", encoded in
-        UTF16LE format and null-terminated.
-
-      * **maxBytesToWrite** -- A limit on the number of bytes to
-        write out.
-
-UTF32ToString(ptr)
-
-   Given a pointer "ptr" to a null-terminated UTF32LE-encoded string
-   in the Emscripten HEAP, returns a copy of that string as a
-   JavaScript "String" object.
-
-   Arguments:
-      * **ptr** -- A pointer to a null-terminated UTF32LE-encoded
-        string in the Emscripten HEAP.
-
-   Returns:
-      A JavaScript "String" object.
-
-stringToUTF32(str, outPtr[, maxBytesToWrite])
-
-   Copies the given JavaScript "String" object "str" to the Emscripten
-   HEAP at address "outPtr", null-terminated and encoded in UTF32LE
-   form.
-
-   The copy will require at most "(str.length+1)*4" bytes of space in
-   the HEAP, but can use less, since "str.length" does not return the
-   number of characters in the string, but the number of UTF-16 code
-   units in the string.
-
-   Arguments:
-      * **str** (*String*) -- A JavaScript "String" object.
-
-      * **outPtr** -- Pointer to data copied from "str", encoded in
-        encoded in UTF32LE format and null-terminated.
-
-      * **maxBytesToWrite** -- A limit on the number of bytes to
-        write out.
-
-intArrayFromString(stringy, dontAddNull[, length])
-
-   This converts a JavaScript string into a C-line array of numbers,
-   0-terminated.
-
-   Arguments:
-      * **stringy** (*String*) -- The string to be converted.
-
-      * **dontAddNull** (*bool*) -- If "true", the new array is not
-        zero-terminated.
-
-      * **length** -- The length of the array (optional).
-
-   Returns:
-      The array created from "stringy".
-
-intArrayToString(array)
-
-   This creates a JavaScript string from a zero-terminated C-line
-   array of numbers.
-
-   Arguments:
-      * **array** -- The array to convert.
-
-   Returns:
-      A "String", containing the content of "array".
-
-writeStringToMemory(string, buffer, dontAddNull)
-
-   Writes a JavaScript string to a specified address in the heap.
-
-      // Allocate space for string and extra '0' at the end
-      var buffer = Module._malloc(myString.length+1);
-
-      // Write the string to memory
-      Module.writeStringToMemory(myString, buffer);
-
-      // We can now send buffer into a C function, it is just a normal char* pointer
-
-   Arguments:
-      * **string** (*String*) -- The string to write into memory.
-
-      * **buffer** (*Number*) -- The address (number) where "string"
-        is to be written.
-
-      * **dontAddNull** (*bool*) -- If "true", the new array is not
-        zero-terminated.
-
-writeArrayToMemory(array, buffer)
-
-   Writes an array to a specified address in the heap. Note that
-   memory should to be allocated for the array before it is written.
-
-   Arguments:
-      * **array** -- The array to write to memory.
-
-      * **buffer** (*Number*) -- The address (number) where "array"
-        is to be written.
-
-writeAsciiToMemory(str, buffer, dontAddNull)
-
-   Writes an ASCII string to a specified address in the heap. Note
-   that memory should to be allocated for the string before it is
-   written.
-
-   The string is assumed to only have characters in the ASCII
-   character set. If ASSERTIONS are enabled and this is not the case,
-   it will fail.
-
-      // Allocate space for string
-      var buffer = Module._malloc(myString.length);
-
-      // Write the string to memory
-      Module.writeStringToMemory(myString, buffer);
-
-   Arguments:
-      * **string** -- The string to write into memory.
-
-      * **buffer** -- The address where "string" is to be written.
-
-      * **dontAddNull** (*bool*) -- If "true", the new string is not
-        zero-terminated.
-
-
-Run dependencies
-================
-
-Note that generally run dependencies are managed by the file packager
-and other parts of the system. It is rare for developers to use this
-API directly.
-
-addRunDependency(id)
-
-   Adds an "id" to the list of run dependencies.
-
-   This adds a run dependency and increments the run dependency
-   counter.
-
-   Arguments:
-      * **id** (*String*) -- An arbitrary id representing the
-        operation.
-
-removeRunDependency(id)
-
-   Removes a specified "id" from the list of run dependencies.
-
-   Arguments:
-      * **id** (*String*) -- The identifier for the specific
-        dependency to be removed (added with "addRunDependency()")
-
-
-Stack trace
-===========
-
-stackTrace()
-
-   Returns the current stack track.
-
-      Note: The stack trace is not available at least on IE10 and
-        Safari 6.
-
-   Returns:
-      The current stack trace, if available.
-
-
-Type accessors for the memory model
-===================================
-
-The Emscripten memory representation uses a typed array buffer
-("ArrayBuffer") to represent memory, with different views into it
-giving access to the different types. The views for accessing
-different types of memory are listed below.
-
-HEAP8
-
-   View for 8-bit signed memory.
-
-HEAP16
-
-   View for 16-bit signed memory.
-
-HEAP32
-
-   View for 32-bit signed memory.
-
-HEAPU8
-
-   View for 32-bit unsigned memory.
-
-HEAPU8
-
-   View for 32-bit unsigned memory.
-
-HEAPU16
-
-   View for 16-bit unsigned memory.
-
-HEAPU32
-
-   View for 32-bit unsigned memory.
-
-HEAPF32
-
-   View for 32-bit float memory.
-
-HEAPF64
-
-   View for 64-bit float memory.
diff --git a/site/build/text/docs/tools_reference/emcc.txt b/site/build/text/docs/tools_reference/emcc.txt
index 8181378f8b225..29282a9f570f7 100644
--- a/site/build/text/docs/tools_reference/emcc.txt
+++ b/site/build/text/docs/tools_reference/emcc.txt
@@ -546,6 +546,15 @@ Options that are modified or new in *emcc* are listed below:
    load during startup. See Avoid memory spikes by separating out
    asm.js.
 
+"-fsanitize=<check>"
+   Instructs the compiler to turn on runtime checks for various forms
+   of undefined or suspicious behavior. For more information, refer
+   to the appropriate compiler documentation. Only the following have
+   been tested:
+
+     * "cfi": Enable [control flow integrity](http://clang.llvm.org/docs/ControlFlowIntegrity.html)
+       checks. Note that this is only supported by Clang/LLVM, and
+       indirect function call checking requires Clang/LLVM 3.9+.
 
 Environment variables
 =====================
diff --git a/site/source/docs/api_reference/Filesystem-API.rst b/site/source/docs/api_reference/Filesystem-API.rst
index ccaa1d4f724d9..c7b306af778ba 100644
--- a/site/source/docs/api_reference/Filesystem-API.rst
+++ b/site/source/docs/api_reference/Filesystem-API.rst
@@ -72,7 +72,7 @@ This is provided to overcome the limitation that browsers do not offer synchrono
 .. _filesystem-api-workerfs:
 
 WORKERFS
------
+--------
 
 .. note:: This file system is only for use when running code inside a worker.
 
diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst
index 1be380628c3a8..6deb379aedd76 100644
--- a/site/source/docs/api_reference/emscripten.h.rst
+++ b/site/source/docs/api_reference/emscripten.h.rst
@@ -573,7 +573,7 @@ Functions
 	:returns: A handle to request (``int``) that can be used to :c:func:`abort <emscripten_async_wget2_abort>` the request.		
 
 
-.. c:function:: emscripten_async_wget2_abort(int handle)
+.. c:function:: void emscripten_async_wget2_abort(int handle)
 
 	Abort an asynchronous request raised using :c:func:`emscripten_async_wget2` or :c:func:`emscripten_async_wget2_data`.
 	
@@ -637,7 +637,7 @@ Emscripten Asynchronous IndexedDB API
 	:param ptr: A pointer to the data to store.
 	:param num: How many bytes to store.
 	:param void* arg: User-defined data that is passed to the callbacks, untouched by the API itself. This may be used by a callback to identify the associated call.
-	:param em_arg_callback_func onload: Callback on successful load of the URL into the buffer. The callback function parameter values are:
+	:param em_arg_callback_func onstore: Callback on successful store of the data buffer to the URL. The callback function parameter values are:
 	
 		- *(void*)* : Equal to ``arg`` (user defined data).
 	
diff --git a/site/source/docs/api_reference/html5.h.rst b/site/source/docs/api_reference/html5.h.rst
index 5a4079149347f..129b187610580 100644
--- a/site/source/docs/api_reference/html5.h.rst
+++ b/site/source/docs/api_reference/html5.h.rst
@@ -1246,8 +1246,11 @@ Defines
 
 .. c:macro:: EMSCRIPTEN_EVENT_POINTERLOCKCHANGE
 			 
-    Emscripten `pointerlockchange <http://www.w3.org/TR/pointerlock/#pointerlockchange-and-pointerlockerror-events>`_ events.
-	
+    Emscripten `pointerlockchange <http://www.w3.org/TR/pointerlock/#pointerlockchange-and-pointerlockerror-events>`_ event.
+
+.. c:macro:: EMSCRIPTEN_EVENT_POINTERLOCKERROR
+
+    Emscripten `pointerlockerror <http://www.w3.org/TR/pointerlock/#pointerlockchange-and-pointerlockerror-events>`_ event.
 
 Struct
 ------
@@ -1291,6 +1294,20 @@ Callback functions
 	:param void* userData: The ``userData`` originally passed to the registration function.
 	:returns: |callback-handler-return-value-doc|
 	:rtype: |EM_BOOL|
+
+.. c:type:: em_pointerlockerror_callback_func
+
+	Function pointer for the :c:func:`pointerlockerror event callback functions <emscripten_set_pointerlockerror_callback>`, defined as:
+
+	.. code-block:: cpp
+
+		typedef EM_BOOL (*em_pointerlockerror_callback_func)(int eventType, const void *reserved, void *userData);
+
+	:param int eventType: The type of pointerlockerror event (:c:data:`EMSCRIPTEN_EVENT_POINTERLOCKERROR`).
+	:param const void* reserved: Reserved for future use; pass in 0.
+	:param void* userData: The ``userData`` originally passed to the registration function.
+	:returns: |callback-handler-return-value-doc|
+	:rtype: |EM_BOOL|
 	
 
 	
@@ -1313,6 +1330,20 @@ Functions
 
 
 
+.. c:function:: EMSCRIPTEN_RESULT emscripten_set_pointerlockerror_callback(const char *target, void *userData, EM_BOOL useCapture, em_pointerlockerror_callback_func callback)
+
+	Registers a callback function for receiving the `pointerlockerror <http://www.w3.org/TR/pointerlock/#pointerlockchange-and-pointerlockerror-events>`_ event.
+
+	:param target: |target-parameter-doc|
+	:type target: const char*
+	:param void* userData: |userData-parameter-doc|
+	:param EM_BOOL useCapture: |useCapture-parameter-doc|
+	:param em_pointerlockerror_callback_func callback: |callback-function-parameter-doc|
+	:returns: :c:data:`EMSCRIPTEN_RESULT_SUCCESS`, or one of the other result values.
+	:rtype: |EMSCRIPTEN_RESULT|
+
+
+
 .. c:function:: EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(EmscriptenPointerlockChangeEvent *pointerlockStatus)
 
 	Returns the current page pointerlock state.
@@ -1748,7 +1779,6 @@ Functions
 	Registers a callback function for receiving the `batterymanager <http://www.w3.org/TR/battery-status/#batterymanager-interface>`_ events: ``chargingchange`` and ``levelchange``.
 
 	:param void* userData: |userData-parameter-doc|
-	:param EM_BOOL useCapture: |useCapture-parameter-doc|
 	:param em_battery_callback_func callback: |callback-function-parameter-doc|
 	:returns: :c:data:`EMSCRIPTEN_RESULT_SUCCESS`, or one of the other result values.
 	:rtype: |EMSCRIPTEN_RESULT|	
@@ -2039,7 +2069,7 @@ Functions
 
 .. c:function:: EMSCRIPTEN_RESULT emscripten_set_element_css_size(const char * target, double width, double height)
 
-	Resizes the css width and height of the element specified by ``target`` on the Emscripten web page.
+	Resizes the CSS width and height of the element specified by ``target`` on the Emscripten web page.
 
 	:param target: Element to resize. If 0 is passed, the element specified by ``Module.canvas`` will be used.
 	:type target: const char*
@@ -2051,7 +2081,7 @@ Functions
 
 .. c:function:: EMSCRIPTEN_RESULT emscripten_get_element_css_size(const char * target, double * width, double * height)
 
-	Gets the current css width and height of the element specified by ``target``.
+	Gets the current CSS width and height of the element specified by ``target``.
 
 	:param target: Element to get size of. If 0 is passed, the element specified by ``Module.canvas`` will be used.
 	:type target: const char*
diff --git a/site/source/docs/api_reference/trace.h.rst b/site/source/docs/api_reference/trace.h.rst
index a42730516ba26..fbecc6d92a084 100644
--- a/site/source/docs/api_reference/trace.h.rst
+++ b/site/source/docs/api_reference/trace.h.rst
@@ -302,7 +302,7 @@ Functions
 
    In most cases, the ``collector_url`` will be ``http://127.0.0.1:5000/``.
 
-.. c:function:: void emscripten_configure_for_google_wtf(void)
+.. c:function:: void emscripten_trace_configure_for_google_wtf(void)
 
    :rtype: void
 
@@ -460,7 +460,7 @@ Functions
    :param address: Memory address which should be annotated.
    :type address: const void*
    :param size: Size of the memory associated with this allocation.
-   :type type: int32_t
+   :type size: int32_t
    :rtype: void
 
    Associate an amount of additional storage with this address. This
diff --git a/site/source/docs/building_from_source/building_emscripten_from_source_on_windows.rst b/site/source/docs/building_from_source/building_emscripten_from_source_on_windows.rst
index 51e0643095bb2..8eaf99def7295 100644
--- a/site/source/docs/building_from_source/building_emscripten_from_source_on_windows.rst
+++ b/site/source/docs/building_from_source/building_emscripten_from_source_on_windows.rst
@@ -44,7 +44,7 @@ These instructions explain how to install **all** the :ref:`required tools <tool
 
 #. Install `Github for Windows <http://windows.github.com/>`_ (or any other git client).
 
-#. Install `Java <http://java.com/en/download/index.jsp>`_.
+#. Install `Java <http://java.com/en/download/index.jsp>`_ (Java is optional, you only need it for Closure Compiler minification).
 
 #. Build :ref:`Fastcomp <LLVM-Backend>` (LLVM + Clang) from source using :ref:`these instructions <building-fastcomp-from-source>`. 
 	
diff --git a/site/source/docs/debugging/CyberDWARF.rst b/site/source/docs/debugging/CyberDWARF.rst
index 33831b8a39655..f3bd2a9b89570 100644
--- a/site/source/docs/debugging/CyberDWARF.rst
+++ b/site/source/docs/debugging/CyberDWARF.rst
@@ -7,17 +7,17 @@ CyberDWARF Debugging
 Building
 ========
 
-To add CyberDWARF support to a build, pass ``-s CYBERDWARF=1`` to ``emcc``. This generates a ``.cd`` file containing type information for debugging and adds a debugging toolkit to the output Javascript.
+To add CyberDWARF support to a build, pass ``-s CYBERDWARF=1`` to ``emcc``. This generates a ``.cd`` file containing type information for debugging and adds a debugging toolkit to the output JavaScript.
 
 Using
 =====
 
-The CyberDWARF debugger is designed to be used from the Javascript devtool console available in most modern browsers.
+The CyberDWARF debugger is designed to be used from the JavaScript devtool console available in most modern browsers.
 
 Heap Pretty Printer
 -------------------
 
-This small example will show how to use CyberDWARF to visualize a simple struct
+This small example will show how to use CyberDWARF to visualize a simple struct.
 
 .. code-block:: cpp
 
@@ -57,7 +57,7 @@ This small example will show how to use CyberDWARF to visualize a simple struct
 
 **Visualizing**
 
-After the page loads, open a Javascript console.
+After the page loads, open a JavaScript console.
 
 .. code-block:: bash
 
diff --git a/site/source/docs/getting_started/FAQ.rst b/site/source/docs/getting_started/FAQ.rst
index 7d5a8e60e369a..1552175ef1e2b 100644
--- a/site/source/docs/getting_started/FAQ.rst
+++ b/site/source/docs/getting_started/FAQ.rst
@@ -194,7 +194,7 @@ How can I tell when the page is fully loaded and it is safe to call compiled fun
 
 (You may need this answer if you see an error saying something like ``you need to wait for the runtime to be ready (e.g. wait for main() to be called)``, which is a check enabled in ``ASSERTIONS`` builds.)
 
-Calling a compiled function before a page has fully loaded can result in an error, if the function relies on files that may not be present (for example the :ref:`.mem <emcc-memory-init-file>` file and :ref:`preloaded <emcc-preload-file>` files are loaded asynchronously).
+Calling a compiled function before a page has fully loaded can result in an error, if the function relies on files that may not be present (for example the :ref:`.mem <emcc-memory-init-file>` file and :ref:`preloaded <emcc-preload-file>` files are loaded asynchronously, and therefore if you just place some JS that calls compiled code in a ``--post-js``, that code will be called synchronously at the end of the combined JS file, potentially before the asynchronous event happens, which is bad).
 
 The easiest way to find out when loading is complete is to add a ``main()`` function, and within it call a JavaScript function to notify your code that loading is complete. 
 
diff --git a/site/source/docs/getting_started/downloads.rst b/site/source/docs/getting_started/downloads.rst
index 2317fd9dddf05..28c9f18433587 100644
--- a/site/source/docs/getting_started/downloads.rst
+++ b/site/source/docs/getting_started/downloads.rst
@@ -154,7 +154,7 @@ Linux
 		# Install node.js
 		sudo apt-get install nodejs
 		
-		# Install Java
+		# Install Java (optional, only needed for Closure Compiler minification)
 		sudo apt-get install default-jre
 
 .. note:: Your system may provide Node.js as ``node`` instead of ``nodejs``. In that case, you may need to also update the ``NODE_JS`` attribute of your ``~/.emscripten`` file.
diff --git a/site/source/docs/optimizing/Optimizing-Code.rst b/site/source/docs/optimizing/Optimizing-Code.rst
index d0e494684c82f..74ff639f979fe 100644
--- a/site/source/docs/optimizing/Optimizing-Code.rst
+++ b/site/source/docs/optimizing/Optimizing-Code.rst
@@ -84,8 +84,8 @@ In addition to the above (defining a separate memory initialization file as :ref
 - Use :ref:`llvm-lto <emcc-llvm-lto>` when compiling from bitcode to JavaScript: ``--llvm-lto 1``. This can break some code as the LTO code path is less tested.
 - Disable :ref:`optimizing-code-inlining`: ``-s INLINING_LIMIT=1``. Compiling with -Os or -Oz generally avoids inlining too.
 - Use :ref:`closure <emcc-closure>` on the outside non-asm.js code: ``--closure 1``. This can break code that doesn't use `closure annotations properly <https://developers.google.com/closure/compiler/docs/api-tutorial3>`_.
-- You can use the ``NO_FILESYSTEM`` option to disable bundling of filesystem support code (the compiler should optimize it out if not used, but may not always succeed). This can be useful if you are building a pure computational library, for example. See ``settings.js`` for more detals.
-- You can use ``EXPORTED_RUNTIME_METHODS`` to define which runtime methods are exported. By default a bunch of useful methods are exported, which you may not need; setting this to a smaller list will cause fewer methods to be exported. In conjunction with the closure compiler, this can be very effective, since closure can eliminate non-exported code. See ``settings.js`` for more detals. See ``test_no_nuthin`` in ``tests/test_other.py`` for an example usage in the test suite.
+- You can use the ``NO_FILESYSTEM`` option to disable bundling of filesystem support code (the compiler should optimize it out if not used, but may not always succeed). This can be useful if you are building a pure computational library, for example. See ``settings.js`` for more details.
+- You can use ``EXPORTED_RUNTIME_METHODS`` to define which runtime methods are exported. By default a bunch of useful methods are exported, which you may not need; setting this to a smaller list will cause fewer methods to be exported. In conjunction with the closure compiler, this can be very effective, since closure can eliminate non-exported code. See ``settings.js`` for more details. See ``test_no_nuthin`` in ``tests/test_other.py`` for an example usage in the test suite.
 - You can use ``ELIMINATE_DUPLICATE_FUNCTIONS`` to remove duplicate functions, which C++ templates often create. See ``settings.js`` for more details.
 - You can move some of your code into the `Emterpreter <https://github.com/kripken/emscripten/wiki/Emterpreter>`_, which will then run much slower (as it is interpreted), but it will transfer all that code into a smaller amount of data.
 - You can use separate modules through `dynamic linking <https://github.com/kripken/emscripten/wiki/Linking>`_. That can increase the total code size of everything, but reduces the maximum size of a single module, which can help in some cases (e.g. if a single big module hits a memory limit).
@@ -126,7 +126,7 @@ You can also do this manually, as follows:
 Running by itself
 -----------------
 
-If you hit memory limits in browsers, it can help to run your project by itself, as opposed to inside a web page containing other content. If you open a new web page (as a new tab, or a new window) that contains just your project, then you have the best chance at avoiding memory framentation issues.
+If you hit memory limits in browsers, it can help to run your project by itself, as opposed to inside a web page containing other content. If you open a new web page (as a new tab, or a new window) that contains just your project, then you have the best chance at avoiding memory fragmentation issues.
 
 
 Outlining
@@ -134,7 +134,7 @@ Outlining
 
 JavaScript engines will often compile very large functions slowly (relative to their size), and fail to optimize them effectively (or at all). One approach to this problem is to use "outlining": breaking them into smaller functions that can be compiled and optimized more effectively. 
 
-Outlining increases overall code size, and can itself make some code less optimised. Despite this, outlining can sometimes improve both startup and runtime speed. For more information see For more information read `Outlining: a workaround for JITs and big functions <http://mozakai.blogspot.com/2013/08/outlining-workaround-for-jits-and-big.html>`_.
+Outlining increases overall code size, and can itself make some code less optimised. Despite this, outlining can sometimes improve both startup and runtime speed. For more information read `Outlining: a workaround for JITs and big functions <http://mozakai.blogspot.com/2013/08/outlining-workaround-for-jits-and-big.html>`_.
 
 The ``OUTLINING_LIMIT`` setting defines the function size at which Emscripten will try to break large functions into smaller ones. Search for this setting in `settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_ for information on how to determine what functions may need to be outlined and how to choose an appropriate function size.
 
diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst
index e0fc28c8f9abb..9f3c6a096cfed 100644
--- a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst
+++ b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst
@@ -376,10 +376,10 @@ If you add it to your own file, you should write something like
 first, so this add ``my_js`` onto ``LibraryManager.library``, the global
 object where all JavaScript library code should be.
 
-JavaScript Limits in library files
+JavaScript limits in library files
 ----------------------------------
 
-If you're not familar with JavaScript, say if you're a C/C++ programmer
+If you're not familiar with JavaScript, say if you're a C/C++ programmer
 and just using emscripten, then the following issues probably won't come up, but
 if you're an experienced JavaScript programmer you need to be aware
 some common JavaScript practices can not be used in certain ways in emscripten
@@ -397,7 +397,7 @@ key-value pairs are special. Interior code inside a function can
 have arbitrary JS, of course).
 
 To avoid this limitation of JS libraries, you can put code in another file using
-the ``--pre-js`` or ``--post-js`` options, which allow arbitary normal
+the ``--pre-js`` or ``--post-js`` options, which allow arbitrary normal
 JS, and it is included and optimized with the rest of the output. That is
 the recommended approach for most cases. Another option is another ``<script>`` tag.
 
@@ -433,7 +433,7 @@ initialization.
    });
 
 A `__postset` is a string the compiler will emit directly to the
-output file. For the example above this code will be emited.
+output file. For the example above this code will be emitted.
 
 .. code-block:: javascript
 
diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst b/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst
index 75c4ec8fb0b6a..88c98791d5eb4 100644
--- a/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst
+++ b/site/source/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.rst
@@ -127,6 +127,7 @@ Once binding is complete, C++ objects can be created and used in JavaScript as t
 
 	While the objects are also available in the global namespace by default, there are cases where they will not be (for example, if you use the :term:`closure compiler` to minify code or wrap compiled code in a function to avoid polluting the global namespace). You can of course use whatever name you like for the module by assigning it to a new variable: ``var MyModuleName = Module;``.
 
+.. important:: You can only use this code when it is :ref:`safe to call compiled code <faq-when-safe-to-call-compiled-functions>`, see more details in that FAQ entry.
 
 JavaScript will automatically garbage collect any of the wrapped C++ objects when there are no more references. If the C++ object doesn't require specific clean up (i.e. it doesn't have a destructor) then no other action needs to be taken.
 
diff --git a/site/source/docs/porting/emterpreter.rst b/site/source/docs/porting/emterpreter.rst
index a3d84c6345efd..86bd5395c5d25 100644
--- a/site/source/docs/porting/emterpreter.rst
+++ b/site/source/docs/porting/emterpreter.rst
@@ -81,7 +81,7 @@ Static Analysis
 
 Building with ``EMTERPRETIFY_ADVISE`` will process the project and perform a static analysis to determine which methods should probably be run in the interpreter. This checks which methods *could* be on the stack underneath a call to a synchronous method, in which case they must be interpreted so that we can save and restore the stack later in an asynchronous way.
 
-The analysis is pessimistic, in that it checks what *could* possibly be called, but might not in practice. For exmaple, function pointers are hard to figure out: Even though the analysis takes into account the **type** of function pointer, if you call a ``void (int)`` method by a function pointer, then the analysis must assume that any ``void (int)`` method (that ever has its address taken, i.e., *could* be called via a function pointer) could be called there. For example, on Doom it suggests that 31% (!) of all methods should be interpreted, while in practice only 1% need to be (as is easy to verify by reading the code).
+The analysis is pessimistic, in that it checks what *could* possibly be called, but might not in practice. For example, function pointers are hard to figure out: Even though the analysis takes into account the **type** of function pointer, if you call a ``void (int)`` method by a function pointer, then the analysis must assume that any ``void (int)`` method (that ever has its address taken, i.e., *could* be called via a function pointer) could be called there. For example, on Doom it suggests that 31% (!) of all methods should be interpreted, while in practice only 1% need to be (as is easy to verify by reading the code).
 
 Dynamic Tools
 ~~~~~~~~~~~~~
@@ -111,7 +111,7 @@ You can see ``main()`` at the bottom (below it is how main is invoked, which you
 
 Adding those methods to the whitelist of interpreted functions, you can then build and run the application again, and repeat this process until everything works properly. You should still carefully review your codebase and see what should be interpreted, but the semi-automatic process described here is easy to use and can be very effective in practice, if you test all relevant code paths.
 
-**Warning**: The runtime checks that ASSERTIONS adds guard against compiled code that is not interpreted. But it does not protect you from non-compiled code. For example, if a compiled method calls a non-compiled method, which then calls back into compiled code, we cannot save and restore the stack: Even if the compiled methods are interpreted, the non-compiled one has no way for us to save it's current execution state. If you try to run synchronous code in this incorrect manner, things will fail in potentially confusing ways: what happens is the emterpreted code returns immediately (in order to wait for the asynchronous callback), and your handwritten code underneath it will then continue to execute, not knowing that the code just returning has not yet completed.
+**Warning**: The runtime checks that ASSERTIONS adds guards against compiled code that is not interpreted. But it does not protect you from non-compiled code. For example, if a compiled method calls a non-compiled method, which then calls back into compiled code, we cannot save and restore the stack: Even if the compiled methods are interpreted, the non-compiled one has no way for us to save its current execution state. If you try to run synchronous code in this incorrect manner, things will fail in potentially confusing ways: what happens is the emterpreted code returns immediately (in order to wait for the asynchronous callback), and your handwritten code underneath it will then continue to execute, not knowing that the code just returning has not yet completed.
 
 Inlining
 ~~~~~~~~
diff --git a/src/closure-externs.js b/src/closure-externs.js
index 492a634718e24..4eb4e3f873e73 100644
--- a/src/closure-externs.js
+++ b/src/closure-externs.js
@@ -193,3 +193,658 @@ Atomics.prototype.xor = function(typedArray, index, value) {};
 Atomics.prototype.wait = function(typedArray, index, valuei, timeout) {};
 Atomics.prototype.wake = function(typedArray, index, value) {};
 Atomics.prototype.isLockFree = function(size) {};
+
+/**
+ * SIMD.js support (not in upstream closure yet).
+ */
+var SIMD;
+//Base objects
+SIMD.Float32x4;
+SIMD.Float64x2;
+SIMD.Int8x16;
+SIMD.Int16x8;
+SIMD.Int32x4;
+SIMD.Uint8x16;
+SIMD.Uint16x8;
+SIMD.Uint32x4;
+SIMD.Bool8x16;
+SIMD.Bool16x8;
+SIMD.Bool32x4;
+SIMD.Bool64x2;
+
+SIMD.Float32x4.abs = function() {};
+SIMD.Float64x2.abs = function() {};
+SIMD.Int8x16.abs = function() {};
+SIMD.Int16x8.abs = function() {};
+SIMD.Int32x4.abs = function() {};
+SIMD.Uint8x16.abs = function() {};
+SIMD.Uint16x8.abs = function() {};
+SIMD.Uint32x4.abs = function() {};
+SIMD.Bool8x16.abs = function() {};
+SIMD.Bool16x8.abs = function() {};
+SIMD.Bool32x4.abs = function() {};
+SIMD.Bool64x2.abs = function() {};
+
+SIMD.Float32x4.add = function() {};
+SIMD.Float64x2.add = function() {};
+SIMD.Int8x16.add = function() {};
+SIMD.Int16x8.add = function() {};
+SIMD.Int32x4.add = function() {};
+SIMD.Uint8x16.add = function() {};
+SIMD.Uint16x8.add = function() {};
+SIMD.Uint32x4.add = function() {};
+SIMD.Bool8x16.add = function() {};
+SIMD.Bool16x8.add = function() {};
+SIMD.Bool32x4.add = function() {};
+SIMD.Bool64x2.add = function() {};
+
+SIMD.Float32x4.addSaturate = function() {};
+SIMD.Float64x2.addSaturate = function() {};
+SIMD.Int8x16.addSaturate = function() {};
+SIMD.Int16x8.addSaturate = function() {};
+SIMD.Int32x4.addSaturate = function() {};
+SIMD.Uint8x16.addSaturate = function() {};
+SIMD.Uint16x8.addSaturate = function() {};
+SIMD.Uint32x4.addSaturate = function() {};
+SIMD.Bool8x16.addSaturate = function() {};
+SIMD.Bool16x8.addSaturate = function() {};
+SIMD.Bool32x4.addSaturate = function() {};
+SIMD.Bool64x2.addSaturate = function() {};
+
+SIMD.Float32x4.allTrue = function() {};
+SIMD.Float64x2.allTrue = function() {};
+SIMD.Int8x16.allTrue = function() {};
+SIMD.Int16x8.allTrue = function() {};
+SIMD.Int32x4.allTrue = function() {};
+SIMD.Uint8x16.allTrue = function() {};
+SIMD.Uint16x8.allTrue = function() {};
+SIMD.Uint32x4.allTrue = function() {};
+SIMD.Bool8x16.allTrue = function() {};
+SIMD.Bool16x8.allTrue = function() {};
+SIMD.Bool32x4.allTrue = function() {};
+SIMD.Bool64x2.allTrue = function() {};
+
+SIMD.Float32x4.and = function() {};
+SIMD.Float64x2.and = function() {};
+SIMD.Int8x16.and = function() {};
+SIMD.Int16x8.and = function() {};
+SIMD.Int32x4.and = function() {};
+SIMD.Uint8x16.and = function() {};
+SIMD.Uint16x8.and = function() {};
+SIMD.Uint32x4.and = function() {};
+SIMD.Bool8x16.and = function() {};
+SIMD.Bool16x8.and = function() {};
+SIMD.Bool32x4.and = function() {};
+SIMD.Bool64x2.and = function() {};
+
+SIMD.Float32x4.check = function() {};
+SIMD.Float64x2.check = function() {};
+SIMD.Int8x16.check = function() {};
+SIMD.Int16x8.check = function() {};
+SIMD.Int32x4.check = function() {};
+SIMD.Uint8x16.check = function() {};
+SIMD.Uint16x8.check = function() {};
+SIMD.Uint32x4.check = function() {};
+SIMD.Bool8x16.check = function() {};
+SIMD.Bool16x8.check = function() {};
+SIMD.Bool32x4.check = function() {};
+SIMD.Bool64x2.check = function() {};
+
+SIMD.Float32x4.div = function() {};
+SIMD.Float64x2.div = function() {};
+SIMD.Int8x16.div = function() {};
+SIMD.Int16x8.div = function() {};
+SIMD.Int32x4.div = function() {};
+SIMD.Uint8x16.div = function() {};
+SIMD.Uint16x8.div = function() {};
+SIMD.Uint32x4.div = function() {};
+SIMD.Bool8x16.div = function() {};
+SIMD.Bool16x8.div = function() {};
+SIMD.Bool32x4.div = function() {};
+SIMD.Bool64x2.div = function() {};
+
+SIMD.Float32x4.equal = function() {};
+SIMD.Float64x2.equal = function() {};
+SIMD.Int8x16.equal = function() {};
+SIMD.Int16x8.equal = function() {};
+SIMD.Int32x4.equal = function() {};
+SIMD.Uint8x16.equal = function() {};
+SIMD.Uint16x8.equal = function() {};
+SIMD.Uint32x4.equal = function() {};
+SIMD.Bool8x16.equal = function() {};
+SIMD.Bool16x8.equal = function() {};
+SIMD.Bool32x4.equal = function() {};
+SIMD.Bool64x2.equal = function() {};
+
+SIMD.Float32x4.extractLane = function() {};
+SIMD.Float64x2.extractLane = function() {};
+SIMD.Int8x16.extractLane = function() {};
+SIMD.Int16x8.extractLane = function() {};
+SIMD.Int32x4.extractLane = function() {};
+SIMD.Uint8x16.extractLane = function() {};
+SIMD.Uint16x8.extractLane = function() {};
+SIMD.Uint32x4.extractLane = function() {};
+SIMD.Bool8x16.extractLane = function() {};
+SIMD.Bool16x8.extractLane = function() {};
+SIMD.Bool32x4.extractLane = function() {};
+SIMD.Bool64x2.extractLane = function() {};
+
+SIMD.Float32x4.fromFloat32x4 = function() {};
+SIMD.Float64x2.fromFloat32x4 = function() {};
+SIMD.Int8x16.fromFloat32x4 = function() {};
+SIMD.Int16x8.fromFloat32x4 = function() {};
+SIMD.Int32x4.fromFloat32x4 = function() {};
+SIMD.Uint8x16.fromFloat32x4 = function() {};
+SIMD.Uint16x8.fromFloat32x4 = function() {};
+SIMD.Uint32x4.fromFloat32x4 = function() {};
+SIMD.Bool8x16.fromFloat32x4 = function() {};
+SIMD.Bool16x8.fromFloat32x4 = function() {};
+SIMD.Bool32x4.fromFloat32x4 = function() {};
+SIMD.Bool64x2.fromFloat32x4 = function() {};
+
+SIMD.Float32x4.fromFloat32x4Bits = function() {};
+SIMD.Float64x2.fromFloat32x4Bits = function() {};
+SIMD.Int8x16.fromFloat32x4Bits = function() {};
+SIMD.Int16x8.fromFloat32x4Bits = function() {};
+SIMD.Int32x4.fromFloat32x4Bits = function() {};
+SIMD.Uint8x16.fromFloat32x4Bits = function() {};
+SIMD.Uint16x8.fromFloat32x4Bits = function() {};
+SIMD.Uint32x4.fromFloat32x4Bits = function() {};
+SIMD.Bool8x16.fromFloat32x4Bits = function() {};
+SIMD.Bool16x8.fromFloat32x4Bits = function() {};
+SIMD.Bool32x4.fromFloat32x4Bits = function() {};
+SIMD.Bool64x2.fromFloat32x4Bits = function() {};
+
+SIMD.Float32x4.fromFloat64x2Bits = function() {};
+SIMD.Float64x2.fromFloat64x2Bits = function() {};
+SIMD.Int8x16.fromFloat64x2Bits = function() {};
+SIMD.Int16x8.fromFloat64x2Bits = function() {};
+SIMD.Int32x4.fromFloat64x2Bits = function() {};
+SIMD.Uint8x16.fromFloat64x2Bits = function() {};
+SIMD.Uint16x8.fromFloat64x2Bits = function() {};
+SIMD.Uint32x4.fromFloat64x2Bits = function() {};
+SIMD.Bool8x16.fromFloat64x2Bits = function() {};
+SIMD.Bool16x8.fromFloat64x2Bits = function() {};
+SIMD.Bool32x4.fromFloat64x2Bits = function() {};
+SIMD.Bool64x2.fromFloat64x2Bits = function() {};
+
+SIMD.Float32x4.fromInt16x8Bits = function() {};
+SIMD.Float64x2.fromInt16x8Bits = function() {};
+SIMD.Int8x16.fromInt16x8Bits = function() {};
+SIMD.Int16x8.fromInt16x8Bits = function() {};
+SIMD.Int32x4.fromInt16x8Bits = function() {};
+SIMD.Uint8x16.fromInt16x8Bits = function() {};
+SIMD.Uint16x8.fromInt16x8Bits = function() {};
+SIMD.Uint32x4.fromInt16x8Bits = function() {};
+SIMD.Bool8x16.fromInt16x8Bits = function() {};
+SIMD.Bool16x8.fromInt16x8Bits = function() {};
+SIMD.Bool32x4.fromInt16x8Bits = function() {};
+SIMD.Bool64x2.fromInt16x8Bits = function() {};
+
+SIMD.Float32x4.fromInt32x4 = function() {};
+SIMD.Float64x2.fromInt32x4 = function() {};
+SIMD.Int8x16.fromInt32x4 = function() {};
+SIMD.Int16x8.fromInt32x4 = function() {};
+SIMD.Int32x4.fromInt32x4 = function() {};
+SIMD.Uint8x16.fromInt32x4 = function() {};
+SIMD.Uint16x8.fromInt32x4 = function() {};
+SIMD.Uint32x4.fromInt32x4 = function() {};
+SIMD.Bool8x16.fromInt32x4 = function() {};
+SIMD.Bool16x8.fromInt32x4 = function() {};
+SIMD.Bool32x4.fromInt32x4 = function() {};
+SIMD.Bool64x2.fromInt32x4 = function() {};
+
+SIMD.Float32x4.fromInt32x4Bits = function() {};
+SIMD.Float64x2.fromInt32x4Bits = function() {};
+SIMD.Int8x16.fromInt32x4Bits = function() {};
+SIMD.Int16x8.fromInt32x4Bits = function() {};
+SIMD.Int32x4.fromInt32x4Bits = function() {};
+SIMD.Uint8x16.fromInt32x4Bits = function() {};
+SIMD.Uint16x8.fromInt32x4Bits = function() {};
+SIMD.Uint32x4.fromInt32x4Bits = function() {};
+SIMD.Bool8x16.fromInt32x4Bits = function() {};
+SIMD.Bool16x8.fromInt32x4Bits = function() {};
+SIMD.Bool32x4.fromInt32x4Bits = function() {};
+SIMD.Bool64x2.fromInt32x4Bits = function() {};
+
+SIMD.Float32x4.fromInt8x16Bits = function() {};
+SIMD.Float64x2.fromInt8x16Bits = function() {};
+SIMD.Int8x16.fromInt8x16Bits = function() {};
+SIMD.Int16x8.fromInt8x16Bits = function() {};
+SIMD.Int32x4.fromInt8x16Bits = function() {};
+SIMD.Uint8x16.fromInt8x16Bits = function() {};
+SIMD.Uint16x8.fromInt8x16Bits = function() {};
+SIMD.Uint32x4.fromInt8x16Bits = function() {};
+SIMD.Bool8x16.fromInt8x16Bits = function() {};
+SIMD.Bool16x8.fromInt8x16Bits = function() {};
+SIMD.Bool32x4.fromInt8x16Bits = function() {};
+SIMD.Bool64x2.fromInt8x16Bits = function() {};
+
+SIMD.Float32x4.fromUint16x8Bits = function() {};
+SIMD.Float64x2.fromUint16x8Bits = function() {};
+SIMD.Int8x16.fromUint16x8Bits = function() {};
+SIMD.Int16x8.fromUint16x8Bits = function() {};
+SIMD.Int32x4.fromUint16x8Bits = function() {};
+SIMD.Uint8x16.fromUint16x8Bits = function() {};
+SIMD.Uint16x8.fromUint16x8Bits = function() {};
+SIMD.Uint32x4.fromUint16x8Bits = function() {};
+SIMD.Bool8x16.fromUint16x8Bits = function() {};
+SIMD.Bool16x8.fromUint16x8Bits = function() {};
+SIMD.Bool32x4.fromUint16x8Bits = function() {};
+SIMD.Bool64x2.fromUint16x8Bits = function() {};
+
+SIMD.Float32x4.fromUint32x4 = function() {};
+SIMD.Float64x2.fromUint32x4 = function() {};
+SIMD.Int8x16.fromUint32x4 = function() {};
+SIMD.Int16x8.fromUint32x4 = function() {};
+SIMD.Int32x4.fromUint32x4 = function() {};
+SIMD.Uint8x16.fromUint32x4 = function() {};
+SIMD.Uint16x8.fromUint32x4 = function() {};
+SIMD.Uint32x4.fromUint32x4 = function() {};
+SIMD.Bool8x16.fromUint32x4 = function() {};
+SIMD.Bool16x8.fromUint32x4 = function() {};
+SIMD.Bool32x4.fromUint32x4 = function() {};
+SIMD.Bool64x2.fromUint32x4 = function() {};
+
+SIMD.Float32x4.fromUint32x4Bits = function() {};
+SIMD.Float64x2.fromUint32x4Bits = function() {};
+SIMD.Int8x16.fromUint32x4Bits = function() {};
+SIMD.Int16x8.fromUint32x4Bits = function() {};
+SIMD.Int32x4.fromUint32x4Bits = function() {};
+SIMD.Uint8x16.fromUint32x4Bits = function() {};
+SIMD.Uint16x8.fromUint32x4Bits = function() {};
+SIMD.Uint32x4.fromUint32x4Bits = function() {};
+SIMD.Bool8x16.fromUint32x4Bits = function() {};
+SIMD.Bool16x8.fromUint32x4Bits = function() {};
+SIMD.Bool32x4.fromUint32x4Bits = function() {};
+SIMD.Bool64x2.fromUint32x4Bits = function() {};
+
+SIMD.Float32x4.fromUint8x16Bits = function() {};
+SIMD.Float64x2.fromUint8x16Bits = function() {};
+SIMD.Int8x16.fromUint8x16Bits = function() {};
+SIMD.Int16x8.fromUint8x16Bits = function() {};
+SIMD.Int32x4.fromUint8x16Bits = function() {};
+SIMD.Uint8x16.fromUint8x16Bits = function() {};
+SIMD.Uint16x8.fromUint8x16Bits = function() {};
+SIMD.Uint32x4.fromUint8x16Bits = function() {};
+SIMD.Bool8x16.fromUint8x16Bits = function() {};
+SIMD.Bool16x8.fromUint8x16Bits = function() {};
+SIMD.Bool32x4.fromUint8x16Bits = function() {};
+SIMD.Bool64x2.fromUint8x16Bits = function() {};
+
+SIMD.Float32x4.greaterThan = function() {};
+SIMD.Float64x2.greaterThan = function() {};
+SIMD.Int8x16.greaterThan = function() {};
+SIMD.Int16x8.greaterThan = function() {};
+SIMD.Int32x4.greaterThan = function() {};
+SIMD.Uint8x16.greaterThan = function() {};
+SIMD.Uint16x8.greaterThan = function() {};
+SIMD.Uint32x4.greaterThan = function() {};
+SIMD.Bool8x16.greaterThan = function() {};
+SIMD.Bool16x8.greaterThan = function() {};
+SIMD.Bool32x4.greaterThan = function() {};
+SIMD.Bool64x2.greaterThan = function() {};
+
+SIMD.Float32x4.greaterThanOrEqual = function() {};
+SIMD.Float64x2.greaterThanOrEqual = function() {};
+SIMD.Int8x16.greaterThanOrEqual = function() {};
+SIMD.Int16x8.greaterThanOrEqual = function() {};
+SIMD.Int32x4.greaterThanOrEqual = function() {};
+SIMD.Uint8x16.greaterThanOrEqual = function() {};
+SIMD.Uint16x8.greaterThanOrEqual = function() {};
+SIMD.Uint32x4.greaterThanOrEqual = function() {};
+SIMD.Bool8x16.greaterThanOrEqual = function() {};
+SIMD.Bool16x8.greaterThanOrEqual = function() {};
+SIMD.Bool32x4.greaterThanOrEqual = function() {};
+SIMD.Bool64x2.greaterThanOrEqual = function() {};
+
+SIMD.Float32x4.lessThan = function() {};
+SIMD.Float64x2.lessThan = function() {};
+SIMD.Int8x16.lessThan = function() {};
+SIMD.Int16x8.lessThan = function() {};
+SIMD.Int32x4.lessThan = function() {};
+SIMD.Uint8x16.lessThan = function() {};
+SIMD.Uint16x8.lessThan = function() {};
+SIMD.Uint32x4.lessThan = function() {};
+SIMD.Bool8x16.lessThan = function() {};
+SIMD.Bool16x8.lessThan = function() {};
+SIMD.Bool32x4.lessThan = function() {};
+SIMD.Bool64x2.lessThan = function() {};
+
+SIMD.Float32x4.lessThanOrEqual = function() {};
+SIMD.Float64x2.lessThanOrEqual = function() {};
+SIMD.Int8x16.lessThanOrEqual = function() {};
+SIMD.Int16x8.lessThanOrEqual = function() {};
+SIMD.Int32x4.lessThanOrEqual = function() {};
+SIMD.Uint8x16.lessThanOrEqual = function() {};
+SIMD.Uint16x8.lessThanOrEqual = function() {};
+SIMD.Uint32x4.lessThanOrEqual = function() {};
+SIMD.Bool8x16.lessThanOrEqual = function() {};
+SIMD.Bool16x8.lessThanOrEqual = function() {};
+SIMD.Bool32x4.lessThanOrEqual = function() {};
+SIMD.Bool64x2.lessThanOrEqual = function() {};
+
+SIMD.Float32x4.load = function() {};
+SIMD.Float64x2.load = function() {};
+SIMD.Int8x16.load = function() {};
+SIMD.Int16x8.load = function() {};
+SIMD.Int32x4.load = function() {};
+SIMD.Uint8x16.load = function() {};
+SIMD.Uint16x8.load = function() {};
+SIMD.Uint32x4.load = function() {};
+SIMD.Bool8x16.load = function() {};
+SIMD.Bool16x8.load = function() {};
+SIMD.Bool32x4.load = function() {};
+SIMD.Bool64x2.load = function() {};
+
+SIMD.Float32x4.max = function() {};
+SIMD.Float64x2.max = function() {};
+SIMD.Int8x16.max = function() {};
+SIMD.Int16x8.max = function() {};
+SIMD.Int32x4.max = function() {};
+SIMD.Uint8x16.max = function() {};
+SIMD.Uint16x8.max = function() {};
+SIMD.Uint32x4.max = function() {};
+SIMD.Bool8x16.max = function() {};
+SIMD.Bool16x8.max = function() {};
+SIMD.Bool32x4.max = function() {};
+SIMD.Bool64x2.max = function() {};
+
+SIMD.Float32x4.maxNum = function() {};
+SIMD.Float64x2.maxNum = function() {};
+SIMD.Int8x16.maxNum = function() {};
+SIMD.Int16x8.maxNum = function() {};
+SIMD.Int32x4.maxNum = function() {};
+SIMD.Uint8x16.maxNum = function() {};
+SIMD.Uint16x8.maxNum = function() {};
+SIMD.Uint32x4.maxNum = function() {};
+SIMD.Bool8x16.maxNum = function() {};
+SIMD.Bool16x8.maxNum = function() {};
+SIMD.Bool32x4.maxNum = function() {};
+SIMD.Bool64x2.maxNum = function() {};
+
+SIMD.Float32x4.min = function() {};
+SIMD.Float64x2.min = function() {};
+SIMD.Int8x16.min = function() {};
+SIMD.Int16x8.min = function() {};
+SIMD.Int32x4.min = function() {};
+SIMD.Uint8x16.min = function() {};
+SIMD.Uint16x8.min = function() {};
+SIMD.Uint32x4.min = function() {};
+SIMD.Bool8x16.min = function() {};
+SIMD.Bool16x8.min = function() {};
+SIMD.Bool32x4.min = function() {};
+SIMD.Bool64x2.min = function() {};
+
+SIMD.Float32x4.minNum = function() {};
+SIMD.Float64x2.minNum = function() {};
+SIMD.Int8x16.minNum = function() {};
+SIMD.Int16x8.minNum = function() {};
+SIMD.Int32x4.minNum = function() {};
+SIMD.Uint8x16.minNum = function() {};
+SIMD.Uint16x8.minNum = function() {};
+SIMD.Uint32x4.minNum = function() {};
+SIMD.Bool8x16.minNum = function() {};
+SIMD.Bool16x8.minNum = function() {};
+SIMD.Bool32x4.minNum = function() {};
+SIMD.Bool64x2.minNum = function() {};
+
+SIMD.Float32x4.mul = function() {};
+SIMD.Float64x2.mul = function() {};
+SIMD.Int8x16.mul = function() {};
+SIMD.Int16x8.mul = function() {};
+SIMD.Int32x4.mul = function() {};
+SIMD.Uint8x16.mul = function() {};
+SIMD.Uint16x8.mul = function() {};
+SIMD.Uint32x4.mul = function() {};
+SIMD.Bool8x16.mul = function() {};
+SIMD.Bool16x8.mul = function() {};
+SIMD.Bool32x4.mul = function() {};
+SIMD.Bool64x2.mul = function() {};
+
+SIMD.Float32x4.neg = function() {};
+SIMD.Float64x2.neg = function() {};
+SIMD.Int8x16.neg = function() {};
+SIMD.Int16x8.neg = function() {};
+SIMD.Int32x4.neg = function() {};
+SIMD.Uint8x16.neg = function() {};
+SIMD.Uint16x8.neg = function() {};
+SIMD.Uint32x4.neg = function() {};
+SIMD.Bool8x16.neg = function() {};
+SIMD.Bool16x8.neg = function() {};
+SIMD.Bool32x4.neg = function() {};
+SIMD.Bool64x2.neg = function() {};
+
+SIMD.Float32x4.not = function() {};
+SIMD.Float64x2.not = function() {};
+SIMD.Int8x16.not = function() {};
+SIMD.Int16x8.not = function() {};
+SIMD.Int32x4.not = function() {};
+SIMD.Uint8x16.not = function() {};
+SIMD.Uint16x8.not = function() {};
+SIMD.Uint32x4.not = function() {};
+SIMD.Bool8x16.not = function() {};
+SIMD.Bool16x8.not = function() {};
+SIMD.Bool32x4.not = function() {};
+SIMD.Bool64x2.not = function() {};
+
+SIMD.Float32x4.notEqual = function() {};
+SIMD.Float64x2.notEqual = function() {};
+SIMD.Int8x16.notEqual = function() {};
+SIMD.Int16x8.notEqual = function() {};
+SIMD.Int32x4.notEqual = function() {};
+SIMD.Uint8x16.notEqual = function() {};
+SIMD.Uint16x8.notEqual = function() {};
+SIMD.Uint32x4.notEqual = function() {};
+SIMD.Bool8x16.notEqual = function() {};
+SIMD.Bool16x8.notEqual = function() {};
+SIMD.Bool32x4.notEqual = function() {};
+SIMD.Bool64x2.notEqual = function() {};
+
+SIMD.Float32x4.or = function() {};
+SIMD.Float64x2.or = function() {};
+SIMD.Int8x16.or = function() {};
+SIMD.Int16x8.or = function() {};
+SIMD.Int32x4.or = function() {};
+SIMD.Uint8x16.or = function() {};
+SIMD.Uint16x8.or = function() {};
+SIMD.Uint32x4.or = function() {};
+SIMD.Bool8x16.or = function() {};
+SIMD.Bool16x8.or = function() {};
+SIMD.Bool32x4.or = function() {};
+SIMD.Bool64x2.or = function() {};
+
+SIMD.Float32x4.prototype.toSource = function() {};
+SIMD.Float64x2.prototype.toSource = function() {};
+SIMD.Int8x16.prototype.toSource = function() {};
+SIMD.Int16x8.prototype.toSource = function() {};
+SIMD.Int32x4.prototype.toSource = function() {};
+SIMD.Uint8x16.prototype.toSource = function() {};
+SIMD.Uint16x8.prototype.toSource = function() {};
+SIMD.Uint32x4.prototype.toSource = function() {};
+SIMD.Bool8x16.prototype.toSource = function() {};
+SIMD.Bool16x8.prototype.toSource = function() {};
+SIMD.Bool32x4.prototype.toSource = function() {};
+SIMD.Bool64x2.prototype.toSource = function() {};
+
+SIMD.Float32x4.reciprocalApproximation = function() {};
+SIMD.Float64x2.reciprocalApproximation = function() {};
+SIMD.Int8x16.reciprocalApproximation = function() {};
+SIMD.Int16x8.reciprocalApproximation = function() {};
+SIMD.Int32x4.reciprocalApproximation = function() {};
+SIMD.Uint8x16.reciprocalApproximation = function() {};
+SIMD.Uint16x8.reciprocalApproximation = function() {};
+SIMD.Uint32x4.reciprocalApproximation = function() {};
+SIMD.Bool8x16.reciprocalApproximation = function() {};
+SIMD.Bool16x8.reciprocalApproximation = function() {};
+SIMD.Bool32x4.reciprocalApproximation = function() {};
+SIMD.Bool64x2.reciprocalApproximation = function() {};
+
+SIMD.Float32x4.reciprocalSqrtApproximation = function() {};
+SIMD.Float64x2.reciprocalSqrtApproximation = function() {};
+SIMD.Int8x16.reciprocalSqrtApproximation = function() {};
+SIMD.Int16x8.reciprocalSqrtApproximation = function() {};
+SIMD.Int32x4.reciprocalSqrtApproximation = function() {};
+SIMD.Uint8x16.reciprocalSqrtApproximation = function() {};
+SIMD.Uint16x8.reciprocalSqrtApproximation = function() {};
+SIMD.Uint32x4.reciprocalSqrtApproximation = function() {};
+SIMD.Bool8x16.reciprocalSqrtApproximation = function() {};
+SIMD.Bool16x8.reciprocalSqrtApproximation = function() {};
+SIMD.Bool32x4.reciprocalSqrtApproximation = function() {};
+SIMD.Bool64x2.reciprocalSqrtApproximation = function() {};
+
+SIMD.Float32x4.replaceLane = function() {};
+SIMD.Float64x2.replaceLane = function() {};
+SIMD.Int8x16.replaceLane = function() {};
+SIMD.Int16x8.replaceLane = function() {};
+SIMD.Int32x4.replaceLane = function() {};
+SIMD.Uint8x16.replaceLane = function() {};
+SIMD.Uint16x8.replaceLane = function() {};
+SIMD.Uint32x4.replaceLane = function() {};
+SIMD.Bool8x16.replaceLane = function() {};
+SIMD.Bool16x8.replaceLane = function() {};
+SIMD.Bool32x4.replaceLane = function() {};
+SIMD.Bool64x2.replaceLane = function() {};
+
+SIMD.Float32x4.select = function() {};
+SIMD.Float64x2.select = function() {};
+SIMD.Int8x16.select = function() {};
+SIMD.Int16x8.select = function() {};
+SIMD.Int32x4.select = function() {};
+SIMD.Uint8x16.select = function() {};
+SIMD.Uint16x8.select = function() {};
+SIMD.Uint32x4.select = function() {};
+SIMD.Bool8x16.select = function() {};
+SIMD.Bool16x8.select = function() {};
+SIMD.Bool32x4.select = function() {};
+SIMD.Bool64x2.select = function() {};
+
+SIMD.Float32x4.shiftLeftByScalar = function() {};
+SIMD.Float64x2.shiftLeftByScalar = function() {};
+SIMD.Int8x16.shiftLeftByScalar = function() {};
+SIMD.Int16x8.shiftLeftByScalar = function() {};
+SIMD.Int32x4.shiftLeftByScalar = function() {};
+SIMD.Uint8x16.shiftLeftByScalar = function() {};
+SIMD.Uint16x8.shiftLeftByScalar = function() {};
+SIMD.Uint32x4.shiftLeftByScalar = function() {};
+SIMD.Bool8x16.shiftLeftByScalar = function() {};
+SIMD.Bool16x8.shiftLeftByScalar = function() {};
+SIMD.Bool32x4.shiftLeftByScalar = function() {};
+SIMD.Bool64x2.shiftLeftByScalar = function() {};
+
+SIMD.Float32x4.shiftRightByScalar = function() {};
+SIMD.Float64x2.shiftRightByScalar = function() {};
+SIMD.Int8x16.shiftRightByScalar = function() {};
+SIMD.Int16x8.shiftRightByScalar = function() {};
+SIMD.Int32x4.shiftRightByScalar = function() {};
+SIMD.Uint8x16.shiftRightByScalar = function() {};
+SIMD.Uint16x8.shiftRightByScalar = function() {};
+SIMD.Uint32x4.shiftRightByScalar = function() {};
+SIMD.Bool8x16.shiftRightByScalar = function() {};
+SIMD.Bool16x8.shiftRightByScalar = function() {};
+SIMD.Bool32x4.shiftRightByScalar = function() {};
+SIMD.Bool64x2.shiftRightByScalar = function() {};
+
+SIMD.Float32x4.shuffle = function() {};
+SIMD.Float64x2.shuffle = function() {};
+SIMD.Int8x16.shuffle = function() {};
+SIMD.Int16x8.shuffle = function() {};
+SIMD.Int32x4.shuffle = function() {};
+SIMD.Uint8x16.shuffle = function() {};
+SIMD.Uint16x8.shuffle = function() {};
+SIMD.Uint32x4.shuffle = function() {};
+SIMD.Bool8x16.shuffle = function() {};
+SIMD.Bool16x8.shuffle = function() {};
+SIMD.Bool32x4.shuffle = function() {};
+SIMD.Bool64x2.shuffle = function() {};
+
+SIMD.Float32x4.splat = function() {};
+SIMD.Float64x2.splat = function() {};
+SIMD.Int8x16.splat = function() {};
+SIMD.Int16x8.splat = function() {};
+SIMD.Int32x4.splat = function() {};
+SIMD.Uint8x16.splat = function() {};
+SIMD.Uint16x8.splat = function() {};
+SIMD.Uint32x4.splat = function() {};
+SIMD.Bool8x16.splat = function() {};
+SIMD.Bool16x8.splat = function() {};
+SIMD.Bool32x4.splat = function() {};
+SIMD.Bool64x2.splat = function() {};
+
+SIMD.Float32x4.sqrt = function() {};
+SIMD.Float64x2.sqrt = function() {};
+SIMD.Int8x16.sqrt = function() {};
+SIMD.Int16x8.sqrt = function() {};
+SIMD.Int32x4.sqrt = function() {};
+SIMD.Uint8x16.sqrt = function() {};
+SIMD.Uint16x8.sqrt = function() {};
+SIMD.Uint32x4.sqrt = function() {};
+SIMD.Bool8x16.sqrt = function() {};
+SIMD.Bool16x8.sqrt = function() {};
+SIMD.Bool32x4.sqrt = function() {};
+SIMD.Bool64x2.sqrt = function() {};
+
+SIMD.Float32x4.store = function() {};
+SIMD.Float64x2.store = function() {};
+SIMD.Int8x16.store = function() {};
+SIMD.Int16x8.store = function() {};
+SIMD.Int32x4.store = function() {};
+SIMD.Uint8x16.store = function() {};
+SIMD.Uint16x8.store = function() {};
+SIMD.Uint32x4.store = function() {};
+SIMD.Bool8x16.store = function() {};
+SIMD.Bool16x8.store = function() {};
+SIMD.Bool32x4.store = function() {};
+SIMD.Bool64x2.store = function() {};
+
+SIMD.Float32x4.sub = function() {};
+SIMD.Float64x2.sub = function() {};
+SIMD.Int8x16.sub = function() {};
+SIMD.Int16x8.sub = function() {};
+SIMD.Int32x4.sub = function() {};
+SIMD.Uint8x16.sub = function() {};
+SIMD.Uint16x8.sub = function() {};
+SIMD.Uint32x4.sub = function() {};
+SIMD.Bool8x16.sub = function() {};
+SIMD.Bool16x8.sub = function() {};
+SIMD.Bool32x4.sub = function() {};
+SIMD.Bool64x2.sub = function() {};
+
+SIMD.Float32x4.subSaturate = function() {};
+SIMD.Float64x2.subSaturate = function() {};
+SIMD.Int8x16.subSaturate = function() {};
+SIMD.Int16x8.subSaturate = function() {};
+SIMD.Int32x4.subSaturate = function() {};
+SIMD.Uint8x16.subSaturate = function() {};
+SIMD.Uint16x8.subSaturate = function() {};
+SIMD.Uint32x4.subSaturate = function() {};
+SIMD.Bool8x16.subSaturate = function() {};
+SIMD.Bool16x8.subSaturate = function() {};
+SIMD.Bool32x4.subSaturate = function() {};
+SIMD.Bool64x2.subSaturate = function() {};
+
+SIMD.Float32x4.swizzle = function() {};
+SIMD.Float64x2.swizzle = function() {};
+SIMD.Int8x16.swizzle = function() {};
+SIMD.Int16x8.swizzle = function() {};
+SIMD.Int32x4.swizzle = function() {};
+SIMD.Uint8x16.swizzle = function() {};
+SIMD.Uint16x8.swizzle = function() {};
+SIMD.Uint32x4.swizzle = function() {};
+SIMD.Bool8x16.swizzle = function() {};
+SIMD.Bool16x8.swizzle = function() {};
+SIMD.Bool32x4.swizzle = function() {};
+SIMD.Bool64x2.swizzle = function() {};
+
+SIMD.Float32x4.xor = function() {};
+SIMD.Float64x2.xor = function() {};
+SIMD.Int8x16.xor = function() {};
+SIMD.Int16x8.xor = function() {};
+SIMD.Int32x4.xor = function() {};
+SIMD.Uint8x16.xor = function() {};
+SIMD.Uint16x8.xor = function() {};
+SIMD.Uint32x4.xor = function() {};
+SIMD.Bool8x16.xor = function() {};
+SIMD.Bool16x8.xor = function() {};
+SIMD.Bool32x4.xor = function() {};
+SIMD.Bool64x2.xor = function() {};
diff --git a/src/deterministic.js b/src/deterministic.js
index ada07bb5017dd..da95835217d3e 100644
--- a/src/deterministic.js
+++ b/src/deterministic.js
@@ -19,7 +19,7 @@ function hashMemory(id) {
   for (var i = 0; i < len; i++) {
     ret = (ret*17 + HEAPU8[i])|0;
   }
-  printErr(id + ':' + ret);
+  return id + ':' + ret;
 }
 
 function hashString(s) {
diff --git a/src/embind/embind.js b/src/embind/embind.js
index b1a1f1deed693..8e34c779c29b6 100644
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -2280,13 +2280,13 @@ var LibraryEmbind = {
     var shift = getShiftFromSize(size);
     name = readLatin1String(name);
 
-    function constructor() {
+    function ctor() {
     }
-    constructor.values = {};
+    ctor.values = {};
 
     registerType(rawType, {
         name: name,
-        constructor: constructor,
+        constructor: ctor,
         'fromWireType': function(c) {
             return this.constructor.values[c];
         },
@@ -2297,7 +2297,7 @@ var LibraryEmbind = {
         'readValueFromPointer': enumReadValueFromPointer(name, shift, isSigned),
         destructorFunction: null,
     });
-    exposePublicSymbol(name, constructor);
+    exposePublicSymbol(name, ctor);
   },
 
   _embind_register_enum_value__deps: [
diff --git a/src/headless.js b/src/headless.js
index d329eb2ac98c8..0a8b2218949f1 100644
--- a/src/headless.js
+++ b/src/headless.js
@@ -145,8 +145,8 @@ var document = {
       case 'div': {
         return {
           appendChild: function() {},
-          requestFullScreen: function() {
-            return document.getElementById('canvas').requestFullScreen();
+          requestFullscreen: function() {
+            return document.getElementById('canvas').requestFullscreen();
           },
         };
       }
@@ -177,7 +177,7 @@ var document = {
     appendChild: function(){},
   },
   exitPointerLock: function(){},
-  cancelFullScreen: function(){},
+  exitFullscreen: function(){},
 };
 var alert = function(x) {
   print(x);
diff --git a/src/headlessCanvas.js b/src/headlessCanvas.js
index 25f7052e1f1f7..64d5ae2539703 100644
--- a/src/headlessCanvas.js
+++ b/src/headlessCanvas.js
@@ -607,7 +607,7 @@ function headlessCanvas() {
     eventListeners: {},
     addEventListener: function(){},
     removeEventListener: function(){},
-    requestFullScreen: function() {
+    requestFullscreen: function() {
       document.fullscreenElement = document.getElementById('canvas');
       window.setTimeout(function() {
         document.callEventListeners('fullscreenchange');
diff --git a/src/jsifier.js b/src/jsifier.js
index 281ac5df3e76c..4d6fcf36a9539 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -418,7 +418,7 @@ function JSify(data, functionsOnly) {
     if (PROXY_TO_WORKER) {
       print('if (ENVIRONMENT_IS_WORKER) {\n');
       print(read('webGLWorker.js'));
-      print(read('proxyWorker.js'));
+      print(processMacros(preprocess(read('proxyWorker.js'), 'proxyWorker.js')));
       print('}');
     }
     if (DETERMINISTIC) {
diff --git a/src/library.js b/src/library.js
index 7b21ac415b687..6970ebfb9a7d3 100644
--- a/src/library.js
+++ b/src/library.js
@@ -916,18 +916,24 @@ LibraryManager.library = {
     {{{ makeStructuralReturn(['ret', '0']) }}};
   },
 
+  llvm_ctpop_i32__asm: true,
+  llvm_ctpop_i32__sig: 'ii',
   llvm_ctpop_i32: function(x) {
-    var ret = 0;
-    while (x) {
-      if (x&1) ret++;
-      x >>>= 1;
-    }
-    return ret;
+    // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
+    // http://bits.stephan-brumme.com/countBits.html
+    x = x | 0;
+    x = x - ((x >>> 1) & 0x55555555) | 0;
+    x = (x & 0x33333333) + ((x >>> 2) & 0x33333333) | 0;
+    return (Math_imul((x + (x >>> 4) & 252645135 /* 0xF0F0F0F, but hits uglify parse bug? */), 0x1010101) >>> 24) | 0;
   },
 
   llvm_ctpop_i64__deps: ['llvm_ctpop_i32'],
+  llvm_ctpop_i64__asm: true,
+  llvm_ctpop_i64__sig: 'iii',
   llvm_ctpop_i64: function(l, h) {
-    return _llvm_ctpop_i32(l) + _llvm_ctpop_i32(h);
+    l = l | 0;
+    h = h | 0;
+    return (_llvm_ctpop_i32(l) | 0) + (_llvm_ctpop_i32(h) | 0) | 0;
   },
 
   llvm_trap: function() {
@@ -1035,7 +1041,8 @@ LibraryManager.library = {
       adjusted: ptr,
       type: type,
       destructor: destructor,
-      refcount: 0
+      refcount: 0,
+      caught: false
     };
     EXCEPTIONS.last = ptr;
     if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
@@ -1076,7 +1083,11 @@ LibraryManager.library = {
   },
   __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv', '$EXCEPTIONS'],
   __cxa_begin_catch: function(ptr) {
-    __ZSt18uncaught_exceptionv.uncaught_exception--;
+    var info = EXCEPTIONS.infos[ptr];
+    if (info && !info.caught) {
+      info.caught = true;
+      __ZSt18uncaught_exceptionv.uncaught_exception--;
+    }
     EXCEPTIONS.caught.push(ptr);
 #if EXCEPTION_DEBUG
 		Module.printErr('cxa_begin_catch ' + [ptr, 'stack', EXCEPTIONS.caught]);
@@ -1356,6 +1367,8 @@ LibraryManager.library = {
   llvm_log_f64: 'Math_log',
   llvm_exp_f32: 'Math_exp',
   llvm_exp_f64: 'Math_exp',
+  llvm_sin_f32: 'Math_sin',
+  llvm_sin_f64: 'Math_sin',
   llvm_trunc_f32: 'Math_trunc',
   llvm_trunc_f64: 'Math_trunc',
   llvm_floor_f32: 'Math_floor',
diff --git a/src/library_browser.js b/src/library_browser.js
index b610d133601d9..95b2ae50d80ec 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -3,7 +3,8 @@
 // Utilities for browser environments
 var LibraryBrowser = {
   $Browser__deps: ['emscripten_set_main_loop', 'emscripten_set_main_loop_timing'],
-  $Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas, vrDevice) { Browser.requestFullScreen(lockPointer, resizeCanvas, vrDevice) };\n' + // exports
+  $Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas, vrDevice) { Module.printErr("Module.requestFullScreen is deprecated. Please call Module.requestFullscreen instead."); Module["requestFullScreen"] = Module["requestFullscreen"]; Browser.requestFullScreen(lockPointer, resizeCanvas, vrDevice) };\n' + // exports
+                     'Module["requestFullscreen"] = function Module_requestFullscreen(lockPointer, resizeCanvas, vrDevice) { Browser.requestFullscreen(lockPointer, resizeCanvas, vrDevice) };\n' + // exports
                      'Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };\n' +
                      'Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' +
                      'Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };\n' +
@@ -74,7 +75,7 @@ var LibraryBrowser = {
         if (Module['postMainLoop']) Module['postMainLoop']();
       }
     },
-    isFullScreen: false,
+    isFullscreen: false,
     pointerLock: false,
     moduleContextCreatedCallbacks: [],
     workers: [],
@@ -291,8 +292,6 @@ var LibraryBrowser = {
         if (contextHandle) {
           ctx = GL.getContext(contextHandle).GLctx;
         }
-        // Set the background of the WebGL canvas to black
-        canvas.style.backgroundColor = "black";
       } else {
         ctx = canvas.getContext('2d');
       }
@@ -313,10 +312,10 @@ var LibraryBrowser = {
 
     destroyContext: function(canvas, useWebGL, setInModule) {},
 
-    fullScreenHandlersInstalled: false,
+    fullscreenHandlersInstalled: false,
     lockPointer: undefined,
     resizeCanvas: undefined,
-    requestFullScreen: function(lockPointer, resizeCanvas, vrDevice) {
+    requestFullscreen: function(lockPointer, resizeCanvas, vrDevice) {
       Browser.lockPointer = lockPointer;
       Browser.resizeCanvas = resizeCanvas;
       Browser.vrDevice = vrDevice;
@@ -325,24 +324,22 @@ var LibraryBrowser = {
       if (typeof Browser.vrDevice === 'undefined') Browser.vrDevice = null;
 
       var canvas = Module['canvas'];
-      function fullScreenChange() {
-        Browser.isFullScreen = false;
+      function fullscreenChange() {
+        Browser.isFullscreen = false;
         var canvasContainer = canvas.parentNode;
-        if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
-             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
-             document['fullScreenElement'] || document['fullscreenElement'] ||
-             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+        if ((document['fullscreenElement'] || document['mozFullScreenElement'] ||
+             document['msFullscreenElement'] || document['webkitFullscreenElement'] ||
              document['webkitCurrentFullScreenElement']) === canvasContainer) {
-          canvas.cancelFullScreen = document['cancelFullScreen'] ||
-                                    document['mozCancelFullScreen'] ||
-                                    document['webkitCancelFullScreen'] ||
-                                    document['msExitFullscreen'] ||
-                                    document['exitFullscreen'] ||
-                                    function() {};
-          canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+          canvas.exitFullscreen = document['exitFullscreen'] ||
+                                  document['cancelFullScreen'] ||
+                                  document['mozCancelFullScreen'] ||
+                                  document['msExitFullscreen'] ||
+                                  document['webkitCancelFullScreen'] ||
+                                  function() {};
+          canvas.exitFullscreen = canvas.exitFullscreen.bind(document);
           if (Browser.lockPointer) canvas.requestPointerLock();
-          Browser.isFullScreen = true;
-          if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          Browser.isFullscreen = true;
+          if (Browser.resizeCanvas) Browser.setFullscreenCanvasSize();
         } else {
           
           // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
@@ -351,16 +348,17 @@ var LibraryBrowser = {
           
           if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
         }
-        if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+        if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullscreen);
+        if (Module['onFullscreen']) Module['onFullscreen'](Browser.isFullscreen);
         Browser.updateCanvasDimensions(canvas);
       }
 
-      if (!Browser.fullScreenHandlersInstalled) {
-        Browser.fullScreenHandlersInstalled = true;
-        document.addEventListener('fullscreenchange', fullScreenChange, false);
-        document.addEventListener('mozfullscreenchange', fullScreenChange, false);
-        document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
-        document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+      if (!Browser.fullscreenHandlersInstalled) {
+        Browser.fullscreenHandlersInstalled = true;
+        document.addEventListener('fullscreenchange', fullscreenChange, false);
+        document.addEventListener('mozfullscreenchange', fullscreenChange, false);
+        document.addEventListener('webkitfullscreenchange', fullscreenChange, false);
+        document.addEventListener('MSFullscreenChange', fullscreenChange, false);
       }
 
       // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
@@ -369,19 +367,27 @@ var LibraryBrowser = {
       canvasContainer.appendChild(canvas);
 
       // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
-      canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+      canvasContainer.requestFullscreen = canvasContainer['requestFullscreen'] ||
                                           canvasContainer['mozRequestFullScreen'] ||
                                           canvasContainer['msRequestFullscreen'] ||
-                                         (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null) ||
-                                         (canvasContainer['webkitRequestFullscreen'] ? function() { canvasContainer['webkitRequestFullscreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+                                         (canvasContainer['webkitRequestFullscreen'] ? function() { canvasContainer['webkitRequestFullscreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null) ||
+                                         (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
 
       if (vrDevice) {
-        canvasContainer.requestFullScreen({ vrDisplay: vrDevice });
+        canvasContainer.requestFullscreen({ vrDisplay: vrDevice });
       } else {
-        canvasContainer.requestFullScreen();
+        canvasContainer.requestFullscreen();
       }
     },
 
+    requestFullScreen: function(lockPointer, resizeCanvas, vrDevice) {
+        Module.printErr('Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead.');
+        Browser.requestFullScreen = function(lockPointer, resizeCanvas, vrDevice) {
+          return Browser.requestFullscreen(lockPointer, resizeCanvas, vrDevice);
+        }
+        return Browser.requestFullscreen(lockPointer, resizeCanvas, vrDevice);
+    },
+
     nextRAF: 0,
 
     fakeRequestAnimationFrame: function(func) {
@@ -653,7 +659,7 @@ var LibraryBrowser = {
 
     windowedWidth: 0,
     windowedHeight: 0,
-    setFullScreenCanvasSize: function() {
+    setFullscreenCanvasSize: function() {
       // check if SDL is available   
       if (typeof SDL != "undefined") {
       	var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
@@ -690,10 +696,8 @@ var LibraryBrowser = {
           h = Math.round(w / Module['forcedAspectRatio']);
         }
       }
-      if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
-           document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
-           document['fullScreenElement'] || document['fullscreenElement'] ||
-           document['msFullScreenElement'] || document['msFullscreenElement'] ||
+      if (((document['fullscreenElement'] || document['mozFullScreenElement'] ||
+           document['msFullscreenElement'] || document['webkitFullscreenElement'] ||
            document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
          var factor = Math.min(screen.width / w, screen.height / h);
          w = Math.round(w * factor);
@@ -1160,6 +1164,14 @@ var LibraryBrowser = {
       GL.newRenderingFrameStarted();
 #endif
 
+#if OFFSCREENCANVAS_SUPPORT
+      // If the current GL context is an OffscreenCanvas, but it was initialized with implicit swap mode, perform the swap
+      // in behalf of the user.
+      if (typeof GL !== 'undefined' && GL.currentContext && !GL.currentContext.attributes.explicitSwapControl && GL.currentContext.GLctx.commit) {
+        GL.currentContext.GLctx.commit();
+      }
+#endif
+
       if (Browser.mainLoop.method === 'timeout' && Module.ctx) {
         Module.printErr('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!');
         Browser.mainLoop.method = ''; // just warn once per call to set main loop
@@ -1281,7 +1293,7 @@ var LibraryBrowser = {
     var canvas = Module['canvas'];
     {{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}};
     {{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}};
-    {{{ makeSetValue('isFullscreen', '0', 'Browser.isFullScreen ? 1 : 0', 'i32') }}};
+    {{{ makeSetValue('isFullscreen', '0', 'Browser.isFullscreen ? 1 : 0', 'i32') }}};
   },
 
   emscripten_create_worker: function(url) {
diff --git a/src/library_fs.js b/src/library_fs.js
index b73536ace7bda..93ed916548816 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -795,8 +795,9 @@ mergeInto(LibraryManager.library, {
       var node = FS.lookupNode(parent, name);
       var err = FS.mayDelete(parent, name, false);
       if (err) {
-        // POSIX says unlink should set EPERM, not EISDIR
-        if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+        // According to POSIX, we should map EISDIR to EPERM, but
+        // we instead do what Linux does (and we must, as we use
+        // the musl linux libc).
         throw new FS.ErrnoError(err);
       }
       if (!parent.node_ops.unlink) {
diff --git a/src/library_gl.js b/src/library_gl.js
index 68423fead3afe..56070e8b92559 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -23,6 +23,7 @@ var LibraryGL = {
     vaos: [],
     contexts: [],
     currentContext: null,
+    offscreenCanvases: {}, // DOM ID -> OffscreenCanvas mappings of <canvas> elements that have their rendering control transferred to offscreen.
 #if USE_WEBGL2
     queries: [],
     samplers: [],
@@ -528,6 +529,7 @@ var LibraryGL = {
       var handle = GL.getNewId(GL.contexts);
       var context = {
         handle: handle,
+        attributes: webGLContextAttributes,
         version: webGLContextAttributes.majorVersion,
         GLctx: ctx
       };
@@ -715,9 +717,22 @@ var LibraryGL = {
     switch(name_) {
       case 0x1F00 /* GL_VENDOR */:
       case 0x1F01 /* GL_RENDERER */:
-      case 0x1F02 /* GL_VERSION */:
+      case 0x9245 /* UNMASKED_VENDOR_WEBGL */:
+      case 0x9246 /* UNMASKED_RENDERER_WEBGL */:
         ret = allocate(intArrayFromString(GLctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
         break;
+      case 0x1F02 /* GL_VERSION */:
+        var glVersion = GLctx.getParameter(GLctx.VERSION);
+        // return GLES version string corresponding to the version of the WebGL context
+#if USE_WEBGL2
+        if (GLctx.canvas.GLctxObject.version >= 2) glVersion = 'OpenGL ES 3.0 (' + glVersion + ')';
+        else
+#endif
+        {
+          glVersion = 'OpenGL ES 2.0 (' + glVersion + ')';
+        }
+        ret = allocate(intArrayFromString(glVersion), 'i8', ALLOC_NORMAL);
+        break;
       case 0x1F03 /* GL_EXTENSIONS */:
         var exts = GLctx.getSupportedExtensions();
         var gl_exts = [];
@@ -729,11 +744,13 @@ var LibraryGL = {
         break;
       case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */:
         var glslVersion = GLctx.getParameter(GLctx.SHADING_LANGUAGE_VERSION);
-        // Map WebGL GL_SHADING_LANGUAGE_VERSION string format to GLES format.
-        if (glslVersion.indexOf('WebGL GLSL ES 1.0') != -1) glslVersion = 'OpenGL ES GLSL ES 1.00 (WebGL)';
-#if USE_WEBGL2
-        else if (glslVersion.indexOf('WebGL GLSL ES 3.00') != -1) glslVersion = 'OpenGL ES GLSL ES 3.00 (WebGL 2)';
-#endif
+        // extract the version number 'N.M' from the string 'WebGL GLSL ES N.M ...'
+        var ver_re = /^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;
+        var ver_num = glslVersion.match(ver_re);
+        if (ver_num !== null) {
+          if (ver_num[1].length == 3) ver_num[1] = ver_num[1] + '0'; // ensure minor version has 2 digits
+          glslVersion = 'OpenGL ES GLSL ES ' + ver_num[1] + ' (' + glslVersion + ')';
+        }
         ret = allocate(intArrayFromString(glslVersion), 'i8', ALLOC_NORMAL);
         break;
       default:
@@ -799,6 +816,14 @@ var LibraryGL = {
         var exts = GLctx.getSupportedExtensions();
         ret = 2*exts.length; // each extension is duplicated, first in unprefixed WebGL form, and then a second time with "GL_" prefix.
         break;
+      case 0x821B: // GL_MAJOR_VERSION
+      case 0x821C: // GL_MINOR_VERSION
+        if (GLctx.canvas.GLctxObject.version < 2) {
+          GL.recordError(0x0500); // GL_INVALID_ENUM
+          return;
+        }
+        ret = name_ == 0x821B ? 3 : 0; // return version 3.0
+        break;
 #endif
     }
 
@@ -3572,6 +3597,16 @@ var LibraryGL = {
                                     GL.textures[texture], level);
   },
 
+#if USE_WEBGL2
+  glFramebufferTextureLayer__sig: 'viiiii',
+  glFramebufferTextureLayer: function(target, attachment, texture, level, layer) {
+#if GL_ASSERTIONS
+    GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTextureLayer', 'texture');
+#endif
+    GLctx.framebufferTextureLayer(target, attachment, GL.textures[texture], level, layer);
+  },
+#endif
+
   glGetFramebufferAttachmentParameteriv__sig: 'viiii',
   glGetFramebufferAttachmentParameteriv: function(target, attachment, pname, params) {
     var result = GLctx.getFramebufferAttachmentParameter(target, attachment, pname);
@@ -7334,7 +7369,6 @@ var LibraryGL = {
   glRenderbufferStorageMultisample__sig: 'viiiii',
   glCopyTexSubImage3D__sig: 'viiiiiiiii',
   glClearBufferfi__sig: 'viifi',
-  glFramebufferTextureLayer__sig: 'viiiii',
 #endif
 };
 
@@ -7355,7 +7389,7 @@ var glFuncs = [[0, 'finish flush'],
 glFuncs[0][1] += ' endTransformFeedback pauseTransformFeedback resumeTransformFeedback';
 glFuncs[1][1] += ' beginTransformFeedback readBuffer endQuery';
 glFuncs[4][1] += ' clearBufferfi';
-glFuncs[5][1] += ' vertexAttribI4i vertexAttribI4ui copyBufferSubData texStorage2D renderbufferStorageMultisample framebufferTextureLayer';
+glFuncs[5][1] += ' vertexAttribI4i vertexAttribI4ui copyBufferSubData texStorage2D renderbufferStorageMultisample';
 // TODO: Removed as a workaround, see https://bugzilla.mozilla.org/show_bug.cgi?id=1202427
 //glFuncs[6][1] += ' drawRangeElements';
 glFuncs[6][1] += ' texStorage3D';
diff --git a/src/library_glfw.js b/src/library_glfw.js
index 1888550823752..6451e42fefc9e 100644
--- a/src/library_glfw.js
+++ b/src/library_glfw.js
@@ -507,7 +507,7 @@ var LibraryGLFW = {
       var resizeNeeded = true;
 
       // If the client is requestiong fullscreen mode
-      if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
+      if (document["fullscreen"] || document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
         GLFW.active.storedX = GLFW.active.x;
         GLFW.active.storedY = GLFW.active.y;
         GLFW.active.storedWidth = GLFW.active.width;
@@ -568,16 +568,23 @@ var LibraryGLFW = {
 #endif
     },
 
-    requestFullScreen: function() {
+    requestFullscreen: function() {
       var RFS = Module["canvas"]['requestFullscreen'] ||
-                Module["canvas"]['requestFullScreen'] ||
                 Module["canvas"]['mozRequestFullScreen'] ||
                 Module["canvas"]['webkitRequestFullScreen'] ||
                 (function() {});
       RFS.apply(Module["canvas"], []);
     },
 
-    cancelFullScreen: function() {
+    requestFullScreen: function() {
+      Module.printErr('GLFW.requestFullScreen() is deprecated. Please call GLFW.requestFullscreen instead.');
+      GLFW.requestFullScreen = function() {
+        return GLFW.requestFullscreen();
+      }
+      return GLFW.requestFullscreen();
+    },
+
+    exitFullscreen: function() {
       var CFS = document['exitFullscreen'] ||
                 document['cancelFullScreen'] ||
                 document['mozCancelFullScreen'] ||
@@ -586,6 +593,14 @@ var LibraryGLFW = {
       CFS.apply(document, []);
     },
 
+    cancelFullScreen: function() {
+      Module.printErr('GLFW.cancelFullScreen() is deprecated. Please call GLFW.exitFullscreen instead.');
+      GLFW.cancelFullScreen = function() {
+        return GLFW.exitFullscreen();
+      }
+      return GLFW.exitFullscreen();
+    },
+
     getTime: function() {
       return _emscripten_get_now() / 1000;
     },
@@ -777,9 +792,9 @@ var LibraryGLFW = {
 
       if (GLFW.active.id == win.id) {
         if (width == screen.width && height == screen.height) {
-          GLFW.requestFullScreen();
+          GLFW.requestFullscreen();
         } else {
-          GLFW.cancelFullScreen();
+          GLFW.exitFullscreen();
           Browser.setCanvasSize(width, height);
           win.width = width;
           win.height = height;
@@ -809,7 +824,7 @@ var LibraryGLFW = {
       if (width <= 0 || height <= 0) return 0;
 
       if (monitor) {
-        GLFW.requestFullScreen();
+        GLFW.requestFullscreen();
       } else {
         Browser.setCanvasSize(width, height);
       }
diff --git a/src/library_glut.js b/src/library_glut.js
index 387d0fd70ccdb..de76ba8cd8fe4 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -249,19 +249,19 @@ var LibraryGLUT = {
 
     // TODO add fullscreen API ala:
     // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
-    onFullScreenEventChange: function(event) {
+    onFullscreenEventChange: function(event) {
       var width;
       var height;
-      if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
+      if (document["fullscreen"] || document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
         width = screen["width"];
         height = screen["height"];
       } else {
         width = GLUT.windowWidth;
         height = GLUT.windowHeight;
         // TODO set position
-        document.removeEventListener('fullscreenchange', GLUT.onFullScreenEventChange, true);
-        document.removeEventListener('mozfullscreenchange', GLUT.onFullScreenEventChange, true);
-        document.removeEventListener('webkitfullscreenchange', GLUT.onFullScreenEventChange, true);
+        document.removeEventListener('fullscreenchange', GLUT.onFullscreenEventChange, true);
+        document.removeEventListener('mozfullscreenchange', GLUT.onFullscreenEventChange, true);
+        document.removeEventListener('webkitfullscreenchange', GLUT.onFullscreenEventChange, true);
       }
       Browser.setCanvasSize(width, height);
       /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */
@@ -272,22 +272,33 @@ var LibraryGLUT = {
       _glutPostRedisplay();
     },
 
+    requestFullscreen: function() {
+      Browser.requestFullscreen(/*lockPointer=*/false, /*resieCanvas=*/false);
+    },
+
     requestFullScreen: function() {
-      var RFS = Module["canvas"]['requestFullscreen'] ||
-                Module["canvas"]['requestFullScreen'] ||
-                Module["canvas"]['mozRequestFullScreen'] ||
-                Module["canvas"]['webkitRequestFullScreen'] ||
-                (function() {});
-      RFS.apply(Module["canvas"], []);
+      Module.printErr('GLUT.requestFullScreen() is deprecated. Please call GLUT.requestFullscreen instead.');
+      GLUT.requestFullScreen = function() {
+        return GLUT.requestFullscreen();
+      }
+      return GLUT.requestFullscreen();
     },
 
-    cancelFullScreen: function() {
+    exitFullscreen: function() {
       var CFS = document['exitFullscreen'] ||
                 document['cancelFullScreen'] ||
                 document['mozCancelFullScreen'] ||
                 document['webkitCancelFullScreen'] ||
-                (function() {});
+          (function() {});
       CFS.apply(document, []);
+    },
+
+    cancelFullScreen: function() {
+      Module.printErr('GLUT.cancelFullScreen() is deprecated. Please call GLUT.exitFullscreen instead.');
+      GLUT.cancelFullScreen = function() {
+        return GLUT.exitFullscreen();
+      }
+      return GLUT.exitFullscreen();
     }
   },
 
@@ -530,7 +541,7 @@ var LibraryGLUT = {
 
   glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'],
   glutReshapeWindow: function(width, height) {
-    GLUT.cancelFullScreen();
+    GLUT.exitFullscreen();
     Browser.setCanvasSize(width, height);
     if (GLUT.reshapeFunc) {
       Runtime.dynCall('vii', GLUT.reshapeFunc, [width, height]);
@@ -540,7 +551,7 @@ var LibraryGLUT = {
 
   glutPositionWindow__deps: ['$GLUT', 'glutPostRedisplay'],
   glutPositionWindow: function(x, y) {
-    GLUT.cancelFullScreen();
+    GLUT.exitFullscreen();
     /* TODO */
     _glutPostRedisplay();
   },
@@ -551,10 +562,10 @@ var LibraryGLUT = {
     GLUT.windowY = 0; // TODO
     GLUT.windowWidth  = Module['canvas'].width;
     GLUT.windowHeight = Module['canvas'].height;
-    document.addEventListener('fullscreenchange', GLUT.onFullScreenEventChange, true);
-    document.addEventListener('mozfullscreenchange', GLUT.onFullScreenEventChange, true);
-    document.addEventListener('webkitfullscreenchange', GLUT.onFullScreenEventChange, true);
-    GLUT.requestFullScreen();
+    document.addEventListener('fullscreenchange', GLUT.onFullscreenEventChange, true);
+    document.addEventListener('mozfullscreenchange', GLUT.onFullscreenEventChange, true);
+    document.addEventListener('webkitfullscreenchange', GLUT.onFullscreenEventChange, true);
+    GLUT.requestFullscreen();
   },
 
   glutInitDisplayMode: function(mode) {
diff --git a/src/library_html5.js b/src/library_html5.js
index 9b18f38fbbbf8..b7db8da9a0a1c 100644
--- a/src/library_html5.js
+++ b/src/library_html5.js
@@ -307,7 +307,7 @@ var LibraryJSEvents = {
         var e = event || window.event;
         JSEvents.fillMouseEventData(JSEvents.wheelEvent, e, target);
         {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaX, 'e["wheelDeltaX"]', 'double') }}};
-        {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaY, '-e["wheelDeltaY"] /* Invert to unify direction with the DOM Level 3 wheel event. */', 'double') }}};
+        {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaY, '-(e["wheelDeltaY"] ? e["wheelDeltaY"] : e["wheelDelta"]) /* 1. Invert to unify direction with the DOM Level 3 wheel event. 2. MSIE does not provide wheelDeltaY, so wheelDelta is used as a fallback. */', 'double') }}};
         {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaZ, '0 /* Not available */', 'double') }}};
         {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaMode, '0 /* DOM_DELTA_PIXEL */', 'i32') }}};
         var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.wheelEvent, userData]);
@@ -546,7 +546,7 @@ var LibraryJSEvents = {
     },
 
     fullscreenEnabled: function() {
-      return document.fullscreenEnabled || document.mozFullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled;
+      return document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled;
     },
     
     fillFullscreenChangeEventData: function(eventStruct, e) {
@@ -732,6 +732,33 @@ var LibraryJSEvents = {
       JSEvents.registerOrRemoveHandler(eventHandler);
     },
 
+    registerPointerlockErrorEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) {
+      if (!target) {
+        target = document; // Pointer lock events need to be captured from 'document' by default instead of 'window'
+      } else {
+        target = JSEvents.findEventTarget(target);
+      }
+
+      var handlerFunc = function(event) {
+        var e = event || window.event;
+
+        var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, 0, userData]);
+        if (shouldCancel) {
+          e.preventDefault();
+        }
+      };
+
+      var eventHandler = {
+        target: target,
+        allowsDeferredCalls: false,
+        eventTypeString: eventTypeString,
+        callbackfunc: callbackfunc,
+        handlerFunc: handlerFunc,
+        useCapture: useCapture
+      };
+      JSEvents.registerOrRemoveHandler(eventHandler);
+    },
+
     requestPointerLock: function(target) {
       if (target.requestPointerLock) {
         target.requestPointerLock();
@@ -1545,6 +1572,22 @@ var LibraryJSEvents = {
     return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}};
   },
 
+  emscripten_set_pointerlockerror_callback: function(target, userData, useCapture, callbackfunc) {
+    if (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) {
+      return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}};
+    }
+    if (!target) target = document;
+    else {
+      target = JSEvents.findEventTarget(target);
+      if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}};
+    }
+    JSEvents.registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "pointerlockerror");
+    JSEvents.registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "mozpointerlockerror");
+    JSEvents.registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "webkitpointerlockerror");
+    JSEvents.registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "mspointerlockerror");
+    return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}};
+  },
+
   emscripten_get_pointerlock_status: function(pointerlockStatus) {
     if (pointerlockStatus) JSEvents.fillPointerlockChangeEventData(pointerlockStatus);
     if (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) {
@@ -1726,6 +1769,7 @@ var LibraryJSEvents = {
     {{{ makeSetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.majorVersion, 1, 'i32') }}};
     {{{ makeSetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.minorVersion, 0, 'i32') }}};
     {{{ makeSetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.enableExtensionsByDefault, 1, 'i32') }}};
+    {{{ makeSetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.explicitSwapControl, 0, 'i32') }}};
   },
 
   emscripten_webgl_create_context__deps: ['$GL'],
@@ -1742,13 +1786,47 @@ var LibraryJSEvents = {
     contextAttributes.majorVersion = {{{ makeGetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.majorVersion, 'i32') }}};
     contextAttributes.minorVersion = {{{ makeGetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.minorVersion, 'i32') }}};
     var enableExtensionsByDefault = {{{ makeGetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.enableExtensionsByDefault, 'i32') }}};
+    contextAttributes.explicitSwapControl = {{{ makeGetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.explicitSwapControl, 'i32') }}};
 
-    if (!target) {
-      target = Module['canvas'];
+    target = target ? Pointer_stringify(target) : '#canvas';
+    var canvas;
+    if (target) {
+      if (target === '#canvas' && Module['canvas']) {
+        target = Module['canvas'].id;
+      }
+      canvas = GL.offscreenCanvases[target] || JSEvents.findEventTarget(target);
     } else {
-      target = JSEvents.findEventTarget(target);
+      canvas = GL.offscreenCanvases[Module['canvas'].id] || Module['canvas'];
+    }
+    if (!canvas) {
+#if GL_DEBUG
+      console.error('emscripten_webgl_create_context failed: Unknown target!');
+#endif
+      return 0;
     }
-    var contextHandle = GL.createContext(target, contextAttributes);
+#if OFFSCREENCANVAS_SUPPORT
+    if (contextAttributes.explicitSwapControl) {
+      var supportsOffscreenCanvas = canvas.transferControlToOffscreen || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas);
+      if (!supportsOffscreenCanvas) {
+#if GL_DEBUG
+        console.error('emscripten_webgl_create_context failed: OffscreenCanvas is not supported!');
+#endif
+        return 0;
+      }
+      if (canvas.transferControlToOffscreen) {
+        GL.offscreenCanvases[canvas.id] = canvas.transferControlToOffscreen();
+        GL.offscreenCanvases[canvas.id].id = canvas.id;
+        canvas = GL.offscreenCanvases[canvas.id];
+      }
+    }
+#else
+    if (contextAttributes.explicitSwapControl) {
+      console.error('emscripten_webgl_create_context failed: explicitSwapControl is not supported, please rebuild with -s OFFSCREENCANVAS_SUPPORT=1 to enable targeting the experimental OffscreenCanvas specification!');
+      return 0;
+    }
+#endif
+
+    var contextHandle = GL.createContext(canvas, contextAttributes);
     return contextHandle;
   },
 
@@ -1761,6 +1839,29 @@ var LibraryJSEvents = {
     return GL.currentContext ? GL.currentContext.handle : 0;
   },
 
+  emscripten_webgl_commit_frame: function() {
+    if (!GL.currentContext || !GL.currentContext.GLctx) {
+#if GL_DEBUG
+      console.error('emscripten_webgl_commit_frame() failed: no GL context set current via emscripten_webgl_make_context_current()!');
+#endif
+      return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}};
+    }
+    if (!GL.currentContext.GLctx.commit) {
+#if GL_DEBUG
+      console.error('emscripten_webgl_commit_frame() failed: OffscreenCanvas is not supported by the current GL context!');
+#endif
+      return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}};
+    }
+    if (!GL.currentContext.attributes.explicitSwapControl) {
+#if GL_DEBUG
+      console.error('emscripten_webgl_commit_frame() cannot be called for canvases with implicit swap control mode!');
+#endif
+      return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}};
+    }
+    GL.currentContext.GLctx.commit();
+    return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}};
+  },
+
   emscripten_webgl_destroy_context: function(contextHandle) {
     GL.deleteContext(contextHandle);
   },
diff --git a/src/library_idbfs.js b/src/library_idbfs.js
index afb4d60609465..3b8970d577338 100644
--- a/src/library_idbfs.js
+++ b/src/library_idbfs.js
@@ -42,6 +42,9 @@ mergeInto(LibraryManager.library, {
       } catch (e) {
         return callback(e);
       }
+      if (!req) {
+        return callback("Unable to connect to IndexedDB");
+      }
       req.onupgradeneeded = function(e) {
         var db = e.target.result;
         var transaction = e.target.transaction;
diff --git a/src/library_nodefs.js b/src/library_nodefs.js
index 28d1c5f0692fe..b833ccb7106de 100644
--- a/src/library_nodefs.js
+++ b/src/library_nodefs.js
@@ -73,6 +73,8 @@ mergeInto(LibraryManager.library, {
       4098/*O_RDWR|O_DSYNC*/: 'rs+'
     },
     flagsToPermissionString: function(flags) {
+      flags &= ~010000000 /*O_PATH*/; // Ignore this flag from musl, otherwise node.js fails to open the file.
+      flags &= ~00004000 /*O_NONBLOCK*/; // Ignore this flag from musl, otherwise node.js fails to open the file.
       flags &= ~0100000 /*O_LARGEFILE*/; // Ignore this flag from musl, otherwise node.js fails to open the file.
       flags &= ~02000000 /*O_CLOEXEC*/; // Some applications may pass it; it makes no sense for a single process.
       if (flags in NODEFS.flagsToPermissionStringMap) {
diff --git a/src/library_pthread.js b/src/library_pthread.js
index 7888d2bdcbd62..3400113b6550c 100644
--- a/src/library_pthread.js
+++ b/src/library_pthread.js
@@ -50,7 +50,7 @@ var LibraryPThread = {
       Atomics.store(HEAPU32, (pthreadPtr + {{{ C_STRUCTS.pthread.profilerBlock }}} ) >> 2, profilerBlock);
 
       // Zero fill contents at startup.
-      for(var i = 0; i < {{{ C_STRUCTS.thread_profiler_block.__size__ }}}; i += 4) Atomics.store(HEAPU32, (profilerBlock + i) >> 2, 0);
+      for (var i = 0; i < {{{ C_STRUCTS.thread_profiler_block.__size__ }}}; i += 4) Atomics.store(HEAPU32, (profilerBlock + i) >> 2, 0);
       Atomics.store(HEAPU32, (pthreadPtr + {{{ C_STRUCTS.thread_profiler_block.currentStatusStartTime }}} ) >> 2, performance.now());
     },
 
@@ -149,6 +149,31 @@ var LibraryPThread = {
         __register_pthread_ptr(0, 0, 0); // Unregister the thread block also inside the asm.js scope.
         threadInfoStruct = 0;
         if (ENVIRONMENT_IS_PTHREAD) {
+          // This worker no longer owns any WebGL OffscreenCanvases, so transfer them back to parent thread.
+          var transferList = [];
+
+#if OFFSCREENCANVAS_SUPPORT
+          var offscreenCanvases = {};
+          if (typeof GL !== 'undefined') {
+            offscreenCanvases = GL.offscreenCanvases;
+            GL.offscreenCanvases = {};
+          }
+          for (var i in offscreenCanvases) {
+            if (offscreenCanvases[i]) transferList.push(offscreenCanvases[i]);
+          }
+          if (transferList.length > 0) {
+            postMessage({
+                targetThread: parentThreadId,
+                cmd: 'objectTransfer',
+                offscreenCanvases: offscreenCanvases,
+                moduleCanvasId: Module['canvas'].id, // moduleCanvasId specifies which canvas is denoted via the "#canvas" shorthand.
+                transferList: transferList
+              }, transferList);
+          }
+          // And clear the OffscreenCanvases from lingering around in this Worker as well.
+          delete Module['canvas'];
+#endif
+
           postMessage({ cmd: 'exit' });
         }
       }
@@ -204,6 +229,18 @@ var LibraryPThread = {
       if (pthread.worker) pthread.worker.pthread = null;
     },
 
+    receiveObjectTransfer: function(data) {
+#if OFFSCREENCANVAS_SUPPORT
+      if (typeof GL !== 'undefined') {
+        for (var i in data.offscreenCanvases) {
+          GL.offscreenCanvases[i] = data.offscreenCanvases[i];
+          GL.offscreenCanvases[i].id = i; // https://bugzilla.mozilla.org/show_bug.cgi?id=1281909
+        }
+        if (!Module['canvas']) Module['canvas'] = GL.offscreenCanvases[data.moduleCanvasId];
+      }
+#endif
+    },
+
     // Allocates the given amount of new web workers and stores them in the pool of unused workers.
     // onFinishedLoading: A callback function that will be called once all of the workers have been initialized and are
     //                    ready to host pthreads. Optional. This is used to mitigate bug https://bugzilla.mozilla.org/show_bug.cgi?id=1049079
@@ -222,6 +259,17 @@ var LibraryPThread = {
         var worker = new Worker(pthreadMainJs);
 
         worker.onmessage = function(e) {
+          // If this message is intended to a recipient that is not the main thread, forward it to the target thread.
+          if (e.data.targetThread && e.data.targetThread != _pthread_self()) {
+            var thread = PThread.pthreads[e.data.targetThread];
+            if (thread) {
+              thread.worker.postMessage(e.data, e.data.transferList);
+            } else {
+              console.error('Internal error! Worker sent a message "' + e.data.cmd + '" to target pthread ' + e.data.targetThread + ', but that thread no longer exists!');
+            }
+            return;
+          }
+
           if (e.data.cmd === 'processQueuedMainThreadWork') {
             // TODO: Must post message to main Emscripten thread in PROXY_TO_WORKER mode.
             _emscripten_main_thread_process_queued_calls();
@@ -242,16 +290,18 @@ var LibraryPThread = {
             Module['print']('Thread ' + e.data.threadId + ': ' + e.data.text);
           } else if (e.data.cmd === 'printErr') {
             Module['printErr']('Thread ' + e.data.threadId + ': ' + e.data.text);
-          } else if (e.data.cmd == 'alert') {
+          } else if (e.data.cmd === 'alert') {
             alert('Thread ' + e.data.threadId + ': ' + e.data.text);
           } else if (e.data.cmd === 'exit') {
-            // todo 
+            // currently no-op
           } else if (e.data.cmd === 'cancelDone') {
-              PThread.freeThreadData(worker.pthread);
-              worker.pthread = undefined; // Detach the worker from the pthread object, and return it to the worker pool as an unused worker.
-              PThread.unusedWorkerPool.push(worker);
-              // TODO: Free if detached.
-              PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker.pthread), 1); // Not a running Worker anymore.
+            PThread.freeThreadData(worker.pthread);
+            worker.pthread = undefined; // Detach the worker from the pthread object, and return it to the worker pool as an unused worker.
+            PThread.unusedWorkerPool.push(worker);
+            // TODO: Free if detached.
+            PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker.pthread), 1); // Not a running Worker anymore.
+          } else if (e.data.cmd === 'objectTransfer') {
+            PThread.receiveObjectTransfer(e.data);
           } else {
             Module['printErr']("worker sent an unknown command " + e.data.cmd);
           }
@@ -292,7 +342,7 @@ var LibraryPThread = {
   },
 
   _kill_thread: function(pthread_ptr) {
-    if (ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _kill_thread() can only ever be called from main JS thread!';
+    if (ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _kill_thread() can only ever be called from main application thread!';
     if (!pthread_ptr) throw 'Internal Error! Null pthread_ptr in _kill_thread!';
     {{{ makeSetValue('pthread_ptr', C_STRUCTS.pthread.self, 0, 'i32') }}};
     var pthread = PThread.pthreads[pthread_ptr];
@@ -305,7 +355,7 @@ var LibraryPThread = {
   },
 
   _cleanup_thread: function(pthread_ptr) {
-    if (ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _cleanup_thread() can only ever be called from main JS thread!';
+    if (ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _cleanup_thread() can only ever be called from main application thread!';
     if (!pthread_ptr) throw 'Internal Error! Null pthread_ptr in _cleanup_thread!';
     {{{ makeSetValue('pthread_ptr', C_STRUCTS.pthread.self, 0, 'i32') }}};
     var pthread = PThread.pthreads[pthread_ptr];
@@ -317,14 +367,14 @@ var LibraryPThread = {
   },
 
   _cancel_thread: function(pthread_ptr) {
-    if (ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _cancel_thread() can only ever be called from main JS thread!';
+    if (ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _cancel_thread() can only ever be called from main application thread!';
     if (!pthread_ptr) throw 'Internal Error! Null pthread_ptr in _cancel_thread!';
     var pthread = PThread.pthreads[pthread_ptr];
     pthread.worker.postMessage({ cmd: 'cancel' });
   },
 
   _spawn_thread: function(threadParams) {
-    if (ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _spawn_thread() can only ever be called from main JS thread!';
+    if (ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! _spawn_thread() can only ever be called from main application thread!';
 
     var worker = PThread.getNewWorker();
     if (worker.pthread !== undefined) throw 'Internal error!';
@@ -375,9 +425,14 @@ var LibraryPThread = {
       arg: threadParams.arg,
       threadInfoStruct: threadParams.pthread_ptr,
       selfThreadId: threadParams.pthread_ptr, // TODO: Remove this since thread ID is now the same as the thread address.
+      parentThreadId: threadParams.parent_pthread_ptr,
       stackBase: threadParams.stackBase,
-      stackSize: threadParams.stackSize
-    });
+      stackSize: threadParams.stackSize,
+#if OFFSCREENCANVAS_SUPPORT
+      moduleCanvasId: threadParams.moduleCanvasId,
+      offscreenCanvases: threadParams.offscreenCanvases,
+#endif
+    }, threadParams.transferList);
   },
 
 #if USE_PTHREADS
@@ -406,12 +461,6 @@ var LibraryPThread = {
 
   pthread_create__deps: ['_spawn_thread', 'pthread_getschedparam', 'pthread_self'],
   pthread_create: function(pthread_ptr, attr, start_routine, arg) {
-    // When running in PROXY_TO_WORKER=1 mode, the pthread creation needs to be forwarded to the main browser thread, and not the main C runtime thread,
-    // so the following is valid only when in non-proxy-to-worker mode.
-#if !PROXY_TO_WORKER
-    if (ENVIRONMENT_IS_PTHREAD) return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_PTHREAD_CREATE') }}}, pthread_ptr, attr, start_routine, arg);
-#endif
-
     if (typeof SharedArrayBuffer === 'undefined') {
       Module['printErr']('Current environment does not support SharedArrayBuffer, pthreads are not available!');
       return {{{ cDefine('EAGAIN') }}};
@@ -420,6 +469,65 @@ var LibraryPThread = {
       Module['printErr']('pthread_create called with a null thread pointer!');
       return {{{ cDefine('EINVAL') }}};
     }
+
+    var transferList = []; // List of JS objects that will transfer ownership to the Worker hosting the thread
+
+#if OFFSCREENCANVAS_SUPPORT
+    // Deduce which WebGL canvases (HTMLCanvasElements or OffscreenCanvases) should be passed over to the
+    // Worker that hosts the spawned pthread.
+    var transferredCanvasNames = {{{ makeGetValue('attr', 36, 'i32') }}}; // Comma-delimited list of IDs "canvas1, canvas2, ..."
+    if (transferredCanvasNames) transferredCanvasNames = Pointer_stringify(transferredCanvasNames).split(',');
+
+    var offscreenCanvases = {}; // Dictionary of OffscreenCanvas objects we'll transfer to the created thread to own
+    var moduleCanvasId = Module['canvas'] ? Module['canvas'].id : '';
+    for (var i in transferredCanvasNames) {
+      var name = transferredCanvasNames[i].trim();
+      var offscreenCanvas;
+      try {
+        if (name == '#canvas') {
+          if (!Module['canvas']) {
+            Module['printErr']('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!');
+            return {{{ cDefine('EINVAL') }}};
+          }
+          name = Module['canvas'].id;
+        }
+        if (GL.offscreenCanvases[name]) {
+          offscreenCanvas = GL.offscreenCanvases[name];
+          GL.offscreenCanvases[name] = null; // This thread no longer owns this canvas.
+          if (Module['canvas'] instanceof OffscreenCanvas && name === Module['canvas'].id) Module['canvas'] = null;
+        } else {
+          var canvas = (Module['canvas'] && Module['canvas'].id === name) ? Module['canvas'] : document.getElementByID(name);
+          if (!canvas) {
+            Module['printErr']('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!');
+            return {{{ cDefine('EINVAL') }}};
+          }
+          if (canvas.controlTransferredOffscreen) {
+            Module['printErr']('pthread_create: cannot transfer canvas with ID "' + name + '" to thread, since the current thread does not have control over it!');
+            return {{{ cDefine('EPERM') }}}; // Operation not permitted, some other thread is accessing the canvas.
+          }
+          if (!canvas.transferControlToOffscreen) {
+            Module['printErr']('pthread_create: cannot transfer control of canvas "' + name + '" to pthread, because current browser does not support OffscreenCanvas!');
+            return {{{ cDefine('ENOSYS') }}}; // Function not implemented, browser doesn't have support for this.
+          }
+          offscreenCanvas = canvas.transferControlToOffscreen();
+          canvas.controlTransferredOffscreen = true;
+          offscreenCanvas.id = canvas.id;
+        }
+        transferList.push(offscreenCanvas);
+        offscreenCanvases[offscreenCanvas.id] = offscreenCanvas;
+      } catch(e) {
+        Module['printErr']('pthread_create: failed to transfer control of canvas "' + name + '" to OffscreenCanvas! Error: ' + e);
+        return {{{ cDefine('EINVAL') }}}; // Hitting this might indicate an implementation bug or some other internal error
+      }
+    }
+#endif
+
+    // Synchronously proxy the thread creation to main thread if possible. If we need to transfer ownership of objects, then
+    // proxy asynchronously via postMessage.
+    if (ENVIRONMENT_IS_PTHREAD && transferList.length == 0) {
+      return _emscripten_sync_run_in_main_thread_4({{{ cDefine('EM_PROXIED_PTHREAD_CREATE') }}}, pthread_ptr, attr, start_routine, arg);
+    }
+
     var stackSize = 0;
     var stackBase = 0;
     var detached = 0; // Default thread attr is PTHREAD_CREATE_JOINABLE, i.e. start as not detached.
@@ -472,14 +580,20 @@ var LibraryPThread = {
       detached: detached,
       startRoutine: start_routine,
       pthread_ptr: threadInfoStruct,
+      parent_pthread_ptr: _pthread_self(),
       arg: arg,
+#if OFFSCREENCANVAS_SUPPORT
+      moduleCanvasId: moduleCanvasId,
+      offscreenCanvases: offscreenCanvases,
+#endif
+      transferList: transferList
     };
 
-    if (ENVIRONMENT_IS_WORKER) {
+    if (ENVIRONMENT_IS_PTHREAD) {
       // The prepopulated pool of web workers that can host pthreads is stored in the main JS thread. Therefore if a
       // pthread is attempting to spawn a new thread, the thread creation must be deferred to the main JS thread.
       threadParams.cmd = 'spawnThread';
-      postMessage(threadParams);
+      postMessage(threadParams, transferList);
     } else {
       // We are the main thread, so we have the pthread warmup pool in this thread and can fire off JS thread creation
       // directly ourselves.
@@ -532,7 +646,7 @@ var LibraryPThread = {
         if (status) {{{ makeSetValue('status', 0, 'threadExitCode', 'i32') }}};
         Atomics.store(HEAPU32, (thread + {{{ C_STRUCTS.pthread.detached }}} ) >> 2, 1); // Mark the thread as detached.
 
-        if (!ENVIRONMENT_IS_WORKER) __cleanup_thread(thread);
+        if (!ENVIRONMENT_IS_PTHREAD) __cleanup_thread(thread);
         else postMessage({ cmd: 'cleanupThread', thread: thread});
         return 0;
       }
@@ -564,7 +678,7 @@ var LibraryPThread = {
       return ERRNO_CODES.ESRCH;
     }
     if (signal != 0) {
-      if (!ENVIRONMENT_IS_WORKER) __kill_thread(thread);
+      if (!ENVIRONMENT_IS_PTHREAD) __kill_thread(thread);
       else postMessage({ cmd: 'killThread', thread: thread});
     }
     return 0;
@@ -586,7 +700,7 @@ var LibraryPThread = {
       return ERRNO_CODES.ESRCH;
     }
     Atomics.compareExchange(HEAPU32, (thread + {{{ C_STRUCTS.pthread.threadStatus }}} ) >> 2, 0, 2); // Signal the thread that it needs to cancel itself.
-    if (!ENVIRONMENT_IS_WORKER) __cancel_thread(thread);
+    if (!ENVIRONMENT_IS_PTHREAD) __cancel_thread(thread);
     else postMessage({ cmd: 'cancelThread', thread: thread});
     return 0;
   },
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 6a8688111ecaa..4abfe5ab927d4 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -706,7 +706,7 @@ var LibrarySDL = {
             SDL.canRequestFullscreen = true;
           } else if (event.type === 'keyup' || event.type === 'mouseup') {
             if (SDL.isRequestingFullscreen) {
-              Module['requestFullScreen'](true, true);
+              Module['requestFullscreen'](/*lockPointer=*/true, /*resizeCanvas=*/true);
               SDL.isRequestingFullscreen = false;
             }
             SDL.canRequestFullscreen = false;
@@ -1739,7 +1739,7 @@ var LibrarySDL = {
   SDL_ShowCursor: function(toggle) {
     switch (toggle) {
       case 0: // SDL_DISABLE
-        if (Browser.isFullScreen) { // only try to lock the pointer when in full screen mode
+        if (Browser.isFullscreen) { // only try to lock the pointer when in full screen mode
           Module['canvas'].requestPointerLock();
           return 0;
         } else { // else return SDL_ENABLE to indicate the failure
@@ -2094,8 +2094,8 @@ var LibrarySDL = {
   SDL_WM_GrabInput: function() {},
   
   SDL_WM_ToggleFullScreen: function(surf) {
-    if (Browser.isFullScreen) {
-      Module['canvas'].cancelFullScreen();
+    if (Browser.isFullscreen) {
+      Module['canvas'].exitFullscreen();
       return 1;
     } else {
       if (!SDL.canRequestFullscreen) {
@@ -3207,7 +3207,7 @@ var LibrarySDL = {
   SDL_DestroyRenderer: function(renderer) {},
 
   SDL_GetWindowFlags: function(x, y) {
-    if (Browser.isFullScreen) {
+    if (Browser.isFullscreen) {
        return 1;
     }
 
@@ -3244,8 +3244,8 @@ var LibrarySDL = {
   SDL_LogSetOutputFunction: function(callback, userdata) {},
 
   SDL_SetWindowFullscreen: function(window, fullscreen) {
-    if (Browser.isFullScreen) {
-      Module['canvas'].cancelFullScreen();
+    if (Browser.isFullscreen) {
+      Module['canvas'].exitFullscreen();
       return 1;
     } else {
       return 0;
diff --git a/src/library_sockfs.js b/src/library_sockfs.js
index 67a21c654fd9f..f74346c64505f 100644
--- a/src/library_sockfs.js
+++ b/src/library_sockfs.js
@@ -280,6 +280,13 @@ mergeInto(LibraryManager.library, {
 
         function handleMessage(data) {
           assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+
+          // An empty ArrayBuffer will emit a pseudo disconnect event
+          // as recv/recvmsg will return zero which indicates that a socket
+          // has performed a shutdown although the connection has not been disconnected yet.
+          if (data.byteLength == 0) {
+            return;
+          }
           data = new Uint8Array(data);  // make a typed array view on the array buffer
 
 #if SOCKET_DEBUG
diff --git a/src/library_tty.js b/src/library_tty.js
index 6f7c26353aef7..f3d70579d6784 100644
--- a/src/library_tty.js
+++ b/src/library_tty.js
@@ -100,15 +100,26 @@ mergeInto(LibraryManager.library, {
             var buf = new Buffer(BUFSIZE);
             var bytesRead = 0;
 
+            var isPosixPlatform = (process.platform != 'win32'); // Node doesn't offer a direct check, so test by exclusion
+
             var fd = process.stdin.fd;
-            // Linux and Mac cannot use process.stdin.fd (which isn't set up as sync)
-            var usingDevice = false;
-            try {
-              fd = fs.openSync('/dev/stdin', 'r');
-              usingDevice = true;
-            } catch (e) {}
+            if (isPosixPlatform) {
+              // Linux and Mac cannot use process.stdin.fd (which isn't set up as sync)
+              var usingDevice = false;
+              try {
+                fd = fs.openSync('/dev/stdin', 'r');
+                usingDevice = true;
+              } catch (e) {}
+            }
 
-            bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);
+            try {
+              bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);
+            } catch(e) {
+              // Cross-platform differences: on Windows, reading EOF throws an exception, but on other OSes,
+              // reading EOF returns 0. Uniformize behavior by treating the EOF exception to return 0.
+              if (e.toString().indexOf('EOF') != -1) bytesRead = 0;
+              else throw e;
+            }
 
             if (usingDevice) { fs.closeSync(fd); }
             if (bytesRead > 0) {
diff --git a/src/preamble.js b/src/preamble.js
index a8525a6bf51a0..6ed8a55bb2d79 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -515,41 +515,57 @@ function stringToAscii(str, outPtr) {
 // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns
 // a copy of that string as a Javascript String object.
 
+#if TEXTDECODER
+var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;
+#endif
 function UTF8ArrayToString(u8Array, idx) {
-  var u0, u1, u2, u3, u4, u5;
-
-  var str = '';
-  while (1) {
-    // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629
-    u0 = u8Array[idx++];
-    if (!u0) return str;
-    if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
-    u1 = u8Array[idx++] & 63;
-    if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
-    u2 = u8Array[idx++] & 63;
-    if ((u0 & 0xF0) == 0xE0) {
-      u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
-    } else {
-      u3 = u8Array[idx++] & 63;
-      if ((u0 & 0xF8) == 0xF0) {
-        u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3;
+#if TEXTDECODER
+  var endPtr = idx;
+  // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
+  // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
+  while (u8Array[endPtr]) ++endPtr;
+
+  if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) {
+    return UTF8Decoder.decode(u8Array.subarray(idx, endPtr));
+  } else {
+#endif
+    var u0, u1, u2, u3, u4, u5;
+
+    var str = '';
+    while (1) {
+      // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629
+      u0 = u8Array[idx++];
+      if (!u0) return str;
+      if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
+      u1 = u8Array[idx++] & 63;
+      if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
+      u2 = u8Array[idx++] & 63;
+      if ((u0 & 0xF0) == 0xE0) {
+        u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
       } else {
-        u4 = u8Array[idx++] & 63;
-        if ((u0 & 0xFC) == 0xF8) {
-          u0 = ((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4;
+        u3 = u8Array[idx++] & 63;
+        if ((u0 & 0xF8) == 0xF0) {
+          u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3;
         } else {
-          u5 = u8Array[idx++] & 63;
-          u0 = ((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5;
+          u4 = u8Array[idx++] & 63;
+          if ((u0 & 0xFC) == 0xF8) {
+            u0 = ((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4;
+          } else {
+            u5 = u8Array[idx++] & 63;
+            u0 = ((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5;
+          }
         }
       }
+      if (u0 < 0x10000) {
+        str += String.fromCharCode(u0);
+      } else {
+        var ch = u0 - 0x10000;
+        str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+      }
     }
-    if (u0 < 0x10000) {
-      str += String.fromCharCode(u0);
-    } else {
-      var ch = u0 - 0x10000;
-      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
-    }
+#if TEXTDECODER
   }
+#endif
 }
 {{{ maybeExport('UTF8ArrayToString') }}}
 
@@ -669,18 +685,36 @@ function lengthBytesUTF8(str) {
 // Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
 // a copy of that string as a Javascript String object.
 
+var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;
 function UTF16ToString(ptr) {
-  var i = 0;
+#if ASSERTIONS
+  assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!');
+#endif
+#if TEXTDECODER
+  var endPtr = ptr;
+  // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
+  // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
+  var idx = endPtr >> 1;
+  while (HEAP16[idx]) ++idx;
+  endPtr = idx << 1;
+
+  if (endPtr - ptr > 32 && UTF16Decoder) {
+    return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));
+  } else {
+#endif
+    var i = 0;
 
-  var str = '';
-  while (1) {
-    var codeUnit = {{{ makeGetValue('ptr', 'i*2', 'i16') }}};
-    if (codeUnit == 0)
-      return str;
-    ++i;
-    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
-    str += String.fromCharCode(codeUnit);
+    var str = '';
+    while (1) {
+      var codeUnit = {{{ makeGetValue('ptr', 'i*2', 'i16') }}};
+      if (codeUnit == 0) return str;
+      ++i;
+      // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+      str += String.fromCharCode(codeUnit);
+    }
+#if TEXTDECODER
   }
+#endif
 }
 {{{ maybeExport('UTF16ToString') }}}
 
@@ -696,6 +730,9 @@ function UTF16ToString(ptr) {
 // Returns the number of bytes written, EXCLUDING the null terminator.
 
 function stringToUTF16(str, outPtr, maxBytesToWrite) {
+#if ASSERTIONS
+  assert(outPtr % 2 == 0, 'Pointer passed to stringToUTF16 must be aligned to two bytes!');
+#endif
 #if ASSERTIONS
   assert(typeof maxBytesToWrite == 'number', 'stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
 #endif
@@ -727,6 +764,9 @@ function lengthBytesUTF16(str) {
 {{{ maybeExport('lengthBytesUTF16') }}}
 
 function UTF32ToString(ptr) {
+#if ASSERTIONS
+  assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!');
+#endif
   var i = 0;
 
   var str = '';
@@ -759,6 +799,9 @@ function UTF32ToString(ptr) {
 // Returns the number of bytes written, EXCLUDING the null terminator.
 
 function stringToUTF32(str, outPtr, maxBytesToWrite) {
+#if ASSERTIONS
+  assert(outPtr % 4 == 0, 'Pointer passed to stringToUTF32 must be aligned to four bytes!');
+#endif
 #if ASSERTIONS
   assert(typeof maxBytesToWrite == 'number', 'stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
 #endif
@@ -912,6 +955,10 @@ function checkStackCookie() {
   if (HEAPU32[(STACK_MAX >> 2)-1] != 0x02135467 || HEAPU32[(STACK_MAX >> 2)-2] != 0x89BACDFE) {
     abort('Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x02135467, but received 0x' + HEAPU32[(STACK_MAX >> 2)-2].toString(16) + ' ' + HEAPU32[(STACK_MAX >> 2)-1].toString(16));
   }
+#if !SAFE_SPLIT_MEMORY
+  // Also test the global address 0 for integrity. This check is not compatible with SAFE_SPLIT_MEMORY though, since that mode already tests all address 0 accesses on its own.
+  if (HEAP32[0] !== 0x63736d65 /* 'emsc' */) throw 'Runtime error: The application has corrupted its heap memory area (address zero)!';
+#endif
 }
 
 function abortStackOverflow(allocSize) {
@@ -1422,8 +1469,17 @@ function setF64(ptr, value) {
 
 // Endianness check (note: assumes compiler arch was little-endian)
 #if SAFE_SPLIT_MEMORY == 0
-HEAP32[0] = 255;
-if (HEAPU8[0] !== 255 || HEAPU8[3] !== 0) throw 'Typed arrays 2 must be run on a little-endian system';
+#if USE_PTHREADS
+if (!ENVIRONMENT_IS_PTHREAD) {
+#endif
+  HEAP32[0] = 0x63736d65; /* 'emsc' */
+#if USE_PTHREADS
+} else {
+  if (HEAP32[0] !== 0x63736d65) throw 'Runtime error: The application has corrupted its heap memory area (address zero)!';
+}
+#endif
+HEAP16[1] = 0x6373;
+if (HEAPU8[2] !== 0x73 || HEAPU8[3] !== 0x63) throw 'Runtime error: expected the system to be little-endian!';
 #endif
 
 Module['HEAP'] = HEAP;
@@ -1721,6 +1777,11 @@ function getUniqueRunDependency(id) {
 }
 
 function addRunDependency(id) {
+#if USE_PTHREADS
+  // We should never get here in pthreads (could no-op this out if called in pthreads, but that might indicate a bug in caller side,
+  // so good to be very explicit)
+  assert(!ENVIRONMENT_IS_PTHREAD);
+#endif
   runDependencies++;
   if (Module['monitorRunDependencies']) {
     Module['monitorRunDependencies'](runDependencies);
diff --git a/src/proxyClient.js b/src/proxyClient.js
index 23e25d493cf56..8210c47b88536 100644
--- a/src/proxyClient.js
+++ b/src/proxyClient.js
@@ -108,6 +108,7 @@ setTimeout(function() {
     height: Module.canvas.height,
     boundingClientRect: cloneObject(Module.canvas.getBoundingClientRect()),
     URL: document.URL,
+    currentScriptUrl: '{{{ filename }}}.js',
     preMain: true });
 }, 0); // delay til next frame, to make sure html is ready
 
diff --git a/src/proxyWorker.js b/src/proxyWorker.js
index baf7bfcf93c10..06ab0c9bdf3b4 100644
--- a/src/proxyWorker.js
+++ b/src/proxyWorker.js
@@ -370,8 +370,14 @@ Module['postMainLoop'] = function() {
 
 // Wait to start running until we receive some info from the client
 
-addRunDependency('gl-prefetch');
-addRunDependency('worker-init');
+#if USE_PTHREADS
+if (!ENVIRONMENT_IS_PTHREAD) {
+#endif
+  addRunDependency('gl-prefetch');
+  addRunDependency('worker-init');
+#if USE_PTHREADS
+}
+#endif
 
 // buffer messages until the program starts to run
 
@@ -391,7 +397,7 @@ function messageResender() {
   }
 }
 
-onmessage = function onmessage(message) {
+function onMessageFromMainEmscriptenThread(message) {
   if (!calledMain && !message.data.preMain) {
     if (!messageBuffer) {
       messageBuffer = [];
@@ -460,6 +466,9 @@ onmessage = function onmessage(message) {
       screen.height = Module.canvas.height_ = message.data.height;
       Module.canvas.boundingClientRect = message.data.boundingClientRect;
       document.URL = message.data.URL;
+#if USE_PTHREADS
+      currentScriptUrl = message.data.currentScriptUrl;
+#endif
       window.fireEvent({ type: 'load' });
       removeRunDependency('worker-init');
       break;
@@ -476,6 +485,14 @@ onmessage = function onmessage(message) {
   }
 };
 
+#if USE_PTHREADS
+if (!ENVIRONMENT_IS_PTHREAD) {
+#endif
+  onmessage = onMessageFromMainEmscriptenThread;
+#if USE_PTHREADS
+}
+#endif
+
 function postCustomMessage(data) {
   postMessage({ target: 'custom', userData: data });
 }
diff --git a/src/pthread-main.js b/src/pthread-main.js
index e392db154ad01..b695b770df0b7 100644
--- a/src/pthread-main.js
+++ b/src/pthread-main.js
@@ -9,6 +9,7 @@ var buffer;
 var threadInfoStruct = 0; // Info area for this thread in Emscripten HEAP (shared). If zero, this worker is not currently hosting an executing pthread.
 
 var selfThreadId = 0; // The ID of this thread. 0 if not hosting a pthread.
+var parentThreadId = 0; // The ID of the parent pthread that launched this thread.
 
 var tempDoublePtr = 0; // A temporary memory area for global float and double marshalling operations.
 
@@ -54,12 +55,16 @@ this.onmessage = function(e) {
     importScripts(e.data.url);
     FS.createStandardStreams();
     postMessage({ cmd: 'loaded' });
+  } else if (e.data.cmd === 'objectTransfer') {
+    PThread.receiveObjectTransfer(e.data);
   } else if (e.data.cmd === 'run') { // This worker was idle, and now should start executing its pthread entry point.
     threadInfoStruct = e.data.threadInfoStruct;
     __register_pthread_ptr(threadInfoStruct, /*isMainBrowserThread=*/0, /*isMainRuntimeThread=*/0); // Pass the thread address inside the asm.js scope to store it for fast access that avoids the need for a FFI out.
     assert(threadInfoStruct);
     selfThreadId = e.data.selfThreadId;
+    parentThreadId = e.data.parentThreadId;
     assert(selfThreadId);
+    assert(parentThreadId);
     // TODO: Emscripten runtime has these variables twice(!), once outside the asm.js module, and a second time inside the asm.js module.
     //       Review why that is? Can those get out of sync?
     STACK_BASE = STACKTOP = e.data.stackBase;
@@ -69,6 +74,8 @@ this.onmessage = function(e) {
     Runtime.establishStackSpace(e.data.stackBase, e.data.stackBase + e.data.stackSize);
     var result = 0;
 
+    PThread.receiveObjectTransfer(e.data);
+
     PThread.setThreadStatus(_pthread_self(), 1/*EM_THREAD_STATUS_RUNNING*/);
 
     try {
@@ -92,7 +99,8 @@ this.onmessage = function(e) {
     }
     // The thread might have finished without calling pthread_exit(). If so, then perform the exit operation ourselves.
     // (This is a no-op if explicit pthread_exit() had been called prior.)
-    PThread.threadExit(result);
+    if (!Module['noExitRuntime']) PThread.threadExit(result);
+    else console.log('pthread noExitRuntime: not quitting.');
   } else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.
     if (threadInfoStruct && PThread.thisThreadCancelState == 0/*PTHREAD_CANCEL_ENABLE*/) {
       PThread.threadCancel();
diff --git a/src/settings.js b/src/settings.js
index 0bc325bf21985..ab78ab7fdad37 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -305,10 +305,14 @@ var ASYNCIFY_WHITELIST = ['qsort',   // Functions in this list are never conside
                           '__fwritex',
                           'MUSL_vfprintf'];
 
-var EXPORTED_RUNTIME_METHODS = [ // Methods that are exported on Module. By default we export quite a bit, you can reduce this list to lower your code size,
+var EXPORTED_RUNTIME_METHODS = [ // Runtime elements that are exported on Module. By default we export quite a bit, you can reduce this list to lower your code size,
                                  // especially when closure is run (exporting prevents closure from eliminating code)
                                  // Note that methods on this list are only exported if they are included (either automatically from linking, or due to being
                                  // in DEFAULT_LIBRARY_FUNCS_TO_INCLUDE)
+                                 // Note that the name may be slightly misleading, as this
+                                 // is for any JS library element, and not just
+                                 // methods. For example, we export the Runtime object
+                                 // by having "Runtime" in this list.
   'FS_createFolder',
   'FS_createPath',
   'FS_createDataFile',
@@ -404,13 +408,17 @@ var OPT_LEVEL = 0;           // this will contain the optimization level (-Ox).
 var DEBUG_LEVEL = 0;         // this will contain the debug level (-gx). you should not modify it.
 
 
-// JS library functions (C functions implemented in JS)
+// JS library elements (C functions implemented in JS)
 // that we include by default. If you want to make sure
 // something is included by the JS compiler, add it here.
 // For example, if you do not use some emscripten_*
 // C API call from C, but you want to call it from JS,
 // add it here (and in EXPORTED FUNCTIONS with prefix
 // "_", if you use closure compiler).
+// Note that the name may be slightly misleading, as this
+// is for any JS library element, and not just
+// functions. For example, you can include the Browser
+// object by adding "$Browser" to this list.
 var DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = ['memcpy', 'memset', 'malloc', 'free'];
 
 var LIBRARY_DEPS_TO_AUTOEXPORT = ['memcpy']; // This list is also used to determine
@@ -746,4 +754,10 @@ var CYBERDWARF = 0; // see http://kripken.github.io/emscripten-site/docs/debuggi
 
 var BUNDLED_CD_DEBUG_FILE = ""; // Path to the CyberDWARF debug file passed to the compiler
 
+var TEXTDECODER = 1; // Is enabled, use the JavaScript TextDecoder API for string marshalling.
+                     // Enabled by default, set this to 0 to disable.
+var OFFSCREENCANVAS_SUPPORT = 0; // If set to 1, enables support for transferring canvases to pthreads and creating WebGL contexts in them,
+                                 // as well as explicit swap control for GL contexts. This needs browser support for the OffscreenCanvas
+                                 // specification.
+
 // Reserved: variables containing POINTER_MASKING.
diff --git a/src/shell.html b/src/shell.html
index 00b4237d24d39..ec4895f074895 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -15,7 +15,7 @@
       div.emscripten { text-align: center; }      
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       #emscripten_logo {
         display: inline-block;
@@ -1201,7 +1201,7 @@
 <span id='controls'>
   <span><input type="checkbox" id="resize">Resize canvas</span>
   <span><input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer &nbsp;&nbsp;&nbsp;</span>
-  <span><input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+  <span><input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                             document.getElementById('resize').checked)">
   </span>
 </span>
diff --git a/src/shell_minimal.html b/src/shell_minimal.html
index e085f006ff9f8..c441444c5e579 100644
--- a/src/shell_minimal.html
+++ b/src/shell_minimal.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       .spinner {
         height: 50px;
@@ -61,7 +61,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/src/struct_info.compiled.json b/src/struct_info.compiled.json
index 09f47d8b882e0..a79ad4d293a42 100644
--- a/src/struct_info.compiled.json
+++ b/src/struct_info.compiled.json
@@ -1 +1 @@
-{"structs":{"utsname":{"sysname":0,"nodename":65,"domainname":325,"machine":260,"version":195,"release":130,"__size__":390},"sockaddr":{"sa_data":2,"sa_family":0,"__size__":16},"addrinfo":{"ai_flags":0,"ai_next":28,"ai_canonname":24,"ai_socktype":8,"ai_addr":20,"ai_protocol":12,"ai_family":4,"ai_addrlen":16,"__size__":32},"timespec":{"tv_sec":0,"tv_nsec":4,"__size__":8},"utimbuf":{"modtime":4,"actime":0,"__size__":8},"EmscriptenVisibilityChangeEvent":{"hidden":0,"visibilityState":4,"__size__":8},"SDL_MouseButtonEvent":{"timestamp":4,"button":16,"state":17,"windowID":8,"which":12,"y":24,"x":20,"padding2":19,"type":0,"padding1":18,"__size__":28},"sockaddr_in":{"sin_port":2,"sin_addr":{"s_addr":4,"__size__":4},"sin_family":0,"sin_zero":8,"__size__":16},"pthread":{"tsd":116,"attr":120,"canceldisable":72,"threadStatus":0,"tsd_used":56,"pid":52,"stack":92,"cancelasync":76,"tid":48,"threadExitCode":4,"detached":80,"profilerBlock":20,"self":24,"stack_size":96,"__size__":216},"WebVRFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"SDL_KeyboardEvent":{"repeat":9,"keysym":12,"state":8,"windowID":4,"__size__":28,"type":0,"padding3":11,"padding2":10},"SDL_MouseMotionEvent":{"yrel":32,"timestamp":4,"state":16,"windowID":8,"which":12,"xrel":28,"y":24,"x":20,"type":0,"__size__":36},"SDL_Rect":{"y":4,"x":0,"h":12,"w":8,"__size__":16},"itimerspec":{"it_interval":{"tv_sec":0,"tv_nsec":4,"__size__":8},"it_value":{"tv_sec":8,"tv_nsec":12,"__size__":8},"__size__":16},"iovec":{"iov_len":4,"iov_base":0,"__size__":8},"timezone":{"tz_dsttime":4,"tz_minuteswest":0,"__size__":8},"flock":{"l_whence":2,"l_type":0,"l_start":4,"__size__":16,"l_len":8,"l_pid":12},"EmscriptenOrientationChangeEvent":{"orientationIndex":0,"orientationAngle":4,"__size__":8},"EmscriptenMouseEvent":{"clientX":16,"clientY":20,"targetX":52,"buttons":42,"timestamp":0,"button":40,"targetY":56,"altKey":32,"canvasY":64,"metaKey":36,"movementX":44,"movementY":48,"shiftKey":28,"ctrlKey":24,"screenY":12,"screenX":8,"canvasX":60,"__size__":72},"SDL_ResizeEvent":{"h":8,"type":0,"w":4,"__size__":12},"tms":{"tms_stime":4,"tms_utime":0,"tms_cstime":12,"tms_cutime":8,"__size__":16},"SDL_Color":{"unused":3,"r":0,"b":2,"g":1,"__size__":4},"EmscriptenKeyboardEvent":{"code":32,"charValue":120,"locale":88,"shiftKey":72,"altKey":76,"which":160,"metaKey":80,"location":64,"key":0,"ctrlKey":68,"charCode":152,"keyCode":156,"repeat":84,"__size__":164},"rusage":{"ru_msgrcv":56,"ru_utime":{"tv_sec":0,"tv_usec":4,"__size__":8},"ru_isrss":28,"ru_stime":{"tv_sec":8,"tv_usec":12,"__size__":8},"ru_nsignals":60,"ru_nivcsw":68,"ru_msgsnd":52,"ru_nswap":40,"ru_minflt":32,"ru_nvcsw":64,"ru_ixrss":20,"ru_inblock":44,"ru_idrss":24,"ru_maxrss":16,"ru_oublock":48,"ru_majflt":36,"__size__":136},"div_t":{"quot":0,"rem":4,"__size__":8},"timeval":{"tv_sec":0,"tv_usec":4,"__size__":8},"rlimit":{"rlim_cur":0,"rlim_max":8,"__size__":16},"in6_addr":{"__in6_union":{"__s6_addr16":0,"__s6_addr":0,"__s6_addr32":0,"__size__":16},"__size__":16},"tm":{"tm_sec":0,"tm_hour":8,"tm_mday":12,"tm_isdst":32,"tm_year":20,"tm_zone":40,"tm_mon":16,"tm_yday":28,"tm_gmtoff":36,"tm_wday":24,"tm_min":4,"__size__":44},"EmscriptenWebGLContextAttributes":{"majorVersion":32,"stencil":8,"preserveDrawingBuffer":20,"failIfMajorPerformanceCaveat":28,"antialias":12,"depth":4,"minorVersion":36,"premultipliedAlpha":16,"enableExtensionsByDefault":40,"alpha":0,"preferLowPowerToHighPerformance":24,"__size__":44},"EmscriptenBatteryEvent":{"dischargingTime":8,"level":16,"charging":24,"chargingTime":0,"__size__":32},"protoent":{"p_aliases":4,"p_proto":8,"p_name":0,"__size__":12},"SDL_Surface":{"userdata":24,"locked":28,"clip_rect":36,"format":4,"h":12,"refcount":56,"map":52,"flags":0,"w":8,"pitch":16,"lock_data":32,"pixels":20,"__size__":60},"EmscriptenTouchEvent":{"touches":20,"shiftKey":8,"altKey":12,"metaKey":16,"ctrlKey":4,"__size__":1684,"numTouches":0},"dirent":{"d_name":11,"d_off":4,"d_ino":0,"d_reclen":8,"d_type":10,"__size__":268},"sockaddr_in6":{"sin6_family":0,"sin6_flowinfo":4,"sin6_scope_id":24,"sin6_addr":{"__in6_union":{"__s6_addr16":8,"__s6_addr":8,"__s6_addr32":8,"__size__":16},"__size__":16},"__size__":28,"sin6_port":2},"SDL_JoyAxisEvent":{"__size__":12,"type":0,"value":8,"which":4,"padding2":7,"padding1":6,"axis":5},"netent":{"n_name":0,"n_net":12,"n_addrtype":8,"n_aliases":4,"__size__":16},"SDL_PixelFormat":{"palette":4,"Gloss":29,"Bmask":20,"Bloss":30,"Rloss":28,"format":0,"Gshift":33,"Aloss":31,"BitsPerPixel":8,"refcount":36,"next":40,"padding":10,"Rmask":12,"Bshift":34,"Gmask":16,"BytesPerPixel":9,"Amask":24,"Rshift":32,"Ashift":35,"__size__":44},"SDL_JoyButtonEvent":{"type":0,"button":5,"state":6,"which":4,"padding1":7,"__size__":8},"EmscriptenPointerlockChangeEvent":{"id":132,"nodeName":4,"isActive":0,"__size__":260},"in_addr":{"s_addr":0,"__size__":4},"EmscriptenDeviceOrientationEvent":{"timestamp":0,"beta":16,"alpha":8,"__size__":40,"gamma":24,"absolute":32},"SDL_WindowEvent":{"data2":16,"type":0,"data1":12,"windowID":4,"__size__":20,"padding1":9,"event":8,"padding3":11,"padding2":10},"SDL_Keysym":{"scancode":0,"mod":8,"unicode":12,"sym":4,"__size__":16},"cmsghdr":{"cmsg_type":8,"cmsg_level":4,"cmsg_len":0,"__size__":12},"EmscriptenUiEvent":{"windowInnerWidth":12,"detail":0,"scrollLeft":32,"documentBodyClientHeight":8,"windowInnerHeight":16,"scrollTop":28,"windowOuterHeight":24,"windowOuterWidth":20,"documentBodyClientWidth":4,"__size__":36},"thread_profiler_block":{"threadStatus":0,"timeSpentInStatus":16,"currentStatusStartTime":8,"name":72,"__size__":104},"stat":{"st_rdev":28,"st_mtim":{"tv_sec":56,"tv_nsec":60,"__size__":8},"st_blocks":44,"st_atim":{"tv_sec":48,"tv_nsec":52,"__size__":8},"st_nlink":16,"__st_ino_truncated":8,"st_ctim":{"tv_sec":64,"tv_nsec":68,"__size__":8},"st_mode":12,"st_blksize":40,"__st_dev_padding":4,"st_dev":0,"st_size":36,"st_gid":24,"__st_rdev_padding":32,"st_uid":20,"st_ino":72,"__size__":76},"pollfd":{"fd":0,"events":4,"revents":6,"__size__":8},"WebVRPositionState":{"linearVelocity":{"y":56,"x":48,"z":64,"w":72,"__size__":32},"orientation":{"y":128,"x":120,"z":136,"w":144,"__size__":32},"timeStamp":0,"angularVelocity":{"y":160,"x":152,"z":168,"w":176,"__size__":32},"hasPosition":8,"angularAcceleration":{"y":192,"x":184,"z":200,"w":208,"__size__":32},"linearAcceleration":{"y":88,"x":80,"z":96,"w":104,"__size__":32},"hasOrientation":112,"position":{"y":24,"x":16,"z":32,"w":40,"__size__":32},"__size__":216},"SDL_TextInputEvent":{"text":8,"windowID":4,"type":0,"__size__":40},"EmscriptenTouchPoint":{"clientX":12,"clientY":16,"identifier":0,"targetX":36,"targetY":40,"isChanged":28,"canvasY":48,"canvasX":44,"pageX":20,"pageY":24,"screenY":8,"screenX":4,"onTarget":32,"__size__":52},"EmscriptenDeviceMotionEvent":{"timestamp":0,"accelerationIncludingGravityZ":48,"accelerationIncludingGravityX":32,"accelerationIncludingGravityY":40,"accelerationY":16,"accelerationX":8,"rotationRateBeta":64,"accelerationZ":24,"rotationRateGamma":72,"rotationRateAlpha":56,"__size__":80},"SDL_AudioSpec":{"padding":10,"userdata":20,"format":4,"channels":6,"callback":16,"samples":8,"freq":0,"size":12,"silence":7,"__size__":24},"hostent":{"h_addrtype":8,"h_addr_list":16,"h_name":0,"__size__":20,"h_aliases":4,"h_length":12},"SDL_MouseWheelEvent":{"timestamp":4,"windowID":8,"which":12,"y":20,"x":16,"type":0,"__size__":24},"EmscriptenFocusEvent":{"id":128,"nodeName":0,"__size__":256},"SDL_version":{"major":0,"patch":2,"minor":1,"__size__":3},"statvfs":{"f_bsize":0,"f_bavail":16,"f_fsid":32,"f_favail":28,"f_files":20,"f_frsize":4,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flag":40,"f_namemax":44,"__size__":72},"linger":{"l_onoff":0,"l_linger":4,"__size__":8},"EmscriptenFullscreenChangeEvent":{"elementWidth":264,"screenWidth":272,"nodeName":8,"elementHeight":268,"fullscreenEnabled":4,"screenHeight":276,"isFullscreen":0,"id":136,"__size__":280},"EmscriptenWheelEvent":{"deltaX":72,"deltaY":80,"deltaZ":88,"deltaMode":96,"mouse":0,"__size__":104},"WebVRIntRect":{"y":4,"x":0,"height":12,"width":8,"__size__":16},"SDL_TouchFingerEvent":{"timestamp":4,"dy":36,"touchId":8,"pressure":40,"dx":32,"type":0,"y":28,"x":24,"fingerId":16,"__size__":48},"SDL_AudioCVT":{"len_ratio":32,"len_cvt":24,"rate_incr":8,"filters":40,"len":20,"needed":0,"filter_index":80,"src_format":4,"len_mult":28,"__size__":88,"buf":16,"dst_format":6},"WebVRPoint":{"y":8,"x":0,"z":16,"w":24,"__size__":32},"statfs":{"f_bsize":4,"f_bavail":16,"f_fsid":28,"f_files":20,"f_frsize":40,"f_namelen":36,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flags":44,"__size__":64},"msghdr":{"msg_iov":8,"msg_iovlen":12,"msg_namelen":4,"msg_controllen":20,"msg_flags":24,"msg_name":0,"msg_control":16,"__size__":28},"EmscriptenGamepadEvent":{"index":1300,"analogButton":528,"timestamp":0,"numButtons":12,"mapping":1368,"digitalButton":1040,"connected":1296,"numAxes":8,"__size__":1432,"id":1304,"axis":16},"SDL_Palette":{"ncolors":0,"colors":4,"version":8,"refcount":12,"__size__":16},"EmscriptenFullscreenStrategy":{"canvasResizedCallbackUserData":16,"canvasResolutionScaleMode":4,"scaleMode":0,"canvasResizedCallback":12,"filteringMode":8,"__size__":20},"timeb":{"dstflag":8,"timezone":6,"time":0,"millitm":4,"__size__":12},"WebVREyeParameters":{"currentFieldOfView":{"leftDegrees":152,"upDegrees":128,"downDegrees":144,"rightDegrees":136,"__size__":32},"recommendedFieldOfView":{"leftDegrees":88,"upDegrees":64,"downDegrees":80,"rightDegrees":72,"__size__":32},"eyeTranslation":{"y":104,"x":96,"z":112,"w":120,"__size__":32},"renderRect":{"y":164,"x":160,"height":172,"width":168,"__size__":16},"minimumFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"maximumFieldOfView":{"leftDegrees":56,"upDegrees":32,"downDegrees":48,"rightDegrees":40,"__size__":32},"__size__":176}},"defines":{"ETXTBSY":26,"EOF":-1,"EMSCRIPTEN_EVENT_MOUSEOVER":35,"ETOOMANYREFS":109,"ENAMETOOLONG":36,"ENOPKG":65,"UUID_TYPE_DCE_TIME":1,"_SC_XOPEN_LEGACY":129,"_SC_XOPEN_VERSION":89,"F_UNLCK":2,"_SC_BC_DIM_MAX":37,"EL3HLT":46,"S_IFDIR":16384,"EMSCRIPTEN_EVENT_KEYPRESS":1,"EINPROGRESS":115,"_SC_BARRIERS":133,"EMSCRIPTEN_EVENT_TOUCHMOVE":24,"SDL_AUDIO_ALLOW_FREQUENCY_CHANGE":1,"AUDIO_U8":8,"EAI_AGAIN":-3,"_PC_MAX_CANON":1,"ENOTSUP":95,"EFBIG":27,"O_CREAT":64,"_SC_2_PBS_LOCATE":170,"EM_PROXIED_SETENV":113,"_CS_POSIX_V6_LP64_OFF64_LIBS":1126,"ENOLINK":67,"ABDAY_7":131078,"ABDAY_6":131077,"ABDAY_5":131076,"ABDAY_4":131075,"ABDAY_3":131074,"ABDAY_2":131073,"ABDAY_1":131072,"EL3RST":47,"YESEXPR":327680,"_SC_V6_ILP32_OFFBIG":177,"SDL_MINOR_VERSION":3,"EM_PROXIED_CLEARENV":112,"_SC_MEMLOCK":17,"ENOTUNIQ":76,"EMSCRIPTEN_RESULT_FAILED":-6,"ABMON_1":131086,"ELNRNG":48,"UUID_VARIANT_MICROSOFT":2,"EMSCRIPTEN_EVENT_TOUCHSTART":22,"ENOANO":55,"EMSCRIPTEN_EVENT_FOCUSIN":14,"EMSCRIPTEN_EVENT_MOUSEUP":6,"ENOPROTOOPT":92,"POLLIN":1,"S_IALLUGO":4095,"_SC_THREAD_KEYS_MAX":74,"EM_THREAD_STATUS_WAITPROXY":5,"O_RDWR":2,"EREMCHG":78,"EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED":27,"_SC_2_PBS":168,"_SC_TRACE_INHERIT":183,"_SC_REGEXP":155,"_CS_POSIX_V6_LP64_OFF64_CFLAGS":1124,"_SC_DELAYTIMER_MAX":26,"S_IWUGO":146,"S_IFREG":32768,"F_GETLK64":12,"O_DIRECTORY":65536,"EM_PROXIED_UTIMES":13,"POLLHUP":16,"S_IFMT":61440,"F_SETLK64":13,"_SC_XOPEN_CRYPT":92,"_SC_CLOCK_SELECTION":137,"_PC_CHOWN_RESTRICTED":6,"E2BIG":7,"ABMON_3":131088,"AM_STR":131110,"SDL_AUDIO_MASK_ENDIAN":4096,"ALT_DIGITS":131119,"EHOSTDOWN":112,"EBFONT":59,"ENOTEMPTY":39,"AUDIO_S16":32784,"TIOCGPGRP":21519,"EBUSY":16,"_SC_MQ_PRIO_MAX":28,"_SC_PAGE_SIZE":30,"EADDRINUSE":98,"ENOTSOCK":88,"PM_STR":131111,"O_WRONLY":1,"_SC_STREAM_MAX":5,"ABMON_9":131094,"ELIBACC":79,"S_IFIFO":4096,"EDQUOT":122,"EAI_SYSTEM":-11,"ENOENT":2,"_SC_TIMERS":11,"O_SYNC":1052672,"SEEK_END":2,"EM_THREAD_STATUS_FINISHED":6,"_PC_REC_MIN_XFER_SIZE":16,"_PC_PATH_MAX":4,"_SC_SPORADIC_SERVER":160,"ECOMM":70,"_SC_NPROCESSORS_ONLN":84,"_CS_POSIX_V6_LPBIG_OFFBIG_LIBS":1130,"_PC_MAX_INPUT":2,"_SC_VERSION":29,"_SC_XBS5_LPBIG_OFFBIG":128,"_SC_CLK_TCK":2,"ABMON_2":131087,"EXFULL":54,"ABMON_7":131092,"ABMON_6":131091,"ABMON_5":131090,"ABMON_4":131089,"ENOTDIR":20,"ABMON_8":131093,"_SC_AIO_MAX":24,"ERA":131116,"EM_PROXIED_UNSETENV":114,"_SC_THREAD_PRIO_INHERIT":80,"_PC_2_SYMLINKS":20,"_SC_XBS5_LP64_OFF64":127,"EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE":30,"ENETRESET":102,"EAFNOSUPPORT":97,"MON_2":131099,"MON_3":131100,"MON_1":131098,"EMSCRIPTEN_EVENT_DEVICEORIENTATION":16,"MON_7":131104,"MON_4":131101,"MON_5":131102,"_SC_SPAWN":159,"MON_8":131105,"MON_9":131106,"_CS_POSIX_V6_ILP32_OFF32_LDFLAGS":1117,"S_IFSOCK":49152,"S_IRUGO":292,"SOCK_DGRAM":2,"POLLERR":8,"EINVAL":22,"_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS":1128,"POLLRDNORM":64,"AUDIO_F32SYS":33056,"_SC_TRACE_SYS_MAX":244,"AI_V4MAPPED":8,"AI_NUMERICHOST":4,"_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS":1,"EHOSTUNREACH":113,"ENOCSI":50,"EPROTONOSUPPORT":93,"_SC_AIO_PRIO_DELTA_MAX":25,"_SC_MONOTONIC_CLOCK":149,"ETIME":62,"ENOTTY":25,"_SC_XOPEN_ENH_I18N":93,"EAI_SERVICE":-8,"EAGAIN":11,"F_SETLKW64":14,"EMSGSIZE":90,"ELIBEXEC":83,"_SC_MEMORY_PROTECTION":19,"EMSCRIPTEN_FULLSCREEN_SCALE_CENTER":3,"SDL_AUDIO_ALLOW_FORMAT_CHANGE":2,"ECANCELED":125,"_SC_SPIN_LOCKS":154,"_SC_XOPEN_SHM":94,"_PC_LINK_MAX":0,"TIOCSPGRP":21520,"EOPNOTSUPP":95,"EMSCRIPTEN_EVENT_MOUSEENTER":33,"EAI_FAIL":-4,"NOEXPR":327681,"_SC_FSYNC":15,"_SC_GETGR_R_SIZE_MAX":69,"EDESTADDRREQ":89,"EADDRNOTAVAIL":99,"AUDIO_S32SYS":32800,"_SC_TRACE_NAME_MAX":243,"_SC_BC_BASE_MAX":36,"EMSCRIPTEN_EVENT_CANVASRESIZED":37,"EPERM":1,"EAI_FAMILY":-6,"O_NOFOLLOW":131072,"SOCK_STREAM":1,"O_APPEND":1024,"_SC_XOPEN_STREAMS":246,"_SC_GETPW_R_SIZE_MAX":70,"MON_6":131103,"EPROTOTYPE":91,"_SC_CPUTIME":138,"EISCONN":106,"_SC_XBS5_ILP32_OFFBIG":126,"S_IFBLK":24576,"T_FMT_AMPM":131115,"EM_PROXIED_FPATHCONF":46,"F_SETLKW":14,"SDL_TOUCH_MOUSEID":-1,"EMSCRIPTEN_EVENT_SCROLL":11,"ELOOP":40,"_SC_OPEN_MAX":4,"_SC_2_FORT_RUN":50,"EMSCRIPTEN_EVENT_VISIBILITYCHANGE":21,"EREMOTE":66,"_SC_RE_DUP_MAX":44,"_SC_THREAD_PRIO_PROTECT":81,"_SC_2_PBS_CHECKPOINT":175,"_SC_2_PBS_TRACK":172,"MON_10":131107,"MON_11":131108,"MON_12":131109,"TCGETS":21505,"_SC_THREAD_PROCESS_SHARED":82,"AF_INET":2,"_SC_SHARED_MEMORY_OBJECTS":22,"F_GETFD":1,"EMSCRIPTEN_EVENT_DEVICEMOTION":17,"SDL_MIX_MAXVOLUME":128,"_PC_ALLOC_SIZE_MIN":18,"TCSETS":21506,"ELIBMAX":82,"_SC_READER_WRITER_LOCKS":153,"EMULTIHOP":72,"_SC_PHYS_PAGES":85,"_SC_MEMLOCK_RANGE":18,"_SC_PRIORITY_SCHEDULING":10,"T_FMT":131114,"AI_ALL":16,"_PC_VDISABLE":8,"THOUSEP":65537,"_SC_TRACE_EVENT_FILTER":182,"ERA_T_FMT":131121,"_SC_THREAD_ATTR_STACKADDR":77,"_SC_THREAD_THREADS_MAX":76,"_SC_LOGIN_NAME_MAX":71,"_SC_2_C_BIND":47,"_PC_NO_TRUNC":7,"ECONNABORTED":103,"EMSCRIPTEN_RESULT_SUCCESS":0,"_SC_SHELL":157,"EFAULT":14,"_SC_V6_LP64_OFF64":178,"_CS_GNU_LIBC_VERSION":2,"ENODATA":61,"_SC_SEM_VALUE_MAX":33,"_SC_MQ_OPEN_MAX":27,"AI_ADDRCONFIG":32,"_SC_HOST_NAME_MAX":180,"_SC_THREAD_STACK_MIN":75,"_SC_TIMEOUTS":164,"POLLOUT":4,"_SC_IPV6":235,"_SC_CHILD_MAX":1,"EDOM":33,"_SC_2_PBS_MESSAGE":171,"EILSEQ":84,"UUID_VARIANT_DCE":1,"_SC_2_C_DEV":48,"_SC_TIMER_MAX":35,"FP_ZERO":2,"EPFNOSUPPORT":96,"ENONET":64,"ECHRNG":44,"_SC_THREADS":67,"_SC_REALTIME_SIGNALS":9,"CLOCKS_PER_SEC":1000000,"ERA_D_T_FMT":131120,"ESRCH":3,"D_FMT":131113,"POLLPRI":2,"_PC_ASYNC_IO":10,"DAY_2":131080,"DAY_3":131081,"DAY_1":131079,"DAY_6":131084,"DAY_7":131085,"DAY_4":131082,"DAY_5":131083,"_SC_SYNCHRONIZED_IO":14,"EL2HLT":51,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF":1,"IPPROTO_UDP":17,"_SC_MAPPED_FILES":16,"EL2NSYNC":45,"_SC_NGROUPS_MAX":3,"ENOMSG":42,"EISDIR":21,"_SC_SEMAPHORES":21,"AI_NUMERICSERV":1024,"EDEADLOCK":35,"EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST":31,"EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE":29,"AUDIO_F32LSB":33056,"_SC_COLL_WEIGHTS_MAX":40,"SO_ERROR":4,"ECONNRESET":104,"AT_SYMLINK_NOFOLLOW":256,"_SC_TRACE_LOG":184,"AUDIO_U16LSB":16,"ESTRPIPE":86,"ESHUTDOWN":108,"_PC_SOCK_MAXBUF":12,"_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS":1129,"EDEADLK":35,"_CS_POSIX_V6_ILP32_OFF32_CFLAGS":1116,"EBADRQC":56,"_SC_THREAD_DESTRUCTOR_ITERATIONS":73,"_SC_TYPED_MEMORY_OBJECTS":165,"_SC_TRACE_EVENT_NAME_MAX":242,"_SC_BC_STRING_MAX":39,"_SC_2_SW_DEV":51,"FP_NAN":0,"F_SETOWN":8,"EMSCRIPTEN_EVENT_RESIZE":10,"_SC_ARG_MAX":0,"_SC_THREAD_PRIORITY_SCHEDULING":79,"F_GETLK":12,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF":2,"FIONREAD":21531,"_SC_THREAD_CPUTIME":139,"EMSCRIPTEN_EVENT_POINTERLOCKCHANGE":20,"EM_THREAD_STATUS_NOTSTARTED":0,"_CS_POSIX_V6_ILP32_OFF32_LIBS":1118,"EUNATCH":49,"AUDIO_S8":32776,"AUDIO_S32LSB":32800,"SDL_AUDIO_MASK_BITSIZE":255,"ERA_D_FMT":131118,"AUDIO_F32MSB":37152,"_CS_POSIX_V6_LP64_OFF64_LDFLAGS":1125,"FP_INFINITE":1,"ECHILD":10,"EAI_MEMORY":-10,"O_TRUNC":512,"ETIMEDOUT":110,"EALREADY":114,"ENXIO":6,"NI_NUMERICHOST":1,"EMFILE":24,"F_GETOWN":9,"EMLINK":31,"F_SETFD":2,"ENFILE":23,"EM_PROXIED_SYSCONF":72,"EM_PROXIED_GETENV":111,"SDL_MAJOR_VERSION":1,"ENOMEM":12,"ENOSR":63,"SDL_AUDIO_ALLOW_ANY_CHANGE":7,"EOWNERDEAD":130,"_PC_PRIO_IO":11,"ELIBSCN":81,"_SC_V6_LPBIG_OFFBIG":179,"EM_PROXIED_CHROOT":37,"EMSCRIPTEN_EVENT_CLICK":4,"EPIPE":32,"_SC_EXPR_NEST_MAX":42,"_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS":1120,"EBADSLT":57,"AUDIO_S16MSB":36880,"S_ISVTX":512,"EMSCRIPTEN_RESULT_DEFERRED":1,"EMSCRIPTEN_RESULT_UNKNOWN_TARGET":-4,"S_IRWXUGO":511,"EM_PROXIED_TZSET":119,"_CS_GNU_LIBPTHREAD_VERSION":3,"_PC_REC_MAX_XFER_SIZE":15,"UUID_VARIANT_OTHER":3,"EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED":32,"EM_PROXIED_PTHREAD_CREATE":137,"EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT":0,"RADIXCHAR":65536,"AF_UNSPEC":0,"ENOSTR":60,"W_OK":2,"AUDIO_S32":32800,"EACCES":13,"R_OK":4,"S_IRWXO":7,"_SC_V6_ILP32_OFF32":176,"EMSCRIPTEN_EVENT_FULLSCREENCHANGE":19,"EIO":5,"EMSCRIPTEN_RESULT_NOT_SUPPORTED":-1,"EM_PROXIED_CONFSTR":68,"_SC_SIGQUEUE_MAX":34,"EWOULDBLOCK":11,"AUDIO_U16SYS":16,"EMSCRIPTEN_EVENT_FOCUSOUT":15,"EAI_OVERFLOW":-12,"SDL_AUDIO_MASK_DATATYPE":256,"MAP_PRIVATE":2,"_SC_TZNAME_MAX":6,"_CS_PATH":0,"SEEK_SET":0,"EBADE":52,"EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED":-2,"INT_MAX":2147483647,"EMSCRIPTEN_EVENT_KEYDOWN":2,"EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH":1,"_SC_MESSAGE_PASSING":20,"_SC_THREAD_SAFE_FUNCTIONS":68,"_SC_SYMLOOP_MAX":173,"_PC_NAME_MAX":3,"O_EXCL":128,"_SC_TRACE_USER_EVENT_MAX":245,"_PC_REC_XFER_ALIGN":17,"EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT":0,"_SC_RAW_SOCKETS":236,"_SC_2_UPE":97,"EMSCRIPTEN_RESULT_NO_DATA":-7,"EMSCRIPTEN_EVENT_BLUR":12,"_SC_RTSIG_MAX":31,"ESOCKTNOSUPPORT":94,"_SC_PRIORITIZED_IO":13,"_SC_XOPEN_UNIX":91,"CODESET":14,"IPPROTO_TCP":6,"_PC_REC_INCR_XFER_SIZE":14,"F_SETLK":13,"_PC_FILESIZEBITS":13,"_SC_XBS5_ILP32_OFF32":125,"RAND_MAX":2147483647,"EM_PROXIED_SYSCALL":138,"ENOLCK":37,"EM_PROXIED_PUTENV":115,"AUDIO_U16":16,"EMSCRIPTEN_EVENT_MOUSELEAVE":34,"EMSCRIPTEN_EVENT_MOUSEOUT":36,"_SC_2_VERSION":46,"_PC_SYNC_IO":9,"EEXIST":17,"FP_NORMAL":4,"O_RDONLY":0,"_SC_SEM_NSEMS_MAX":32,"_SC_IOV_MAX":60,"EPROTO":71,"_SC_TRACE":181,"ESRMNT":69,"_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS":1121,"SDL_PIXELFORMAT_RGBA8888":-2042224636,"INADDR_LOOPBACK":2130706433,"EXDEV":18,"EM_THREAD_STATUS_RUNNING":1,"EMSCRIPTEN_EVENT_BEFOREUNLOAD":28,"EM_THREAD_STATUS_WAITFUTEX":3,"EMSCRIPTEN_RESULT_INVALID_TARGET":-3,"_SC_THREAD_SPORADIC_SERVER":161,"F_SETFL":4,"AI_PASSIVE":1,"ELIBBAD":80,"_SC_LINE_MAX":43,"D_T_FMT":131112,"ERANGE":34,"ESTALE":116,"F_DUPFD":0,"AUDIO_F32":33056,"CLOCK_MONOTONIC":1,"EMSCRIPTEN_EVENT_GAMEPADCONNECTED":26,"F_GETOWN_EX":16,"_SC_ASYNCHRONOUS_IO":12,"ENOTRECOVERABLE":131,"ENOBUFS":105,"EIDRM":43,"EMSCRIPTEN_EVENT_ORIENTATIONCHANGE":18,"CRNCYSTR":262159,"EINTR":4,"EADV":68,"ENOSYS":38,"_CS_POSIX_V6_ILP32_OFFBIG_LIBS":1122,"EM_PROXIED_UTIME":12,"F_GETFL":3,"S_IXUGO":73,"_SC_2_FORT_DEV":49,"SDL_COMPILEDVERSION":1300,"EBADMSG":74,"EUSERS":87,"CLOCK_REALTIME":0,"ENODEV":19,"AF_INET6":10,"_SC_ATEXIT_MAX":87,"_SC_SAVED_IDS":8,"SOL_SOCKET":1,"S_IFLNK":40960,"AUDIO_S16LSB":32784,"POLLNVAL":32,"EMSCRIPTEN_EVENT_TOUCHCANCEL":25,"EMSCRIPTEN_RESULT_INVALID_PARAM":-5,"EMSCRIPTEN_EVENT_MOUSEDOWN":5,"EM_THREAD_STATUS_SLEEPING":2,"_SC_JOB_CONTROL":7,"NI_NAMEREQD":8,"EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT":2,"EMSCRIPTEN_EVENT_MOUSEMOVE":8,"UUID_TYPE_DCE_RANDOM":4,"ENOTCONN":107,"_SC_ADVISORY_INFO":132,"ENETUNREACH":101,"_SC_XOPEN_REALTIME_THREADS":131,"_SC_2_LOCALEDEF":52,"_PC_SYMLINK_MAX":19,"X_OK":1,"EMSCRIPTEN_EVENT_KEYUP":3,"AI_CANONNAME":2,"UUID_VARIANT_NCS":0,"ESPIPE":29,"AUDIO_S32MSB":36896,"EMSCRIPTEN_EVENT_WHEEL":9,"SDL_AUDIO_ALLOW_CHANNELS_CHANGE":4,"_SC_XOPEN_REALTIME":130,"EAI_NONAME":-2,"_PC_PIPE_BUF":5,"EROFS":30,"EM_PROXIED_ATEXIT":110,"ECONNREFUSED":111,"_SC_2_PBS_ACCOUNTING":169,"EMSCRIPTEN_EVENT_FOCUS":13,"AUDIO_S16SYS":32784,"ENETDOWN":100,"ENOEXEC":8,"ENOSPC":28,"EBADF":9,"EAI_SOCKTYPE":-7,"EDOTDOT":73,"_SC_THREAD_ATTR_STACKSIZE":78,"EBADFD":77,"O_ACCMODE":2097155,"EBADR":53,"EM_PROXIED_SBRK":73,"S_IFCHR":8192,"SDL_PATCHLEVEL":0,"ABMON_12":131097,"PTHREAD_KEYS_MAX":128,"ENOMEDIUM":123,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE":0,"AUDIO_U16MSB":4112,"EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR":2,"_SC_2_CHAR_TERM":95,"EMSCRIPTEN_EVENT_TOUCHEND":23,"_SC_AIO_LISTIO_MAX":23,"_SC_BC_SCALE_MAX":38,"ENOTBLK":15,"EAI_BADFLAGS":-1,"EOVERFLOW":75,"EMSCRIPTEN_EVENT_DBLCLICK":7,"SDL_AUDIO_MASK_SIGNED":32768,"EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST":1,"ABMON_11":131096,"ABMON_10":131095,"AT_FDCWD":-100,"_SC_TTY_NAME_MAX":72}}
\ No newline at end of file
+{"structs":{"utsname":{"sysname":0,"nodename":65,"domainname":325,"machine":260,"version":195,"release":130,"__size__":390},"sockaddr":{"sa_data":2,"sa_family":0,"__size__":16},"addrinfo":{"ai_flags":0,"ai_next":28,"ai_canonname":24,"ai_socktype":8,"ai_addr":20,"ai_protocol":12,"ai_family":4,"ai_addrlen":16,"__size__":32},"timespec":{"tv_sec":0,"tv_nsec":4,"__size__":8},"utimbuf":{"modtime":4,"actime":0,"__size__":8},"EmscriptenVisibilityChangeEvent":{"hidden":0,"visibilityState":4,"__size__":8},"SDL_MouseButtonEvent":{"timestamp":4,"button":16,"state":17,"windowID":8,"which":12,"y":24,"x":20,"padding2":19,"type":0,"padding1":18,"__size__":28},"sockaddr_in":{"sin_port":2,"sin_addr":{"s_addr":4,"__size__":4},"sin_family":0,"sin_zero":8,"__size__":16},"pthread":{"tsd":116,"attr":120,"canceldisable":72,"threadStatus":0,"tsd_used":56,"pid":52,"stack":92,"cancelasync":76,"tid":48,"threadExitCode":4,"detached":80,"profilerBlock":20,"self":24,"stack_size":96,"__size__":220},"WebVRFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"SDL_KeyboardEvent":{"repeat":9,"keysym":12,"state":8,"windowID":4,"__size__":28,"type":0,"padding3":11,"padding2":10},"SDL_MouseMotionEvent":{"yrel":32,"timestamp":4,"state":16,"windowID":8,"which":12,"xrel":28,"y":24,"x":20,"type":0,"__size__":36},"SDL_Rect":{"y":4,"x":0,"h":12,"w":8,"__size__":16},"itimerspec":{"it_interval":{"tv_sec":0,"tv_nsec":4,"__size__":8},"it_value":{"tv_sec":8,"tv_nsec":12,"__size__":8},"__size__":16},"iovec":{"iov_len":4,"iov_base":0,"__size__":8},"timezone":{"tz_dsttime":4,"tz_minuteswest":0,"__size__":8},"flock":{"l_whence":2,"l_type":0,"l_start":4,"__size__":16,"l_len":8,"l_pid":12},"EmscriptenOrientationChangeEvent":{"orientationIndex":0,"orientationAngle":4,"__size__":8},"EmscriptenMouseEvent":{"clientX":16,"clientY":20,"targetX":52,"buttons":42,"timestamp":0,"button":40,"targetY":56,"altKey":32,"canvasY":64,"metaKey":36,"movementX":44,"movementY":48,"shiftKey":28,"ctrlKey":24,"screenY":12,"screenX":8,"canvasX":60,"__size__":72},"SDL_ResizeEvent":{"h":8,"type":0,"w":4,"__size__":12},"tms":{"tms_stime":4,"tms_utime":0,"tms_cstime":12,"tms_cutime":8,"__size__":16},"SDL_Color":{"unused":3,"r":0,"b":2,"g":1,"__size__":4},"EmscriptenKeyboardEvent":{"code":32,"charValue":120,"locale":88,"shiftKey":72,"altKey":76,"which":160,"metaKey":80,"location":64,"key":0,"ctrlKey":68,"charCode":152,"keyCode":156,"repeat":84,"__size__":164},"rusage":{"ru_msgrcv":56,"ru_utime":{"tv_sec":0,"tv_usec":4,"__size__":8},"ru_isrss":28,"ru_stime":{"tv_sec":8,"tv_usec":12,"__size__":8},"ru_nsignals":60,"ru_nivcsw":68,"ru_msgsnd":52,"ru_nswap":40,"ru_minflt":32,"ru_nvcsw":64,"ru_ixrss":20,"ru_inblock":44,"ru_idrss":24,"ru_maxrss":16,"ru_oublock":48,"ru_majflt":36,"__size__":136},"div_t":{"quot":0,"rem":4,"__size__":8},"timeval":{"tv_sec":0,"tv_usec":4,"__size__":8},"rlimit":{"rlim_cur":0,"rlim_max":8,"__size__":16},"in6_addr":{"__in6_union":{"__s6_addr16":0,"__s6_addr":0,"__s6_addr32":0,"__size__":16},"__size__":16},"tm":{"tm_sec":0,"tm_hour":8,"tm_mday":12,"tm_isdst":32,"tm_year":20,"tm_zone":40,"tm_mon":16,"tm_yday":28,"tm_gmtoff":36,"tm_wday":24,"tm_min":4,"__size__":44},"EmscriptenWebGLContextAttributes":{"majorVersion":32,"stencil":8,"preserveDrawingBuffer":20,"failIfMajorPerformanceCaveat":28,"explicitSwapControl":44,"antialias":12,"depth":4,"minorVersion":36,"premultipliedAlpha":16,"enableExtensionsByDefault":40,"alpha":0,"preferLowPowerToHighPerformance":24,"__size__":48},"EmscriptenBatteryEvent":{"dischargingTime":8,"level":16,"charging":24,"chargingTime":0,"__size__":32},"protoent":{"p_aliases":4,"p_proto":8,"p_name":0,"__size__":12},"SDL_Surface":{"userdata":24,"locked":28,"clip_rect":36,"format":4,"h":12,"refcount":56,"map":52,"flags":0,"w":8,"pitch":16,"lock_data":32,"pixels":20,"__size__":60},"EmscriptenTouchEvent":{"touches":20,"shiftKey":8,"altKey":12,"metaKey":16,"ctrlKey":4,"__size__":1684,"numTouches":0},"EmscriptenFocusEvent":{"id":128,"nodeName":0,"__size__":256},"sockaddr_in6":{"sin6_family":0,"sin6_flowinfo":4,"sin6_scope_id":24,"sin6_addr":{"__in6_union":{"__s6_addr16":8,"__s6_addr":8,"__s6_addr32":8,"__size__":16},"__size__":16},"__size__":28,"sin6_port":2},"SDL_JoyAxisEvent":{"__size__":12,"type":0,"value":8,"which":4,"padding2":7,"padding1":6,"axis":5},"netent":{"n_name":0,"n_net":12,"n_addrtype":8,"n_aliases":4,"__size__":16},"SDL_PixelFormat":{"palette":4,"Gloss":29,"Bmask":20,"Bloss":30,"Rloss":28,"format":0,"Gshift":33,"Aloss":31,"BitsPerPixel":8,"refcount":36,"next":40,"padding":10,"Rmask":12,"Bshift":34,"Gmask":16,"BytesPerPixel":9,"Amask":24,"Rshift":32,"Ashift":35,"__size__":44},"SDL_JoyButtonEvent":{"type":0,"button":5,"state":6,"which":4,"padding1":7,"__size__":8},"EmscriptenPointerlockChangeEvent":{"id":132,"nodeName":4,"isActive":0,"__size__":260},"in_addr":{"s_addr":0,"__size__":4},"EmscriptenDeviceOrientationEvent":{"timestamp":0,"beta":16,"alpha":8,"__size__":40,"gamma":24,"absolute":32},"SDL_WindowEvent":{"data2":16,"type":0,"data1":12,"windowID":4,"__size__":20,"padding1":9,"event":8,"padding3":11,"padding2":10},"SDL_Keysym":{"scancode":0,"mod":8,"unicode":12,"sym":4,"__size__":16},"cmsghdr":{"cmsg_type":8,"cmsg_level":4,"cmsg_len":0,"__size__":12},"EmscriptenUiEvent":{"windowInnerWidth":12,"detail":0,"scrollLeft":32,"documentBodyClientHeight":8,"windowInnerHeight":16,"scrollTop":28,"windowOuterHeight":24,"windowOuterWidth":20,"documentBodyClientWidth":4,"__size__":36},"thread_profiler_block":{"threadStatus":0,"timeSpentInStatus":16,"currentStatusStartTime":8,"name":72,"__size__":104},"stat":{"st_rdev":28,"st_mtim":{"tv_sec":56,"tv_nsec":60,"__size__":8},"st_blocks":44,"st_atim":{"tv_sec":48,"tv_nsec":52,"__size__":8},"st_nlink":16,"__st_ino_truncated":8,"st_ctim":{"tv_sec":64,"tv_nsec":68,"__size__":8},"st_mode":12,"st_blksize":40,"__st_dev_padding":4,"st_dev":0,"st_size":36,"st_gid":24,"__st_rdev_padding":32,"st_uid":20,"st_ino":72,"__size__":76},"pollfd":{"fd":0,"events":4,"revents":6,"__size__":8},"WebVRPositionState":{"linearVelocity":{"y":56,"x":48,"z":64,"w":72,"__size__":32},"orientation":{"y":128,"x":120,"z":136,"w":144,"__size__":32},"timeStamp":0,"angularVelocity":{"y":160,"x":152,"z":168,"w":176,"__size__":32},"hasPosition":8,"angularAcceleration":{"y":192,"x":184,"z":200,"w":208,"__size__":32},"linearAcceleration":{"y":88,"x":80,"z":96,"w":104,"__size__":32},"hasOrientation":112,"position":{"y":24,"x":16,"z":32,"w":40,"__size__":32},"__size__":216},"dirent":{"d_name":11,"d_off":4,"d_ino":0,"d_reclen":8,"d_type":10,"__size__":268},"EmscriptenTouchPoint":{"clientX":12,"clientY":16,"identifier":0,"targetX":36,"targetY":40,"isChanged":28,"canvasY":48,"canvasX":44,"pageX":20,"pageY":24,"screenY":8,"screenX":4,"onTarget":32,"__size__":52},"EmscriptenDeviceMotionEvent":{"timestamp":0,"accelerationIncludingGravityZ":48,"accelerationIncludingGravityX":32,"accelerationIncludingGravityY":40,"accelerationY":16,"accelerationX":8,"rotationRateBeta":64,"accelerationZ":24,"rotationRateGamma":72,"rotationRateAlpha":56,"__size__":80},"SDL_AudioSpec":{"padding":10,"userdata":20,"format":4,"channels":6,"callback":16,"samples":8,"freq":0,"size":12,"silence":7,"__size__":24},"hostent":{"h_addrtype":8,"h_addr_list":16,"h_name":0,"__size__":20,"h_aliases":4,"h_length":12},"SDL_MouseWheelEvent":{"timestamp":4,"windowID":8,"which":12,"y":20,"x":16,"type":0,"__size__":24},"linger":{"l_onoff":0,"l_linger":4,"__size__":8},"SDL_version":{"major":0,"patch":2,"minor":1,"__size__":3},"statvfs":{"f_bsize":0,"f_bavail":16,"f_fsid":32,"f_favail":28,"f_files":20,"f_frsize":4,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flag":40,"f_namemax":44,"__size__":72},"EmscriptenFullscreenChangeEvent":{"elementWidth":264,"screenWidth":272,"nodeName":8,"elementHeight":268,"fullscreenEnabled":4,"screenHeight":276,"isFullscreen":0,"id":136,"__size__":280},"EmscriptenWheelEvent":{"deltaX":72,"deltaY":80,"deltaZ":88,"deltaMode":96,"mouse":0,"__size__":104},"WebVRIntRect":{"y":4,"x":0,"height":12,"width":8,"__size__":16},"SDL_TouchFingerEvent":{"timestamp":4,"dy":36,"touchId":8,"pressure":40,"dx":32,"type":0,"y":28,"x":24,"fingerId":16,"__size__":48},"SDL_AudioCVT":{"len_ratio":32,"len_cvt":24,"rate_incr":8,"filters":40,"len":20,"needed":0,"filter_index":80,"src_format":4,"len_mult":28,"__size__":88,"buf":16,"dst_format":6},"WebVRPoint":{"y":8,"x":0,"z":16,"w":24,"__size__":32},"timeb":{"dstflag":8,"timezone":6,"time":0,"millitm":4,"__size__":12},"statfs":{"f_bsize":4,"f_bavail":16,"f_fsid":28,"f_files":20,"f_frsize":40,"f_namelen":36,"f_blocks":8,"f_ffree":24,"f_bfree":12,"f_flags":44,"__size__":64},"msghdr":{"msg_iov":8,"msg_iovlen":12,"msg_namelen":4,"msg_controllen":20,"msg_flags":24,"msg_name":0,"msg_control":16,"__size__":28},"WebVREyeParameters":{"currentFieldOfView":{"leftDegrees":152,"upDegrees":128,"downDegrees":144,"rightDegrees":136,"__size__":32},"recommendedFieldOfView":{"leftDegrees":88,"upDegrees":64,"downDegrees":80,"rightDegrees":72,"__size__":32},"eyeTranslation":{"y":104,"x":96,"z":112,"w":120,"__size__":32},"renderRect":{"y":164,"x":160,"height":172,"width":168,"__size__":16},"minimumFieldOfView":{"leftDegrees":24,"upDegrees":0,"downDegrees":16,"rightDegrees":8,"__size__":32},"maximumFieldOfView":{"leftDegrees":56,"upDegrees":32,"downDegrees":48,"rightDegrees":40,"__size__":32},"__size__":176},"SDL_Palette":{"ncolors":0,"colors":4,"version":8,"refcount":12,"__size__":16},"EmscriptenFullscreenStrategy":{"canvasResizedCallbackUserData":16,"canvasResolutionScaleMode":4,"scaleMode":0,"canvasResizedCallback":12,"filteringMode":8,"__size__":20},"EmscriptenGamepadEvent":{"index":1300,"analogButton":528,"timestamp":0,"numButtons":12,"mapping":1368,"digitalButton":1040,"connected":1296,"numAxes":8,"__size__":1432,"id":1304,"axis":16},"SDL_TextInputEvent":{"text":8,"windowID":4,"type":0,"__size__":40}},"defines":{"ETXTBSY":26,"EOF":-1,"EMSCRIPTEN_EVENT_MOUSEOVER":35,"ETOOMANYREFS":109,"ENAMETOOLONG":36,"ENOPKG":65,"UUID_TYPE_DCE_TIME":1,"_SC_XOPEN_LEGACY":129,"_SC_XOPEN_VERSION":89,"F_UNLCK":2,"_SC_BC_DIM_MAX":37,"EL3HLT":46,"S_IFDIR":16384,"EMSCRIPTEN_EVENT_KEYPRESS":1,"EINPROGRESS":115,"_SC_BARRIERS":133,"EMSCRIPTEN_EVENT_TOUCHMOVE":24,"SDL_AUDIO_ALLOW_FREQUENCY_CHANGE":1,"AUDIO_U8":8,"EAI_AGAIN":-3,"_PC_MAX_CANON":1,"ENOTSUP":95,"EFBIG":27,"O_CREAT":64,"EMSCRIPTEN_EVENT_POINTERLOCKERROR":38,"_SC_2_PBS_LOCATE":170,"EM_PROXIED_SETENV":113,"_CS_POSIX_V6_LP64_OFF64_LIBS":1126,"ENOLINK":67,"ABDAY_7":131078,"ABDAY_6":131077,"ABDAY_5":131076,"ABDAY_4":131075,"ABDAY_3":131074,"ABDAY_2":131073,"ABDAY_1":131072,"EL3RST":47,"YESEXPR":327680,"_SC_V6_ILP32_OFFBIG":177,"SDL_MINOR_VERSION":3,"EM_PROXIED_CLEARENV":112,"_SC_MEMLOCK":17,"ENOTUNIQ":76,"EMSCRIPTEN_RESULT_FAILED":-6,"ABMON_1":131086,"ELNRNG":48,"UUID_VARIANT_MICROSOFT":2,"EMSCRIPTEN_EVENT_TOUCHSTART":22,"ENOANO":55,"EMSCRIPTEN_EVENT_FOCUSIN":14,"EMSCRIPTEN_EVENT_MOUSEUP":6,"ENOPROTOOPT":92,"POLLIN":1,"S_IALLUGO":4095,"_SC_THREAD_KEYS_MAX":74,"EM_THREAD_STATUS_WAITPROXY":5,"O_RDWR":2,"EREMCHG":78,"EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED":27,"_SC_2_PBS":168,"_SC_TRACE_INHERIT":183,"_SC_REGEXP":155,"_CS_POSIX_V6_LP64_OFF64_CFLAGS":1124,"_SC_DELAYTIMER_MAX":26,"S_IWUGO":146,"S_IFREG":32768,"F_GETLK64":12,"O_DIRECTORY":65536,"EM_PROXIED_UTIMES":13,"POLLHUP":16,"S_IFMT":61440,"F_SETLK64":13,"_SC_XOPEN_CRYPT":92,"_SC_CLOCK_SELECTION":137,"_PC_CHOWN_RESTRICTED":6,"E2BIG":7,"ABMON_3":131088,"AM_STR":131110,"SDL_AUDIO_MASK_ENDIAN":4096,"ALT_DIGITS":131119,"EHOSTDOWN":112,"EBFONT":59,"ENOTEMPTY":39,"AUDIO_S16":32784,"TIOCGPGRP":21519,"EBUSY":16,"_SC_MQ_PRIO_MAX":28,"_SC_PAGE_SIZE":30,"EADDRINUSE":98,"ENOTSOCK":88,"PM_STR":131111,"O_WRONLY":1,"_SC_STREAM_MAX":5,"ABMON_9":131094,"ELIBACC":79,"S_IFIFO":4096,"EDQUOT":122,"EAI_SYSTEM":-11,"ENOENT":2,"_SC_TIMERS":11,"O_SYNC":1052672,"SEEK_END":2,"EM_THREAD_STATUS_FINISHED":6,"_PC_REC_MIN_XFER_SIZE":16,"_PC_PATH_MAX":4,"_SC_SPORADIC_SERVER":160,"ECOMM":70,"_SC_NPROCESSORS_ONLN":84,"_CS_POSIX_V6_LPBIG_OFFBIG_LIBS":1130,"_PC_MAX_INPUT":2,"_SC_VERSION":29,"_SC_XBS5_LPBIG_OFFBIG":128,"_SC_CLK_TCK":2,"ABMON_2":131087,"EXFULL":54,"ABMON_7":131092,"ABMON_6":131091,"ABMON_5":131090,"ABMON_4":131089,"ENOTDIR":20,"ABMON_8":131093,"_SC_AIO_MAX":24,"ERA":131116,"EM_PROXIED_UNSETENV":114,"_SC_THREAD_PRIO_INHERIT":80,"_PC_2_SYMLINKS":20,"_SC_XBS5_LP64_OFF64":127,"EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE":30,"ENETRESET":102,"EAFNOSUPPORT":97,"MON_2":131099,"MON_3":131100,"MON_1":131098,"EMSCRIPTEN_EVENT_DEVICEORIENTATION":16,"MON_7":131104,"MON_4":131101,"MON_5":131102,"_SC_SPAWN":159,"MON_8":131105,"MON_9":131106,"_CS_POSIX_V6_ILP32_OFF32_LDFLAGS":1117,"S_IFSOCK":49152,"S_IRUGO":292,"SOCK_DGRAM":2,"POLLERR":8,"EINVAL":22,"_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS":1128,"POLLRDNORM":64,"AUDIO_F32SYS":33056,"_SC_TRACE_SYS_MAX":244,"AI_V4MAPPED":8,"AI_NUMERICHOST":4,"_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS":1,"EHOSTUNREACH":113,"ENOCSI":50,"EPROTONOSUPPORT":93,"_SC_AIO_PRIO_DELTA_MAX":25,"_SC_MONOTONIC_CLOCK":149,"ETIME":62,"ENOTTY":25,"_SC_XOPEN_ENH_I18N":93,"EAI_SERVICE":-8,"EAGAIN":11,"F_SETLKW64":14,"EMSGSIZE":90,"ELIBEXEC":83,"_SC_MEMORY_PROTECTION":19,"EMSCRIPTEN_FULLSCREEN_SCALE_CENTER":3,"SDL_AUDIO_ALLOW_FORMAT_CHANGE":2,"ECANCELED":125,"_SC_SPIN_LOCKS":154,"_SC_XOPEN_SHM":94,"_PC_LINK_MAX":0,"TIOCSPGRP":21520,"EOPNOTSUPP":95,"EMSCRIPTEN_EVENT_MOUSEENTER":33,"EAI_FAIL":-4,"NOEXPR":327681,"_SC_FSYNC":15,"_SC_GETGR_R_SIZE_MAX":69,"EDESTADDRREQ":89,"EADDRNOTAVAIL":99,"AUDIO_S32SYS":32800,"_SC_TRACE_NAME_MAX":243,"_SC_BC_BASE_MAX":36,"EMSCRIPTEN_EVENT_CANVASRESIZED":37,"EPERM":1,"EAI_FAMILY":-6,"O_NOFOLLOW":131072,"SOCK_STREAM":1,"O_APPEND":1024,"_SC_XOPEN_STREAMS":246,"_SC_GETPW_R_SIZE_MAX":70,"MON_6":131103,"EPROTOTYPE":91,"_SC_CPUTIME":138,"EISCONN":106,"_SC_XBS5_ILP32_OFFBIG":126,"S_IFBLK":24576,"T_FMT_AMPM":131115,"SDL_PIXELFORMAT_RGBA8888":-2042224636,"F_SETLKW":14,"SDL_TOUCH_MOUSEID":-1,"EMSCRIPTEN_EVENT_SCROLL":11,"ELOOP":40,"_SC_OPEN_MAX":4,"_SC_2_FORT_RUN":50,"EMSCRIPTEN_EVENT_VISIBILITYCHANGE":21,"EREMOTE":66,"_SC_RE_DUP_MAX":44,"_SC_THREAD_PRIO_PROTECT":81,"_SC_2_PBS_CHECKPOINT":175,"_SC_2_PBS_TRACK":172,"MON_10":131107,"MON_11":131108,"MON_12":131109,"TCGETS":21505,"_SC_THREAD_PROCESS_SHARED":82,"AF_INET":2,"_SC_SHARED_MEMORY_OBJECTS":22,"F_GETFD":1,"EMSCRIPTEN_EVENT_DEVICEMOTION":17,"SDL_MIX_MAXVOLUME":128,"_PC_ALLOC_SIZE_MIN":18,"TCSETS":21506,"ELIBMAX":82,"_SC_READER_WRITER_LOCKS":153,"EMULTIHOP":72,"IPPROTO_TCP":6,"_SC_PHYS_PAGES":85,"_SC_MEMLOCK_RANGE":18,"_SC_PRIORITY_SCHEDULING":10,"T_FMT":131114,"AI_ALL":16,"_PC_VDISABLE":8,"THOUSEP":65537,"_SC_TRACE_EVENT_FILTER":182,"ERA_T_FMT":131121,"_SC_THREAD_ATTR_STACKADDR":77,"_SC_THREAD_THREADS_MAX":76,"_SC_LOGIN_NAME_MAX":71,"_SC_2_C_BIND":47,"_PC_NO_TRUNC":7,"ECONNABORTED":103,"EMSCRIPTEN_RESULT_SUCCESS":0,"_SC_SHELL":157,"EFAULT":14,"_SC_V6_LP64_OFF64":178,"_CS_GNU_LIBC_VERSION":2,"ENODATA":61,"_SC_SEM_VALUE_MAX":33,"_SC_MQ_OPEN_MAX":27,"AI_ADDRCONFIG":32,"_SC_HOST_NAME_MAX":180,"_SC_THREAD_STACK_MIN":75,"_SC_TIMEOUTS":164,"POLLOUT":4,"_SC_IPV6":235,"_SC_CHILD_MAX":1,"EDOM":33,"_SC_2_PBS_MESSAGE":171,"EILSEQ":84,"UUID_VARIANT_DCE":1,"_SC_2_C_DEV":48,"_SC_TIMER_MAX":35,"FP_ZERO":2,"EPFNOSUPPORT":96,"ENONET":64,"ECHRNG":44,"_SC_THREADS":67,"_SC_REALTIME_SIGNALS":9,"CLOCKS_PER_SEC":1000000,"ERA_D_T_FMT":131120,"ESRCH":3,"D_FMT":131113,"POLLPRI":2,"_PC_ASYNC_IO":10,"DAY_2":131080,"DAY_3":131081,"DAY_1":131079,"DAY_6":131084,"DAY_7":131085,"DAY_4":131082,"DAY_5":131083,"_SC_SYNCHRONIZED_IO":14,"EL2HLT":51,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF":1,"IPPROTO_UDP":17,"_SC_MAPPED_FILES":16,"EL2NSYNC":45,"_SC_NGROUPS_MAX":3,"ENOMSG":42,"EISDIR":21,"_SC_SEMAPHORES":21,"AI_NUMERICSERV":1024,"EDEADLOCK":35,"EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST":31,"EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE":29,"AUDIO_F32LSB":33056,"_SC_COLL_WEIGHTS_MAX":40,"SO_ERROR":4,"ECONNRESET":104,"AT_SYMLINK_NOFOLLOW":256,"_SC_TRACE_LOG":184,"AUDIO_U16LSB":16,"ESTRPIPE":86,"ESHUTDOWN":108,"_PC_SOCK_MAXBUF":12,"_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS":1129,"EDEADLK":35,"_CS_POSIX_V6_ILP32_OFF32_CFLAGS":1116,"EBADRQC":56,"_SC_THREAD_DESTRUCTOR_ITERATIONS":73,"_SC_TYPED_MEMORY_OBJECTS":165,"_SC_TRACE_EVENT_NAME_MAX":242,"_SC_BC_STRING_MAX":39,"_SC_2_SW_DEV":51,"FP_NAN":0,"F_SETOWN":8,"EMSCRIPTEN_EVENT_RESIZE":10,"_SC_ARG_MAX":0,"_SC_THREAD_PRIORITY_SCHEDULING":79,"F_GETLK":12,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF":2,"FIONREAD":21531,"_SC_THREAD_CPUTIME":139,"EMSCRIPTEN_EVENT_POINTERLOCKCHANGE":20,"EM_THREAD_STATUS_NOTSTARTED":0,"_CS_POSIX_V6_ILP32_OFF32_LIBS":1118,"EUNATCH":49,"AUDIO_S8":32776,"AUDIO_S32LSB":32800,"SDL_AUDIO_MASK_BITSIZE":255,"ERA_D_FMT":131118,"AUDIO_F32MSB":37152,"_CS_POSIX_V6_LP64_OFF64_LDFLAGS":1125,"FP_INFINITE":1,"ECHILD":10,"EAI_MEMORY":-10,"EM_PROXIED_FPATHCONF":46,"O_TRUNC":512,"ETIMEDOUT":110,"EALREADY":114,"ENXIO":6,"NI_NUMERICHOST":1,"EMFILE":24,"F_GETOWN":9,"EMLINK":31,"F_SETFD":2,"ENFILE":23,"EM_PROXIED_SYSCONF":72,"EM_PROXIED_GETENV":111,"SDL_MAJOR_VERSION":1,"ENOMEM":12,"ENOSR":63,"SDL_AUDIO_ALLOW_ANY_CHANGE":7,"EOWNERDEAD":130,"_PC_PRIO_IO":11,"ELIBSCN":81,"_SC_V6_LPBIG_OFFBIG":179,"EM_PROXIED_CHROOT":37,"EMSCRIPTEN_EVENT_CLICK":4,"_SC_EXPR_NEST_MAX":42,"_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS":1120,"EBADSLT":57,"AUDIO_S16MSB":36880,"S_ISVTX":512,"EMSCRIPTEN_RESULT_DEFERRED":1,"EMSCRIPTEN_RESULT_UNKNOWN_TARGET":-4,"S_IRWXUGO":511,"EM_PROXIED_TZSET":119,"_CS_GNU_LIBPTHREAD_VERSION":3,"_PC_REC_MAX_XFER_SIZE":15,"UUID_VARIANT_OTHER":3,"EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED":32,"EM_PROXIED_PTHREAD_CREATE":137,"EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT":0,"RADIXCHAR":65536,"AF_UNSPEC":0,"ENOSTR":60,"W_OK":2,"AUDIO_S32":32800,"EACCES":13,"R_OK":4,"S_IRWXO":7,"_SC_V6_ILP32_OFF32":176,"EMSCRIPTEN_EVENT_FULLSCREENCHANGE":19,"EIO":5,"EMSCRIPTEN_RESULT_NOT_SUPPORTED":-1,"EM_PROXIED_CONFSTR":68,"_SC_SIGQUEUE_MAX":34,"EWOULDBLOCK":11,"AUDIO_U16SYS":16,"EMSCRIPTEN_EVENT_FOCUSOUT":15,"EAI_OVERFLOW":-12,"SDL_AUDIO_MASK_DATATYPE":256,"MAP_PRIVATE":2,"_SC_TZNAME_MAX":6,"_CS_PATH":0,"SEEK_SET":0,"EBADE":52,"EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED":-2,"INT_MAX":2147483647,"EMSCRIPTEN_EVENT_KEYDOWN":2,"EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH":1,"_SC_MESSAGE_PASSING":20,"_SC_THREAD_SAFE_FUNCTIONS":68,"_SC_SYMLOOP_MAX":173,"_PC_NAME_MAX":3,"O_EXCL":128,"_SC_TRACE_USER_EVENT_MAX":245,"_PC_REC_XFER_ALIGN":17,"EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT":0,"_SC_RAW_SOCKETS":236,"_SC_2_UPE":97,"EMSCRIPTEN_RESULT_NO_DATA":-7,"EMSCRIPTEN_EVENT_BLUR":12,"_SC_RTSIG_MAX":31,"ESOCKTNOSUPPORT":94,"_SC_PRIORITIZED_IO":13,"_SC_XOPEN_UNIX":91,"CODESET":14,"EPIPE":32,"_PC_REC_INCR_XFER_SIZE":14,"F_SETLK":13,"_PC_FILESIZEBITS":13,"_SC_XBS5_ILP32_OFF32":125,"RAND_MAX":2147483647,"EM_PROXIED_SYSCALL":138,"ENOLCK":37,"EM_PROXIED_PUTENV":115,"AUDIO_U16":16,"EMSCRIPTEN_EVENT_MOUSELEAVE":34,"EMSCRIPTEN_EVENT_MOUSEOUT":36,"_SC_2_VERSION":46,"_PC_SYNC_IO":9,"EEXIST":17,"FP_NORMAL":4,"O_RDONLY":0,"_SC_SEM_NSEMS_MAX":32,"_SC_IOV_MAX":60,"EPROTO":71,"_SC_TRACE":181,"ESRMNT":69,"_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS":1121,"INADDR_LOOPBACK":2130706433,"EXDEV":18,"EM_THREAD_STATUS_RUNNING":1,"EMSCRIPTEN_EVENT_BEFOREUNLOAD":28,"EM_THREAD_STATUS_WAITFUTEX":3,"EMSCRIPTEN_RESULT_INVALID_TARGET":-3,"_SC_THREAD_SPORADIC_SERVER":161,"F_SETFL":4,"AI_PASSIVE":1,"ELIBBAD":80,"_SC_LINE_MAX":43,"D_T_FMT":131112,"ERANGE":34,"ESTALE":116,"F_DUPFD":0,"AUDIO_F32":33056,"CLOCK_MONOTONIC":1,"EMSCRIPTEN_EVENT_GAMEPADCONNECTED":26,"F_GETOWN_EX":16,"_SC_ASYNCHRONOUS_IO":12,"ENOTRECOVERABLE":131,"ENOBUFS":105,"EIDRM":43,"EMSCRIPTEN_EVENT_ORIENTATIONCHANGE":18,"CRNCYSTR":262159,"EINTR":4,"EADV":68,"ENOSYS":38,"_CS_POSIX_V6_ILP32_OFFBIG_LIBS":1122,"EM_PROXIED_UTIME":12,"F_GETFL":3,"S_IXUGO":73,"_SC_2_FORT_DEV":49,"SDL_COMPILEDVERSION":1300,"EBADMSG":74,"EUSERS":87,"CLOCK_REALTIME":0,"ENODEV":19,"AF_INET6":10,"_SC_ATEXIT_MAX":87,"_SC_SAVED_IDS":8,"SOL_SOCKET":1,"S_IFLNK":40960,"AUDIO_S16LSB":32784,"POLLNVAL":32,"EMSCRIPTEN_EVENT_TOUCHCANCEL":25,"EMSCRIPTEN_RESULT_INVALID_PARAM":-5,"EMSCRIPTEN_EVENT_MOUSEDOWN":5,"EM_THREAD_STATUS_SLEEPING":2,"_SC_JOB_CONTROL":7,"NI_NAMEREQD":8,"EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT":2,"EMSCRIPTEN_EVENT_MOUSEMOVE":8,"UUID_TYPE_DCE_RANDOM":4,"ENOTCONN":107,"_SC_ADVISORY_INFO":132,"ENETUNREACH":101,"_SC_XOPEN_REALTIME_THREADS":131,"_SC_2_LOCALEDEF":52,"_PC_SYMLINK_MAX":19,"X_OK":1,"EMSCRIPTEN_EVENT_KEYUP":3,"AI_CANONNAME":2,"UUID_VARIANT_NCS":0,"ESPIPE":29,"AUDIO_S32MSB":36896,"EMSCRIPTEN_EVENT_WHEEL":9,"SDL_AUDIO_ALLOW_CHANNELS_CHANGE":4,"_SC_XOPEN_REALTIME":130,"EAI_NONAME":-2,"_PC_PIPE_BUF":5,"EROFS":30,"EM_PROXIED_ATEXIT":110,"ECONNREFUSED":111,"_SC_2_PBS_ACCOUNTING":169,"EMSCRIPTEN_EVENT_FOCUS":13,"AUDIO_S16SYS":32784,"ENETDOWN":100,"ENOEXEC":8,"ENOSPC":28,"EBADF":9,"EAI_SOCKTYPE":-7,"EDOTDOT":73,"_SC_THREAD_ATTR_STACKSIZE":78,"EBADFD":77,"O_ACCMODE":2097155,"EBADR":53,"EM_PROXIED_SBRK":73,"S_IFCHR":8192,"SDL_PATCHLEVEL":0,"ABMON_12":131097,"PTHREAD_KEYS_MAX":128,"ENOMEDIUM":123,"EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE":0,"AUDIO_U16MSB":4112,"EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR":2,"_SC_2_CHAR_TERM":95,"EMSCRIPTEN_EVENT_TOUCHEND":23,"_SC_AIO_LISTIO_MAX":23,"_SC_BC_SCALE_MAX":38,"ENOTBLK":15,"EAI_BADFLAGS":-1,"EOVERFLOW":75,"EMSCRIPTEN_EVENT_DBLCLICK":7,"SDL_AUDIO_MASK_SIGNED":32768,"EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST":1,"ABMON_11":131096,"ABMON_10":131095,"AT_FDCWD":-100,"_SC_TTY_NAME_MAX":72}}
\ No newline at end of file
diff --git a/src/struct_info.json b/src/struct_info.json
index 80814ea2197bc..c828bf084ae09 100644
--- a/src/struct_info.json
+++ b/src/struct_info.json
@@ -1198,6 +1198,7 @@
             "EMSCRIPTEN_EVENT_MOUSEOVER",
             "EMSCRIPTEN_EVENT_MOUSEOUT",
             "EMSCRIPTEN_EVENT_CANVASRESIZED",
+            "EMSCRIPTEN_EVENT_POINTERLOCKERROR",
 
             "EMSCRIPTEN_RESULT_SUCCESS",
             "EMSCRIPTEN_RESULT_DEFERRED",
@@ -1371,7 +1372,8 @@
               "failIfMajorPerformanceCaveat",
               "majorVersion",
               "minorVersion",
-              "enableExtensionsByDefault"
+              "enableExtensionsByDefault",
+              "explicitSwapControl"
             ],
             "EmscriptenFullscreenStrategy": [
               "scaleMode",
diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h
index 7d979e252606b..785aa00b9228c 100644
--- a/system/include/emscripten/html5.h
+++ b/system/include/emscripten/html5.h
@@ -53,6 +53,7 @@ extern "C" {
 #define EMSCRIPTEN_EVENT_MOUSEOVER             35
 #define EMSCRIPTEN_EVENT_MOUSEOUT              36
 #define EMSCRIPTEN_EVENT_CANVASRESIZED         37
+#define EMSCRIPTEN_EVENT_POINTERLOCKERROR      38
 
 #define EMSCRIPTEN_RESULT int
 
@@ -292,6 +293,9 @@ typedef struct EmscriptenPointerlockChangeEvent {
 typedef EM_BOOL (*em_pointerlockchange_callback_func)(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData);
 extern EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(const char *target, void *userData, EM_BOOL useCapture, em_pointerlockchange_callback_func callback);
 
+typedef EM_BOOL (*em_pointerlockerror_callback_func)(int eventType, const void *reserved, void *userData);
+extern EMSCRIPTEN_RESULT emscripten_set_pointerlockerror_callback(const char *target, void *userData, EM_BOOL useCapture, em_pointerlockerror_callback_func callback);
+
 extern EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(EmscriptenPointerlockChangeEvent *pointerlockStatus);
 
 extern EMSCRIPTEN_RESULT emscripten_request_pointerlock(const char *target, EM_BOOL deferUntilInEventHandler);
@@ -405,6 +409,7 @@ typedef struct EmscriptenWebGLContextAttributes {
   int minorVersion;
 
   EM_BOOL enableExtensionsByDefault;
+  EM_BOOL explicitSwapControl;
 } EmscriptenWebGLContextAttributes;
 
 extern void emscripten_webgl_init_context_attributes(EmscriptenWebGLContextAttributes *attributes);
@@ -425,6 +430,8 @@ extern EMSCRIPTEN_RESULT emscripten_set_webglcontextrestored_callback(const char
 
 extern EM_BOOL emscripten_is_webgl_context_lost(const char *target);
 
+extern EMSCRIPTEN_RESULT emscripten_webgl_commit_frame();
+
 extern EMSCRIPTEN_RESULT emscripten_set_element_css_size(const char *target, double width, double height);
 extern EMSCRIPTEN_RESULT emscripten_get_element_css_size(const char *target, double *width, double *height);
 
diff --git a/system/include/emscripten/threading.h b/system/include/emscripten/threading.h
index 1c8e9b0503279..cc01d2fcab6fb 100644
--- a/system/include/emscripten/threading.h
+++ b/system/include/emscripten/threading.h
@@ -148,6 +148,15 @@ void emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS expectedS
 // When thread profiler is not enabled (not building with --threadprofiling), this is a no-op.
 void emscripten_set_thread_name(pthread_t threadId, const char *name);
 
+// Gets the stored pointer to a string representing the canvases to transfer to the created thread.
+int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t *a, const char **str);
+
+// Specifies a comma-delimited list of canvas DOM element IDs to transfer to the thread to be created.
+// Note: this pointer is weakly stored (not copied) to the given pthread_attr_t, so must be held alive until
+// pthread_create() has been called. If 0 or "", no canvases are transferred. The special value "#canvas" denotes
+// the element stored in Module.canvas.
+int emscripten_pthread_attr_settransferredcanvases(pthread_attr_t *a, const char *str);
+
 struct thread_profiler_block
 {
 	// One of THREAD_STATUS_*
diff --git a/system/include/emscripten/xmmintrin.h b/system/include/emscripten/xmmintrin.h
index 6266dea13bd97..9b21252361abf 100644
--- a/system/include/emscripten/xmmintrin.h
+++ b/system/include/emscripten/xmmintrin.h
@@ -126,7 +126,7 @@ _mm_store_ps(float *__p, __m128 __a)
 #define _MM_HINT_NTA 0
 // No prefetch available, dummy it out.
 static __inline__ void __attribute__((__always_inline__))
-_mm_prefetch(void *__p, int __i)
+_mm_prefetch(const void *__p, int __i)
 {
   ((void)__p);
   ((void)__i);
diff --git a/system/lib/compiler-rt/lib/builtins/udivmodti4.c b/system/lib/compiler-rt/lib/builtins/udivmodti4.c
new file mode 100644
index 0000000000000..803168849c6c2
--- /dev/null
+++ b/system/lib/compiler-rt/lib/builtins/udivmodti4.c
@@ -0,0 +1,238 @@
+/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===
+ *
+ *                    The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __udivmodti4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */ 
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+/* Effects: if rem != 0, *rem = a % b 
+ * Returns: a / b 
+ */
+
+/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+
+COMPILER_RT_ABI tu_int
+__udivmodti4(tu_int a, tu_int b, tu_int* rem)
+{
+    const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+    const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
+    utwords n;
+    n.all = a;
+    utwords d;
+    d.all = b;
+    utwords q;
+    utwords r;
+    unsigned sr;
+    /* special cases, X is unknown, K != 0 */
+    if (n.s.high == 0)
+    {
+        if (d.s.high == 0)
+        {
+            /* 0 X
+             * ---
+             * 0 X
+             */
+            if (rem)
+                *rem = n.s.low % d.s.low;
+            return n.s.low / d.s.low;
+        }
+        /* 0 X
+         * ---
+         * K X
+         */
+        if (rem)
+            *rem = n.s.low;
+        return 0;
+    }
+    /* n.s.high != 0 */
+    if (d.s.low == 0)
+    {
+        if (d.s.high == 0)
+        {
+            /* K X
+             * ---
+             * 0 0
+             */
+            if (rem)
+                *rem = n.s.high % d.s.low;
+            return n.s.high / d.s.low;
+        }
+        /* d.s.high != 0 */
+        if (n.s.low == 0)
+        {
+            /* K 0
+             * ---
+             * K 0
+             */
+            if (rem)
+            {
+                r.s.high = n.s.high % d.s.high;
+                r.s.low = 0;
+                *rem = r.all;
+            }
+            return n.s.high / d.s.high;
+        }
+        /* K K
+         * ---
+         * K 0
+         */
+        if ((d.s.high & (d.s.high - 1)) == 0)     /* if d is a power of 2 */
+        {
+            if (rem)
+            {
+                r.s.low = n.s.low;
+                r.s.high = n.s.high & (d.s.high - 1);
+                *rem = r.all;
+            }
+            return n.s.high >> __builtin_ctzll(d.s.high);
+        }
+        /* K K
+         * ---
+         * K 0
+         */
+        sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+        /* 0 <= sr <= n_udword_bits - 2 or sr large */
+        if (sr > n_udword_bits - 2)
+        {
+           if (rem)
+                *rem = n.all;
+            return 0;
+        }
+        ++sr;
+        /* 1 <= sr <= n_udword_bits - 1 */
+        /* q.all = n.all << (n_utword_bits - sr); */
+        q.s.low = 0;
+        q.s.high = n.s.low << (n_udword_bits - sr);
+        /* r.all = n.all >> sr; */
+        r.s.high = n.s.high >> sr;
+        r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+    }
+    else  /* d.s.low != 0 */
+    {
+        if (d.s.high == 0)
+        {
+            /* K X
+             * ---
+             * 0 K
+             */
+            if ((d.s.low & (d.s.low - 1)) == 0)     /* if d is a power of 2 */
+            {
+                if (rem)
+                    *rem = n.s.low & (d.s.low - 1);
+                if (d.s.low == 1)
+                    return n.all;
+                sr = __builtin_ctzll(d.s.low);
+                q.s.high = n.s.high >> sr;
+                q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+                return q.all;
+            }
+            /* K X
+             * ---
+             * 0 K
+             */
+            sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)
+                                   - __builtin_clzll(n.s.high);
+            /* 2 <= sr <= n_utword_bits - 1
+             * q.all = n.all << (n_utword_bits - sr);
+             * r.all = n.all >> sr;
+             */
+            if (sr == n_udword_bits)
+            {
+                q.s.low = 0;
+                q.s.high = n.s.low;
+                r.s.high = 0;
+                r.s.low = n.s.high;
+            }
+            else if (sr < n_udword_bits)  // 2 <= sr <= n_udword_bits - 1
+            {
+                q.s.low = 0;
+                q.s.high = n.s.low << (n_udword_bits - sr);
+                r.s.high = n.s.high >> sr;
+                r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+            }
+            else              // n_udword_bits + 1 <= sr <= n_utword_bits - 1
+            {
+                q.s.low = n.s.low << (n_utword_bits - sr);
+                q.s.high = (n.s.high << (n_utword_bits - sr)) |
+                           (n.s.low >> (sr - n_udword_bits));
+                r.s.high = 0;
+                r.s.low = n.s.high >> (sr - n_udword_bits);
+            }
+        }
+        else
+        {
+            /* K X
+             * ---
+             * K K
+             */
+            sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
+            /*0 <= sr <= n_udword_bits - 1 or sr large */
+            if (sr > n_udword_bits - 1)
+            {
+               if (rem)
+                    *rem = n.all;
+                return 0;
+            }
+            ++sr;
+            /* 1 <= sr <= n_udword_bits
+             * q.all = n.all << (n_utword_bits - sr);
+             * r.all = n.all >> sr;
+             */
+            q.s.low = 0;
+            if (sr == n_udword_bits)
+            {
+                q.s.high = n.s.low;
+                r.s.high = 0;
+                r.s.low = n.s.high;
+            }
+            else
+            {
+                r.s.high = n.s.high >> sr;
+                r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
+                q.s.high = n.s.low << (n_udword_bits - sr);
+            }
+        }
+    }
+    /* Not a special case
+     * q and r are initialized with:
+     * q.all = n.all << (n_utword_bits - sr);
+     * r.all = n.all >> sr;
+     * 1 <= sr <= n_utword_bits - 1
+     */
+    su_int carry = 0;
+    for (; sr > 0; --sr)
+    {
+        /* r:q = ((r:q)  << 1) | carry */
+        r.s.high = (r.s.high << 1) | (r.s.low  >> (n_udword_bits - 1));
+        r.s.low  = (r.s.low  << 1) | (q.s.high >> (n_udword_bits - 1));
+        q.s.high = (q.s.high << 1) | (q.s.low  >> (n_udword_bits - 1));
+        q.s.low  = (q.s.low  << 1) | carry;
+        /* carry = 0;
+         * if (r.all >= d.all)
+         * {
+         *     r.all -= d.all;
+         *      carry = 1;
+         * }
+         */
+        const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
+        carry = s & 1;
+        r.all -= d.all & s;
+    }
+    q.all = (q.all << 1) | carry;
+    if (rem)
+        *rem = r.all;
+    return q.all;
+}
+
+#endif /* CRT_HAS_128BIT */
diff --git a/system/lib/libc/musl/arch/emscripten/bits/alltypes.h b/system/lib/libc/musl/arch/emscripten/bits/alltypes.h
index e927d2ecf9ce1..a19a46fae9df6 100644
--- a/system/lib/libc/musl/arch/emscripten/bits/alltypes.h
+++ b/system/lib/libc/musl/arch/emscripten/bits/alltypes.h
@@ -90,7 +90,13 @@ typedef long suseconds_t;
 
 
 #if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+#ifdef __EMSCRIPTEN__
+// For canvas transfer implementation in Emscripten, use an extra 10th control field
+// to pass a pointer to a string denoting the WebGL canvases to transfer.
+typedef struct { union { int __i[10]; unsigned __s[10]; } __u; } pthread_attr_t;
+#else
 typedef struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
+#endif
 #define __DEFINED_pthread_attr_t
 #endif
 
diff --git a/system/lib/libc/musl/arch/emscripten/bits/alltypes.h.in b/system/lib/libc/musl/arch/emscripten/bits/alltypes.h.in
index 39c013b0d960e..e40b43a6a7741 100644
--- a/system/lib/libc/musl/arch/emscripten/bits/alltypes.h.in
+++ b/system/lib/libc/musl/arch/emscripten/bits/alltypes.h.in
@@ -16,8 +16,8 @@ TYPEDEF double double_t;
 TYPEDEF long time_t;
 TYPEDEF long suseconds_t;
 
-TYPEDEF struct { union { int __i[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[6]; void *__p[6]; } __u; } pthread_mutex_t;
+TYPEDEF struct { union { int __i[10]; unsigned __s[10]; } __u; } pthread_attr_t;
+TYPEDEF struct { union { int __i[7]; void *__p[7]; } __u; } pthread_mutex_t;
 TYPEDEF struct { union { int __i[12]; void *__p[12]; } __u; } pthread_cond_t;
 TYPEDEF struct { union { int __i[8]; void *__p[8]; } __u; } pthread_rwlock_t;
 TYPEDEF struct { union { int __i[5]; void *__p[5]; } __u; } pthread_barrier_t;
diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c
index 996683b398f25..c630fcdc46682 100644
--- a/system/lib/pthread/library_pthread.c
+++ b/system/lib/pthread/library_pthread.c
@@ -28,6 +28,21 @@
 char *gets(char *);
 #endif
 
+// Extra pthread_attr_t field:
+#define _a_transferredcanvases __u.__s[9]
+
+int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t *a, const char **str)
+{
+	*str = (const char *)a->_a_transferredcanvases;
+	return 0;
+}
+
+int emscripten_pthread_attr_settransferredcanvases(pthread_attr_t *a, const char *str)
+{
+	a->_a_transferredcanvases = (int)str;
+	return 0;
+}
+
 int _pthread_getcanceltype()
 {
 	return pthread_self()->cancelasync;
diff --git a/system/lib/pthreads.symbols b/system/lib/pthreads.symbols
index f09466a381e48..e596b2633cbd4 100644
--- a/system/lib/pthreads.symbols
+++ b/system/lib/pthreads.symbols
@@ -78,6 +78,8 @@
          U emscripten_get_now
          U emscripten_is_main_runtime_thread
          T emscripten_main_thread_process_queued_calls
+         T emscripten_pthread_attr_settransferredcanvases
+         T emscripten_pthread_attr_gettransferredcanvases
          T emscripten_sync_run_in_main_thread
          T emscripten_sync_run_in_main_thread_0
          T emscripten_sync_run_in_main_thread_1
diff --git a/tests/ascii_corpus.txt b/tests/ascii_corpus.txt
new file mode 100644
index 0000000000000..766bc19f3b368
--- /dev/null
+++ b/tests/ascii_corpus.txt
@@ -0,0 +1,35 @@
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed posuere interdum sem. Quisque ligula eros ullamcorper quis, lacinia quis facilisis sed sapien. Mauris varius diam vitae arcu. Sed arcu lectus auctor vitae, consectetuer et venenatis eget velit. Sed augue orci, lacinia eu tincidunt et eleifend nec lacus. Donec ultricies nisl ut felis, suspendisse potenti. Lorem ipsum ligula ut hendrerit mollis, ipsum erat vehicula risus, eu suscipit sem libero nec erat. Aliquam erat volutpat. Sed congue augue vitae neque. Nulla consectetuer porttitor pede. Fusce purus morbi tortor magna condimentum vel, placerat id blandit sit amet tortor.
+
+Mauris sed libero. Suspendisse facilisis nulla in lacinia laoreet, lorem velit accumsan velit vel mattis libero nisl et sem. Proin interdum maecenas massa turpis sagittis in, interdum non lobortis vitae massa. Quisque purus lectus, posuere eget imperdiet nec sodales id arcu. Vestibulum elit pede dictum eu, viverra non tincidunt eu ligula.
+
+Nam molestie nec tortor. Donec placerat leo sit amet velit. Vestibulum id justo ut vitae massa. Proin in dolor mauris consequat aliquam. Donec ipsum, vestibulum ullamcorper venenatis augue. Aliquam tempus nisi in auctor vulputate, erat felis pellentesque augue nec, pellentesque lectus justo nec erat. Aliquam et nisl. Quisque sit amet dolor in justo pretium condimentum.
+
+Vivamus placerat lacus vel vehicula scelerisque, dui enim adipiscing lacus sit amet sagittis, libero enim vitae mi. In neque magna posuere, euismod ac tincidunt tempor est. Ut suscipit nisi eu purus. Proin ut pede mauris eget ipsum. Integer vel quam nunc commodo consequat. Integer ac eros eu tellus dignissim viverra. Maecenas erat aliquam erat volutpat. Ut venenatis ipsum quis turpis. Integer cursus scelerisque lorem. Sed nec mauris id quam blandit consequat. Cras nibh mi hendrerit vitae, dapibus et aliquam et magna. Nulla vitae elit. Mauris consectetuer odio vitae augue.
+
+Cras lobortis sem ultrices leo. Donec magna fusce ac ante. Nullam est nisi blandit eget, suscipit vitae posuere quis ante. Quisque vitae tortor tellus feugiat adipiscing. Morbi ac elit et diam bibendum bibendum. Suspendisse id diam, donec adipiscing vulputate metus. Cras pellentesque vestibulum sem. Maecenas ut elit quis nisl vestibulum bibendum. Aenean eu erat quis turpis consequat vehicula. Morbi lacus velit, tristique ut iaculis volutpat in velit. Duis nec mauris et velit mollis aliquam, nullam posuere. Mauris at turpis sit amet dui imperdiet lobortis, proin eu felis.
+
+Donec nec dui, in viverra tristique sapien. Suspendisse tincidunt consequat ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut lacinia luctus nunc. Etiam molestie hendrerit risus. Curabitur venenatis risus varius odio. Quisque elit ante, lacinia eget mollis sed, fermentum nec nisl. Nullam volutpat odio dolor tempor posuere. Suspendisse et elit vel sem interdum consequat. Aenean pulvinar nisl vel neque. Morbi mi ac neque ullamcorper dignissim. Nulla suscipit ipsum. Duis adipiscing turpis vitae turpis. In quis nisl ut tincidunt felis sit amet ipsum. Fusce facilisis nam tortor orci, facilisis sit amet accumsan vel, aliquam nec odio. Fusce accumsan libero et nisi. Lorem ipsum pede id faucibus aliquet, diam velit commodo elit, quis ultricies justo metus sit amet metus. Suspendisse interdum nulla sit amet enim. Etiam ultrices fusce nibh. Maecenas sed dolor vitae nisi volutpat commodo. Nulla interdum egestas lectus. Maecenas imperdiet arcu et orci.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed posuere interdum sem. Quisque ligula eros ullamcorper quis, lacinia quis facilisis sed sapien. Mauris varius diam vitae arcu. Sed arcu lectus auctor vitae, consectetuer et venenatis eget velit. Sed augue orci, lacinia eu tincidunt et eleifend nec lacus. Donec ultricies nisl ut felis, suspendisse potenti. Lorem ipsum ligula ut hendrerit mollis, ipsum erat vehicula risus, eu suscipit sem libero nec erat. Aliquam erat volutpat. Sed congue augue vitae neque. Nulla consectetuer porttitor pede. Fusce purus morbi tortor magna condimentum vel, placerat id blandit sit amet tortor.
+
+Mauris sed libero. Suspendisse facilisis nulla in lacinia laoreet, lorem velit accumsan velit vel mattis libero nisl et sem. Proin interdum maecenas massa turpis sagittis in, interdum non lobortis vitae massa. Quisque purus lectus, posuere eget imperdiet nec sodales id arcu. Vestibulum elit pede dictum eu, viverra non tincidunt eu ligula.
+
+Nam molestie nec tortor. Donec placerat leo sit amet velit. Vestibulum id justo ut vitae massa. Proin in dolor mauris consequat aliquam. Donec ipsum, vestibulum ullamcorper venenatis augue. Aliquam tempus nisi in auctor vulputate, erat felis pellentesque augue nec, pellentesque lectus justo nec erat. Aliquam et nisl. Quisque sit amet dolor in justo pretium condimentum.
+
+Vivamus placerat lacus vel vehicula scelerisque, dui enim adipiscing lacus sit amet sagittis, libero enim vitae mi. In neque magna posuere, euismod ac tincidunt tempor est. Ut suscipit nisi eu purus. Proin ut pede mauris eget ipsum. Integer vel quam nunc commodo consequat. Integer ac eros eu tellus dignissim viverra. Maecenas erat aliquam erat volutpat. Ut venenatis ipsum quis turpis. Integer cursus scelerisque lorem. Sed nec mauris id quam blandit consequat. Cras nibh mi hendrerit vitae, dapibus et aliquam et magna. Nulla vitae elit. Mauris consectetuer odio vitae augue.
+
+Cras lobortis sem ultrices leo. Donec magna fusce ac ante. Nullam est nisi blandit eget, suscipit vitae posuere quis ante. Quisque vitae tortor tellus feugiat adipiscing. Morbi ac elit et diam bibendum bibendum. Suspendisse id diam, donec adipiscing vulputate metus. Cras pellentesque vestibulum sem. Maecenas ut elit quis nisl vestibulum bibendum. Aenean eu erat quis turpis consequat vehicula. Morbi lacus velit, tristique ut iaculis volutpat in velit. Duis nec mauris et velit mollis aliquam, nullam posuere. Mauris at turpis sit amet dui imperdiet lobortis, proin eu felis.
+
+Donec nec dui, in viverra tristique sapien. Suspendisse tincidunt consequat ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut lacinia luctus nunc. Etiam molestie hendrerit risus. Curabitur venenatis risus varius odio. Quisque elit ante, lacinia eget mollis sed, fermentum nec nisl. Nullam volutpat odio dolor tempor posuere. Suspendisse et elit vel sem interdum consequat. Aenean pulvinar nisl vel neque. Morbi mi ac neque ullamcorper dignissim. Nulla suscipit ipsum. Duis adipiscing turpis vitae turpis. In quis nisl ut tincidunt felis sit amet ipsum. Fusce facilisis nam tortor orci, facilisis sit amet accumsan vel, aliquam nec odio. Fusce accumsan libero et nisi. Lorem ipsum pede id faucibus aliquet, diam velit commodo elit, quis ultricies justo metus sit amet metus. Suspendisse interdum nulla sit amet enim. Etiam ultrices fusce nibh. Maecenas sed dolor vitae nisi volutpat commodo. Nulla interdum egestas lectus. Maecenas imperdiet arcu et orci.
+
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed posuere interdum sem. Quisque ligula eros ullamcorper quis, lacinia quis facilisis sed sapien. Mauris varius diam vitae arcu. Sed arcu lectus auctor vitae, consectetuer et venenatis eget velit. Sed augue orci, lacinia eu tincidunt et eleifend nec lacus. Donec ultricies nisl ut felis, suspendisse potenti. Lorem ipsum ligula ut hendrerit mollis, ipsum erat vehicula risus, eu suscipit sem libero nec erat. Aliquam erat volutpat. Sed congue augue vitae neque. Nulla consectetuer porttitor pede. Fusce purus morbi tortor magna condimentum vel, placerat id blandit sit amet tortor.
+
+Mauris sed libero. Suspendisse facilisis nulla in lacinia laoreet, lorem velit accumsan velit vel mattis libero nisl et sem. Proin interdum maecenas massa turpis sagittis in, interdum non lobortis vitae massa. Quisque purus lectus, posuere eget imperdiet nec sodales id arcu. Vestibulum elit pede dictum eu, viverra non tincidunt eu ligula.
+
+Nam molestie nec tortor. Donec placerat leo sit amet velit. Vestibulum id justo ut vitae massa. Proin in dolor mauris consequat aliquam. Donec ipsum, vestibulum ullamcorper venenatis augue. Aliquam tempus nisi in auctor vulputate, erat felis pellentesque augue nec, pellentesque lectus justo nec erat. Aliquam et nisl. Quisque sit amet dolor in justo pretium condimentum.
+
+Vivamus placerat lacus vel vehicula scelerisque, dui enim adipiscing lacus sit amet sagittis, libero enim vitae mi. In neque magna posuere, euismod ac tincidunt tempor est. Ut suscipit nisi eu purus. Proin ut pede mauris eget ipsum. Integer vel quam nunc commodo consequat. Integer ac eros eu tellus dignissim viverra. Maecenas erat aliquam erat volutpat. Ut venenatis ipsum quis turpis. Integer cursus scelerisque lorem. Sed nec mauris id quam blandit consequat. Cras nibh mi hendrerit vitae, dapibus et aliquam et magna. Nulla vitae elit. Mauris consectetuer odio vitae augue.
+
+Cras lobortis sem ultrices leo. Donec magna fusce ac ante. Nullam est nisi blandit eget, suscipit vitae posuere quis ante. Quisque vitae tortor tellus feugiat adipiscing. Morbi ac elit et diam bibendum bibendum. Suspendisse id diam, donec adipiscing vulputate metus. Cras pellentesque vestibulum sem. Maecenas ut elit quis nisl vestibulum bibendum. Aenean eu erat quis turpis consequat vehicula. Morbi lacus velit, tristique ut iaculis volutpat in velit. Duis nec mauris et velit mollis aliquam, nullam posuere. Mauris at turpis sit amet dui imperdiet lobortis, proin eu felis.
+
+Donec nec dui, in viverra tristique sapien. Suspendisse tincidunt consequat ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut lacinia luctus nunc. Etiam molestie hendrerit risus. Curabitur venenatis risus varius odio. Quisque elit ante, lacinia eget mollis sed, fermentum nec nisl. Nullam volutpat odio dolor tempor posuere. Suspendisse et elit vel sem interdum consequat. Aenean pulvinar nisl vel neque. Morbi mi ac neque ullamcorper dignissim. Nulla suscipit ipsum. Duis adipiscing turpis vitae turpis. In quis nisl ut tincidunt felis sit amet ipsum. Fusce facilisis nam tortor orci, facilisis sit amet accumsan vel, aliquam nec odio. Fusce accumsan libero et nisi. Lorem ipsum pede id faucibus aliquet, diam velit commodo elit, quis ultricies justo metus sit amet metus. Suspendisse interdum nulla sit amet enim. Etiam ultrices fusce nibh. Maecenas sed dolor vitae nisi volutpat commodo. Nulla interdum egestas lectus. Maecenas imperdiet arcu et orci.
diff --git a/tests/benchmark_utf16.cpp b/tests/benchmark_utf16.cpp
new file mode 100644
index 0000000000000..0720964fdce87
--- /dev/null
+++ b/tests/benchmark_utf16.cpp
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <iostream>
+#include <cassert>
+#include <emscripten.h>
+
+double test(const unsigned short *str) {
+  double res = EM_ASM_DOUBLE({
+    var t0 = _emscripten_get_now();
+    var str = Module.UTF16ToString($0);
+    var t1 = _emscripten_get_now();
+    Module.print('t: ' + (t1 - t0) + ', len(result): ' + str.length + ', result: ' + str.slice(0, 100));
+    return (t1-t0);
+  }, str);
+  return res;
+}
+
+unsigned short *utf16_corpus = 0;
+long utf16_corpus_length = 0;
+
+unsigned short *randomString(int len) {
+  if (!utf16_corpus) {
+//    FILE *handle = fopen("ascii_corpus.txt", "rb");
+    FILE *handle = fopen("utf16_corpus.txt", "rb");
+    fseek(handle, 0, SEEK_END);
+    utf16_corpus_length = ftell(handle)/2;
+    assert(utf16_corpus_length > 0);
+    utf16_corpus = new unsigned short[utf16_corpus_length+1];
+    fseek(handle, 0, SEEK_SET);
+    fread(utf16_corpus, 2, utf16_corpus_length, handle);
+    fclose(handle);
+    utf16_corpus[utf16_corpus_length] = 0;
+  }
+  int startIdx = rand() % (utf16_corpus_length - len);
+  while((utf16_corpus[startIdx] & 0xFF00) == 0xDC00) {
+    ++startIdx;
+    if (startIdx + len > utf16_corpus_length) len = utf16_corpus_length - startIdx;
+  }
+  assert(len > 0);
+  unsigned short *s = new unsigned short[len+1];
+  memcpy(s, utf16_corpus + startIdx, len*2);
+  s[len] = 0;
+  while(((unsigned short)s[len-1] & 0xFF00) == 0xD800) { s[--len] = 0; }
+  assert(len >= 0);
+  return s;
+}
+
+int main() {
+  srand(time(NULL));
+  double t = 0;
+  double t2 = emscripten_get_now();
+  for(int i = 0; i < 10; ++i) {
+    // FF Nightly: Already on small strings of 64 bytes in length, TextDecoder trumps in performance.
+    unsigned short *str = randomString(100);
+    t += test(str);
+    free(str);
+  }
+  double t3 = emscripten_get_now();
+  printf("OK. Time: %f (%f).\n", t, t3-t2);
+
+#ifdef REPORT_RESULT
+  int result = 0;
+  REPORT_RESULT();
+#endif
+}
diff --git a/tests/benchmark_utf8.cpp b/tests/benchmark_utf8.cpp
new file mode 100644
index 0000000000000..c677b23b2d3d9
--- /dev/null
+++ b/tests/benchmark_utf8.cpp
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <iostream>
+#include <cassert>
+#include <emscripten.h>
+
+double test(const char *str) {
+  double res = EM_ASM_DOUBLE({
+    var t0 = _emscripten_get_now();
+    var str = Module.UTF8ToString($0);
+    var t1 = _emscripten_get_now();
+//    Module.print('t: ' + (t1 - t0) + ', len(result): ' + str.length + ', result: ' + str.slice(0, 100));
+    return (t1-t0);
+  }, str);
+  return res;
+}
+
+char *utf8_corpus = 0;
+long utf8_corpus_length = 0;
+
+char *randomString(int len) {
+  if (!utf8_corpus) {
+//    FILE *handle = fopen("ascii_corpus.txt", "rb");
+    FILE *handle = fopen("utf8_corpus.txt", "rb");
+    fseek(handle, 0, SEEK_END);
+    utf8_corpus_length = ftell(handle);
+    assert(utf8_corpus_length > 0);
+    utf8_corpus = new char[utf8_corpus_length+1];
+    fseek(handle, 0, SEEK_SET);
+    fread(utf8_corpus, 1, utf8_corpus_length, handle);
+    fclose(handle);
+    utf8_corpus[utf8_corpus_length] = '\0';
+  }
+  int startIdx = rand() % (utf8_corpus_length - len);
+  while(((unsigned char)utf8_corpus[startIdx] & 0xC0) == 0x80) {
+    ++startIdx;
+    if (startIdx + len > utf8_corpus_length) len = utf8_corpus_length - startIdx;
+  }
+  assert(len > 0);
+  char *s = new char[len+1];
+  memcpy(s, utf8_corpus + startIdx, len);
+  s[len] = '\0';
+  while(((unsigned char)s[len-1] & 0xC0) == 0x80) { s[--len] = '\0'; }
+  while(((unsigned char)s[len-1] & 0xC0) == 0xC0) { s[--len] = '\0'; }
+  assert(len >= 0);
+  return s;
+}
+
+int main() {
+  srand(time(NULL));
+  double t = 0;
+  double t2 = emscripten_get_now();
+  for(int i = 0; i < 100000; ++i) {
+    // FF Nightly: Already on small strings of 64 bytes in length, TextDecoder trumps in performance.
+    char *str = randomString(8);
+    t += test(str);
+    free(str);
+  }
+  double t3 = emscripten_get_now();
+  printf("OK. Time: %f (%f).\n", t, t3-t2);
+
+#ifdef REPORT_RESULT
+  int result = 0;
+  REPORT_RESULT();
+#endif
+}
diff --git a/tests/canvas_style_proxy_shell.html b/tests/canvas_style_proxy_shell.html
index 1f795e5d1ee49..166e712e7e40b 100644
--- a/tests/canvas_style_proxy_shell.html
+++ b/tests/canvas_style_proxy_shell.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       .spinner {
         height: 50px;
@@ -61,7 +61,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/tests/core/test_llvm_intrinsics.in b/tests/core/test_llvm_intrinsics.in
index 04f60ed6648eb..a0df641f786d6 100644
--- a/tests/core/test_llvm_intrinsics.in
+++ b/tests/core/test_llvm_intrinsics.in
@@ -17,6 +17,8 @@ extern float llvm_trunc_f32(float x);
 extern double llvm_trunc_f64(double x);
 extern float llvm_floor_f32(float x);
 extern double llvm_floor_f64(double x);
+extern float llvm_sin_f32(float x);
+extern double llvm_sin_f64(double x);
 }
 
 int main(void) {
@@ -38,8 +40,18 @@ int main(void) {
          llvm_cttz_i32(1 << 10, 0));
   printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1),
          llvm_ctpop_i32(0x3101));
-  printf("%d\n", (int)llvm_ctpop_i32(-594093059));
 
+  printf("llvm_ctpop_i32:\n");
+  printf("%d\n", (int)llvm_ctpop_i32(-594093059)); // 22
+  printf("%d\n", (int)llvm_ctpop_i32(0xdeadbeef)); // 24
+  printf("%d\n", (int)llvm_ctpop_i32(0x00000000)); // 0
+  printf("%d\n", (int)llvm_ctpop_i32(0xffffffff)); // 32
+  printf("%d\n", (int)llvm_ctpop_i32(0x55555555)); // 16
+  printf("%d\n", (int)llvm_ctpop_i32(0xa55a5aa5)); // 16
+  printf("%d\n", (int)llvm_ctpop_i32(0xaaaaaaaa)); // 16
+  printf("%d\n", (int)llvm_ctpop_i32(0x80000000)); // 1
+  printf("%d\n", (int)llvm_ctpop_i32(0x00000001)); // 1
+  printf("llvm_expect_i32:\n");
   printf("%d\n", llvm_expect_i32(x % 27, 3));
 
   int64_t a = 1;
@@ -52,6 +64,8 @@ int main(void) {
   printf("%d\n", (int)llvm_trunc_f64(-12.42));
   printf("%d\n", (int)llvm_floor_f32(27.665f));
   printf("%d\n", (int)llvm_floor_f64(-8.95));
+  printf("%.1f\n", llvm_sin_f32(90.0f * 3.14/180));
+  printf("%.1f\n", llvm_sin_f64(270.0 * 3.14/180));
 
   return 0;
 }
diff --git a/tests/core/test_llvm_intrinsics.out b/tests/core/test_llvm_intrinsics.out
index 5a137f8765ec4..157433ceb7a6e 100644
--- a/tests/core/test_llvm_intrinsics.out
+++ b/tests/core/test_llvm_intrinsics.out
@@ -5,7 +5,17 @@ c5,de,15,8a
 23,21
 40,10
 5,4
+llvm_ctpop_i32:
 22
+24
+0
+32
+16
+16
+16
+1
+1
+llvm_expect_i32:
 13
 72057594037927936
 125
@@ -13,4 +23,6 @@ c5,de,15,8a
 18
 -12
 27
--9
\ No newline at end of file
+-9
+1.0
+-1.0
diff --git a/tests/cstdio/test_remove.cpp b/tests/cstdio/test_remove.cpp
new file mode 100644
index 0000000000000..6bc14bd2a1958
--- /dev/null
+++ b/tests/cstdio/test_remove.cpp
@@ -0,0 +1,63 @@
+#include <assert.h>
+#include <errno.h>
+#include <cstdio>
+#include <iostream>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+void create_file(const char *path, const char *buffer, int mode) {
+  int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+  assert(fd >= 0);
+
+  int err = write(fd, buffer, sizeof(char) * strlen(buffer));
+  assert(err ==  (sizeof(char) * strlen(buffer)));
+
+  close(fd);
+}
+
+void setup() {
+  create_file("file", "abcdef", 0777);
+  mkdir("dir", 0777);
+  create_file("dir/file", "abcdef", 0777);
+  mkdir("dir/subdir", 0777);
+}
+
+void cleanup() {
+  // make sure we get it all regardless of anything failing
+  unlink("file");
+  unlink("dir/file");
+  rmdir("dir/subdir");
+  rmdir("dir");
+}
+
+void test() {
+  int err;
+  
+  err = std::remove("dir/file");
+  assert(!err);
+
+  err = std::remove("file");
+  assert(!err);
+
+  // should fail, folder is not empty
+  err = std::remove("dir");
+  assert(err);
+
+  err = std::remove("dir/subdir");
+  assert(!err);
+
+  err = std::remove("dir");
+  assert(!err);
+
+  std::cout << "success";
+}
+
+int main() {
+  atexit(cleanup);
+  setup();
+  test();
+  return EXIT_SUCCESS;
+}
diff --git a/tests/embind/shell.html b/tests/embind/shell.html
index e9f102838190e..e7ec861adaf07 100644
--- a/tests/embind/shell.html
+++ b/tests/embind/shell.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
     </style>
   </head>
   <body>
@@ -25,7 +25,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/tests/gl_in_mainthread_after_pthread.cpp b/tests/gl_in_mainthread_after_pthread.cpp
new file mode 100644
index 0000000000000..2a1b25a927e6c
--- /dev/null
+++ b/tests/gl_in_mainthread_after_pthread.cpp
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <GLES2/gl2.h>
+#include <math.h>
+#include <assert.h>
+#include <emscripten/emscripten.h>
+#include <emscripten/html5.h>
+#include <emscripten/threading.h>
+#include <bits/errno.h>
+#include <stdlib.h>
+
+pthread_t thread;
+
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
+
+int threadRunning = 0;
+
+void *ThreadMain(void *arg)
+{
+  printf("Thread started. You should see the WebGL canvas fade from black to red.\n");
+  EmscriptenWebGLContextAttributes attr;
+  emscripten_webgl_init_context_attributes(&attr);
+  attr.explicitSwapControl = EM_TRUE;
+  ctx = emscripten_webgl_create_context(0, &attr);
+  emscripten_webgl_make_context_current(ctx);
+
+  double color = 0;
+  for(int i = 0; i < 100; ++i)
+  {
+    color += 0.01;
+    glClearColor(color, 0, 0, 1);
+    glClear(GL_COLOR_BUFFER_BIT);
+    EMSCRIPTEN_RESULT r = emscripten_webgl_commit_frame();
+    assert(r == EMSCRIPTEN_RESULT_SUCCESS);
+
+    double now = emscripten_get_now();
+    while(emscripten_get_now() - now < 16) /*no-op*/;
+  }
+
+  emscripten_webgl_make_context_current(0);
+  emscripten_webgl_destroy_context(ctx);
+  emscripten_atomic_store_u32(&threadRunning, 0);
+  printf("Thread quit\n");
+  pthread_exit(0);
+}
+
+void CreateThread()
+{
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  emscripten_pthread_attr_settransferredcanvases(&attr, "#canvas");
+  int rc = pthread_create(&thread, &attr, ThreadMain, 0);
+  if (rc == ENOSYS)
+  {
+    printf("Test Skipped! OffscreenCanvas is not supported!\n");
+#ifdef REPORT_RESULT
+    int result = 0; // But report success, so that runs on non-supporting browsers don't raise noisy errors.
+    REPORT_RESULT();
+#endif
+    exit(0);
+  }
+  pthread_attr_destroy(&attr);
+  emscripten_atomic_store_u32(&threadRunning, 1);
+}
+
+//#define TEST_MAIN_THREAD_EXPLICIT_COMMIT
+
+void MainThreadRender()
+{
+  static double color = 0;
+  color += 0.01;
+  glClearColor(0, color, 0, 1);
+  glClear(GL_COLOR_BUFFER_BIT);
+#ifdef TEST_MAIN_THREAD_EXPLICIT_COMMIT
+  EMSCRIPTEN_RESULT r = emscripten_webgl_commit_frame();
+  assert(r == EMSCRIPTEN_RESULT_SUCCESS);
+  // In explicit swap control mode, whatever we draw here shouldn't show up.
+  glClearColor(1, 0, 1, 1);
+  glClear(GL_COLOR_BUFFER_BIT);
+#endif
+#
+  if (color >= 1.0)
+  {
+    printf("Test finished.\n");
+    emscripten_cancel_main_loop();
+#ifdef REPORT_RESULT
+    int result = 0;
+    REPORT_RESULT();
+#endif
+  }
+}
+
+void PollThreadExit(void *)
+{
+  if (!emscripten_atomic_load_u32(&threadRunning))
+  {
+    EmscriptenWebGLContextAttributes attr;
+    emscripten_webgl_init_context_attributes(&attr);
+#ifdef TEST_MAIN_THREAD_EXPLICIT_COMMIT
+    attr.explicitSwapControl = EM_TRUE;
+#endif
+    ctx = emscripten_webgl_create_context(0, &attr);
+    emscripten_webgl_make_context_current(ctx);
+    printf("Main thread rendering. You should see the WebGL canvas fade from black to green.\n");
+    emscripten_set_main_loop(MainThreadRender, 0, 0);
+  }
+  else
+  {
+    emscripten_async_call(PollThreadExit, 0, 1000);
+  }
+}
+
+int main()
+{
+  EM_ASM(Module['noExitRuntime'] = true;);
+  CreateThread();
+  emscripten_async_call(PollThreadExit, 0, 1000);
+  return 0;
+}
diff --git a/tests/gl_in_pthread.cpp b/tests/gl_in_pthread.cpp
new file mode 100644
index 0000000000000..aac7d596df54f
--- /dev/null
+++ b/tests/gl_in_pthread.cpp
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <GLES2/gl2.h>
+#include <math.h>
+#include <assert.h>
+#include <emscripten/emscripten.h>
+#include <emscripten/html5.h>
+#include <emscripten/threading.h>
+#include <bits/errno.h>
+#include <stdlib.h>
+
+pthread_t thread;
+
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
+
+int threadRunning = 0;
+int numThreadsCreated = 0;
+
+void *ThreadMain(void *arg)
+{
+  switch(numThreadsCreated)
+  {
+    case 1: printf("Thread 1 started: you should see the WebGL canvas fade from black to red.\n"); break;
+    case 2: printf("Thread 2 started: you should see the WebGL canvas fade from black to green.\n"); break;
+    case 3: printf("Thread 3 started: you should see the WebGL canvas fade from black to blue.\n"); break;
+  }
+  EmscriptenWebGLContextAttributes attr;
+  emscripten_webgl_init_context_attributes(&attr);
+  attr.explicitSwapControl = EM_TRUE;
+  ctx = emscripten_webgl_create_context(0, &attr);
+  emscripten_webgl_make_context_current(ctx);
+
+  double color = 0;
+  for(int i = 0; i < 100; ++i)
+  {
+    color += 0.01;
+    switch(numThreadsCreated)
+    {
+      case 1: glClearColor(color, 0, 0, 1); break;
+      case 2: glClearColor(0, color, 0, 1); break;
+      case 3: glClearColor(0, 0, color, 1); break;
+    }
+    glClear(GL_COLOR_BUFFER_BIT);
+    EMSCRIPTEN_RESULT r = emscripten_webgl_commit_frame();
+    assert(r == EMSCRIPTEN_RESULT_SUCCESS);
+
+    double now = emscripten_get_now();
+    while(emscripten_get_now() - now < 16) /*no-op*/;
+  }
+
+  emscripten_webgl_make_context_current(0);
+  emscripten_webgl_destroy_context(ctx);
+  emscripten_atomic_store_u32(&threadRunning, 0);
+  printf("Thread quit\n");
+  pthread_exit(0);
+}
+
+void CreateThread()
+{
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  emscripten_pthread_attr_settransferredcanvases(&attr, "#canvas");
+  int rc = pthread_create(&thread, &attr, ThreadMain, 0);
+  if (rc == ENOSYS)
+  {
+    printf("Test Skipped! OffscreenCanvas is not supported!\n");
+#ifdef REPORT_RESULT
+    int result = 1; // But report success, so that runs on non-supporting browsers don't raise noisy errors.
+    REPORT_RESULT();
+#endif
+    exit(0);
+  }  
+  pthread_attr_destroy(&attr);
+  emscripten_atomic_store_u32(&threadRunning, 1);
+  ++numThreadsCreated;
+}
+
+int result = 0;
+
+void PollTestExit(void *)
+{
+  emscripten_async_call(PollTestExit, 0, 1000);
+}
+
+void PollThreadExit(void *)
+{
+  if (!emscripten_atomic_load_u32(&threadRunning))
+  {
+    if (numThreadsCreated >= 3)
+    {
+      emscripten_atomic_store_u32(&result, 1);
+      return;
+    }
+    else
+    {
+      CreateThread();
+    }
+  }
+  emscripten_async_call(PollThreadExit, 0, 1000);
+}
+
+void *mymain(void*)
+{
+  EM_ASM(Module['noExitRuntime'] = true;);
+  CreateThread();
+  emscripten_async_call(PollThreadExit, 0, 1000);
+  emscripten_async_call(PollTestExit, 0, 1000);
+  return 0;
+}
+
+// #define TEST_CHAINED_WEBGL_CONTEXT_PASSING
+
+int main()
+{
+#ifdef TEST_CHAINED_WEBGL_CONTEXT_PASSING
+  EM_ASM(Module['noExitRuntime'] = true;);
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  emscripten_pthread_attr_settransferredcanvases(&attr, "#canvas");
+  int rc = pthread_create(&thread, &attr, mymain, 0);
+  if (rc == ENOSYS)
+  {
+    printf("Test Skipped! OffscreenCanvas is not supported!\n");
+#ifdef REPORT_RESULT
+    int result = 1; // But report success, so that runs on non-supporting browsers don't raise noisy errors.
+    REPORT_RESULT();
+#endif
+    exit(0);
+  }
+#else
+  mymain(0);
+#endif
+  return 0;
+}
diff --git a/tests/pthread/test_pthread_malloc_free.cpp b/tests/pthread/test_pthread_malloc_free.cpp
index e86d2efe7ff8d..0fdb75c6564c2 100644
--- a/tests/pthread/test_pthread_malloc_free.cpp
+++ b/tests/pthread/test_pthread_malloc_free.cpp
@@ -4,6 +4,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <errno.h>
 #include <vector>
 
 #define NUM_BLOCKS_TO_ALLOC 50000
diff --git a/tests/pthread/test_pthread_mandelbrot.cpp b/tests/pthread/test_pthread_mandelbrot.cpp
index 7539003a1b1fb..5605279175ef8 100644
--- a/tests/pthread/test_pthread_mandelbrot.cpp
+++ b/tests/pthread/test_pthread_mandelbrot.cpp
@@ -281,6 +281,9 @@ pthread_t thread[MAX_NUM_THREADS];
 double timeSpentInMandelbrot[MAX_NUM_THREADS] = {};
 unsigned long long numIters[MAX_NUM_THREADS] = {};
 
+uint32_t numThreadsRunning = 0;
+uint32_t maxThreadsRunning = 1;
+
 bool use_sse = true;
 
 int tasksDone = 0;
@@ -289,6 +292,7 @@ int tasksPending[MAX_NUM_THREADS] = {};
 void *mandelbrot_thread(void *arg)
 {
   int idx = (int)arg;
+  emscripten_atomic_add_u32(&numThreadsRunning, 1);
 
   char threadName[32];
   sprintf(threadName, "Worker %d", idx);
@@ -355,7 +359,7 @@ void register_tasks()
 
   numTasks = EM_ASM_INT_V(return parseInt(document.getElementById('num_threads').value));
   if (numTasks < 1) numTasks = 1;
-  if (numTasks > MAX_NUM_THREADS) numTasks = MAX_NUM_THREADS;
+  if (numTasks > emscripten_num_logical_cores()) numTasks = emscripten_num_logical_cores();
 
   // Register tasks.
   emscripten_atomic_store_u32(&tasksDone, 0);
@@ -374,7 +378,7 @@ void wait_tasks()
   // Wait for each task to finish.
   for(;;)
   {
-    int td = tasksDone;
+    int td = emscripten_atomic_load_u32(&tasksDone);
     if (td >= numTasks)
       break;
     emscripten_futex_wait(&tasksDone, td, 1);
@@ -385,6 +389,9 @@ void wait_tasks()
 
 void main_tick()
 {
+  const int threadsRunning = emscripten_atomic_load_u32(&numThreadsRunning);
+  if (threadsRunning < maxThreadsRunning) return;
+
   wait_tasks();
   numItersDoneOnCanvas += numItersPerFrame;
 
@@ -548,7 +555,8 @@ int main(int argc, char** argv)
     outputImage[i] = 0x00000000;
 
 #ifndef SINGLETHREADED
-  for(int i = 0; i < MAX_NUM_THREADS; ++i)
+  maxThreadsRunning = emscripten_num_logical_cores() < MAX_NUM_THREADS ? emscripten_num_logical_cores() : MAX_NUM_THREADS;
+  for(int i = 0; i < maxThreadsRunning; ++i)
   {
     pthread_attr_t attr;
     pthread_attr_init(&attr);
diff --git a/tests/pthread/test_pthread_mandelbrot_shell.html b/tests/pthread/test_pthread_mandelbrot_shell.html
index 3bffad411531f..86583bf5cda58 100644
--- a/tests/pthread/test_pthread_mandelbrot_shell.html
+++ b/tests/pthread/test_pthread_mandelbrot_shell.html
@@ -15,7 +15,7 @@
       div.emscripten { text-align: center; }      
       div.emscripten_border { border: 1px solid black; background: black;}
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       #emscripten_logo {
         display: inline-block;
@@ -1197,7 +1197,7 @@
 <span id='controls' style="display:none">
   <span><input type="checkbox" id="resize">Resize canvas</span>
   <span><input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer &nbsp;&nbsp;&nbsp;</span>
-  <span><input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+  <span><input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                             document.getElementById('resize').checked)">
   </span>
 </span>
diff --git a/tests/runner.py b/tests/runner.py
index ae47453ab6686..bb5b04dc21634 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -120,12 +120,19 @@ class RunnerCore(unittest.TestCase):
 
   env = {}
 
+  EM_TESTRUNNER_DETECT_TEMPFILE_LEAKS = int(os.getenv('EM_TESTRUNNER_DETECT_TEMPFILE_LEAKS')) if os.getenv('EM_TESTRUNNER_DETECT_TEMPFILE_LEAKS') != None else 0
+
+  temp_files_before_run = []
+
   def skipme(self): # used by tests we ask on the commandline to be skipped, see right before call to unittest.main
     return self.skip('requested to be skipped')
 
   def is_emterpreter(self):
     return False
 
+  def is_wasm_backend(self):
+    return LLVM_TARGET == WASM_TARGET
+
   def uses_memory_init_file(self):
     if self.emcc_args is None:
       return None
@@ -136,6 +143,12 @@ def uses_memory_init_file(self):
 
   def setUp(self):
     Settings.reset()
+
+    if self.EM_TESTRUNNER_DETECT_TEMPFILE_LEAKS:
+      for root, dirnames, filenames in os.walk(TEMP_DIR):
+        for dirname in dirnames: self.temp_files_before_run.append(os.path.normpath(os.path.join(root, dirname)))
+        for filename in filenames: self.temp_files_before_run.append(os.path.normpath(os.path.join(root, filename)))
+
     self.banned_js_engines = []
     self.use_all_engines = use_all_engines
     if not self.save_dir:
@@ -163,6 +176,19 @@ def tearDown(self):
       os.chdir(os.path.join(self.get_dir(), '..'))
       try_delete(self.get_dir())
 
+      if self.EM_TESTRUNNER_DETECT_TEMPFILE_LEAKS and not os.environ.get('EMCC_DEBUG'):
+        temp_files_after_run = []
+        for root, dirnames, filenames in os.walk(TEMP_DIR):
+          for dirname in dirnames: temp_files_after_run.append(os.path.normpath(os.path.join(root, dirname)))
+          for filename in filenames: temp_files_after_run.append(os.path.normpath(os.path.join(root, filename)))
+
+        left_over_files = list(set(temp_files_after_run) - set(self.temp_files_before_run))
+        if len(left_over_files) > 0:
+          print >> sys.stderr, 'ERROR: After running test, there are ' + str(len(left_over_files)) + ' new temporary files/directories left behind:'
+          for f in left_over_files:
+            print >> sys.stderr, 'leaked file: ' + f
+          raise Exception('Test leaked ' + str(len(left_over_files)) + ' temporary files!')
+
       # Make sure we don't leave stuff around
       #if not self.has_prev_ll:
       #  for temp_file in os.listdir(TEMP_DIR):
@@ -579,6 +605,10 @@ def do_run_from_file(self, src, expected_output, args=[], output_nicerizer=None,
 
   ## Does a complete test - builds, runs, checks output, etc.
   def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[], assert_returncode=None):
+    if Settings.DISABLE_EXCEPTION_CATCHING != 1 and self.is_wasm_backend():
+      return self.skip("wasm backend doesn't support exceptions yet")
+    if Settings.ASYNCIFY == 1 and self.is_wasm_backend():
+      return self.skip("wasm backend doesn't support ASYNCIFY yet")
     if force_c or (main_file is not None and main_file[-2:]) == '.c':
       basename = 'src.c'
       Building.COMPILER = to_cc(Building.COMPILER)
@@ -1093,9 +1123,12 @@ def show():
     numFailures += len(names)
     resultMessages.append('Could not find %s tests' % (len(names),))
 
+  print 'Test suites:'
+  print [s[0] for s in suites]
   # Run the discovered tests
   testRunner = unittest.TextTestRunner(verbosity=2)
   for mod_name, suite in suites:
+    print 'Running %s: (%s tests)' % (mod_name, suite.countTestCases())
     res = testRunner.run(suite)
     msg = '%s: %s run, %s errors, %s failures, %s skipped' % (mod_name,
         res.testsRun, len(res.errors), len(res.failures), len(res.skipped)
@@ -1113,4 +1146,3 @@ def show():
   # Return the number of failures as the process exit code for automating success/failure reporting.
   exitcode = min(numFailures, 255)
   sys.exit(exitcode)
-
diff --git a/tests/sdl_canvas_size.html b/tests/sdl_canvas_size.html
index 7cecd119e6716..c2d670082d214 100644
--- a/tests/sdl_canvas_size.html
+++ b/tests/sdl_canvas_size.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
     </style>
   </head>
   <body>
@@ -28,7 +28,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/tests/test_browser.py b/tests/test_browser.py
index 173f56c8f468c..c372341d69c33 100644
--- a/tests/test_browser.py
+++ b/tests/test_browser.py
@@ -2729,7 +2729,9 @@ def test_webidl(self):
                             'glue']).communicate()[0]
     assert os.path.exists('glue.cpp')
     assert os.path.exists('glue.js')
-    self.btest(os.path.join('webidl', 'test.cpp'), '1', args=['--post-js', 'glue.js', '-I' + path_from_root('tests', 'webidl'), '-DBROWSER'])
+    for opts in [[], ['-O1'], ['-O2']]:
+      print opts
+      self.btest(os.path.join('webidl', 'test.cpp'), '1', args=['--post-js', 'glue.js', '-I' + path_from_root('tests', 'webidl'), '-DBROWSER'] + opts)
 
   def test_dynamic_link(self):
     open('pre.js', 'w').write('''
@@ -2877,7 +2879,8 @@ def test_pthread_create(self):
 
   # Test that a pthread can spawn another pthread of its own.
   def test_pthread_create_pthread(self):
-    self.btest(path_from_root('tests', 'pthread', 'test_pthread_create_pthread.cpp'), expected='1', args=['-O3', '-s', 'USE_PTHREADS=2', '--separate-asm', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'NO_EXIT_RUNTIME=1'], timeout=30)
+    for opt in [['-s', 'USE_PTHREADS=2', '--separate-asm'], ['-s', 'USE_PTHREADS=1', '--proxy-to-worker']]:
+      self.btest(path_from_root('tests', 'pthread', 'test_pthread_create_pthread.cpp'), expected='1', args=opt + ['-O3', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'NO_EXIT_RUNTIME=1'], timeout=30)
 
   # Test another case of pthreads spawning pthreads, but this time the callers immediately join on the threads they created.
   def test_pthread_nested_spawns(self):
@@ -3141,3 +3144,16 @@ def test_binaryen(self):
     self.btest('browser_test_hello_world.c', expected='0', args=['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
     self.btest('browser_test_hello_world.c', expected='0', args=['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"', '-O2'])
 
+  def test_utf8_textdecoder(self):
+    self.btest('benchmark_utf8.cpp', expected='0', args=['--embed-file', path_from_root('tests/utf8_corpus.txt') + '@/utf8_corpus.txt'])
+
+  def test_utf16_textdecoder(self):
+    self.btest('benchmark_utf16.cpp', expected='0', args=['--embed-file', path_from_root('tests/utf16_corpus.txt') + '@/utf16_corpus.txt', '-s', 'EXTRA_EXPORTED_RUNTIME_METHODS=["UTF16ToString","stringToUTF16","lengthBytesUTF16"]'])
+
+  def test_webgl_offscreen_canvas_in_pthread(self):
+    for args in [[], ['-DTEST_CHAINED_WEBGL_CONTEXT_PASSING']]:
+      self.btest('gl_in_pthread.cpp', expected='1', args=args + ['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT=1'])
+
+  def test_webgl_offscreen_canvas_in_mainthread_after_pthread(self):
+    for args in [[], ['-DTEST_MAIN_THREAD_EXPLICIT_COMMIT']]:
+      self.btest('gl_in_mainthread_after_pthread.cpp', expected='0', args=args+['-s', 'USE_PTHREADS=1', '-s', 'PTHREAD_POOL_SIZE=2', '-s', 'OFFSCREENCANVAS_SUPPORT=1'])
diff --git a/tests/test_core.py b/tests/test_core.py
index e93c16f9d194c..02b3cf1c0e9a3 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -17,17 +17,24 @@ def decorated(self):
     f(self)
   return decorated
 
-def no_emterpreter(f):
+# Generic decorator that calls a function named 'condition' on the test class and
+# skips the test if that function returns true
+def skip_if(func, condition):
   def decorated(self):
-    if self.is_emterpreter(): return self.skip('todo')
-    f(self)
+    if self.__getattribute__(condition)():
+      return self.skip(condition)
+    return func(self)
   return decorated
 
+def no_emterpreter(f):
+  return skip_if(f, 'is_emterpreter')
+
 def no_wasm(f):
-  def decorated(self):
-    if self.is_wasm(): return self.skip('todo')
-    f(self)
-  return decorated
+  return skip_if(f, 'is_wasm')
+
+def no_wasm_backend(f):
+  return skip_if(f, 'is_wasm_backend')
+
 
 class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
   def is_emterpreter(self):
@@ -35,7 +42,7 @@ def is_emterpreter(self):
   def is_split_memory(self):
     return 'SPLIT_MEMORY=' in str(self.emcc_args)
   def is_wasm(self):
-    return 'BINARYEN' in str(self.emcc_args) or LLVM_TARGET == WASM_TARGET
+    return 'BINARYEN' in str(self.emcc_args) or self.is_wasm_backend()
 
   def test_hello_world(self):
       test_path = path_from_root('tests', 'core', 'test_hello_world')
@@ -58,6 +65,7 @@ def test_sintvars(self):
 
       self.do_run_from_file(src, output, force_c=True)
 
+  @no_wasm_backend
   def test_i64(self):
       src = '''
         #include <stdio.h>
@@ -281,6 +289,7 @@ def test_i64(self):
 
       self.do_run(src, '*1*\n*0*\n*0*\n')
 
+  @no_wasm_backend
   def test_i64_b(self):
       test_path = path_from_root('tests', 'core', 'test_i64_b')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -293,6 +302,7 @@ def test_i64_cmp(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_i64_cmp2(self):
       test_path = path_from_root('tests', 'core', 'test_i64_cmp2')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -305,12 +315,14 @@ def test_i64_double(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_i64_umul(self):
       test_path = path_from_root('tests', 'core', 'test_i64_umul')
       src, output = (test_path + s for s in ('.in', '.out'))
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_i64_precise(self):
       src = r'''
         #include <inttypes.h>
@@ -378,6 +390,7 @@ def test_i64_precise(self):
         }
       ''', 'c = 4ca38a6bd2973f97')
 
+  @no_wasm_backend
   def test_i64_llabs(self):
     Settings.PRECISE_I64_MATH = 2
 
@@ -416,6 +429,7 @@ def test_i64_varargs(self):
 
     self.do_run_from_file(src, output, 'waka fleefl asdfasdfasdfasdf'.split(' '))
 
+  @no_wasm_backend
   def test_llvm_fabs(self):
     Settings.PRECISE_F32 = 1
     test_path = path_from_root('tests', 'core', 'test_llvm_fabs')
@@ -477,6 +491,7 @@ def test_literal_negative_zero(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm
   def test_llvm_intrinsics(self):
     Settings.PRECISE_I64_MATH = 2 # for bswap64
 
@@ -485,6 +500,7 @@ def test_llvm_intrinsics(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_bswap64(self):
     test_path = path_from_root('tests', 'core', 'test_bswap64')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -500,10 +516,12 @@ def test_bswap64(self):
   def test_sha1(self):
     self.do_run(open(path_from_root('tests', 'sha1.c')).read(), 'SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6')
 
+  @no_wasm_backend
   def test_asmjs_unknown_emscripten(self):
     # No other configuration is supported, so always run this.
     self.do_run(open(path_from_root('tests', 'asmjs-unknown-emscripten.c')).read(), '')
 
+  @no_wasm_backend
   def test_cube2md5(self):
     self.emcc_args += ['--embed-file', 'cube2md5.txt']
     shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt'))
@@ -634,6 +652,7 @@ def test_align64(self):
 0.00,10,123.46,0.00 : 0.00,10,123.46,0.00
 ''')
 
+  @no_wasm_backend
   def test_align_moar(self):
     self.emcc_args = self.emcc_args + ['-msse']
     def test():
@@ -755,6 +774,7 @@ def test_bitfields(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_floatvars(self):
     test_path = path_from_root('tests', 'core', 'test_floatvars')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -786,6 +806,7 @@ def test_zero_multiplication(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_isnan(self):
     test_path = path_from_root('tests', 'core', 'test_isnan')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -815,17 +836,19 @@ def test_math_hyperbolic(self):
       expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read()
       self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_math_lgamma(self):
       test_path = path_from_root('tests', 'math', 'lgamma')
       src, output = (test_path + s for s in ('.in', '.out'))
 
       self.do_run_from_file(src, output)
 
-      if Settings.ALLOW_MEMORY_GROWTH == 0:
+      if Settings.ALLOW_MEMORY_GROWTH == 0 and not self.is_wasm():
         print 'main module'
         Settings.MAIN_MODULE = 1
         self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_frexp(self):
       test_path = path_from_root('tests', 'core', 'test_frexp')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -848,6 +871,7 @@ def test_fcvt(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_llrint(self):
     test_path = path_from_root('tests', 'core', 'test_llrint')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -963,6 +987,7 @@ def ensure_stack_restore_count(function_name, expected_count):
     ensure_stack_restore_count('function _alloca_gets_restored', 1)
     ensure_stack_restore_count('function _stack_usage', 1)
 
+  @no_wasm_backend
   def test_strings(self):
       test_path = path_from_root('tests', 'core', 'test_strings')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -1111,52 +1136,62 @@ def test_libcextra(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_regex(self):
       test_path = path_from_root('tests', 'core', 'test_regex')
       src, output = (test_path + s for s in ('.in', '.out'))
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp2(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp2')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp3(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp3')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp4(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp4')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp_funcptr(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp_funcptr')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp_repeat(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp_repeat')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp_stacked(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp_stacked')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp_exc(self):
     test_path = path_from_root('tests', 'core', 'test_longjmp_exc')
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_longjmp_throw(self):
     for disable_throw in [0, 1]:
       print disable_throw
@@ -1165,6 +1200,7 @@ def test_longjmp_throw(self):
       src, output = (test_path + s for s in ('.cpp', '.out'))
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_setjmp_many(self):
     src = r'''
       #include <stdio.h>
@@ -1181,6 +1217,7 @@ def test_setjmp_many(self):
       print num
       self.do_run(src.replace('NUM', str(num)), '0\n' * num)
 
+  @no_wasm_backend
   def test_setjmp_many_2(self):
     src = r'''
 #include <setjmp.h>
@@ -1209,6 +1246,7 @@ def test_setjmp_many_2(self):
 
     self.do_run(src, r'''d is at 24''')
 
+  @no_wasm_backend
   def test_setjmp_noleak(self):
     src = r'''
 #include <setjmp.h>
@@ -1261,7 +1299,7 @@ def test_exceptions(self):
       Settings.EXCEPTION_DEBUG = 1
 
       Settings.DISABLE_EXCEPTION_CATCHING = 0
-      if '-O2' in self.emcc_args:
+      if '-O2' in self.emcc_args and not self.is_wasm():
         self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
 
       src = '''
@@ -1389,6 +1427,7 @@ def test_exceptions_3(self):
     print '2'
     self.do_run(src, 'Caught exception: Hello\nDone.', ['2'], no_build=True)
 
+  @no_wasm_backend
   def test_exceptions_white_list(self):
     Settings.DISABLE_EXCEPTION_CATCHING = 2
     Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
@@ -1418,13 +1457,14 @@ def test_exceptions_white_list(self):
     disabled_size = len(open('src.cpp.o.js').read())
     shutil.copyfile('src.cpp.o.js', 'disabled.js')
 
-    print size, empty_size, fake_size, disabled_size
+    if not self.is_wasm():
+      print size, empty_size, fake_size, disabled_size
 
-    assert size - empty_size > 0.0025*size, [empty_size, size] # big change when we disable entirely
-    assert size - fake_size > 0.0025*size, [fake_size, size]
-    assert abs(empty_size - fake_size) < 0.007*size, [empty_size, fake_size]
-    assert empty_size - disabled_size < 0.007*size, [empty_size, disabled_size] # full disable removes a little bit more
-    assert fake_size - disabled_size < 0.007*size, [disabled_size, fake_size]
+      assert size - empty_size > 0.0025*size, [empty_size, size] # big change when we disable entirely
+      assert size - fake_size > 0.0025*size, [fake_size, size]
+      assert abs(empty_size - fake_size) < 0.007*size, [empty_size, fake_size]
+      assert empty_size - disabled_size < 0.007*size, [empty_size, disabled_size] # full disable removes a little bit more
+      assert fake_size - disabled_size < 0.007*size, [disabled_size, fake_size]
 
   def test_exceptions_white_list_2(self):
     Settings.DISABLE_EXCEPTION_CATCHING = 2
@@ -1472,6 +1512,30 @@ def test_exceptions_uncaught(self):
       '''
       self.do_run(src, 'success')
 
+  def test_exceptions_uncaught_2(self):
+      Settings.DISABLE_EXCEPTION_CATCHING = 0
+
+      src = r'''
+        #include <iostream>
+        #include <exception>
+
+        int main() {
+          try {
+              throw std::exception();
+          } catch(std::exception) {
+            try {
+              throw;
+            } catch(std::exception) {}
+          }
+
+          if (std::uncaught_exception())
+            std::cout << "ERROR: uncaught_exception still set.";
+          else
+            std::cout << "OK";
+        }
+      '''
+      self.do_run(src, 'OK\n')
+
   def test_exceptions_typed(self):
     Settings.DISABLE_EXCEPTION_CATCHING = 0
     self.emcc_args += ['-s', 'SAFE_HEAP=0'] # Throwing null will cause an ignorable null pointer access.
@@ -1560,6 +1624,7 @@ def test_exceptions_libcxx(self):
     src, output = (test_path + s for s in ('.cpp', '.txt'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_bad_typeid(self):
     Settings.ERROR_ON_UNDEFINED_SYMBOLS = 1
     Settings.DISABLE_EXCEPTION_CATCHING = 0
@@ -1586,6 +1651,7 @@ class Polymorphic {virtual void member(){}};
 }
     ''', 'exception caught: std::bad_typeid')
 
+  @no_wasm_backend
   def test_iostream_ctors(self): # iostream stuff must be globally constructed before user global constructors, so iostream works in global constructors
     self.do_run(r'''
 #include <iostream>
@@ -1613,6 +1679,7 @@ def test_inherit(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_isdigit_l(self):
       test_path = path_from_root('tests', 'core', 'test_isdigit_l')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -1631,6 +1698,7 @@ def test_polymorph(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_complex(self):
     self.do_run(r'''
 #include <complex.h>
@@ -1667,6 +1735,7 @@ def test_complex(self):
 value = real 0.50 imag 0.00
 value = real 0.00 imag 1.00''', force_c=True)
 
+  @no_wasm_backend
   def test_segfault(self):
     Settings.SAFE_HEAP = 1
 
@@ -1761,6 +1830,11 @@ def test_rename(self):
     src = open(path_from_root('tests', 'stdio', 'test_rename.c'), 'r').read()
     self.do_run(src, 'success', force_c=True)
 
+  @no_wasm_backend
+  def test_remove(self):
+    src = open(path_from_root('tests', 'cstdio', 'test_remove.cpp'), 'r').read()
+    self.do_run(src, 'success')
+
   def test_alloca_stack(self):
     test_path = path_from_root('tests', 'core', 'test_alloca_stack')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -1773,6 +1847,7 @@ def test_stack_byval(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_stack_varargs(self):
     Settings.INLINING_LIMIT = 50
     Settings.TOTAL_STACK = 2048
@@ -1782,6 +1857,7 @@ def test_stack_varargs(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_stack_varargs2(self):
     Settings.TOTAL_STACK = 1536
     src = r'''
@@ -1865,6 +1941,8 @@ def test_stack_void(self):
 
     self.do_run_from_file(src, output)
 
+  # Fails in wasm because of excessive slowness in the wasm-shell
+  @no_wasm
   def test_life(self):
     self.emcc_args += ['-std=c99']
     src = open(path_from_root('tests', 'life.c'), 'r').read()
@@ -1940,6 +2018,7 @@ def test_mod_globalstruct(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_pystruct(self):
       src = '''
         #include <stdio.h>
@@ -2022,6 +2101,7 @@ def check_warnings(output):
 
       self.do_run_from_file(src, output, output_processor=check_warnings)
 
+  @no_wasm_backend
   def test_sizeof(self):
       # Has invalid writes between printouts
       Settings.SAFE_HEAP = 0
@@ -2039,6 +2119,7 @@ def test_llvm_used(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_set_align(self):
     Settings.SAFE_HEAP = 1
 
@@ -2046,6 +2127,7 @@ def test_set_align(self):
     src, output = (test_path + s for s in ('.c', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_emscripten_api(self):
       test_path = path_from_root('tests', 'core', 'test_emscripten_api')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -2141,6 +2223,7 @@ def test_em_asm_unicode(self):
 }
 ''', 'hello world…')
 
+  @no_wasm_backend
   def test_em_asm_unused_arguments(self):
     src = r'''
       #include <stdio.h>
@@ -2160,6 +2243,7 @@ def test_em_asm_unused_arguments(self):
   # Maybe tests will later be joined into larger compilation units?
   # Then this must still be compiled separately from other code using EM_ASM
   # macros with arities 1-3. Otherwise this may incorrectly report a success.
+  @no_wasm_backend
   def test_em_asm_parameter_pack(self):
     Building.COMPILER_TEST_OPTS += ['-std=c++11']
     src = r'''
@@ -2251,6 +2335,7 @@ def test_memorygrowth(self):
     self.emcc_args += ['--tracing']
     self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*')
 
+  @no_wasm_backend
   def test_memorygrowth_2(self):
     self.emcc_args += ['-s', 'ALLOW_MEMORY_GROWTH=0'] # start with 0
 
@@ -2397,6 +2482,7 @@ def test_biggerswitch(self):
 59899: 598995989959899
 Success!''')
 
+  @no_wasm_backend
   def test_indirectbr(self):
       Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS)
 
@@ -2405,6 +2491,7 @@ def test_indirectbr(self):
 
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_indirectbr_many(self):
       test_path = path_from_root('tests', 'core', 'test_indirectbr_many')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -2442,6 +2529,7 @@ def test_pack(self):
         '''
       self.do_run(src, '*4,3,4*\n*6,4,6*')
 
+  @no_wasm_backend
   def test_varargs(self):
       test_path = path_from_root('tests', 'core', 'test_varargs')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -2633,6 +2721,7 @@ def test_structbyval(self):
       generated = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read()
       print >> sys.stderr, 'skipping C/C++ conventions warning check, since not i386-pc-linux-gnu'
 
+  @no_wasm_backend
   def test_stdlibs(self):
       # safe heap prints a warning that messes up our output.
       Settings.SAFE_HEAP = 0
@@ -2778,6 +2867,7 @@ def test_tcgetattr(self):
     src = open(path_from_root('tests', 'termios', 'test_tcgetattr.c'), 'r').read()
     self.do_run(src, 'success', force_c=True)
 
+  @no_wasm_backend
   def test_time(self):
     src = open(path_from_root('tests', 'time', 'src.c'), 'r').read()
     expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read()
@@ -2790,6 +2880,7 @@ def test_timeb(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_time_c(self):
     test_path = path_from_root('tests', 'core', 'test_time_c')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -2808,6 +2899,7 @@ def test_strptime_tm(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_strptime_days(self):
     test_path = path_from_root('tests', 'core', 'test_strptime_days')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -2820,12 +2912,14 @@ def test_strptime_reentrant(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_strftime(self):
     test_path = path_from_root('tests', 'core', 'test_strftime')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_intentional_fault(self):
     # Some programs intentionally segfault themselves, we should compile that into a throw
     src = r'''
@@ -2858,6 +2952,8 @@ def test_copyop(self):
 
       self.do_run_from_file(src, output)
 
+  # Currently broken under V8_ENGINE but not node
+  @no_wasm_backend
   def test_memcpy_memcmp(self):
       test_path = path_from_root('tests', 'core', 'test_memcpy_memcmp')
       src, output = (test_path + s for s in ('.in', '.out'))
@@ -3280,7 +3376,6 @@ def test_dlfcn_data_and_fptr(self):
     dirname = self.get_dir()
     filename = os.path.join(dirname, 'liblib.cpp')
     Settings.EXPORTED_FUNCTIONS = ['_func']
-    Settings.EXPORTED_GLOBALS = ['_global']
     self.build(lib_src, dirname, filename)
     shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so'))
 
@@ -3340,7 +3435,6 @@ def test_dlfcn_data_and_fptr(self):
       }
       '''
     Settings.EXPORTED_FUNCTIONS = ['_main']
-    Settings.EXPORTED_GLOBALS = []
     self.do_run(src, 'In func: 13*First calling main_fptr from lib.*Second calling lib_fptr from main.*parent_func called from child*parent_func called from child*Var: 42*',
                  output_nicerizer=lambda x, err: x.replace('\n', '*'),
                  post_build=self.dlfcn_post_build)
@@ -4567,6 +4661,7 @@ def test_rand(self):
 '''
     self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_strtod(self):
     src = r'''
       #include <stdio.h>
@@ -4647,6 +4742,7 @@ def test_strtok(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_parseInt(self):
     src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read()
     expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read()
@@ -4658,6 +4754,7 @@ def test_transtrcase(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_printf(self):
     self.banned_js_engines = [NODE_JS, V8_ENGINE] # SpiderMonkey and V8 do different things to float64 typed arrays, un-NaNing, etc.
     src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read()
@@ -4682,6 +4779,7 @@ def test_vsnprintf(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_printf_more(self):
     test_path = path_from_root('tests', 'core', 'test_printf_more')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -4706,6 +4804,7 @@ def test_strstr(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_fnmatch(self):
     # Run one test without assertions, for additional coverage
     #assert 'asm2m' in test_modes
@@ -4718,12 +4817,14 @@ def test_fnmatch(self):
     src, output = (test_path + s for s in ('.c', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_2(self):
     # doubles
     for ftype in ['float', 'double']:
@@ -4779,18 +4880,21 @@ def test_sscanf_2(self):
 Pass: 0.000012 0.000012
 Pass: 0.000012 0.000012''')
 
+  @no_wasm_backend
   def test_sscanf_n(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_n')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_whitespace(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_whitespace')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_other_whitespace(self):
     Settings.SAFE_HEAP = 0 # use i16s in printf
 
@@ -4799,6 +4903,7 @@ def test_sscanf_other_whitespace(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_3(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_3')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -4817,6 +4922,7 @@ def test_sscanf_5(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_6(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_6')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -4828,18 +4934,21 @@ def test_sscanf_skip(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_caps(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_caps')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_hex(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_hex')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_sscanf_float(self):
     test_path = path_from_root('tests', 'core', 'test_sscanf_float')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -4851,12 +4960,13 @@ def test_langinfo(self):
     expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
     self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/langinfo.h'])
 
+  @no_wasm_backend
   def test_files(self):
     self.banned_js_engines = [SPIDERMONKEY_ENGINE] # closure can generate variables called 'gc', which pick up js shell stuff
-    if '-O2' in self.emcc_args:
+    if '-O2' in self.emcc_args and not self.is_wasm():
       self.emcc_args += ['--closure', '1'] # Use closure here, to test we don't break FS stuff
       self.emcc_args = filter(lambda x: x != '-g', self.emcc_args) # ensure we test --closure 1 --memory-init-file 1 (-g would disable closure)
-    elif '-O3' in self.emcc_args:
+    elif '-O3' in self.emcc_args and not self.is_wasm():
       print 'closure 2'
       self.emcc_args += ['--closure', '2'] # Use closure 2 here for some additional coverage
 
@@ -4893,8 +5003,12 @@ def process(filename):
       print mode
       self.emcc_args = orig_args + mode
       try_delete(mem_file)
+
+      def clean(out, err):
+        return '\n'.join(filter(lambda line: 'binaryen' not in line, (out + err).split('\n')))
+
       self.do_run(src, map(lambda x: x if 'SYSCALL_DEBUG=1' not in mode else ('syscall! 146,SYS_writev' if self.run_name == 'default' else 'syscall! 146'), ('size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n5 bytes to dev/null: 5\nok.\ntexte\n', 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n5 bytes to dev/null: 5\nok.\n')),
-                  post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+                  post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'], output_nicerizer=clean)
       if self.uses_memory_init_file():
         assert os.path.exists(mem_file)
 
@@ -4926,7 +5040,7 @@ def process(filename):
       }
       '''
     def clean(out, err):
-      return '\n'.join(filter(lambda line: 'warning' not in line, (out + err).split('\n')))
+      return '\n'.join(filter(lambda line: 'warning' not in line and 'binaryen' not in line, (out + err).split('\n')))
     self.do_run(src, ('got: 35\ngot: 45\ngot: 25\ngot: 15\n \nisatty? 0,0,1\n', 'got: 35\ngot: 45\ngot: 25\ngot: 15\nisatty? 0,0,1\n', 'isatty? 0,0,1\ngot: 35\ngot: 45\ngot: 25\ngot: 15\n'), post_build=post, output_nicerizer=clean)
 
   def test_mount(self):
@@ -4990,6 +5104,7 @@ def test_fgets_eol(self):
     self.emcc_args += ['--embed-file', 'eol.txt']
     self.do_run(src, 'SUCCESS\n')
 
+  @no_wasm_backend
   def test_fscanf(self):
     open(os.path.join(self.get_dir(), 'three_numbers.txt'), 'w').write('''-1 0.1 -.1''')
     src = r'''
@@ -5014,6 +5129,7 @@ def test_fscanf(self):
     self.emcc_args += ['--embed-file', 'three_numbers.txt']
     self.do_run(src, 'match = 3\nx = -1.0, y = 0.1, z = -0.1\n')
 
+  @no_wasm_backend
   def test_fscanf_2(self):
     open('a.txt', 'w').write('''1/2/3 4/5/6 7/8/9
 ''')
@@ -5060,6 +5176,7 @@ def test_fileno(self):
     self.emcc_args += ['--embed-file', 'empty.txt']
     self.do_run(src, '3\n')
 
+  @no_wasm_backend
   def test_readdir(self):
     self.banned_js_engines = [V8_ENGINE] # stderr printing limitations in v8
     src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read()
@@ -5092,6 +5209,7 @@ def test_stat_mknod(self):
     src = open(path_from_root('tests', 'stat', 'test_mknod.c'), 'r').read()
     self.do_run(src, 'success', force_c=True)
 
+  @no_wasm_backend
   def test_fcntl(self):
     add_pre_run = '''
 def process(filename):
@@ -5105,11 +5223,13 @@ def process(filename):
     expected = open(path_from_root('tests', 'fcntl', 'output.txt'), 'r').read()
     self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
 
+  @no_wasm_backend
   def test_fcntl_open(self):
     src = open(path_from_root('tests', 'fcntl-open', 'src.c'), 'r').read()
     expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read()
     self.do_run(src, expected, force_c=True, extra_emscripten_args=['-H', 'libc/fcntl.h'])
 
+  @no_wasm_backend
   def test_fcntl_misc(self):
     add_pre_run = '''
 def process(filename):
@@ -5168,15 +5288,29 @@ def test_utf(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_utf32(self):
     Settings.EXTRA_EXPORTED_RUNTIME_METHODS = ['UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32']
     self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.')
     self.do_run(open(path_from_root('tests', 'utf32.cpp')).read(), 'OK.', args=['-fshort-wchar'])
 
+  @no_wasm_backend
   def test_utf8(self):
     Building.COMPILER_TEST_OPTS += ['-std=c++11']
     self.do_run(open(path_from_root('tests', 'utf8.cpp')).read(), 'OK.')
 
+  @no_wasm_backend
+  def test_utf8_textdecoder(self):
+    Building.COMPILER_TEST_OPTS += ['--embed-file', path_from_root('tests/utf8_corpus.txt')+ '@/utf8_corpus.txt']
+    self.do_run(open(path_from_root('tests', 'benchmark_utf8.cpp')).read(), 'OK.')
+
+  @no_wasm_backend
+  def test_utf16_textdecoder(self):
+    Settings.EXTRA_EXPORTED_RUNTIME_METHODS = ['UTF16ToString', 'stringToUTF16', 'lengthBytesUTF16']
+    Building.COMPILER_TEST_OPTS += ['--embed-file', path_from_root('tests/utf16_corpus.txt')+ '@/utf16_corpus.txt']
+    self.do_run(open(path_from_root('tests', 'benchmark_utf16.cpp')).read(), 'OK.')
+
+  @no_wasm_backend
   def test_wprintf(self):
     test_path = path_from_root('tests', 'core', 'test_wprintf')
     src, output = (test_path + s for s in ('.c', '.out'))
@@ -5185,12 +5319,14 @@ def test_wprintf(self):
       self.emcc_args = orig_args + mode
       self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_direct_string_constant_usage(self):
     test_path = path_from_root('tests', 'core', 'test_direct_string_constant_usage')
     src, output = (test_path + s for s in ('.in', '.out'))
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_std_cout_new(self):
     test_path = path_from_root('tests', 'core', 'test_std_cout_new')
     src, output = (test_path + s for s in ('.in', '.out'))
@@ -5206,6 +5342,7 @@ def test_istream(self):
       Settings.LINKABLE = linkable # regression check for issue #273
       self.do_run_from_file(src, output)
 
+  @no_wasm
   def test_fs_base(self):
     Settings.INCLUDE_FULL_LIBRARY = 1
     try:
@@ -5223,6 +5360,7 @@ def process(filename):
     finally:
       Settings.INCLUDE_FULL_LIBRARY = 0
 
+  @no_wasm_backend
   def test_fs_nodefs_rw(self):
     Settings.SYSCALL_DEBUG = 1
     src = open(path_from_root('tests', 'fs', 'test_nodefs_rw.c'), 'r').read()
@@ -5240,6 +5378,7 @@ def test_fs_trackingdelegate(self):
     out = path_from_root('tests', 'fs', 'test_trackingdelegate.out')
     self.do_run_from_file(src, out)
 
+  @no_wasm_backend
   def test_fs_writeFile(self):
     self.emcc_args += ['-s', 'DISABLE_EXCEPTION_CATCHING=1'] # see issue 2334
     src = path_from_root('tests', 'fs', 'test_writeFile.cc')
@@ -5255,6 +5394,7 @@ def test_fs_append(self):
     src = open(path_from_root('tests', 'fs', 'test_append.c'), 'r').read()
     self.do_run(src, 'success', force_c=True)
 
+  @no_wasm_backend
   def test_fs_mmap(self):
     orig_compiler_opts = Building.COMPILER_TEST_OPTS[:]
     for fs in ['MEMFS']:
@@ -5263,6 +5403,7 @@ def test_fs_mmap(self):
       Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
       self.do_run_from_file(src, out)
 
+  @no_wasm_backend
   def test_unistd_access(self):
     self.clear()
     orig_compiler_opts = Building.COMPILER_TEST_OPTS[:]
@@ -5277,11 +5418,13 @@ def test_unistd_curdir(self):
     expected = open(path_from_root('tests', 'unistd', 'curdir.out'), 'r').read()
     self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_unistd_close(self):
     src = open(path_from_root('tests', 'unistd', 'close.c'), 'r').read()
     expected = open(path_from_root('tests', 'unistd', 'close.out'), 'r').read()
     self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_unistd_confstr(self):
     src = open(path_from_root('tests', 'unistd', 'confstr.c'), 'r').read()
     expected = open(path_from_root('tests', 'unistd', 'confstr.out'), 'r').read()
@@ -5296,6 +5439,7 @@ def test_unistd_dup(self):
     expected = open(path_from_root('tests', 'unistd', 'dup.out'), 'r').read()
     self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_unistd_pathconf(self):
     src = open(path_from_root('tests', 'unistd', 'pathconf.c'), 'r').read()
     expected = open(path_from_root('tests', 'unistd', 'pathconf.out'), 'r').read()
@@ -5319,6 +5463,7 @@ def test_unistd_isatty(self):
     src = open(path_from_root('tests', 'unistd', 'isatty.c'), 'r').read()
     self.do_run(src, 'success', force_c=True)
 
+  @no_wasm_backend
   def test_unistd_sysconf(self):
     src = open(path_from_root('tests', 'unistd', 'sysconf.c'), 'r').read()
     expected = open(path_from_root('tests', 'unistd', 'sysconf.out'), 'r').read()
@@ -5329,6 +5474,7 @@ def test_unistd_login(self):
     expected = open(path_from_root('tests', 'unistd', 'login.out'), 'r').read()
     self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_unistd_unlink(self):
     self.clear()
     orig_compiler_opts = Building.COMPILER_TEST_OPTS[:]
@@ -5383,6 +5529,7 @@ def test_unistd_io(self):
       Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
       self.do_run(src, expected, js_engines=[NODE_JS])
 
+  @no_wasm_backend
   def test_unistd_misc(self):
     orig_compiler_opts = Building.COMPILER_TEST_OPTS[:]
     for fs in ['MEMFS', 'NODEFS']:
@@ -5391,6 +5538,7 @@ def test_unistd_misc(self):
       Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
       self.do_run(src, expected, js_engines=[NODE_JS])
 
+  @no_wasm_backend
   def test_posixtime(self):
     test_path = path_from_root('tests', 'core', 'test_posixtime')
     src, output = (test_path + s for s in ('.c', '.out'))
@@ -5408,6 +5556,7 @@ def test_uname(self):
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_env(self):
     src = open(path_from_root('tests', 'env', 'src.c'), 'r').read()
     expected = open(path_from_root('tests', 'env', 'output.txt'), 'r').read()
@@ -5416,6 +5565,7 @@ def test_env(self):
       expected.replace('{{{ THIS_PROGRAM }}}', './this.program') # spidermonkey, v8
     ])
 
+  @no_wasm_backend
   def test_environ(self):
     src = open(path_from_root('tests', 'env', 'src-mini.c'), 'r').read()
     expected = open(path_from_root('tests', 'env', 'output-mini.txt'), 'r').read()
@@ -5448,6 +5598,7 @@ def test_799(self):
 PORT: 3979
 ''')
 
+  @no_wasm_backend
   def test_ctype(self):
     src = open(path_from_root('tests', 'ctype', 'src.c'), 'r').read()
     expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read()
@@ -5464,13 +5615,14 @@ def test_atomic(self):
     src, output = (test_path + s for s in ('.in', '.out'))
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_atomic_cxx(self):
     test_path = path_from_root('tests', 'core', 'test_atomic_cxx')
     src, output = (test_path + s for s in ('.cpp', '.txt'))
     Building.COMPILER_TEST_OPTS += ['-std=c++11']
     self.do_run_from_file(src, output)
 
-    if Settings.ALLOW_MEMORY_GROWTH == 0:
+    if Settings.ALLOW_MEMORY_GROWTH == 0 and not self.is_wasm():
       print 'main module'
       Settings.MAIN_MODULE = 1
       self.do_run_from_file(src, output)
@@ -5488,6 +5640,7 @@ def test_netinet_in(self):
 
   # libc++ tests
 
+  @no_wasm_backend
   def test_iostream_and_determinism(self):
     src = '''
       #include <iostream>
@@ -5520,6 +5673,7 @@ def test_stdvec(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_random_device(self):
     Building.COMPILER_TEST_OPTS += ['-std=c++11']
 
@@ -5692,6 +5846,7 @@ def test_dlmalloc_partial(self):
 '''
     self.do_run(src, 'new 4!\n*1,0*')
 
+  @no_wasm_backend
   def test_dlmalloc_partial_2(self):
     if 'SAFE_HEAP' in str(self.emcc_args): return self.skip('we do unsafe stuff here')
     # present part of the symbols of dlmalloc, not all. malloc is harder to link than new which is weak.
@@ -5745,6 +5900,7 @@ def test_mmap(self):
     self.do_run_from_file(src, output)
     self.do_run_from_file(src, output, force_c=True)
 
+  @no_wasm_backend
   def test_mmap_file(self):
     for extra_args in [[], ['--no-heap-copy']]:
       self.emcc_args += ['--embed-file', 'data.dat'] + extra_args
@@ -5760,6 +5916,7 @@ def test_mmap_file(self):
       src = open(path_from_root('tests', 'mmap_file.c')).read()
       self.do_run(src, '*\n' + s[0:20] + '\n' + s[4096:4096+20] + '\n*\n')
 
+  @no_wasm_backend
   def test_cubescript(self):
     assert 'asm3' in test_modes
     if self.run_name == 'asm3':
@@ -6040,11 +6197,13 @@ def test_simd_dyncall(self):
     self.emcc_args = self.emcc_args + ['-msse']
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_gcc_unmangler(self):
     Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('third_party')]
 
     self.do_run(open(path_from_root('third_party', 'gcc_demangler.c')).read(), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'])
 
+  @no_wasm_backend
   def test_lua(self):
     if self.emcc_args: self.emcc_args = ['-g1'] + self.emcc_args
 
@@ -6070,6 +6229,7 @@ def get_freetype(self):
     return self.get_library('freetype',
                             os.path.join('objs', '.libs', 'libfreetype.a'))
 
+  @no_wasm_backend
   def test_freetype(self):
     if WINDOWS: return self.skip('test_freetype uses a ./configure script to build and therefore currently only runs on Linux and OS X.')
     assert 'asm2g' in test_modes
@@ -6126,6 +6286,7 @@ def process(filename):
                  ['font.ttf', 'ea', '40', '32', '0'],
                  no_build=True)
 
+  @no_wasm_backend
   def test_sqlite(self):
     # gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
     self.banned_js_engines = [NODE_JS] # OOM in older node
@@ -6152,8 +6313,9 @@ def test_sqlite(self):
                  includes=[path_from_root('tests', 'sqlite')],
                  force_c=True)
 
+  @no_wasm_backend
   def test_zlib(self):
-    if '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args: # without asm, closure minifies Math.imul badly
+    if '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args and not self.is_wasm(): # without asm, closure minifies Math.imul badly
       self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
 
     assert 'asm2g' in test_modes
@@ -6174,6 +6336,7 @@ def test_zlib(self):
                  includes=[path_from_root('tests', 'zlib'), os.path.join(self.get_dir(), 'building', 'zlib')],
                  force_c=True)
 
+  @no_wasm_backend
   def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
     Settings.DEAD_FUNCTIONS = ['__ZSt9terminatev']
 
@@ -6211,6 +6374,7 @@ def test():
         assert len(old) > len(new)
         assert old.count('tempBigInt') > new.count('tempBigInt')
 
+  @no_wasm_backend
   def test_poppler(self):
     if WINDOWS: return self.skip('test_poppler depends on freetype, which uses a ./configure script to build and therefore currently only runs on Linux and OS X.')
 
@@ -6408,6 +6572,7 @@ def clean(text):
       Settings.ALLOW_MEMORY_GROWTH = 0
       do_test()
 
+  @no_wasm_backend
   def test_python(self):
     Settings.EMULATE_FUNCTION_POINTER_CASTS = 1
 
@@ -6438,6 +6603,7 @@ def test_lifetime(self):
   # Test cases in separate files. Note that these files may contain invalid .ll!
   # They are only valid enough for us to read for test purposes, not for llvm-as
   # to process.
+  @no_wasm_backend
   def test_cases(self):
     if Building.LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
 
@@ -6553,6 +6719,8 @@ def do_autodebug_post(self, filename):
     Building.llvm_as(filename)
     Building.llvm_dis(filename)
 
+  # Broken on V8 but not node
+  @no_wasm_backend
   def test_autodebug(self):
     if Building.LLVM_OPTS: return self.skip('LLVM opts mess us up')
     Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0']
@@ -6589,6 +6757,7 @@ def test_autodebug(self):
 
   ### Integration tests
 
+  @no_wasm_backend
   def test_ccall(self):
     post = '''
 def process(filename):
@@ -6635,6 +6804,7 @@ def process(filename):
       self.emcc_args += ['--closure', '1']
       self.do_run_from_file(src, output, post_build=post)
 
+  @no_wasm_backend
   def test_dead_functions(self):
     src = r'''
       #include <stdio.h>
@@ -6789,6 +6959,7 @@ def test_asm_pgo(self):
     shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js'))
     assert open('pgoed.js').read() == open('pgoed2.js').read()
 
+  @no_wasm_backend
   def test_exported_response(self):
     src = r'''
       #include <stdio.h>
@@ -6812,6 +6983,7 @@ def test_exported_response(self):
     self.do_run(src, '''waka 5!''')
     assert 'other_function' in open('src.cpp.o.js').read()
 
+  @no_wasm_backend
   def test_large_exported_response(self):
     src = r'''
       #include <stdio.h>
@@ -6848,6 +7020,7 @@ def test_large_exported_response(self):
     self.do_run(src, '''waka 4999!''')
     assert '_exported_func_from_response_file_1' in open('src.cpp.o.js').read()
 
+  @no_wasm_backend
   def test_add_function(self):
     Settings.INVOKE_RUN = 0
     Settings.RESERVED_FUNCTION_POINTERS = 1
@@ -6901,6 +7074,7 @@ def test_add_function(self):
     Settings.EMULATED_FUNCTION_POINTERS = 1 # with emulation, we don't need to reserve
     self.do_run(src, expected)
 
+  @no_wasm_backend
   def test_getFuncWrapper_sig_alias(self):
     src = r'''
     #include <stdio.h>
@@ -6923,6 +7097,7 @@ def test_getFuncWrapper_sig_alias(self):
     '''
     self.do_run(src, 'func1\nfunc2\n')
 
+  @no_wasm_backend
   def test_emulate_function_pointer_casts(self):
     Settings.EMULATE_FUNCTION_POINTER_CASTS = 1
 
@@ -6949,6 +7124,7 @@ def test_emulate_function_pointer_casts(self):
     '''
     self.do_run(src, '|1.266,1|\n')
 
+  @no_wasm_backend
   def test_demangle_stacks(self):
     Settings.DEMANGLE_SUPPORT = 1
     if '-O' in str(self.emcc_args):
@@ -6967,6 +7143,7 @@ def test_tracing(self):
 
     self.do_run_from_file(src, output)
 
+  @no_wasm_backend
   def test_eval_ctors(self):
     if '-O2' not in str(self.emcc_args) or '-O1' in str(self.emcc_args): return self.skip('need js optimizations')
 
@@ -7038,6 +7215,7 @@ def test1():
     Settings.ASSERTIONS = 1
     self.do_run(src, output)
 
+  @no_wasm_backend
   def test_embind(self):
     Building.COMPILER_TEST_OPTS += ['--bind']
 
@@ -7059,6 +7237,7 @@ def test_embind(self):
     '''
     self.do_run(src, 'abs(-10): 10\nabs(-11): 11');
 
+  @no_wasm_backend
   def test_embind_2(self):
     Settings.NO_EXIT_RUNTIME = 1 # we emit some post.js that we need to see
     Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js']
@@ -7081,6 +7260,7 @@ def test_embind_2(self):
     '''
     self.do_run(src, 'lerp 166');
 
+  @no_wasm_backend
   def test_embind_3(self):
     Settings.NO_EXIT_RUNTIME = 1 # we emit some post.js that we need to see
     Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js']
@@ -7110,6 +7290,7 @@ def test_embind_3(self):
     '''
     self.do_run(src, 'UnboundTypeError: Cannot call compute due to unbound types: Pi');
 
+  @no_wasm_backend
   def test_scriptaclass(self):
       Settings.EXPORT_BINDINGS = 1
 
@@ -7158,7 +7339,7 @@ def process(filename):
 '''
       # XXX disable due to possible v8 bug -- self.do_run(src, '*166*\n*ok*', post_build=post)
 
-      if '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args: # without asm, closure minifies Math.imul badly
+      if '-O2' in self.emcc_args and 'ASM_JS=0' not in self.emcc_args and not self.is_wasm(): # without asm, closure minifies Math.imul badly
         self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
 
       # Way 2: use CppHeaderParser
@@ -7356,6 +7537,7 @@ def post3(filename):
 *ok*
 ''', post_build=(post2, post3))
 
+  @no_wasm_backend
   def test_scriptaclass_2(self):
       Settings.EXPORT_BINDINGS = 1
 
@@ -7400,6 +7582,7 @@ def process(filename):
 '''
       self.do_run(src, '|hello|43|world|41|', post_build=post)
 
+  @no_wasm_backend
   def test_webidl(self):
     assert 'asm2' in test_modes
     if self.run_name == 'asm2':
@@ -7515,6 +7698,7 @@ def test_safe_heap(self):
       assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
 
   @no_emterpreter
+  @no_wasm_backend
   def test_source_map(self):
     if NODE_JS not in JS_ENGINES: return self.skip('sourcemapper requires Node to run')
     if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
@@ -7666,6 +7850,7 @@ def test_emscripten_log(self):
 Success!
 ''')
 
+  @no_wasm_backend
   def test_float_literals(self):
     self.do_run_from_file(path_from_root('tests', 'test_float_literals.cpp'), path_from_root('tests', 'test_float_literals.out'))
 
@@ -7966,6 +8151,8 @@ def test_memprof_requirements(self):
     self.emcc_args += ['--js-library', os.path.join(self.get_dir(), 'lib.js')]
     self.do_run(open(os.path.join(self.get_dir(), 'main.cpp'), 'r').read(), 'able to run memprof')
 
+  # Currently broken using V8_ENGINE but not node
+  @no_wasm_backend
   def test_fs_dict(self):
       Settings.FORCE_FILESYSTEM = 1
       open(self.in_dir('pre.js'), 'w').write('''
@@ -7979,6 +8166,7 @@ def test_fs_dict(self):
       self.emcc_args += ['--pre-js', 'pre.js']
       self.do_run('', 'object\nobject\nobject')
 
+  @no_wasm_backend
   def test_stack_overflow_check(self):
     args = self.emcc_args + ['-s', 'TOTAL_STACK=1048576']
     self.emcc_args = args + ['-s', 'STACK_OVERFLOW_CHECK=1', '-s', 'ASSERTIONS=0']
@@ -8064,10 +8252,15 @@ def setUp(self):
 asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-g", "-s", "ASSERTIONS=1", "-s", "SAFE_HEAP=1"])
 asm2i = make_run("asm2i", compiler=CLANG, emcc_args=["-O2", '-s', 'EMTERPRETIFY=1'])
 #asm2m = make_run("asm2m", compiler=CLANG, emcc_args=["-O2", "--memory-init-file", "0", "-s", "MEM_INIT_METHOD=2", "-s", "ASSERTIONS=1"])
-#binaryen0 = make_run("binaryen", compiler=CLANG, emcc_args=['-O0', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"'])
-#binaryen1 = make_run("binaryen", compiler=CLANG, emcc_args=['-O1', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"'])
-#binaryen2 = make_run("binaryen", compiler=CLANG, emcc_args=['-O2', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"'])
-#binaryen3 = make_run("binaryen", compiler=CLANG, emcc_args=['-O3', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-s-expr"'])
+binaryen0 = make_run("binaryen0", compiler=CLANG, emcc_args=['-O0', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
+binaryen1 = make_run("binaryen1", compiler=CLANG, emcc_args=['-O1', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
+binaryen2 = make_run("binaryen2", compiler=CLANG, emcc_args=['-O2', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
+binaryen3 = make_run("binaryen3", compiler=CLANG, emcc_args=['-O3', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
+
+# This only works when .emscripten specifies a JS_ENGINE with native wasm support.
+binaryen_native = make_run("binaryen_native", compiler=CLANG, emcc_args=['-O2', '-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="native-wasm"'])
+
+
 #normalyen = make_run("normalyen", compiler=CLANG, emcc_args=['-O0', '-s', 'GLOBAL_BASE=1024']) # useful comparison to binaryen
 #spidaryen = make_run("binaryen", compiler=CLANG, emcc_args=['-O0', '-s', 'BINARYEN=1', '-s', 'BINARYEN_SCRIPTS="spidermonkify.py"'])
 
diff --git a/tests/test_fflush.html b/tests/test_fflush.html
index 810e2518e067c..adb9459b2ceb6 100644
--- a/tests/test_fflush.html
+++ b/tests/test_fflush.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       .spinner {
         height: 50px;
@@ -61,7 +61,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/tests/test_html5_fullscreen.html b/tests/test_html5_fullscreen.html
index 9fcdcfc487b26..8f0c3e7b27e04 100644
--- a/tests/test_html5_fullscreen.html
+++ b/tests/test_html5_fullscreen.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       .spinner {
         height: 50px;
@@ -61,7 +61,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/tests/test_html5_pointerlockerror.c b/tests/test_html5_pointerlockerror.c
new file mode 100644
index 0000000000000..8580f29d845fc
--- /dev/null
+++ b/tests/test_html5_pointerlockerror.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <emscripten.h>
+#include <string.h>
+#include <emscripten/html5.h>
+
+void report_result(int result)
+{
+  if (result == 0) {
+    printf("Test successful!\n");
+  } else {
+    printf("Test failed!\n");
+  }
+#ifdef REPORT_RESULT
+  REPORT_RESULT();
+#endif
+}
+
+const char *emscripten_result_to_string(EMSCRIPTEN_RESULT result) {
+  if (result == EMSCRIPTEN_RESULT_SUCCESS) return "EMSCRIPTEN_RESULT_SUCCESS";
+  if (result == EMSCRIPTEN_RESULT_DEFERRED) return "EMSCRIPTEN_RESULT_DEFERRED";
+  if (result == EMSCRIPTEN_RESULT_NOT_SUPPORTED) return "EMSCRIPTEN_RESULT_NOT_SUPPORTED";
+  if (result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED) return "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED";
+  if (result == EMSCRIPTEN_RESULT_INVALID_TARGET) return "EMSCRIPTEN_RESULT_INVALID_TARGET";
+  if (result == EMSCRIPTEN_RESULT_UNKNOWN_TARGET) return "EMSCRIPTEN_RESULT_UNKNOWN_TARGET";
+  if (result == EMSCRIPTEN_RESULT_INVALID_PARAM) return "EMSCRIPTEN_RESULT_INVALID_PARAM";
+  if (result == EMSCRIPTEN_RESULT_FAILED) return "EMSCRIPTEN_RESULT_FAILED";
+  if (result == EMSCRIPTEN_RESULT_NO_DATA) return "EMSCRIPTEN_RESULT_NO_DATA";
+  return "Unknown EMSCRIPTEN_RESULT!";
+}
+
+#define TEST_RESULT(x) if (ret != EMSCRIPTEN_RESULT_SUCCESS) printf("%s returned %s.\n", #x, emscripten_result_to_string(ret));
+
+int gotClick = 0;
+
+EM_BOOL click_callback(int eventType, const EmscriptenMouseEvent *e, void *userData)
+{
+  if (e->screenX != 0 && e->screenY != 0 && e->clientX != 0 && e->clientY != 0 && e->canvasX != 0 && e->canvasY != 0 && e->targetX != 0 && e->targetY != 0)
+  {
+    if (eventType == EMSCRIPTEN_EVENT_CLICK && !gotClick) {
+      gotClick = 1;
+      printf("Request pointer lock...\n");
+      EMSCRIPTEN_RESULT ret = emscripten_request_pointerlock(0, 0);
+      TEST_RESULT(ret);
+      if (ret != EMSCRIPTEN_RESULT_SUCCESS) {
+        printf("ERROR! emscripten_request_pointerlock() failure\n");
+        report_result(1);
+      }
+    }
+  }
+
+  return 0;
+}
+
+EM_BOOL pointerlockchange_callback(int eventType, const EmscriptenPointerlockChangeEvent *e, void *userData) {
+  printf("ERROR! received 'pointerlockchange' event\n");
+  report_result(1);
+
+  return 0;
+}
+
+EM_BOOL pointerlockerror_callback(int eventType, const void *reserved, void *userData) {
+  if (eventType != EMSCRIPTEN_EVENT_POINTERLOCKERROR) {
+    printf("ERROR! invalid event type for 'pointerlockerror' callback\n");
+    report_result(1);
+    return 0;
+  }
+
+  printf("SUCCESS! received 'pointerlockerror' event\n");
+  report_result(0);
+
+  return 0;
+}
+
+int main()
+{
+  printf("'pointerlockerror' event test:\n");
+  printf("Reject the pointer lock request after clicking on canvas.\n");
+
+  // Make the canvas area stand out from the background.
+  emscripten_set_canvas_size(400, 300);
+  EM_ASM(Module['canvas'].style.backgroundColor = 'black';);
+
+  EMSCRIPTEN_RESULT ret = emscripten_set_click_callback(0, 0, 1, click_callback);
+  TEST_RESULT(emscripten_set_click_callback);
+  ret = emscripten_set_pointerlockchange_callback("#window", 0, 1, pointerlockchange_callback);
+  TEST_RESULT(emscripten_set_pointerlockchange_callback);
+  ret = emscripten_set_pointerlockerror_callback("#window", 0, 1, pointerlockerror_callback);
+  TEST_RESULT(emscripten_set_pointerlockerror_callback);
+
+  /* For the events to function, one must either call emscripten_set_main_loop or enable Module.noExitRuntime by some other means. 
+     Otherwise the application will exit after leaving main(), and the atexit handlers will clean up all event hooks (by design). */
+  EM_ASM(Module['noExitRuntime'] = true);
+  return 0;
+}
diff --git a/tests/test_interactive.py b/tests/test_interactive.py
index f9e6c3bbb5535..c18f8a34b6b95 100644
--- a/tests/test_interactive.py
+++ b/tests/test_interactive.py
@@ -28,6 +28,9 @@ def test_html5_fullscreen(self):
   def test_html5_mouse(self):
     self.btest(path_from_root('tests', 'test_html5_mouse.c'), expected='0')
 
+  def test_html5_pointerlockerror(self):
+    self.btest(path_from_root('tests', 'test_html5_pointerlockerror.c'), expected='0')
+
   def test_sdl_mousewheel(self):
     self.btest(path_from_root('tests', 'test_sdl_mousewheel.c'), expected='0')
 
diff --git a/tests/test_other.py b/tests/test_other.py
index 0ed461cf52a9b..5c3f2f4621923 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -6,6 +6,38 @@
 from tools.shared import *
 from runner import RunnerCore, path_from_root, get_zlib_library, get_bullet_library
 
+# Runs an emcc task (used from another process in test test_emcc_multiprocess_cache_access, needs to be at top level for it to be pickleable).
+def multiprocess_task(c_file, cache_dir_name):
+  output = subprocess.check_output([PYTHON, EMCC, c_file, '--cache', cache_dir_name], stderr=subprocess.STDOUT)
+  if len(output.strip()) > 0:
+    print '------'
+    print output
+    print '------'
+  sys.exit(1 if 'generating system library: libc.bc' in output else 0)
+
+class clean_write_access_to_canonical_temp_dir:
+  def clean_emcc_files_in_temp_dir(self):
+    for x in os.listdir(CANONICAL_TEMP_DIR):
+      if x.startswith('emcc-') or x.startswith('a.out'):
+        os.unlink(os.path.join(CANONICAL_TEMP_DIR, x))
+
+  def __enter__(self):
+    self.CANONICAL_TEMP_DIR_exists = os.path.exists(CANONICAL_TEMP_DIR)
+    if not self.CANONICAL_TEMP_DIR_exists:
+      os.makedirs(CANONICAL_TEMP_DIR)
+    else:
+      # Delete earlier files in the canonical temp directory so that
+      # previous leftover files don't have a possibility of confusing
+      # the test result e.g. on failure of the actual task
+      self.clean_emcc_files_in_temp_dir()
+
+  def __exit__(self, type, value, traceback):
+    if not self.CANONICAL_TEMP_DIR_exists:
+      try_delete(CANONICAL_TEMP_DIR)
+      pass
+    else:
+      self.clean_emcc_files_in_temp_dir()
+
 class other(RunnerCore):
   def test_emcc(self):
     for compiler in [EMCC, EMXX]:
@@ -116,6 +148,7 @@ def test_emcc(self):
           os.chdir(os.path.dirname(path))
           self.assertContained('hello, world!', run_js(os.path.basename(path)))
           os.chdir(last)
+          try_delete(path)
       finally:
         os.chdir(self.get_dir())
       self.clear()
@@ -311,6 +344,38 @@ def check_success(command):
         os.environ['EMCC_FAST_COMPILER'] = old_fastcomp
     self.assertFalse(os.path.exists('a.out.js'))
 
+  # Test that if multiple processes attempt to access or build stuff to the cache on demand, that exactly one of the processes
+  # will, and the other processes will block to wait until that process finishes.
+  def test_emcc_multiprocess_cache_access(self):
+    tempdirname = tempfile.mkdtemp(prefix='emscripten_test_emcache_', dir=TEMP_DIR)
+    prev_cwd = os.getcwd()
+    try:
+      os.chdir(tempdirname)
+      c_file = os.path.join(tempdirname, 'test.c')
+      open(c_file, 'w').write(r'''
+        #include <stdio.h>
+        int main() {
+          printf("hello, world!\n");
+          return 0;
+        }
+        ''')
+      cache_dir_name = os.path.join(tempdirname, 'emscripten_cache')
+      tasks = []
+      num_times_libc_was_built = 0
+      for i in range(3):
+        p = multiprocessing.Process(target=multiprocess_task, args=(c_file,cache_dir_name,))
+        p.start()
+        tasks += [p]
+      for p in tasks:
+        p.join()
+        num_times_libc_was_built += p.exitcode
+      assert os.path.exists(cache_dir_name), 'The cache directory %s must exist after the build' % cache_dir_name
+      assert os.path.exists(os.path.join(cache_dir_name, 'asmjs', 'libc.bc')), 'The cache directory must contain a built libc'
+      assert num_times_libc_was_built == 1, 'Exactly one child process should have triggered libc build! (instead %d processes did)' % num_times_libc_was_built
+    finally:
+      os.chdir(prev_cwd) # On Windows, we can't have CWD in the directory we're deleting
+      try_delete(tempdirname)
+
   def test_emcc_cache_flag(self):
     tempdirname = tempfile.mkdtemp(prefix='emscripten_test_emcache_', dir=TEMP_DIR)
     try:
@@ -1944,33 +2009,31 @@ def test_m_mm(self):
 
   def test_emcc_debug_files(self):
     if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
-    if not os.path.exists(CANONICAL_TEMP_DIR):
-      os.makedirs(CANONICAL_TEMP_DIR)
+
     for opts in [0, 1, 2, 3]:
       for debug in [None, '1', '2']:
         print opts, debug
         try:
           if debug: os.environ['EMCC_DEBUG'] = debug
-          for x in os.listdir(CANONICAL_TEMP_DIR):
-            if x.startswith('emcc-'):
-              os.unlink(os.path.join(CANONICAL_TEMP_DIR, x))
-          check_execute([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-O'+ str(opts)], stderr=PIPE)
-          if debug is None:
-            for x in os.listdir(CANONICAL_TEMP_DIR):
-              if x.startswith('emcc-'):
-                assert 0
-          elif debug == '1':
-            assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-0-linktime.bc'))
-            assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-1-original.js'))
-          elif debug == '2':
-            assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-0-basebc.bc'))
-            assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-1-linktime.bc'))
-            assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-2-original.js'))
+          with clean_write_access_to_canonical_temp_dir():
+            check_execute([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '-O'+ str(opts)], stderr=PIPE)
+            if debug is None:
+              for x in os.listdir(CANONICAL_TEMP_DIR):
+                if x.startswith('emcc-'):
+                  assert 0
+            elif debug == '1':
+              assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-0-linktime.bc'))
+              assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-1-original.js'))
+            elif debug == '2':
+              assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-0-basebc.bc'))
+              assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-1-linktime.bc'))
+              assert os.path.exists(os.path.join(CANONICAL_TEMP_DIR, 'emcc-2-original.js'))
         finally:
           if debug: del os.environ['EMCC_DEBUG']
 
   def test_debuginfo(self):
     if os.environ.get('EMCC_DEBUG'): return self.skip('cannot run in debug mode')
+
     try:
       os.environ['EMCC_DEBUG'] = '1'
       for args, expect_llvm, expect_js in [
@@ -1984,13 +2047,17 @@ def test_debuginfo(self):
           (['-O2', '-g4'], True, True), # drop llvm debug info as js opts kill it anyway
         ]:
         print args, expect_llvm, expect_js
-        output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
+        with clean_write_access_to_canonical_temp_dir():
+          output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
         assert expect_llvm == ('strip-debug' not in err)
         assert expect_js == ('registerize' not in err)
     finally:
       del os.environ['EMCC_DEBUG']
 
   def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1
+    scons_path = Building.which('scons')
+    if not scons_path:
+      return self.skip('Skipping other.test_scons: The tool "scons" was not found in PATH!')
     try_delete(os.path.join(self.get_dir(), 'test'))
     shutil.copytree(path_from_root('tests', 'scons'), os.path.join(self.get_dir(), 'test'))
     shutil.copytree(path_from_root('tools', 'scons', 'site_scons'), os.path.join(self.get_dir(), 'test', 'site_scons'))
@@ -2696,7 +2763,8 @@ def test_os_oz(self):
           (['-O3'], 'LLVM opts: -O3'),
         ]:
         print args, expect
-        output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
+        with clean_write_access_to_canonical_temp_dir():
+          output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp')] + args, stdout=PIPE, stderr=PIPE).communicate()
         self.assertContained(expect, err)
         if '-O3' in args or '-Oz' in args or '-Os' in args:
           self.assertContained('registerizeHarder', err)
@@ -2843,6 +2911,9 @@ def test_incorrect_static_call(self):
         assert ('''unexpected argument type float at index 1 in call to 'doit', should be i32''' in stderr) == asserts, stderr
 
   def test_llvm_lit(self):
+    grep_path = Building.which('grep')
+    if not grep_path:
+      return self.skip('Skipping other.test_llvm_lit: This test needs the "grep" tool in PATH. If you are using emsdk on Windows, you can obtain it via installing and activating the gnu package.')
     llvm_src = get_fastcomp_src_dir()
     LLVM_LIT = os.path.join(LLVM_ROOT, 'llvm-lit.py')
     if not os.path.exists(LLVM_LIT):
@@ -4761,7 +4832,8 @@ def test(args, expected):
       try:
         os.environ['EMCC_DEBUG'] = '1'
         os.environ['EMCC_NATIVE_OPTIMIZER'] = '1'
-        out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O2',] + args, stderr=PIPE).communicate()
+        with clean_write_access_to_canonical_temp_dir():
+          out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-O2',] + args, stderr=PIPE).communicate()
       finally:
         if old_debug: os.environ['EMCC_DEBUG'] = old_debug
         else: del os.environ['EMCC_DEBUG']
@@ -5484,6 +5556,38 @@ def test_realpath(self):
     Popen([PYTHON, EMCC, 'src.c', '--embed-file', 'boot']).communicate()
     self.assertContained('Resolved: /boot/README.txt', run_js('a.out.js'))
 
+  def test_realpath_nodefs(self):
+    open('src.c', 'w').write(r'''
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <emscripten.h>
+
+#define TEST_PATH "/working/TEST_NODEFS.txt"
+
+int
+main(int argc, char **argv)
+{
+  errno = 0;
+  EM_ASM({
+    FS.mkdir('/working');
+    FS.mount(NODEFS, { root: '.' }, '/working');
+  });
+  char *t_realpath_buf = realpath(TEST_PATH, NULL);
+  if (NULL == t_realpath_buf) {
+    perror("Resolve failed");
+    return 1;
+  } else {
+    printf("Resolved: %s", t_realpath_buf);
+    free(t_realpath_buf);
+    return 0;
+  }
+}
+''')
+    open('TEST_NODEFS.txt', 'w').write(' ')
+    Popen([PYTHON, EMCC, 'src.c']).communicate()
+    self.assertContained('Resolved: /working/TEST_NODEFS.txt', run_js('a.out.js'))
+
   def test_realpath_2(self):
     open('src.c', 'w').write(r'''
 #include <stdlib.h>
@@ -6144,7 +6248,8 @@ def test(p1, p2, p3, last, expected):
 C c;
 int main() {}
       ''')
-      out, err = Popen([PYTHON, EMCC, 'src.cpp', '-Oz'], stderr=PIPE).communicate()
+      with clean_write_access_to_canonical_temp_dir():
+        out, err = Popen([PYTHON, EMCC, 'src.cpp', '-Oz'], stderr=PIPE).communicate()
       self.assertContained('___syscall54', err) # the failing call should be mentioned
       self.assertContained('ctorEval.js', err) # with a stack trace
       self.assertContained('ctor_evaller: not successful', err) # with logging
diff --git a/tests/test_sanity.py b/tests/test_sanity.py
index dacb968113b58..60a65eae9d9d4 100644
--- a/tests/test_sanity.py
+++ b/tests/test_sanity.py
@@ -339,12 +339,12 @@ def test_emcc(self):
 
     # emcc should check sanity if no ${EM_CONFIG}_sanity
     restore()
-    time.sleep(0.1)
+    time.sleep(1)
     assert not os.path.exists(SANITY_FILE) # restore is just the settings, not the sanity
     output = self.check_working(EMCC)
     self.assertContained(SANITY_MESSAGE, output)
     assert os.path.exists(SANITY_FILE) # EMCC should have checked sanity successfully
-    assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
+    assert mtime(SANITY_FILE) > mtime(CONFIG_FILE)
     assert generate_sanity() == open(SANITY_FILE).read()
     self.assertNotContained(SANITY_FAIL_MESSAGE, output)
 
diff --git a/tests/test_sockets.py b/tests/test_sockets.py
index 66a065497a047..8d8d14a7376b6 100644
--- a/tests/test_sockets.py
+++ b/tests/test_sockets.py
@@ -341,6 +341,12 @@ def test_getprotobyname(self):
   def test_sockets_echo(self):
     sockets_include = '-I'+path_from_root('tests', 'sockets')
 
+    # Note: in the WebsockifyServerHarness and CompiledServerHarness tests below, explicitly use consecutive server listen ports,
+    # because server teardown might not occur deterministically (python dtor time) and is a bit racy.
+    # WebsockifyServerHarness uses two port numbers, x and x-1, so increment it by two.
+    # CompiledServerHarness only uses one. Start with 49160 & 49159 as the first server port addresses. If adding new tests,
+    # increment the used port addresses below.
+
     # Websockify-proxied servers can't run dgram tests
     harnesses = [
       (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 49160), 0),
@@ -366,18 +372,20 @@ def test_sockets_async_echo(self):
 
     # Websockify-proxied servers can't run dgram tests
     harnesses = [
-      (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_ASYNC=1'], 49165), 0),
-      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0', '-DTEST_ASYNC=1'], 49166), 0),
-      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1', '-DTEST_ASYNC=1'], 49167), 1),
+      (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_ASYNC=1'], 49166), 0),
+      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0', '-DTEST_ASYNC=1'], 49167), 0),
+      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1', '-DTEST_ASYNC=1'], 49168), 1),
       # The following forces non-NULL addr and addlen parameters for the accept call
-      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0', '-DTEST_ACCEPT_ADDR=1', '-DTEST_ASYNC=1'], 49168), 0)
+      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0', '-DTEST_ACCEPT_ADDR=1', '-DTEST_ASYNC=1'], 49169), 0)
     ]
 
     for harness, datagram in harnesses:
+      print 'harness:', harness
       with harness:
         self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram, '-DTEST_ASYNC=1', sockets_include])
 
     # Deliberately attempt a connection on a port that will fail to test the error callback and getsockopt
+    print 'expect fail'
     self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=49169', '-DTEST_ASYNC=1', sockets_include])
 
   def test_sockets_echo_bigdata(self):
@@ -394,9 +402,9 @@ def test_sockets_echo_bigdata(self):
     output = input.replace('#define MESSAGE "pingtothepong"', '#define MESSAGE "%s"' % message)
 
     harnesses = [
-      (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 49170), 0),
-      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 49171), 0),
-      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 49172), 1)
+      (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 49171), 0),
+      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 49172), 0),
+      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 49173), 1)
     ]
 
     for harness, datagram in harnesses:
diff --git a/tests/test_sse1.cpp b/tests/test_sse1.cpp
index ec04509e06525..5844201b0ee44 100644
--- a/tests/test_sse1.cpp
+++ b/tests/test_sse1.cpp
@@ -329,6 +329,9 @@ int main()
 	_mm_prefetch(dummyData, _MM_HINT_NTA);
 	_mm_sfence();
 
+	const char *ptr = (const char*)dummyData;
+	_mm_prefetch(ptr, _MM_HINT_T0);
+
 	// SSE1 Misc instructions:
 #ifdef TEST_M64
 	/*M64*/Assert(_mm_movemask_pi8(m1) == 100); // Return int with eight lowest bits set depending on the highest bits of the 8 uint8 input channels of the m64.
diff --git a/tests/test_sse_full.h b/tests/test_sse_full.h
index b6d7bcb9b516c..39b7cf32fb64d 100644
--- a/tests/test_sse_full.h
+++ b/tests/test_sse_full.h
@@ -353,7 +353,6 @@ __m128 ExtractInRandomOrder(float *arr, int i, int n, int prime)
 			}
 
 #define const_int8_unroll(Ret_type, F, func) \
-	F(Ret_type, func, -1); \
 	F(Ret_type, func, 0); \
 	F(Ret_type, func, 1); \
 	F(Ret_type, func, 2); \
@@ -376,8 +375,7 @@ __m128 ExtractInRandomOrder(float *arr, int i, int n, int prime)
 	F(Ret_type, func, 128); \
 	F(Ret_type, func, 191); \
 	F(Ret_type, func, 254); \
-	F(Ret_type, func, 255); \
-	F(Ret_type, func, 309);
+	F(Ret_type, func, 255);
 
 #define Ret_M128_Tint(Ret_type, func) const_int8_unroll(Ret_type, Ret_M128_Tint_body, func)
 #define Ret_M128i_Tint(Ret_type, func) const_int8_unroll(Ret_type, Ret_M128i_Tint_body, func)
diff --git a/tests/unistd/unlink.c b/tests/unistd/unlink.c
index 2e512146a942c..68051c1370649 100644
--- a/tests/unistd/unlink.c
+++ b/tests/unistd/unlink.c
@@ -79,7 +79,9 @@ void test() {
 
   err = unlink("dir-readonly");
   assert(err == -1);
-#ifdef __linux__
+
+  // emscripten uses 'musl' what is an implementation of the standard library for Linux-based systems
+#if defined(__linux__) || defined(__EMSCRIPTEN__)
   assert(errno == EISDIR);
 #else
   assert(errno == EPERM);
diff --git a/tests/utf16_corpus.txt b/tests/utf16_corpus.txt
new file mode 100644
index 0000000000000..707bd6ad718da
Binary files /dev/null and b/tests/utf16_corpus.txt differ
diff --git a/tests/utf8_corpus.txt b/tests/utf8_corpus.txt
new file mode 100644
index 0000000000000..126a0b548eefa
--- /dev/null
+++ b/tests/utf8_corpus.txt
@@ -0,0 +1,152 @@
+This is an excerpt from the page "UTF-8 Sampler" at http://www.columbia.edu/~fdc/utf8/index.html#notes, containing the sentence "I can eat glass and it doesn't hurt me" in several languages.
+
+Sanskrit: काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥
+Sanskrit (standard transcription): kācaṃ śaknomyattum; nopahinasti mām.
+Classical Greek: ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.
+Greek (monotonic): Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.
+Greek (polytonic): Μπορῶ νὰ φάω σπασμένα γυαλιὰ χωρὶς νὰ πάθω τίποτα. 
+Latin: Vitrum edere possum; mihi non nocet.
+Old French: Je puis mangier del voirre. Ne me nuit.
+French: Je peux manger du verre, ça ne me fait pas mal.
+Provençal / Occitan: Pòdi manjar de veire, me nafrariá pas.
+Québécois: J'peux manger d'la vitre, ça m'fa pas mal.
+Walloon: Dji pou magnî do vêre, çoula m' freut nén må. 
+Picard: Ch'peux mingi du verre, cha m'foé mie n'ma. 
+Kreyòl Ayisyen (Haitï): Mwen kap manje vè, li pa blese'm.
+Basque: Kristala jan dezaket, ez dit minik ematen.
+Catalan / Català: Puc menjar vidre, que no em fa mal.
+Spanish: Puedo comer vidrio, no me hace daño.
+Aragonés: Puedo minchar beire, no me'n fa mal . 
+Galician: Eu podo xantar cristais e non cortarme.
+European Portuguese: Posso comer vidro, não me faz mal.
+Brazilian Portuguese (8): Posso comer vidro, não me machuca.
+Caboverdiano/Kabuverdianu (Cape Verde): M' podê cumê vidru, ca ta maguâ-m'.
+Papiamentu: Ami por kome glas anto e no ta hasimi daño.
+Italian: Posso mangiare il vetro e non mi fa male.
+Milanese: Sôn bôn de magnà el véder, el me fa minga mal.
+Roman: Me posso magna' er vetro, e nun me fa male.
+Napoletano: M' pozz magna' o'vetr, e nun m' fa mal.
+Venetian: Mi posso magnare el vetro, no'l me fa mae.
+Zeneise (Genovese): Pòsso mangiâ o veddro e o no me fà mâ.
+Sicilian: Puotsu mangiari u vitru, nun mi fa mali. 
+Romansch (Grischun): Jau sai mangiar vaider, senza che quai fa donn a mai. 
+Romanian: Pot să mănânc sticlă și ea nu mă rănește.
+Esperanto: Mi povas manĝi vitron, ĝi ne damaĝas min. 
+Cornish: Mý a yl dybry gwéder hag éf ny wra ow ankenya.
+Welsh: Dw i'n gallu bwyta gwydr, 'dyw e ddim yn gwneud dolur i mi.
+Manx Gaelic: Foddym gee glonney agh cha jean eh gortaghey mee.
+Old Irish (Ogham): ᚛᚛ᚉᚑᚅᚔᚉᚉᚔᚋ ᚔᚈᚔ ᚍᚂᚐᚅᚑ ᚅᚔᚋᚌᚓᚅᚐ᚜
+Old Irish (Latin): Con·iccim ithi nglano. Ním·géna.
+Irish: Is féidir liom gloinne a ithe. Ní dhéanann sí dochar ar bith dom.
+Ulster Gaelic: Ithim-sa gloine agus ní miste damh é.
+Scottish Gaelic: S urrainn dhomh gloinne ithe; cha ghoirtich i mi.
+Anglo-Saxon (Runes): ᛁᚳ᛫ᛗᚨᚷ᛫ᚷᛚᚨᛋ᛫ᛖᚩᛏᚪᚾ᛫ᚩᚾᛞ᛫ᚻᛁᛏ᛫ᚾᛖ᛫ᚻᛖᚪᚱᛗᛁᚪᚧ᛫ᛗᛖ᛬
+Anglo-Saxon (Latin): Ic mæg glæs eotan ond hit ne hearmiað me.
+Middle English: Ich canne glas eten and hit hirtiþ me nouȝt.
+English: I can eat glass and it doesn't hurt me.
+English (IPA): [aɪ kæn iːt glɑːs ænd ɪt dɐz nɒt hɜːt miː] (Received Pronunciation)
+English (Braille): ⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑
+Jamaican: Mi kian niam glas han i neba hot mi.
+Lalland Scots / Doric: Ah can eat gless, it disnae hurt us. 
+Gothic (4): ЌЌЌ ЌЌЌЍ Ќ̈ЍЌЌ, ЌЌ ЌЌЍ ЍЌ ЌЌЌЌ ЌЍЌЌЌЌЌ.
+Old Norse (Runes): ᛖᚴ ᚷᛖᛏ ᛖᛏᛁ ᚧ ᚷᛚᛖᚱ ᛘᚾ ᚦᛖᛋᛋ ᚨᚧ ᚡᛖ ᚱᚧᚨ ᛋᚨᚱ
+Old Norse (Latin): Ek get etið gler án þess að verða sár.
+Norsk / Norwegian (Nynorsk): Eg kan eta glas utan å skada meg.
+Norsk / Norwegian (Bokmål): Jeg kan spise glass uten å skade meg.
+Føroyskt / Faroese: Eg kann eta glas, skaðaleysur.
+Íslenska / Icelandic: Ég get etið gler án þess að meiða mig.
+Svenska / Swedish: Jag kan äta glas utan att skada mig.
+Dansk / Danish: Jeg kan spise glas, det gør ikke ondt på mig.
+Sønderjysk: Æ ka æe glass uhen at det go mæ naue.
+Frysk / Frisian: Ik kin glês ite, it docht me net sear.
+Nederlands / Dutch: Ik kan glas eten, het doet mij geen kwaad.
+Kirchröadsj/Bôchesserplat: Iech ken glaas èèse, mer 't deet miech jing pieng.
+Afrikaans: Ek kan glas eet, maar dit doen my nie skade nie.
+Lëtzebuergescht / Luxemburgish: Ech kan Glas iessen, daat deet mir nët wei.
+Deutsch / German: Ich kann Glas essen, ohne mir zu schaden.
+Ruhrdeutsch: Ich kann Glas verkasematuckeln, ohne dattet mich wat jucken tut.
+Langenfelder Platt: Isch kann Jlaas kimmeln, uuhne datt mich datt weh dääd.
+Lausitzer Mundart ("Lusatian"): Ich koann Gloos assn und doas dudd merr ni wii.
+Odenwälderisch: Iech konn glaasch voschbachteln ohne dass es mir ebbs daun doun dud.
+Sächsisch / Saxon: 'sch kann Glos essn, ohne dass'sch mer wehtue.
+Pfälzisch: Isch konn Glass fresse ohne dasses mer ebbes ausmache dud.
+Schwäbisch / Swabian: I kå Glas frässa, ond des macht mr nix!
+Deutsch (Voralberg): I ka glas eassa, ohne dass mar weh tuat.
+Bayrisch / Bavarian: I koh Glos esa, und es duard ma ned wei.
+Allemannisch: I kaun Gloos essen, es tuat ma ned weh.
+Schwyzerdütsch (Zürich): Ich chan Glaas ässe, das schadt mir nöd.
+Schwyzerdütsch (Luzern): Ech cha Glâs ässe, das schadt mer ned. 
+Hungarian: Meg tudom enni az üveget, nem lesz tőle bajom.
+Suomi / Finnish: Voin syödä lasia, se ei vahingoita minua.
+Sami (Northern): Sáhtán borrat lása, dat ii leat bávččas.
+Erzian: Мон ярсан суликадо, ды зыян эйстэнзэ а ули.
+Northern Karelian: Mie voin syvvä lasie ta minla ei ole kipie.
+Southern Karelian: Minä voin syvvä st'oklua dai minule ei ole kibie. 
+Estonian: Ma võin klaasi süüa, see ei tee mulle midagi.
+Latvian: Es varu ēst stiklu, tas man nekaitē.
+Lithuanian: Aš galiu valgyti stiklą ir jis manęs nežeidžia 
+Czech: Mohu jíst sklo, neublíží mi.
+Slovak: Môžem jesť sklo. Nezraní ma.
+Polska / Polish: Mogę jeść szkło i mi nie szkodzi.
+Slovenian: Lahko jem steklo, ne da bi mi škodovalo.
+Bosnian, Croatian, Montenegrin and Serbian (Latin): Ja mogu jesti staklo, i to mi ne šteti.
+Bosnian, Montenegrin and Serbian (Cyrillic): Ја могу јести стакло, и то ми не штети.
+Macedonian: Можам да јадам стакло, а не ме штета.
+Russian: Я могу есть стекло, оно мне не вредит.
+Belarusian (Cyrillic): Я магу есці шкло, яно мне не шкодзіць.
+Belarusian (Lacinka): Ja mahu jeści škło, jano mne ne škodzić.
+Ukrainian: Я можу їсти скло, і воно мені не зашкодить.
+Bulgarian: Мога да ям стъкло, то не ми вреди.
+Georgian: მინას ვჭამ და არა მტკივა.
+Armenian: Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։
+Albanian: Unë mund të ha qelq dhe nuk më gjen gjë.
+Turkish: Cam yiyebilirim, bana zararı dokunmaz.
+Turkish (Ottoman): جام ييه بلورم بڭا ضررى طوقونمز
+Bangla / Bengali: আমি কাঁচ খেতে পারি, তাতে আমার কোনো ক্ষতি হয় না।
+Marathi: मी काच खाऊ शकतो, मला ते दुखत नाही.
+Kannada: ನನಗೆ ಹಾನಿ ಆಗದೆ, ನಾನು ಗಜನ್ನು ತಿನಬಹುದು
+Hindi: मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती.
+Tamil: நான் கண்ணாடி சாப்பிடுவேன், அதனால் எனக்கு ஒரு கேடும் வராது.
+Telugu: నేను గాజు తినగలను మరియు అలా చేసినా నాకు ఏమి ఇబ్బంది లేదు
+Sinhalese: මට වීදුරු කෑමට හැකියි. එයින් මට කිසි හානියක් සිදු නොවේ.
+Urdu(3): میں کانچ کھا سکتا ہوں اور مجھے تکلیف نہیں ہوتی ۔
+Pashto(3): زه شيشه خوړلې شم، هغه ما نه خوږوي
+Farsi / Persian(3): .من می توانم بدونِ احساس درد شيشه بخورم
+Arabic(3): أنا قادر على أكل الزجاج و هذا لا يؤلمني. 
+Maltese: Nista' niekol il-ħġieġ u ma jagħmilli xejn.
+Hebrew(3): אני יכול לאכול זכוכית וזה לא מזיק לי.
+Yiddish(3): איך קען עסן גלאָז און עס טוט מיר נישט װײ. 
+Twi: Metumi awe tumpan, ɜnyɜ me hwee.
+Hausa (Latin): Inā iya taunar gilāshi kuma in gamā lāfiyā.
+Hausa (Ajami) (2): إِنا إِىَ تَونَر غِلَاشِ كُمَ إِن غَمَا لَافِىَا
+Yoruba(4): Mo lè je̩ dígí, kò ní pa mí lára.
+Lingala: Nakokí kolíya biténi bya milungi, ekosála ngáí mabé tɛ́.
+(Ki)Swahili: Naweza kula bilauri na sikunyui.
+Malay: Saya boleh makan kaca dan ia tidak mencederakan saya.
+Tagalog: Kaya kong kumain nang bubog at hindi ako masaktan.
+Chamorro: Siña yo' chumocho krestat, ti ha na'lalamen yo'.
+Fijian: Au rawa ni kana iloilo, ia au sega ni vakacacani kina.
+Javanese: Aku isa mangan beling tanpa lara.
+Burmese: က္ယ္ဝန္‌တော္‌၊က္ယ္ဝန္‌မ မ္ယက္‌စားနုိင္‌သည္‌။ ၎က္ရောင္‌့ ထိခုိက္‌မ္ဟု မရ္ဟိပာ။ (9)
+Vietnamese (quốc ngữ): Tôi có thể ăn thủy tinh mà không hại gì.
+Vietnamese (nôm) (4): 些 ࣎ 世 咹 水 晶 ও 空 ࣎ 害 咦
+Khmer: ខ្ញុំអាចញុំកញ្ចក់បាន ដោយគ្មានបញ្ហារ
+Lao: ຂອ້ຍກິນແກ້ວໄດ້ໂດຍທີ່ມັນບໍ່ໄດ້ເຮັດໃຫ້ຂອ້ຍເຈັບ.
+Thai: ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ
+Mongolian (Cyrillic): Би шил идэй чадна, надад хортой биш
+Mongolian (Classic) (5): ᠪᠢ ᠰᠢᠯᠢ ᠢᠳᠡᠶᠦ ᠴᠢᠳᠠᠨᠠ ᠂ ᠨᠠᠳᠤᠷ ᠬᠣᠤᠷᠠᠳᠠᠢ ᠪᠢᠰᠢ 
+Nepali: म काँच खान सक्छू र मलाई केहि नी हुन्‍न् ।
+Tibetan: ཤེལ་སྒོ་ཟ་ནས་ང་ན་གི་མ་རེད།
+Chinese: 我能吞下玻璃而不伤身体。
+Chinese (Traditional): 我能吞下玻璃而不傷身體。
+Taiwanese(6): Góa ē-tàng chia̍h po-lê, mā bē tio̍h-siong.
+Japanese: 私はガラスを食べられます。それは私を傷つけません。
+Korean: 나는 유리를 먹을 수 있어요. 그래도 아프지 않아요
+Bislama: Mi save kakae glas, hemi no save katem mi.
+Hawaiian: Hiki iaʻu ke ʻai i ke aniani; ʻaʻole nō lā au e ʻeha.
+Marquesan: E koʻana e kai i te karahi, mea ʻā, ʻaʻe hauhau.
+Inuktitut (10): ᐊᓕᒍᖅ ᓂᕆᔭᕌᖓᒃᑯ ᓱᕋᙱᑦᑐᓐᓇᖅᑐᖓ
+Chinook Jargon: Naika məkmək kakshət labutay, pi weyk ukuk munk-sik nay.
+Navajo: Tsésǫʼ yishą́ągo bííníshghah dóó doo shił neezgai da. 
+Lojban: mi kakne le nu citka le blaci .iku'i le se go'i na xrani mi
+Nórdicg: Ljœr ye caudran créneþ ý jor cẃran.
\ No newline at end of file
diff --git a/tests/webgl_create_context.cpp b/tests/webgl_create_context.cpp
index cc1ca2ca75863..147202b961cac 100644
--- a/tests/webgl_create_context.cpp
+++ b/tests/webgl_create_context.cpp
@@ -87,18 +87,14 @@ int main()
     attrs.antialias = antialias;
     printf("Requesting depth: %d, stencil: %d, antialias: %d\n", depth, stencil, antialias);
 
-    if (!first)
-    {
-      EM_ASM(var canvas2 = Module.canvas.cloneNode();
-        Module.canvas.parentElement.appendChild(canvas2);
-   //   Module.canvas.parentElement.removeChild(canvas);
-      Module.canvas = canvas2;
-      );
-    }
-    first = false;
+    EM_ASM(
+      var canvas2 = document.createElement('canvas');
+      Module.canvas.parentElement.appendChild(canvas2);
+      canvas2.id = 'customCanvas';
+    );
     
     assert(emscripten_webgl_get_current_context() == 0);
-    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(0, &attrs);
+    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context("customCanvas", &attrs);
     assert(context > 0); // Must have received a valid context.
     EMSCRIPTEN_RESULT res = emscripten_webgl_make_context_current(context);
     assert(res == EMSCRIPTEN_RESULT_SUCCESS);
@@ -144,6 +140,11 @@ int main()
     res = emscripten_webgl_destroy_context(context);
     assert(res == 0);
     assert(emscripten_webgl_get_current_context() == 0);
+
+    EM_ASM(
+      var canvas2 = document.getElementById('customCanvas');
+      canvas2.parentElement.removeChild(canvas2);
+    );
   }
   
   // result will be reported when mainLoop completes
diff --git a/tests/webgl_destroy_context_shell.html b/tests/webgl_destroy_context_shell.html
index cc4604ac87cbb..ccd058357e944 100644
--- a/tests/webgl_destroy_context_shell.html
+++ b/tests/webgl_destroy_context_shell.html
@@ -10,7 +10,7 @@
       div.emscripten { text-align: center; }
       div.emscripten_border { border: 1px solid black; }
       /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
-      canvas.emscripten { border: 0px none; }
+      canvas.emscripten { border: 0px none; background-color: black; }
 
       .spinner {
         height: 50px;
@@ -61,7 +61,7 @@
       <input type="checkbox" id="resize">Resize canvas
       <input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
       &nbsp;&nbsp;&nbsp;
-      <input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, 
+      <input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked, 
                                                                                 document.getElementById('resize').checked)">
     </div>
     
diff --git a/tests/webidl/post.js b/tests/webidl/post.js
index c7b99a23b8e44..ecb8bfebc09a4 100644
--- a/tests/webidl/post.js
+++ b/tests/webidl/post.js
@@ -229,9 +229,12 @@ try {
 
 // Check for overflowing the stack
 
+var before = Date.now();
+
 for (var i = 0; i < 1000000; i++) {
   var temp = new TheModule.StringUser('abc', 1);
   TheModule.destroy(temp);
+  if (Date.now() - before >= 1000) break;
 }
 
 //
diff --git a/tests/webidl/test.cpp b/tests/webidl/test.cpp
index 8719ec1f3682b..b79c139e6d6bd 100644
--- a/tests/webidl/test.cpp
+++ b/tests/webidl/test.cpp
@@ -12,6 +12,13 @@ typedef EnumNamespace::EnumInNamespace EnumNamespace_EnumInNamespace;
 #ifdef BROWSER
 int main() {
   printf("main().\n");
+  EM_ASM({
+    // simple test that everything is functional
+    var sme = new Module.Parent(42);
+    sme.mulVal(2);
+    var got = sme.getVal();
+    assert(got === 84, "got: " + got);
+  });
   int result = 1;
   REPORT_RESULT();
 }
diff --git a/tools/cache.py b/tools/cache.py
index d1e22fba31977..e329737cdd127 100644
--- a/tools/cache.py
+++ b/tools/cache.py
@@ -1,14 +1,31 @@
 import os.path, sys, shutil, time, logging
-
-import tempfiles
+import tempfiles, filelock
 
 # Permanent cache for dlmalloc and stdlibc++
 class Cache:
+
+  # If EM_EXCLUSIVE_CACHE_ACCESS is true, this process is allowed to have direct access to
+  # the Emscripten cache without having to obtain an interprocess lock for it. Generally this
+  # is false, and this is used in the case that Emscripten process recursively calls to itself
+  # when building the cache, in which case the parent Emscripten process has already locked
+  # the cache. Essentially the env. var EM_EXCLUSIVE_CACHE_ACCESS signals from parent to
+  # child process that the child can reuse the lock that the parent already has acquired.
+  EM_EXCLUSIVE_CACHE_ACCESS = int(os.environ.get('EM_EXCLUSIVE_CACHE_ACCESS') or 0)
+
   def __init__(self, dirname=None, debug=False, use_subdir=True):
     if dirname is None:
       dirname = os.environ.get('EM_CACHE')
     if not dirname:
       dirname = os.path.expanduser(os.path.join('~', '.emscripten_cache'))
+
+    def try_remove_ending(thestring, ending):
+      if thestring.endswith(ending):
+        return thestring[:-len(ending)]
+      return thestring
+
+    self.filelock_name = try_remove_ending(try_remove_ending(dirname, '/'), '\\') + '.lock'
+    self.filelock = filelock.FileLock(self.filelock_name)
+
     if use_subdir:
       if os.environ.get('EMCC_WASM_BACKEND') and os.environ.get('EMCC_WASM_BACKEND') != '0':
         dirname = os.path.join(dirname, 'wasm')
@@ -17,8 +34,34 @@ def __init__(self, dirname=None, debug=False, use_subdir=True):
     self.dirname = dirname
     self.debug = debug
 
+  def acquire_cache_lock(self):
+    if not self.EM_EXCLUSIVE_CACHE_ACCESS:
+      logging.debug('Cache: acquiring multiprocess file lock to Emscripten cache')
+      try:
+        self.filelock.acquire(60)
+      except filelock.Timeout:
+        # The multiprocess cache locking can be disabled altogether by setting EM_EXCLUSIVE_CACHE_ACCESS=1 environment
+        # variable before building. (in that case, use "embuilder.py build ALL" to prepopulate the cache)
+        logging.warning('Accessing the Emscripten cache at "' + self.dirname + '" is taking a long time, another process should be writing to it. If there are none and you suspect this process has deadlocked, try deleting the lock file "' + self.filelock_name + '" and try again. If this occurs deterministically, consider filing a bug.')
+        self.filelock.acquire()
+
+      self.prev_EM_EXCLUSIVE_CACHE_ACCESS = os.environ.get('EM_EXCLUSIVE_CACHE_ACCESS')
+      os.environ['EM_EXCLUSIVE_CACHE_ACCESS'] = '1'
+      logging.debug('Cache: done')
+
+  def release_cache_lock(self):
+    if not self.EM_EXCLUSIVE_CACHE_ACCESS:
+      if self.prev_EM_EXCLUSIVE_CACHE_ACCESS: os.environ['EM_EXCLUSIVE_CACHE_ACCESS'] = self.prev_EM_EXCLUSIVE_CACHE_ACCESS
+      else: del os.environ['EM_EXCLUSIVE_CACHE_ACCESS']
+      self.filelock.release()
+      logging.debug('Cache: released multiprocess file lock to Emscripten cache')
+
   def ensure(self):
-    shared.safe_ensure_dirs(self.dirname)
+    self.acquire_cache_lock()
+    try:
+      shared.safe_ensure_dirs(self.dirname)
+    finally:
+      self.release_cache_lock()
 
   def erase(self):
     tempfiles.try_delete(self.dirname)
@@ -26,6 +69,9 @@ def erase(self):
       open(self.dirname + '__last_clear', 'w').write('last clear: ' + time.asctime() + '\n')
     except Exception, e:
       print >> sys.stderr, 'failed to save last clear time: ', e
+    self.filelock = None
+    tempfiles.try_delete(self.filelock_name)
+    self.filelock = filelock.FileLock(self.filelock_name)
 
   def get_path(self, shortname):
     return os.path.join(self.dirname, shortname)
@@ -35,18 +81,24 @@ def get_path(self, shortname):
   def get(self, shortname, creator, extension='.bc', what=None, force=False):
     if not shortname.endswith(extension): shortname += extension
     cachename = os.path.join(self.dirname, shortname)
-    if os.path.exists(cachename) and not force:
-      return cachename
-    if what is None:
-      if shortname.endswith(('.bc', '.so', '.a')): what = 'system library'
-      else: what = 'system asset'
-    message = 'generating ' + what + ': ' + shortname + '...'
-    logging.warn(message)
-    self.ensure()
-    temp = creator()
-    if temp != cachename:
-      shutil.copyfile(temp, cachename)
-    logging.warn(' '*len(message) + 'ok')
+
+    self.acquire_cache_lock()
+    try:
+      if os.path.exists(cachename) and not force:
+        return cachename
+      if what is None:
+        if shortname.endswith(('.bc', '.so', '.a')): what = 'system library'
+        else: what = 'system asset'
+      message = 'generating ' + what + ': ' + shortname + '...'
+      logging.warn(message)
+      self.ensure()
+      temp = creator()
+      if temp != cachename:
+        shutil.copyfile(temp, cachename)
+      logging.warn(' '*len(message) + 'ok')
+    finally:
+      self.release_cache_lock()
+
     return cachename
 
 # Given a set of functions of form (ident, text), and a preferred chunk size,
diff --git a/tools/ctor_evaller.py b/tools/ctor_evaller.py
index 603511cde666b..21822554dc4f4 100644
--- a/tools/ctor_evaller.py
+++ b/tools/ctor_evaller.py
@@ -17,12 +17,6 @@
 
 config = shared.Configuration()
 
-if shared.DEBUG:
-  temp_file = os.path.join(shared.CANONICAL_TEMP_DIR, 'ctorEval.js')
-  shared.safe_ensure_dirs(shared.CANONICAL_TEMP_DIR)
-else:
-  temp_file = config.get_temp_files().get('.ctorEval.js').name
-
 # helpers
 
 def get_asm(js):
@@ -101,7 +95,13 @@ def add_func(asm, func):
   static_bump = int(js[static_bump_start + len(static_bump_op):static_bump_end])
   # Generate a safe sandboxed environment. We replace all ffis with errors. Otherwise,
   # asm.js can't call outside, so we are ok.
-  open(temp_file, 'w').write('''
+#  if shared.DEBUG:
+#    temp_file = os.path.join(shared.CANONICAL_TEMP_DIR, 'ctorEval.js')
+#    shared.safe_ensure_dirs(shared.CANONICAL_TEMP_DIR)
+#  else:
+#    temp_file = config.get_temp_files().get('.ctorEval.js').name
+  with config.get_temp_files().get_file('.ctorEval.js') as temp_file:
+    open(temp_file, 'w').write('''
 var totalMemory = %d;
 var totalStack = %d;
 
@@ -213,20 +213,21 @@ def add_func(asm, func):
 console.log(JSON.stringify([numSuccessful, Array.prototype.slice.call(heap.subarray(globalBase, newSize)), atexits]));
 
 ''' % (total_memory, total_stack, mem_init, global_base, static_bump, asm, json.dumps(ctors)))
-  # Execute the sandboxed code. If an error happened due to calling an ffi, that's fine,
-  # us exiting with an error tells the caller that we failed. If it times out, give up.
-  out_file = config.get_temp_files().get('.out').name
-  err_file = config.get_temp_files().get('.err').name
-  proc = subprocess.Popen(shared.NODE_JS + [temp_file], stdout=open(out_file, 'w'), stderr=open(err_file, 'w'))
-  try:
-    shared.jsrun.timeout_run(proc, timeout=10, full_output=True)
-    if proc.returncode != 0:
-      shared.logging.debug('unexpected error while trying to eval ctors:\n' + open(err_file).read())
+    # Execute the sandboxed code. If an error happened due to calling an ffi, that's fine,
+    # us exiting with an error tells the caller that we failed. If it times out, give up.
+    out_file = config.get_temp_files().get('.out').name
+    err_file = config.get_temp_files().get('.err').name
+    proc = subprocess.Popen(shared.NODE_JS + [temp_file], stdout=open(out_file, 'w'), stderr=open(err_file, 'w'))
+    try:
+      shared.jsrun.timeout_run(proc, timeout=10, full_output=True)
+      if proc.returncode != 0:
+        shared.logging.debug('unexpected error while trying to eval ctors:\n' + open(err_file).read())
+        return (0, 0, 0, 0)
+    except Exception, e:
+      if 'Timed out' not in str(e): raise e
+      shared.logging.debug('ctors timed out\n')
       return (0, 0, 0, 0)
-  except Exception, e:
-    if 'Timed out' not in str(e): raise e
-    shared.logging.debug('ctors timed out\n')
-    return (0, 0, 0, 0)
+
   # out contains the new mem init and other info
   num_successful, mem_init_raw, atexits = json.loads(open(out_file).read())
   mem_init = ''.join(map(chr, mem_init_raw))
diff --git a/tools/duplicate_function_eliminator.py b/tools/duplicate_function_eliminator.py
index ae1387b9450be..88727036c98d1 100644
--- a/tools/duplicate_function_eliminator.py
+++ b/tools/duplicate_function_eliminator.py
@@ -8,17 +8,17 @@
 def process_shell(js, js_engine, shell, equivalentfn_hash_info=None):
   suffix = '.eliminatedupes'
 
-  temp_file = temp_files.get(suffix + '.js').name
-  f = open(temp_file, 'w')
-  f.write(shell)
-  f.write('\n')
+  with temp_files.get_file(suffix + '.js') as temp_file:
+    f = open(temp_file, 'w')
+    f.write(shell)
+    f.write('\n')
 
-  f.write(equivalentfn_hash_info)
-  f.close()
+    f.write(equivalentfn_hash_info)
+    f.close()
 
-  (output,error) = subprocess.Popen(js_engine +
-      [DUPLICATE_FUNCTION_ELIMINATOR, temp_file, '--use-hash-info', '--no-minimize-whitespace'],
-      stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
+    (output,error) = subprocess.Popen(js_engine +
+        [DUPLICATE_FUNCTION_ELIMINATOR, temp_file, '--use-hash-info', '--no-minimize-whitespace'],
+        stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
   assert len(output) > 0
   assert len(error) == 0
 
@@ -154,6 +154,8 @@ def write_equivalent_fn_hash_to_file(f, json_files, passed_in_filename):
 # the global set of function implementation hashes. If set to
 # False, we assume that we have to use the global hash info to
 # reduce the set of duplicate functions
+# Returns the filename of the processed JS file, which is expected to be
+# deleted by the caller once done.
 def run_on_js(filename, gen_hash_info=False):
   js_engine=shared.NODE_JS
 
@@ -247,8 +249,14 @@ def write_chunk(chunk, i):
       if DEBUG: print >> sys.stderr, 'splitting up js optimization into %d chunks, using %d cores  (total: %.2f MB)' % (len(chunks), cores, total_size/(1024*1024.))
       pool = multiprocessing.Pool(processes=cores)
       filenames = pool.map(run_on_chunk, commands, chunksize=1)
-      pool.terminate()
-      pool.join()
+      try:
+        # Shut down the pool, since otherwise processes are left alive and would only be lazily terminated,
+        # and in other parts of the toolchain we also build up multiprocessing pools.
+        pool.terminate()
+        pool.join()
+      except Exception, e:
+        # On Windows we get occassional "Access is denied" errors when attempting to tear down the pool, ignore these.
+        logging.debug('Attempting to tear down multiprocessing pool failed with an exception: ' + str(e))
     else:
       # We can't parallize, but still break into chunks to avoid uglify/node memory issues
       if len(chunks) > 1 and DEBUG: print >> sys.stderr, 'splitting up js optimization into %d chunks' % (len(chunks))
@@ -348,11 +356,12 @@ def eliminate_duplicate_funcs(file_name):
 
     # Generate the JSON for the equivalent hash first
     processed_file = run_on_js(filename=file_name, gen_hash_info=True)
-
-    save_temp_file(processed_file)
-
-    # Use the hash to reduce the JS file
-    final_file = run_on_js(filename=processed_file, gen_hash_info=False)
+    try:
+      save_temp_file(processed_file)
+      # Use the hash to reduce the JS file
+      final_file = run_on_js(filename=processed_file, gen_hash_info=False)
+    finally:
+      os.remove(processed_file)
 
     save_temp_file(final_file)
 
diff --git a/tools/emterpretify.py b/tools/emterpretify.py
index 86a29f853cd08..10990274c772a 100755
--- a/tools/emterpretify.py
+++ b/tools/emterpretify.py
@@ -764,12 +764,12 @@ def process(code):
   tabled_funcs = asm.get_table_funcs()
   exported_funcs = [func.split(':')[0] for func in asm.exports]
 
-  temp = temp_files.get('.js').name # infile + '.tmp.js'
 
   # find emterpreted functions reachable by non-emterpreted ones, we will force a trampoline for them later
 
-  shared.Building.js_optimizer(infile, ['findReachable'], extra_info={ 'blacklist': list(emterpreted_funcs) }, output_filename=temp, just_concat=True)
-  asm = asm_module.AsmModule(temp)
+  with temp_files.get_file('.js') as temp: # infile + '.tmp.js'
+    shared.Building.js_optimizer(infile, ['findReachable'], extra_info={ 'blacklist': list(emterpreted_funcs) }, output_filename=temp, just_concat=True)
+    asm = asm_module.AsmModule(temp)
   lines = asm.funcs_js.split('\n')
 
   reachable_funcs = set([])
@@ -782,10 +782,10 @@ def process(code):
   external_emterpreted_funcs = filter(lambda func: func in tabled_funcs or func in exported_funcs or func in reachable_funcs, emterpreted_funcs)
 
   # process functions, generating bytecode
-  shared.Building.js_optimizer(infile, ['emterpretify'], extra_info={ 'emterpretedFuncs': list(emterpreted_funcs), 'externalEmterpretedFuncs': list(external_emterpreted_funcs), 'opcodes': OPCODES, 'ropcodes': ROPCODES, 'ASYNC': ASYNC, 'PROFILING': PROFILING, 'ASSERTIONS': ASSERTIONS }, output_filename=temp, just_concat=True)
-
-  # load the module and modify it
-  asm = asm_module.AsmModule(temp)
+  with temp_files.get_file('.js') as temp:
+    shared.Building.js_optimizer(infile, ['emterpretify'], extra_info={ 'emterpretedFuncs': list(emterpreted_funcs), 'externalEmterpretedFuncs': list(external_emterpreted_funcs), 'opcodes': OPCODES, 'ropcodes': ROPCODES, 'ASYNC': ASYNC, 'PROFILING': PROFILING, 'ASSERTIONS': ASSERTIONS }, output_filename=temp, just_concat=True)
+    # load the module and modify it
+    asm = asm_module.AsmModule(temp)
 
   relocations = [] # list of places that need to contain absolute offsets, we will add eb to them at runtime to relocate them
 
diff --git a/tools/file_packager.py b/tools/file_packager.py
index 4c5a7501df23e..42ea9aef5e73c 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -16,6 +16,9 @@
   --preload  ,
   --embed    See emcc --help for more details on those options.
 
+  --exclude E [F..] Specifies filename pattern matches to use for excluding given files from being added to the package.
+                    See https://docs.python.org/2/library/fnmatch.html for syntax.
+
   --no-closure In general, the file packager emits closure compiler-compatible code, which requires an eval().
                With this flag passed, we avoid emitting the eval. emcc passes this flag by default whenever
                it knows that closure is not run.
diff --git a/tools/filelock.py b/tools/filelock.py
new file mode 100644
index 0000000000000..069d3d3feef7a
--- /dev/null
+++ b/tools/filelock.py
@@ -0,0 +1,425 @@
+#!/usr/bin/python2
+
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to <http://unlicense.org>
+
+# This software package was obtained from
+# https://github.com/benediktschmitt/py-filelock
+
+"""
+A platform independent file lock that supports the with-statement.
+"""
+
+
+# Modules
+# ------------------------------------------------
+import os
+import threading
+import time
+try:
+    import warnings
+except ImportError:
+    warnings = None
+
+try:
+    import msvcrt
+except ImportError:
+    msvcrt = None
+
+try:
+    import fcntl
+except ImportError:
+    fcntl = None
+
+import logging
+
+# Backward compatibility
+# ------------------------------------------------
+try:
+    TimeoutError
+except NameError:
+    TimeoutError = OSError
+
+
+# Data
+# ------------------------------------------------
+__all__ = [
+    "Timeout",
+    "BaseFileLock",
+    "WindowsFileLock",
+    "UnixFileLock",
+    "SoftFileLock",
+    "FileLock"
+]
+
+__version__ = "2.0.6"
+
+
+# Exceptions
+# ------------------------------------------------
+class Timeout(TimeoutError):
+    """
+    Raised when the lock could not be acquired in *timeout*
+    seconds.
+    """
+
+    def __init__(self, lock_file):
+        """
+        """
+        #: The path of the file lock.
+        self.lock_file = lock_file
+        return None
+
+    def __str__(self):
+        temp = "The file lock '{}' could not be acquired."\
+               .format(self.lock_file)
+        return temp
+
+
+# Classes
+# ------------------------------------------------
+class BaseFileLock(object):
+    """
+    Implements the base class of a file lock.
+    """
+
+    def __init__(self, lock_file, timeout = -1):
+        """
+        """
+        # The path to the lock file.
+        self._lock_file = lock_file
+
+        # The file descriptor for the *_lock_file* as it is returned by the
+        # os.open() function.
+        # This file lock is only NOT None, if the object currently holds the
+        # lock.
+        self._lock_file_fd = None
+
+        # The default timeout value.
+        self.timeout = timeout
+
+        # We use this lock primarily for the lock counter.
+        self._thread_lock = threading.Lock()
+
+        # The lock counter is used for implementing the nested locking
+        # mechanism. Whenever the lock is acquired, the counter is increased and
+        # the lock is only released, when this value is 0 again.
+        self._lock_counter = 0
+        return None
+
+    @property
+    def lock_file(self):
+        """
+        The path to the lock file.
+        """
+        return self._lock_file
+
+    @property
+    def timeout(self):
+        """
+        You can set a default timeout for the filelock. It will be used as
+        fallback value in the acquire method, if no timeout value (*None*) is
+        given.
+
+        If you want to disable the timeout, set it to a negative value.
+
+        A timeout of 0 means, that there is exactly one attempt to acquire the
+        file lock.
+
+        .. versionadded:: 2.0.0
+        """
+        return self._timeout
+
+    @timeout.setter
+    def timeout(self, value):
+        """
+        """
+        self._timeout = float(value)
+        return None
+
+    # Platform dependent locking
+    # --------------------------------------------
+
+    def _acquire(self):
+        """
+        Platform dependent. If the file lock could be
+        acquired, self._lock_file_fd holds the file descriptor
+        of the lock file.
+        """
+        raise NotImplementedError()
+
+    def _release(self):
+        """
+        Releases the lock and sets self._lock_file_fd to None.
+        """
+        raise NotImplementedError()
+
+    # Platform independent methods
+    # --------------------------------------------
+
+    @property
+    def is_locked(self):
+        """
+        True, if the object holds the file lock.
+
+        .. versionchanged:: 2.0.0
+
+            This was previously a method and is now a property.
+        """
+        return self._lock_file_fd is not None
+
+    def acquire(self, timeout=None, poll_intervall=0.05):
+        """
+        Acquires the file lock or fails with a :exc:`Timeout` error.
+
+        .. code-block:: python
+
+            # You can use this method in the context manager (recommended)
+            with lock.acquire():
+                pass
+
+            # Or you use an equal try-finally construct:
+            lock.acquire()
+            try:
+                pass
+            finally:
+                lock.release()
+
+        :arg float timeout:
+            The maximum time waited for the file lock.
+            If ``timeout <= 0``, there is no timeout and this method will
+            block until the lock could be acquired.
+            If ``timeout`` is None, the default :attr:`~timeout` is used.
+
+        :arg float poll_intervall:
+            We check once in *poll_intervall* seconds if we can acquire the
+            file lock.
+
+        :raises Timeout:
+            if the lock could not be acquired in *timeout* seconds.
+
+        .. versionchanged:: 2.0.0
+
+            This method returns now a *proxy* object instead of *self*,
+            so that it can be used in a with statement without side effects.
+        """
+        # Use the default timeout, if no timeout is provided.
+        if timeout is None:
+            timeout = self.timeout
+
+        # Increment the number right at the beginning.
+        # We can still undo it, if something fails.
+        with self._thread_lock:
+            self._lock_counter += 1
+
+        try:
+            start_time = time.time()
+            while True:
+                with self._thread_lock:
+                    if not self.is_locked:
+                        self._acquire()
+
+                if self.is_locked:
+                    break
+                elif timeout >= 0 and time.time() - start_time > timeout:
+                    raise Timeout(self._lock_file)
+                else:
+                    time.sleep(poll_intervall)
+        except:
+            # Something did go wrong, so decrement the counter.
+            with self._thread_lock:
+                self._lock_counter = max(0, self._lock_counter - 1)
+
+            raise
+
+        # This class wraps the lock to make sure __enter__ is not called
+        # twiced when entering the with statement.
+        # If we would simply return *self*, the lock would be acquired again
+        # in the *__enter__* method of the BaseFileLock, but not released again
+        # automatically.
+        class ReturnProxy(object):
+
+            def __init__(self, lock):
+                self.lock = lock
+                return None
+
+            def __enter__(self):
+                return self.lock
+
+            def __exit__(self, exc_type, exc_value, traceback):
+                self.lock.release()
+                return None
+
+        return ReturnProxy(lock = self)
+
+    def release(self, force = False):
+        """
+        Releases the file lock.
+
+        Please note, that the lock is only completly released, if the lock
+        counter is 0.
+
+        Also note, that the lock file itself is not automatically deleted.
+
+        :arg bool force:
+            If true, the lock counter is ignored and the lock is released in
+            every case.
+        """
+        with self._thread_lock:
+
+            if self.is_locked:
+                self._lock_counter -= 1
+
+                if self._lock_counter == 0 or force:
+                    self._release()
+                    self._lock_counter = 0
+        return None
+
+    def __enter__(self):
+        self.acquire()
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.release()
+        return None
+
+    def __del__(self):
+        self.release(force = True)
+        return None
+
+
+# Windows locking mechanism
+# ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class WindowsFileLock(BaseFileLock):
+    """
+    Uses the :func:`msvcrt.locking` function to hard lock the lock file on
+    windows systems.
+    """
+
+    def _acquire(self):
+        open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
+
+        try:
+            fd = os.open(self._lock_file, open_mode)
+        except OSError:
+            pass
+        else:
+            try:
+                msvcrt.locking(fd, msvcrt.LK_NBLCK, 1)
+            except (IOError, OSError):
+                os.close(fd)
+            else:
+                self._lock_file_fd = fd
+        return None
+
+    def _release(self):
+        fd = self._lock_file_fd
+        self._lock_file_fd = None
+        msvcrt.locking(fd, msvcrt.LK_UNLCK, 1)
+        os.close(fd)
+
+        try:
+            os.remove(self._lock_file)
+        # Probably another instance of the application
+        # that acquired the file lock.
+        except OSError:
+            pass
+        return None
+
+# Unix locking mechanism
+# ~~~~~~~~~~~~~~~~~~~~~~
+
+class UnixFileLock(BaseFileLock):
+    """
+    Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems.
+    """
+
+    def _acquire(self):
+        open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
+        fd = os.open(self._lock_file, open_mode)
+
+        try:
+            fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+        except (IOError, OSError):
+            os.close(fd)
+        else:
+            self._lock_file_fd = fd
+        return None
+
+    def _release(self):
+        fd = self._lock_file_fd
+        self._lock_file_fd = None
+        fcntl.flock(fd, fcntl.LOCK_UN)
+        os.close(fd)
+        return None
+
+# Soft lock
+# ~~~~~~~~~
+
+class SoftFileLock(BaseFileLock):
+    """
+    Simply watches the existence of the lock file.
+    """
+
+    def _acquire(self):
+        open_mode = os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_TRUNC
+        try:
+            fd = os.open(self._lock_file, open_mode)
+        except (IOError, OSError):
+            pass
+        else:
+            self._lock_file_fd = fd
+        return None
+
+    def _release(self):
+        os.close(self._lock_file_fd)
+        self._lock_file_fd = None
+
+        try:
+            os.remove(self._lock_file)
+        # The file is already deleted and that's what we want.
+        except OSError:
+            pass
+        return None
+
+
+# Platform filelock
+# ~~~~~~~~~~~~~~~~~
+
+#: Alias for the lock, which should be used for the current platform. On
+#: Windows, this is an alias for :class:`WindowsFileLock`, on Unix for
+#: :class:`UnixFileLock` and otherwise for :class:`SoftFileLock`.
+FileLock = None
+
+if msvcrt:
+    FileLock = WindowsFileLock
+elif fcntl:
+    FileLock = UnixFileLock
+else:
+    FileLock = SoftFileLock
+
+    if warnings is not None:
+        warnings.warn("only soft file lock is available")
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index 1fefa81164b49..f6f5c8073a5a7 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -227,18 +227,18 @@ def minify_shell(self, shell, minify_whitespace, source_map=False):
     else:
       self.globs = []
 
-    temp_file = temp_files.get('.minifyglobals.js').name
-    f = open(temp_file, 'w')
-    f.write(shell)
-    f.write('\n')
-    f.write('// EXTRA_INFO:' + json.dumps(self.serialize()))
-    f.close()
+    with temp_files.get_file('.minifyglobals.js') as temp_file:
+      f = open(temp_file, 'w')
+      f.write(shell)
+      f.write('\n')
+      f.write('// EXTRA_INFO:' + json.dumps(self.serialize()))
+      f.close()
 
-    output = subprocess.Popen(self.js_engine +
-        [JS_OPTIMIZER, temp_file, 'minifyGlobals', 'noPrintMetadata'] +
-        (['minifyWhitespace'] if minify_whitespace else []) +
-        (['--debug'] if source_map else []),
-        stdout=subprocess.PIPE).communicate()[0]
+      output = subprocess.Popen(self.js_engine +
+          [JS_OPTIMIZER, temp_file, 'minifyGlobals', 'noPrintMetadata'] +
+          (['minifyWhitespace'] if minify_whitespace else []) +
+          (['--debug'] if source_map else []),
+          stdout=subprocess.PIPE).communicate()[0]
 
     assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output
     #print >> sys.stderr, "minified SHELL 3333333333333333", output, "\n44444444444444444444"
@@ -444,8 +444,14 @@ def write_chunk(chunk, i):
       if DEBUG: print >> sys.stderr, 'splitting up js optimization into %d chunks, using %d cores  (total: %.2f MB)' % (len(chunks), cores, total_size/(1024*1024.))
       pool = multiprocessing.Pool(processes=cores)
       filenames = pool.map(run_on_chunk, commands, chunksize=1)
-      pool.terminate()
-      pool.join()
+      try:
+        # Shut down the pool, since otherwise processes are left alive and would only be lazily terminated,
+        # and in other parts of the toolchain we also build up multiprocessing pools.
+        pool.terminate()
+        pool.join()
+      except Exception, e:
+        # On Windows we get occassional "Access is denied" errors when attempting to tear down the pool, ignore these.
+        logging.debug('Attempting to tear down multiprocessing pool failed with an exception: ' + str(e))
     else:
       # We can't parallize, but still break into chunks to avoid uglify/node memory issues
       if len(chunks) > 1 and DEBUG: print >> sys.stderr, 'splitting up js optimization into %d chunks' % (len(chunks))
@@ -461,34 +467,35 @@ def write_chunk(chunk, i):
     end_asm = '// EMSCRIPTEN_END_ASM\n'
     cl_sep = 'wakaUnknownBefore(); var asm=wakaUnknownAfter(global,env,buffer)\n'
 
-    cle = temp_files.get('.cl.js').name
-    c = open(cle, 'w')
-    pre_1, pre_2 = pre.split(start_asm)
-    post_1, post_2 = post.split(end_asm)
-    c.write(pre_1)
-    c.write(cl_sep)
-    c.write(post_2)
-    c.close()
-    cld = cle
-    if split_memory:
-      if DEBUG: print >> sys.stderr, 'running splitMemory on shell code'
-      cld = run_on_chunk(js_engine + [JS_OPTIMIZER, cld, 'splitMemoryShell'])
-      f = open(cld, 'a')
-      f.write(suffix_marker)
-      f.close()
-    if closure:
-      if DEBUG: print >> sys.stderr, 'running closure on shell code'
-      cld = shared.Building.closure_compiler(cld, pretty='minifyWhitespace' not in passes)
-      temp_files.note(cld)
-    elif cleanup:
-      if DEBUG: print >> sys.stderr, 'running cleanup on shell code'
-      next = cld + '.cl.js'
-      temp_files.note(next)
-      proc = subprocess.Popen(js_engine + [JS_OPTIMIZER, cld, 'noPrintMetadata', 'JSDCE'] + (['minifyWhitespace'] if 'minifyWhitespace' in passes else []), stdout=open(next, 'w'))
-      proc.communicate()
-      assert proc.returncode == 0
-      cld = next
-    coutput = open(cld).read()
+    with temp_files.get_file('.cl.js') as cle:
+      c = open(cle, 'w')
+      pre_1, pre_2 = pre.split(start_asm)
+      post_1, post_2 = post.split(end_asm)
+      c.write(pre_1)
+      c.write(cl_sep)
+      c.write(post_2)
+      c.close()
+      cld = cle
+      if split_memory:
+        if DEBUG: print >> sys.stderr, 'running splitMemory on shell code'
+        cld = run_on_chunk(js_engine + [JS_OPTIMIZER, cld, 'splitMemoryShell'])
+        f = open(cld, 'a')
+        f.write(suffix_marker)
+        f.close()
+      if closure:
+        if DEBUG: print >> sys.stderr, 'running closure on shell code'
+        cld = shared.Building.closure_compiler(cld, pretty='minifyWhitespace' not in passes)
+        temp_files.note(cld)
+      elif cleanup:
+        if DEBUG: print >> sys.stderr, 'running cleanup on shell code'
+        next = cld + '.cl.js'
+        temp_files.note(next)
+        proc = subprocess.Popen(js_engine + [JS_OPTIMIZER, cld, 'noPrintMetadata', 'JSDCE'] + (['minifyWhitespace'] if 'minifyWhitespace' in passes else []), stdout=open(next, 'w'))
+        proc.communicate()
+        assert proc.returncode == 0
+        cld = next
+      coutput = open(cld).read()
+
     coutput = coutput.replace('wakaUnknownBefore();', start_asm)
     after = 'wakaUnknownAfter'
     start = coutput.find(after)
diff --git a/tools/jsrun.py b/tools/jsrun.py
index 57ff97c6cf52f..0f315e6d288d0 100644
--- a/tools/jsrun.py
+++ b/tools/jsrun.py
@@ -30,7 +30,7 @@ def make_command(filename, engine=None, args=[]):
   # label a path to nodejs containing a 'd8' as spidermonkey instead.
   jsengine = os.path.split(engine[0])[-1]
   # Use "'d8' in" because the name can vary, e.g. d8_g, d8, etc.
-  return engine + [filename] + (['--'] if 'd8' in jsengine or 'jsc' in jsengine else []) + args
+  return engine + [filename] + (['--expose-wasm', '--'] if 'd8' in jsengine or 'jsc' in jsengine else []) + args
 
 def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False, assert_returncode=0, error_limit=-1):
   #  # code to serialize out the test suite files
@@ -74,4 +74,3 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo
   if assert_returncode is not None and proc.returncode is not assert_returncode:
     raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)[:error_limit])
   return ret
-
diff --git a/tools/ports/binaryen.py b/tools/ports/binaryen.py
index 1b0b8b901ae15..5b2d5f80a5361 100644
--- a/tools/ports/binaryen.py
+++ b/tools/ports/binaryen.py
@@ -1,6 +1,6 @@
 import os, shutil, logging
 
-TAG = 'version_9'
+TAG = 'version_11'
 
 def needed(settings, shared, ports):
   if not settings.BINARYEN: return False
diff --git a/tools/shared.py b/tools/shared.py
index 070e61663fe0a..4f99ce07aed68 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -676,6 +676,7 @@ def get_clang_native_env():
 
     env['INCLUDE'] = os.path.join(visual_studio_2013_path, 'VC\\INCLUDE')
     env['LIB'] = os.path.join(visual_studio_2013_path, 'VC\\LIB\\amd64') + ';' + os.path.join(windows_sdk_dir, 'lib\\winv6.3\\um\\x64')
+    env['PATH'] = env['PATH'] + ';' + os.path.join(visual_studio_2013_path, 'VC\\BIN')
 
   # Current configuration above is all Visual Studio -specific, so on non-Windowses, no action needed.
 
@@ -1535,6 +1536,12 @@ def consider_archive(f):
 
       response_fh = open(response_file, 'w')
       for arg in actual_files:
+        # Starting from LLVM 3.9.0 trunk around July 2016, LLVM escapes backslashes in response files, so Windows paths
+        # "c:\path\to\file.txt" with single slashes no longer work. LLVM upstream dev 3.9.0 from January 2016 still treated
+        # backslashes without escaping. To preserve compatibility with both versions of llvm-link, don't pass backslash
+        # path delimiters at all to response files, but always use forward slashes.
+        if WINDOWS: arg = arg.replace('\\', '/')
+
         # escaped double quotes allows 'space' characters in pathname the response file can use
         response_fh.write("\"" + arg + "\"\n")
       response_fh.close()
diff --git a/tools/system_libs.py b/tools/system_libs.py
index a994a474eab16..2c86ab6598a5f 100644
--- a/tools/system_libs.py
+++ b/tools/system_libs.py
@@ -238,7 +238,7 @@ def create_dlmalloc_split(libname):
 
   def create_wasm_compiler_rt(libname):
     srcdir = shared.path_from_root('system', 'lib', 'compiler-rt', 'lib', 'builtins')
-    filenames = ['addtf3.c', 'ashlti3.c', 'ashrti3.c', 'comparetf2.c', 'divtf3.c', 'divti3.c',
+    filenames = ['addtf3.c', 'ashlti3.c', 'ashrti3.c', 'comparetf2.c', 'divtf3.c', 'divti3.c', 'udivmodti4.c',
                  'extenddftf2.c', 'extendsftf2.c',
                  'fixdfti.c', 'fixsfti.c', 'fixtfdi.c', 'fixtfsi.c', 'fixtfti.c',
                  'fixunsdfti.c', 'fixunssfti.c', 'fixunstfdi.c', 'fixunstfsi.c', 'fixunstfti.c',
@@ -255,7 +255,7 @@ def create_wasm_compiler_rt(libname):
       o = in_temp(os.path.basename(src) + '.o')
       # Use clang directly instead of emcc. Since emcc's intermediate format (produced by -S) is LLVM IR, there's no way to
       # get emcc to output wasm .s files, which is what we archive in compiler_rt.
-      commands.append([shared.CLANG_CC, '--target=wasm32', '-S', shared.path_from_root('system', 'lib', src), '-O2', '-o', o])
+      commands.append([shared.CLANG_CC, '--target=wasm32', '-S', shared.path_from_root('system', 'lib', src), '-O2', '-o', o] + shared.EMSDK_OPTS)
       o_s.append(o)
     run_commands(commands)
     lib = in_temp(libname)
diff --git a/tools/tempfiles.py b/tools/tempfiles.py
index 370751ea94ad0..3e1b25a22d895 100644
--- a/tools/tempfiles.py
+++ b/tools/tempfiles.py
@@ -39,13 +39,27 @@ def note(self, filename):
     self.to_clean.append(filename)
 
   def get(self, suffix):
-    """Returns a named temp file  with the given prefix."""
+    """Returns a named temp file with the given prefix."""
     named_file = tempfile.NamedTemporaryFile(dir=self.tmp, suffix=suffix, delete=False)
     self.note(named_file.name)
     return named_file
 
+  def get_file(self, suffix):
+    """Returns an object representing a RAII-like access to a temp file, that has convenient pythonesque
+    semantics for being used via a construct 'with TempFiles.get_file(..) as filename:'. The file will be
+    deleted immediately once the 'with' block is exited."""
+    class TempFileObject:
+      def __enter__(self_):
+        self_.file = tempfile.NamedTemporaryFile(dir=self.tmp, suffix=suffix, delete=False)
+        self_.file.close() # NamedTemporaryFile passes out open file handles, but callers prefer filenames (and open their own handles manually if needed)
+        return self_.file.name
+
+      def __exit__(self_, type, value, traceback):
+        try_delete(self_.file.name)
+    return TempFileObject()
+
   def get_dir(self):
-    """Returns a named temp file  with the given prefix."""
+    """Returns a named temp directory with the given prefix."""
     directory = tempfile.mkdtemp(dir=self.tmp)
     self.note(directory)
     return directory