[pypy-commit] benchmarks default: Add ICBD as a benchmark. This comes from Kevin Modzelewski on pypy-dev.

arigo noreply at buildbot.pypy.org
Wed Dec 10 10:26:58 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r292:67706c915134
Date: 2014-12-10 09:15 +0000
http://bitbucket.org/pypy/benchmarks/changeset/67706c915134/

Log:	Add ICBD as a benchmark. This comes from Kevin Modzelewski on pypy-
	dev.

diff too long, truncating to 2000 out of 90238 lines

diff --git a/benchmarks.py b/benchmarks.py
--- a/benchmarks.py
+++ b/benchmarks.py
@@ -82,7 +82,8 @@
              'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast',
              'raytrace-simple', 'crypto_pyaes', 'bm_mako', 'bm_chameleon',
              'json_bench', 'pidigits', 'hexiom2', 'eparse', 'deltablue',
-             'bm_dulwich_log', 'bm_krakatau', 'bm_mdp', 'pypy_interp']:
+             'bm_dulwich_log', 'bm_krakatau', 'bm_mdp', 'pypy_interp',
+             'bm_icbd']:
     _register_new_bm(name, name, globals(), **opts.get(name, {}))
 
 for name in ['names', 'iteration', 'tcp', 'pb', ]:#'web']:#, 'accepts']:
diff --git a/own/bm_icbd.py b/own/bm_icbd.py
new file mode 100644
--- /dev/null
+++ b/own/bm_icbd.py
@@ -0,0 +1,35 @@
+import sys, os, subprocess, time
+this_dir = os.path.abspath(os.path.dirname(__file__))
+
+def main(n):
+    # HAAAAAACK with subprocess because I can't get the thing
+    # to run in-process :-(  As a result, it doesn't make
+    # sense to run it more than once.
+
+    d = os.environ.copy()
+    d['PYTHONPATH'] = 'icbd'
+    t0 = time.time()
+    popen = subprocess.Popen(
+                     [sys.executable,
+                      '-m', 'icbd.type_analyzer.analyze_all',
+                      '-I', 'stdlib/python2.5_tiny',
+                      '-I', '.',
+                      '-E', 'icbd/type_analyzer/tests',
+                      '-E', 'icbd/compiler/benchmarks',
+                      '-E', 'icbd/compiler/tests',
+                      '-I', 'stdlib/type_mocks',
+                      '-n',
+                      'icbd'], cwd=this_dir, env=d, stdout=subprocess.PIPE)
+    popen.communicate()
+    time_elapsed = time.time() - t0
+    return [time_elapsed] * n
+
+if __name__ == "__main__":
+    import util, optparse
+    parser = optparse.OptionParser(
+        usage="%prog [options]",
+        description="Test the performance of the ICBD benchmark")
+    util.add_standard_options_to(parser)
+    options, args = parser.parse_args()
+
+    util.run_benchmark(options, options.num_runs, main)
diff --git a/own/icbd/.gitignore b/own/icbd/.gitignore
new file mode 100644
--- /dev/null
+++ b/own/icbd/.gitignore
@@ -0,0 +1,24 @@
+*.pyc
+*.d
+*.sw?
+*.out
+*.out[0-9]
+*.o
+*.s
+*.s[0-9]
+*.gen.bc
+*.gen.c
+*.comb.ll
+*.gen.ll
+*opt.ll
+*.so
+icbd/compiler/tests/[0-9]
+icbd/compiler/tests/[0-9][0-9]
+icbd/compiler/tests/*.hpp
+icbd/compiler/tests/*[0-9].cpp
+icbd/compiler/tests/Makefile
+*.shed
+*.ppm
+icbd/compiler/dist
+*.pyicbd
+*.pyd
diff --git a/own/icbd/LICENSE b/own/icbd/LICENSE
new file mode 100644
--- /dev/null
+++ b/own/icbd/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014, Kevin Modzelewski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS 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.
diff --git a/own/icbd/README.md b/own/icbd/README.md
new file mode 100644
--- /dev/null
+++ b/own/icbd/README.md
@@ -0,0 +1,109 @@
+# icbd
+
+> ICBD is a defunct project, but I'm releasing the source code in case any one is interested.
+
+ICBD is a static type analyzer and static compiler for Python.  It originated
+from the desire at Dropbox to have additional type information for our growing
+codebases, without requiring programmers to add type annotations.  There are
+other static type analyzers for Python out there; the goal of ICBD was to
+produce one that would work well on the Dropbox codebase, which meant
+concretely:
+
+- Handling untypable code as gracefully as possible
+- "Acceptable" running times for multi-100k LOC codebases
+- A plugin system for handling code that is inherently not statically analyzable
+
+These goals were somewhat met, perhaps to the limits of using whole-program type
+inference; the running time for the Dropbox codebase was about 15 minutes, which
+I believe is better than alternatives but is not good enough for easy use.
+
+The plugin system was able to get anecdotally get ICBD to successfully analyze a
+sufficient fraction of the Dropbox codebase, though when typing failed, it was
+difficult to tell why.
+
+### Testing it out
+
+You need to install pygments and simplejson to run ICBD; once you do, run
+
+```
+bash icbd/type_analyzer/run.sh icbd
+```
+
+to have ICBD analyze its own codebase (it doesn't do particularly well since
+there are no plugins for its getattr usage).  You can see the output at
+file:///tmp/icbd_icbd/icbd/type_analyzer/type_checker.html
+
+### Technical approach
+
+ICBD treats every Python expression as a constraint on the allowable types of
+the program: `a = o.x` encodes the constraint that "a will have the type of o's
+x attribute", `f(x)` encodes the constaint that "f accepts a type argument of
+type type(x)", etc.  At a high level, ICBD then does a graph fixed-point
+analysis to determine a set of types that satisfy the constraints, and emits
+errors when types could not be found (ex: `a, b, c = 1, 2`).
+
+The guessed types start at the BOTTOM type, and ICBD iteratively finds
+unsatisfied constraints and raises the involved types to attempt to satisfy the
+constraints.  In theory, if ICBD always raises types monotonically and to the
+minimum satisfying type, this process will converge on a deterministic set of
+lowest (or in some sense, most descriptive) types.
+
+In practice, this is somewhat harder because the type constraints are dependent
+on other types -- for example, attribute lookup dependencies can change based on
+learning that an attribute may actually be a instance attribute.  This doesn't
+seem to be that big a deal, though.
+
+### Comparison to Python type analyzers
+
+ICBD only analyzes a single version of each function, and assumes that any
+combination of seen argument types could occur together.  For example, in this
+snippet:
+
+```python
+def add_int_or_str(a, b):
+    return a + b
+
+add_int_or_str(1, 2)
+add_int_or_str("hello ", "world")
+```
+
+ICBD will report an error, saying that an int cannot be added to a string.
+Other analyzers will notice that add_int_or_str does not actually receive an
+(int, str) combination of arguments and handle this correctly, but at an
+exponentially-large cost.
+
+This means that ICBD does not handle polymorphic functions very gracefully,
+but in practice this seems to net be a common thing for applications code, and
+the plugin system makes it possible to handle on a one-off basis.
+
+#### Quick note about HM
+
+People often ask "why don't you just apply HM (Hindley-Milner) which computes
+the types ideally".  Yes, it's true that HM has some nice ideality properties,
+but it only applies to a fairly-restrictive type system.  I'm not a type
+theorist, but my understanding is that to properly represent the Python type
+system you need
+
+- Dependent types to represent attributes, and
+- Rank-n polymorphism to represent global variables
+
+both of which I believe make the inference problem undecidable.  (Is there
+really any Haskell program that uses 0 type annotations?)
+
+Of course in theory it's possible to translate Python code into, for example,
+Haskell, but I don't see any reason to believe this can be done in an automated
+way such that the generated Haskell has any meaningful relation to the original
+Python.  For example, one could build an X86 emulator in Haskell, and use that
+to run the Python interpreter, but the types on the Haskell program have no
+usefulness to the original Python programmer.
+
+# Compiler
+
+ICBD also includes a static compiler, in icbd/compiler.  Assuming that the type
+analyzer can come up with a complete set of types for your program (a big
+assumption), in theory it should be possible to compile the Python as if it were
+a more traditionally-typed static language.
+
+In practice I doubt that real code can really be 100% typed; the ICBD compiler
+served as the starting point for the [Pyston](https://github.com/dropbox/pyston)
+project, which replaces it.
diff --git a/own/icbd/demos/demo.py b/own/icbd/demos/demo.py
new file mode 100644
--- /dev/null
+++ b/own/icbd/demos/demo.py
@@ -0,0 +1,291 @@
+if 0:
+                                                        ""
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Basic type analysis:
+                                                        a = 2
+                                                        b = '3'
+                                                        d = {a:b}
+                                                        ch = ord(b[2].lower()[0])
+                                                        print ch
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Name errors:
+                                                        ch *= e
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Nested-type manipulation:
+                                                        d = {1:[1], 3:[4]}
+                                                        d[1].append(2)
+                                                        
+                                                        l = [range(i) for i in xrange(5)]
+                                                        l.append([-1])
+                                                        l2 = [k[0] for k in l]
+                                                        l2.append(1)
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Function type inference:
+                                                        def func(x, y):
+                                                            return b * (x + y)
+                                                        r = func(3, 4)
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Higher-level types:
+                                                        def f(x):
+                                                            def g():
+                                                                return x
+                                                            return g
+                                                        
+                                                        inner = f(2)
+                                                        print f(1)() + inner()
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        # Control-flow analysis:
+                                                        if inner():
+                                                            x = 3
+                                                        else:
+                                                            x = [0]
+                                                        print l2[x]
+                                                        
+                                                        def fib(x):
+                                                            if x <= 1:
+                                                                return x
+                                                            return fib(x-1) + fib(x-2)
+                                                        fib(2)
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        def foo():
+                                                            return foo()
+                                                        if 0:
+                                                            x = 0
+                                                        else:
+                                                            x = foo()
+                                                        print x
+                                                        
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Classes:
+                                                        class C(object):
+                                                            def __init__(self, x):
+                                                                self.x = x
+                                                            def bar(self, z):
+                                                                return self.x * z
+                                                            def baz(self, k):
+                                                                return k**2
+                                                        
+                                                        c = C(2)
+                                                        c.baz(3)
+                                                        
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        # attributes
+                                                        print c.x
+                                                        z = c.bar(3)
+                                                        c.y = 3
+                                                        z = c.x * c.y
+                                                        z *= c.z
+                                                        
+                                                        
+                                                        
+
+
+
+
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        
+                                                        # Complex type analysis:
+                                                        def f1(x):
+                                                            def g(y):
+                                                                return x * y
+                                                            return g
+                                                        
+                                                        a = f1('')
+                                                        b = a(2)
+                                                        
+                                                        def f2(x):
+                                                            def g(y):
+                                                                return x * y
+                                                            return g
+                                                        
+                                                        a = f2(1)
+                                                        b = a(2)
+
+
+
+
+
+
+                                                        ""
diff --git a/own/icbd/demos/demo_compact.py b/own/icbd/demos/demo_compact.py
new file mode 100644
--- /dev/null
+++ b/own/icbd/demos/demo_compact.py
@@ -0,0 +1,105 @@
+# Basic type analysis:
+a = 2
+b = '3'
+d = {a:b}
+c = ord(b[2].lower()[0])
+print c
+
+
+# Name errors:
+c *= e
+
+# Nested-type manipulation:
+d = {1:[1], 3:[4]}
+d[1].append(2)
+
+l = [range(i) for i in xrange(5)]
+l.append([-1])
+l2 = [k[0] for k in l]
+l2.append(1)
+
+
+# Argument-type checking, based on inferred types
+l2.append('')
+
+
+
+# Function type inference:
+def f(x, y):
+    return b * (x + y)
+r = f(3, 4)
+
+
+
+# Higher-level types:
+def f(x):
+    def g():
+        return x
+    return g
+
+f1 = f(2)
+print f(1)() + f1()
+
+
+
+
+# Control-flow analysis:
+if f1():
+    x = 3
+else:
+    x = [0]
+print l2[x]
+
+def fib(x):
+    if x <= 1:
+        return x
+    return fib(x-1) + fib(x-2)
+fib(2)
+
+
+def foo():
+    return foo()
+if 0:
+    x = 0
+else:
+    x = foo()
+print x
+
+
+# Classes:
+class Foo(object):
+    def __init__(self, x):
+        self.x = x
+    def bar(self, z):
+        return self.x * z
+    def baz(self, k):
+        return k**2
+
+f = Foo(2)
+f.baz(3)
+
+# attributes
+print f.x
+z = f.bar(3)
+f.y = 3
+z = f.x * f.y
+z *= f.z
+
+
+# Complex type analysis:
+def f1(x):
+    def g(y):
+        return x * y
+    return g
+
+a = f1('')
+b = a(2)
+
+def f2(x):
+    def g(y):
+        return x * y
+    return g
+
+a = f2(1)
+b = a(2)
+
diff --git a/own/icbd/demos/ray.html b/own/icbd/demos/ray.html
new file mode 100644
--- /dev/null
+++ b/own/icbd/demos/ray.html
@@ -0,0 +1,15385 @@
+<!doctype html>
+<html lang="en-us">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <title>Emscripten-Generated Code</title>
+    <style>
+      .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+      canvas.emscripten { border: 1px solid black; }
+      textarea.emscripten { font-family: monospace; width: 80%; }
+      div.emscripten { text-align: center; }
+    </style>
+  </head>
+  <body>
+    <hr/>
+    <div class="emscripten" id="status">Downloading...</div>
+    <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+    <hr/>
+    <div class="emscripten"><input type="button" value="fullscreen" onclick="Module.requestFullScreen()"></div>
+    <hr/>
+    <textarea class="emscripten" id="output" rows="8"></textarea>
+    <hr>
+    <script type='text/javascript'>
+      // connect to canvas
+      var Module = {
+        preRun: [],
+        postRun: [],
+        print: (function() {
+          var element = document.getElementById('output');
+          element.value = ''; // clear browser cache
+          return function(text) {
+            // These replacements are necessary if you render to raw HTML
+            //text = text.replace(/&/g, "&");
+            //text = text.replace(/</g, "<");
+            //text = text.replace(/>/g, ">");
+            //text = text.replace('\n', '<br>', 'g');
+            element.value += text + "\n";
+            element.scrollTop = 99999; // focus on bottom
+          };
+        })(),
+        printErr: function(text) {
+          if (0) { // XXX disabled for safety typeof dump == 'function') {
+            dump(text + '\n'); // fast, straight to the real console
+          } else {
+            console.log(text);
+          }
+        },
+        canvas: document.getElementById('canvas'),
+        setStatus: function(text) {
+          if (Module.setStatus.interval) clearInterval(Module.setStatus.interval);
+          document.getElementById('status').innerHTML = text;
+          if (text) {
+            var counter = 0;
+            Module.setStatus.interval = setInterval(function() {
+              counter++;
+              counter %= 3;
+              var dots = ' ';
+              for (var i = 0; i < counter; i++) dots += '.';
+              dots += '*';
+              for (var i = counter; i < 2; i++) dots += '.';
+              document.getElementById('status').innerHTML = text.replace('...', dots);
+            }, 300);
+          }
+        },
+        totalDependencies: 0,
+        monitorRunDependencies: function(left) {
+          this.totalDependencies = Math.max(this.totalDependencies, left);
+          Module.setStatus(left ? 'Preparing: ' + (this.totalDependencies-left) + '/' + this.totalDependencies + '...' : 'All downloads complete.');
+        }
+      };
+      Module.setStatus('Downloading...');
+    </script>      
+    <script type='text/javascript'>
+
+      // Note: Some Emscripten settings will significantly limit the speed of the generated code.
+// Note: Some Emscripten settings may limit the speed of the generated code.
+// TODO: " u s e   s t r i c t ";
+
+try {
+  this['Module'] = Module;
+} catch(e) {
+  this['Module'] = Module = {};
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  Module['print'] = function(x) {
+    process['stdout'].write(x + '\n');
+  };
+  Module['printErr'] = function(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function(filename) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename).toString();
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename).toString();
+    }
+    return ret;
+  };
+
+  Module['load'] = function(f) {
+    globalEval(read(f));
+  };
+
+  if (!Module['arguments']) {
+    Module['arguments'] = process['argv'].slice(2);
+  }
+} else if (ENVIRONMENT_IS_SHELL) {
+  Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  // Polyfill over SpiderMonkey/V8 differences
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function(f) { snarf(f) };
+  }
+
+  if (!Module['arguments']) {
+    if (typeof scriptArgs != 'undefined') {
+      Module['arguments'] = scriptArgs;
+    } else if (typeof arguments != 'undefined') {
+      Module['arguments'] = arguments;
+    }
+  }
+} else if (ENVIRONMENT_IS_WEB) {
+  if (!Module['print']) {
+    Module['print'] = function(x) {
+      console.log(x);
+    };
+  }
+
+  if (!Module['printErr']) {
+    Module['printErr'] = function(x) {
+      console.log(x);
+    };
+  }
+
+  Module['read'] = function(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (!Module['arguments']) {
+    if (typeof arguments != 'undefined') {
+      Module['arguments'] = arguments;
+    }
+  }
+} else if (ENVIRONMENT_IS_WORKER) {
+  // We can do very little here...
+
+  Module['load'] = importScripts;
+
+} else {
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+if (!Module['preRun']) Module['preRun'] = [];
+if (!Module['postRun']) Module['postRun'] = [];
+
+  
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      var logg = log2(quantum);
+      return '((((' +target + ')+' + (quantum-1) + ')>>' + logg + ')<<' + logg + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (/^\[\d+\ x\ (.*)\]/.test(type)) return true; // [15 x ?] blocks. Like structs
+  if (/<?{ ?[^}]* ?}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  bitshift64: function (low, high, op, bits) {
+    var ander = Math.pow(2, bits)-1;
+    if (bits < 32) {
+      switch (op) {
+        case 'shl':
+          return [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))];
+        case 'ashr':
+          return [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0];
+        case 'lshr':
+          return [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits];
+      }
+    } else if (bits == 32) {
+      switch (op) {
+        case 'shl':
+          return [0, low];
+        case 'ashr':
+          return [high, (high|0) < 0 ? ander : 0];
+        case 'lshr':
+          return [high, 0];
+      }
+    } else { // bits > 32
+      switch (op) {
+        case 'shl':
+          return [0, low << (bits - 32)];
+        case 'ashr':
+          return [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0];
+        case 'lshr':
+          return [high >>>  (bits - 32) , 0];
+      }
+    }
+    abort('unknown bitshift64 op: ' + [value, op, bits]);
+  },
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type, quantumSize) {
+    if (Runtime.QUANTUM_SIZE == 1) return 1;
+    var size = {
+      '%i1': 1,
+      '%i8': 1,
+      '%i16': 2,
+      '%i32': 4,
+      '%i64': 8,
+      "%float": 4,
+      "%double": 8
+    }['%'+type]; // add '%' since float and double confuse Closure compiler as keys, and also spidermonkey as a compiler will remove 's from '_i8' etc
+    if (!size) {
+      if (type[type.length-1] == '*') {
+        size = Runtime.QUANTUM_SIZE; // A pointer
+      } else if (type[0] == 'i') {
+        var bits = parseInt(type.substr(1));
+        assert(bits % 8 == 0);
+        size = bits/8;
+      }
+    }
+    return size;
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    type.flatIndexes = type.fields.map(function(field) {
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = size;
+      } else if (Runtime.isStructType(field)) {
+        size = Types.types[field].flatSize;
+        alignSize = Types.types[field].alignSize;
+      } else {
+        throw 'Unclear type in struct: ' + field + ', in ' + type.name_ + ' :: ' + dump(Types.types[type.name_]);
+      }
+      alignSize = type.packed ? 1 : Math.min(alignSize, Runtime.QUANTUM_SIZE);
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      assert(type.fields.length === struct.length, 'Number of named fields must match the type for ' + typeName);
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  addFunction: function (func) {
+    var ret = FUNCTION_TABLE.length;
+    FUNCTION_TABLE.push(func);
+    FUNCTION_TABLE.push(0);
+    return ret;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func) {
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function() {
+        FUNCTION_TABLE[func].apply(null, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xff;
+      if (needed) {
+        buffer.push(code);
+        needed--;
+      }
+      if (buffer.length == 0) {
+        if (code < 128) return String.fromCharCode(code);
+        buffer.push(code);
+        if (code > 191 && code < 224) {
+          needed = 1;
+        } else {
+          needed = 2;
+        }
+        return '';
+      }
+      if (needed > 0) return '';
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var ret;
+      if (c1 > 191 && c1 < 224) {
+        ret = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
+      } else {
+        ret = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function(string) {
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  stackAlloc: function stackAlloc(size) { var ret = STACKTOP;STACKTOP += size;STACKTOP = ((((STACKTOP)+3)>>2)<<2);assert(STACKTOP < STACK_ROOT + STACK_MAX, "Ran out of stack"); return ret; },
+  staticAlloc: function staticAlloc(size) { var ret = STATICTOP;STATICTOP += size;STATICTOP = ((((STATICTOP)+3)>>2)<<2); if (STATICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function alignMemory(size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 4))*(quantum ? quantum : 4); return ret; },
+  makeBigInt: function makeBigInt(low,high,unsigned) { var ret = (unsigned ? (((low)>>>0)+(((high)>>>0)*4294967296)) : (((low)>>>0)+(((high)|0)*4294967296))); return ret; },
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+
+var CorrectionsMonitor = {
+  MAX_ALLOWED: 0, // XXX
+  corrections: 0,
+  sigs: {},
+
+  note: function(type, succeed, sig) {
+    if (!succeed) {
+      this.corrections++;
+      if (this.corrections >= this.MAX_ALLOWED) abort('\n\nToo many corrections!');
+    }
+  },
+
+  print: function() {
+  }
+};
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = false; // Used in checking for thrown exceptions.
+
+var ABORT = false;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD;
+var tempI64, tempI64b;
+
+function abort(text) {
+  Module.print(text + ':\n' + (new Error).stack);
+  ABORT = true;
+  throw "Assertion: " + text;
+}
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Adding
+//
+//         __attribute__((used))
+//
+//       to the function definition will prevent that.
+//
+// Note: Closure optimizations will minify function names, making
+//       functions no longer callable. If you run closure (on by default
+//       in -O2 and above), you should export the functions you will call
+//       by calling emcc with something like
+//
+//         -s EXPORTED_FUNCTIONS='["_func1","_func2"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length+1);
+      writeStringToMemory(value, ret);
+      return ret;
+    } else if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  try {
+    var func = eval('_' + ident);
+  } catch(e) {
+    try {
+      func = globalScope['Module']['_' + ident]; // closure exported function
+    } catch(e) {}
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+Module["ccall"] = ccall;
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  // TODO: optimize this, eval the whole function once instead of going through ccall each time
+  return function() {
+    return ccall(ident, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': HEAP32[((ptr)>>2)]=value; break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': (tempDoubleF64[0]=value,HEAP32[((ptr)>>2)]=tempDoubleI32[0],HEAP32[(((ptr)+(4))>>2)]=tempDoubleI32[1]); break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return (tempDoubleI32[0]=HEAP32[((ptr)>>2)],tempDoubleI32[1]=HEAP32[(((ptr)+(4))>>2)],tempDoubleF64[0]);
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+// Allocates memory for some data and initializes it properly.
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+
+function allocate(slab, types, allocator) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+
+  if (zeroinit) {
+      _memset(ret, 0, size);
+      return ret;
+  }
+  
+  var i = 0, type;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+    assert(type, 'Must know what type to store in allocate!');
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+    i += Runtime.getNativeTypeSize(type);
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  var utf8 = new Runtime.UTF8Processor();
+  var nullTerminated = typeof(length) == "undefined";
+  var ret = "";
+  var i = 0;
+  var t;
+  while (1) {
+    t = HEAPU8[((ptr)+(i))];
+    if (nullTerminated && t == 0) break;
+    ret += utf8.processCChar(t);
+    i += 1;
+    if (!nullTerminated && i == length) break;
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+function Array_stringify(array) {
+  var ret = "";
+  for (var i = 0; i < array.length; i++) {
+    ret += String.fromCharCode(array[i]);
+  }
+  return ret;
+}
+Module['Array_stringify'] = Array_stringify;
+
+// Memory management
+
+var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers to stacked or malloced memory. Such comparisons should
+                    //      be false, but can turn out true. We should probably set the top bit to prevent such issues.
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return ((x+4095)>>12)<<12;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STACK_ROOT, STACKTOP, STACK_MAX;
+var STATICTOP;
+function enlargeMemory() {
+  // TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top.
+  Module.printErr('Warning: Enlarging memory arrays, this is not fast! ' + [STATICTOP, TOTAL_MEMORY]);
+  assert(STATICTOP >= TOTAL_MEMORY);
+  assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite
+  while (TOTAL_MEMORY <= STATICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it
+    TOTAL_MEMORY = alignMemoryPage(2*TOTAL_MEMORY);
+  }
+  var oldHEAP8 = HEAP8;
+  var buffer = new ArrayBuffer(TOTAL_MEMORY);
+  HEAP8 = new Int8Array(buffer);
+  HEAP16 = new Int16Array(buffer);
+  HEAP32 = new Int32Array(buffer);
+  HEAPU8 = new Uint8Array(buffer);
+  HEAPU16 = new Uint16Array(buffer);
+  HEAPU32 = new Uint32Array(buffer);
+  HEAPF32 = new Float32Array(buffer);
+  HEAPF64 = new Float64Array(buffer);
+  HEAP8.set(oldHEAP8);
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 10485760;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+  assert(!!Int32Array && !!Float64Array && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+         'Cannot fallback to non-typed array case: Code is too specialized');
+
+  var buffer = new ArrayBuffer(TOTAL_MEMORY);
+  HEAP8 = new Int8Array(buffer);
+  HEAP16 = new Int16Array(buffer);
+  HEAP32 = new Int32Array(buffer);
+  HEAPU8 = new Uint8Array(buffer);
+  HEAPU16 = new Uint16Array(buffer);
+  HEAPU32 = new Uint32Array(buffer);
+  HEAPF32 = new Float32Array(buffer);
+  HEAPF64 = new Float64Array(buffer);
+
+  // Endianness check (note: assumes compiler arch was little-endian)
+  HEAP32[0] = 255;
+  assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+var base = intArrayFromString('(null)'); // So printing %s of NULL gives '(null)'
+                                         // Also this ensures we leave 0 as an invalid address, 'NULL'
+STATICTOP = base.length;
+for (var i = 0; i < base.length; i++) {
+  HEAP8[(i)]=base[i]
+}
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+STACK_ROOT = STACKTOP = Runtime.alignMemory(STATICTOP);
+STACK_MAX = STACK_ROOT + TOTAL_STACK;
+
+var tempDoublePtr = Runtime.alignMemory(STACK_MAX, 8);
+var tempDoubleI8  = HEAP8.subarray(tempDoublePtr);
+var tempDoubleI32 = HEAP32.subarray(tempDoublePtr >> 2);
+var tempDoubleF32 = HEAPF32.subarray(tempDoublePtr >> 2);
+var tempDoubleF64 = HEAPF64.subarray(tempDoublePtr >> 3);
+function copyTempFloat(ptr) { // functions, because inlining this code is increases code size too much
+  tempDoubleI8[0] = HEAP8[ptr];
+  tempDoubleI8[1] = HEAP8[ptr+1];
+  tempDoubleI8[2] = HEAP8[ptr+2];
+  tempDoubleI8[3] = HEAP8[ptr+3];
+}
+function copyTempDouble(ptr) {
+  tempDoubleI8[0] = HEAP8[ptr];
+  tempDoubleI8[1] = HEAP8[ptr+1];
+  tempDoubleI8[2] = HEAP8[ptr+2];
+  tempDoubleI8[3] = HEAP8[ptr+3];
+  tempDoubleI8[4] = HEAP8[ptr+4];
+  tempDoubleI8[5] = HEAP8[ptr+5];
+  tempDoubleI8[6] = HEAP8[ptr+6];
+  tempDoubleI8[7] = HEAP8[ptr+7];
+}
+STACK_MAX = tempDoublePtr + 8;
+
+STATICTOP = alignMemoryPage(STACK_MAX);
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    var func = callback.func;
+    if (typeof func === 'number') {
+      func = FUNCTION_TABLE[func];
+    }
+    func(callback.arg === undefined ? null : callback.arg);
+  }
+}
+
+var __ATINIT__ = []; // functions called during startup
+var __ATMAIN__ = []; // functions called when main() is to be run
+var __ATEXIT__ = []; // functions called during shutdown
+
+function initRuntime() {
+  callRuntimeCallbacks(__ATINIT__);
+}
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+
+  // Print summary of correction activity
+  CorrectionsMonitor.print();
+}
+
+function String_len(ptr) {
+  var i = 0;
+  while (HEAP8[((ptr)+(i))]) i++; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
+  return i;
+}
+Module['String_len'] = String_len;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+        assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ')  at offset ' + i + ' not in 0x00-0xFF.');
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[((buffer)+(i))]=chr
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[((buffer)+(i))]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+var STRING_TABLE = [];
+
+function unSign(value, bits, ignore, sig) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+  // TODO: clean up previous line
+}
+function reSign(value, bits, ignore, sig) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+function addRunDependency() {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency() {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) run();
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+// === Body ===
+
+
+
+
+function ____init___0($self, $initx, $inity, $initz) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_70=(($self+4)|0);
+      (tempDoubleF64[0]=$initx,HEAP32[(($_tmp_70)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_70)+(4))>>2)]=tempDoubleI32[1]);
+      var $_tmp_71=(($self+20)|0);
+      (tempDoubleF64[0]=$inity,HEAP32[(($_tmp_71)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_71)+(4))>>2)]=tempDoubleI32[1]);
+      var $_tmp_72=(($self+12)|0);
+      (tempDoubleF64[0]=$initz,HEAP32[(($_tmp_72)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_72)+(4))>>2)]=tempDoubleI32[1]);
+      __label__ = 5; break;
+    case 5: 
+      ;
+      return;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function ____init___1($self, $initx, $inity, $initz) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_218=(($self+4)|0);
+      (tempDoubleF64[0]=$initx,HEAP32[(($_tmp_218)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_218)+(4))>>2)]=tempDoubleI32[1]);
+      var $_tmp_219=(($self+20)|0);
+      (tempDoubleF64[0]=$inity,HEAP32[(($_tmp_219)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_219)+(4))>>2)]=tempDoubleI32[1]);
+      var $_tmp_220=(($self+12)|0);
+      (tempDoubleF64[0]=$initz,HEAP32[(($_tmp_220)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_220)+(4))>>2)]=tempDoubleI32[1]);
+      __label__ = 5; break;
+    case 5: 
+      ;
+      return;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function _main($argc, $argv) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      var $call1=_SDL_Init(32);
+      var $w=HEAP32[((_MYW)>>2)];
+      var $h=HEAP32[((_MYH)>>2)];
+      var $call2=_SDL_SetVideoMode(2 * $w, 2 * $h, 32, 0);
+      HEAP32[((_screen)>>2)]=$call2;
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_8=((_global_closure+4)|0);
+      (tempDoubleF64[0]=0.00001,HEAP32[(($_tmp_8)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_8)+(4))>>2)]=tempDoubleI32[1]);
+      var $_tmp_9=((_global_closure+12)|0);
+      (tempDoubleF64[0]=1000000000,HEAP32[(($_tmp_9)>>2)]=tempDoubleI32[0],HEAP32[((($_tmp_9)+(4))>>2)]=tempDoubleI32[1]);
+      var $_tmp_10=_cls1_init();
+      var $_tmp_11=0;
+      var $_tmp_12=0;
+      var $_tmp_13=0;
+      ____init___0($_tmp_10, $_tmp_11, $_tmp_12, $_tmp_13);
+      var $_tmp_14=_cls1_init();
+      var $_tmp_15=1;
+      var $_tmp_16=0;
+      var $_tmp_17=0;
+      ____init___0($_tmp_14, $_tmp_15, $_tmp_16, $_tmp_17);
+      var $_tmp_18=_cls1_init();
+      var $_tmp_19=0;
+      var $_tmp_20=1;
+      var $_tmp_21=0;
+      ____init___0($_tmp_18, $_tmp_19, $_tmp_20, $_tmp_21);
+      var $_tmp_22=((_global_closure+24)|0);
+      HEAP32[(($_tmp_22)>>2)]=$_tmp_18;
+      _cls1_incref($_tmp_18);
+      var $_tmp_23=_cls1_init();
+      var $_tmp_24=0;
+      var $_tmp_25=0;
+      var $_tmp_26=1;
+      ____init___0($_tmp_23, $_tmp_24, $_tmp_25, $_tmp_26);
+      var $_tmp_27=__reflectThrough_0($_tmp_14, $_tmp_18);
+      var $_tmp_28=____eq___0($_tmp_27, $_tmp_14);
+      _cls1_decref($_tmp_27);
+      var $_tmp_29=_bool_nonzero($_tmp_28);
+      var $_tmp_30=$_tmp_29 ^ 1;
+      var $_tmp_31=_bool_nonzero($_tmp_30);
+      _cls1_decref($_tmp_23);
+      _cls1_decref($_tmp_10);
+      _cls1_decref($_tmp_14);
+      if ($_tmp_31) { __label__ = 5; break; } else { __label__ = 6; break; }
+    case 5: 
+      __label__ = 7; break;
+    case 6: 
+      __label__ = 8; break;
+    case 7: 
+      var $_tmp_32=_int_div(1, 0);
+      var $_tmp_33=_int_str($_tmp_32);
+      var $_tmp_34=_str_buf($_tmp_33);
+      var $_tmp_35=_str_len($_tmp_33);
+      var $tmp4_0=((STRING_TABLE._str_0)|0);
+      var $0=_printf($tmp4_0, (tempInt=STACKTOP,STACKTOP += 8,assert(STACKTOP < STACK_ROOT + STACK_MAX, "Ran out of stack"),HEAP32[((tempInt)>>2)]=$_tmp_35,HEAP32[(((tempInt)+(4))>>2)]=$_tmp_34,tempInt));
+      _str_decref($_tmp_33);
+      __label__ = 8; break;
+    case 8: 
+      var $_tmp_36=_cls1_init();
+      var $_tmp_37=-1;
+      var $_tmp_38=-1;
+      var $_tmp_39=0;
+      ____init___0($_tmp_36, $_tmp_37, $_tmp_38, $_tmp_39);
+      var $_tmp_40=__reflectThrough_0($_tmp_36, $_tmp_18);
+      _cls1_decref($_tmp_36);
+      var $_tmp_41=_cls1_init();
+      var $_tmp_42=-1;
+      var $_tmp_43=1;
+      var $_tmp_44=0;
+      ____init___0($_tmp_41, $_tmp_42, $_tmp_43, $_tmp_44);
+      var $_tmp_45=____eq___0($_tmp_40, $_tmp_41);
+      _cls1_decref($_tmp_40);
+      _cls1_decref($_tmp_41);
+      var $_tmp_46=_bool_nonzero($_tmp_45);
+      var $_tmp_47=$_tmp_46 ^ 1;
+      var $_tmp_48=_bool_nonzero($_tmp_47);
+      _cls1_decref($_tmp_18);
+      if ($_tmp_48) { __label__ = 9; break; } else { __label__ = 10; break; }
+    case 9: 
+      __label__ = 11; break;
+    case 10: 
+      __label__ = 12; break;
+    case 11: 
+      var $_tmp_49=_int_div(1, 0);
+      var $_tmp_50=_int_str($_tmp_49);
+      var $_tmp_51=_str_buf($_tmp_50);
+      var $_tmp_52=_str_len($_tmp_50);
+      var $tmp8_0=((STRING_TABLE._str_0)|0);
+      var $1=_printf($tmp8_0, (tempInt=STACKTOP,STACKTOP += 8,assert(STACKTOP < STACK_ROOT + STACK_MAX, "Ran out of stack"),HEAP32[((tempInt)>>2)]=$_tmp_52,HEAP32[(((tempInt)+(4))>>2)]=$_tmp_51,tempInt));
+      _str_decref($_tmp_50);
+      __label__ = 12; break;
+    case 12: 
+      var $_tmp_53=_cls0_init();
+      var $_tmp_54=0;
+      var $_tmp_55=0;
+      var $_tmp_56=0;
+      ____init___1($_tmp_53, $_tmp_54, $_tmp_55, $_tmp_56);
+      var $_tmp_57=((_global_closure+20)|0);
+      HEAP32[(($_tmp_57)>>2)]=$_tmp_53;
+      _cls0_incref($_tmp_53);
+      var $_tmp_58=_cls1_init();
+      var $_tmp_59=3;
+      var $_tmp_60=4;
+      var $_tmp_61=12;
+      ____init___0($_tmp_58, $_tmp_59, $_tmp_60, $_tmp_61);
+      var $_tmp_62=_cls1_init();
+      var $_tmp_63=1;
+      var $_tmp_64=1;
+      var $_tmp_65=1;
+      ____init___0($_tmp_62, $_tmp_63, $_tmp_64, $_tmp_65);
+      __main_0();
+      _cls1_decref($_tmp_58);
+      _cls0_decref($_tmp_53);
+      _cls1_decref($_tmp_62);
+      __label__ = 13; break;
+    case 13: 
+      var $_tmp_68=HEAP32[((((_global_closure+20)|0))>>2)];
+      _cls0_decref($_tmp_68);
+      var $_tmp_69=HEAP32[((((_global_closure+24)|0))>>2)];
+      _cls1_decref($_tmp_69);
+      _teardown_runtime();
+      ;
+      return 0;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+Module["_main"] = _main;_main["X"]=1;
+
+function __magnitude_0($self) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_97=__dot_0($self, $self);
+      var $_tmp_98=_math_sqrt($_tmp_97);
+      ;
+      return $_tmp_98;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function ____add___0($self, $other) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_99=(($self+4)|0);
+      var $_tmp_100=(tempDoubleI32[0]=HEAP32[(($_tmp_99)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_99)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_101=(($other+4)|0);
+      var $_tmp_102=(tempDoubleI32[0]=HEAP32[(($_tmp_101)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_101)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_103=_float_add($_tmp_100, $_tmp_102);
+      var $_tmp_104=(($self+20)|0);
+      var $_tmp_105=(tempDoubleI32[0]=HEAP32[(($_tmp_104)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_104)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_106=(($other+20)|0);
+      var $_tmp_107=(tempDoubleI32[0]=HEAP32[(($_tmp_106)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_106)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_108=_float_add($_tmp_105, $_tmp_107);
+      var $_tmp_109=(($self+12)|0);
+      var $_tmp_110=(tempDoubleI32[0]=HEAP32[(($_tmp_109)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_109)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_111=(($other+12)|0);
+      var $_tmp_112=(tempDoubleI32[0]=HEAP32[(($_tmp_111)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_111)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_113=_float_add($_tmp_110, $_tmp_112);
+      var $_tmp_114=_cls1_init();
+      ____init___0($_tmp_114, $_tmp_103, $_tmp_108, $_tmp_113);
+      ;
+      return $_tmp_114;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function ____sub___0($self, $other) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_115=(($self+4)|0);
+      var $_tmp_116=(tempDoubleI32[0]=HEAP32[(($_tmp_115)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_115)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_117=(($other+4)|0);
+      var $_tmp_118=(tempDoubleI32[0]=HEAP32[(($_tmp_117)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_117)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_119=_float_sub($_tmp_116, $_tmp_118);
+      var $_tmp_120=(($self+20)|0);
+      var $_tmp_121=(tempDoubleI32[0]=HEAP32[(($_tmp_120)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_120)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_122=(($other+20)|0);
+      var $_tmp_123=(tempDoubleI32[0]=HEAP32[(($_tmp_122)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_122)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_124=_float_sub($_tmp_121, $_tmp_123);
+      var $_tmp_125=(($self+12)|0);
+      var $_tmp_126=(tempDoubleI32[0]=HEAP32[(($_tmp_125)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_125)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_127=(($other+12)|0);
+      var $_tmp_128=(tempDoubleI32[0]=HEAP32[(($_tmp_127)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_127)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_129=_float_sub($_tmp_126, $_tmp_128);
+      var $_tmp_130=_cls1_init();
+      ____init___0($_tmp_130, $_tmp_119, $_tmp_124, $_tmp_129);
+      ;
+      return $_tmp_130;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function __scale_0($self, $factor) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_131=(($self+4)|0);
+      var $_tmp_132=(tempDoubleI32[0]=HEAP32[(($_tmp_131)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_131)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_133=_float_mul($factor, $_tmp_132);
+      var $_tmp_134=(($self+20)|0);
+      var $_tmp_135=(tempDoubleI32[0]=HEAP32[(($_tmp_134)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_134)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_136=_float_mul($factor, $_tmp_135);
+      var $_tmp_137=(($self+12)|0);
+      var $_tmp_138=(tempDoubleI32[0]=HEAP32[(($_tmp_137)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_137)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_139=_float_mul($factor, $_tmp_138);
+      var $_tmp_140=_cls1_init();
+      ____init___0($_tmp_140, $_tmp_133, $_tmp_136, $_tmp_139);
+      ;
+      return $_tmp_140;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function __dot_0($self, $other) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_141=(($self+4)|0);
+      var $_tmp_142=(tempDoubleI32[0]=HEAP32[(($_tmp_141)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_141)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_143=(($other+4)|0);
+      var $_tmp_144=(tempDoubleI32[0]=HEAP32[(($_tmp_143)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_143)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_145=_float_mul($_tmp_142, $_tmp_144);
+      var $_tmp_146=(($self+20)|0);
+      var $_tmp_147=(tempDoubleI32[0]=HEAP32[(($_tmp_146)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_146)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_148=(($other+20)|0);
+      var $_tmp_149=(tempDoubleI32[0]=HEAP32[(($_tmp_148)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_148)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_150=_float_mul($_tmp_147, $_tmp_149);
+      var $_tmp_151=_float_add($_tmp_145, $_tmp_150);
+      var $_tmp_152=(($self+12)|0);
+      var $_tmp_153=(tempDoubleI32[0]=HEAP32[(($_tmp_152)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_152)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_154=(($other+12)|0);
+      var $_tmp_155=(tempDoubleI32[0]=HEAP32[(($_tmp_154)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_154)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_156=_float_mul($_tmp_153, $_tmp_155);
+      var $_tmp_157=_float_add($_tmp_151, $_tmp_156);
+      ;
+      return $_tmp_157;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function __cross_0($self, $other) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 
+      var $_tmp_158=(($self+20)|0);
+      var $_tmp_159=(tempDoubleI32[0]=HEAP32[(($_tmp_158)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_158)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_160=(($other+12)|0);
+      var $_tmp_161=(tempDoubleI32[0]=HEAP32[(($_tmp_160)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_160)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_162=_float_mul($_tmp_159, $_tmp_161);
+      var $_tmp_163=(($self+12)|0);
+      var $_tmp_164=(tempDoubleI32[0]=HEAP32[(($_tmp_163)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_163)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_165=(($other+20)|0);
+      var $_tmp_166=(tempDoubleI32[0]=HEAP32[(($_tmp_165)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_165)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_167=_float_mul($_tmp_164, $_tmp_166);
+      var $_tmp_168=_float_sub($_tmp_162, $_tmp_167);
+      var $_tmp_169=(($self+12)|0);
+      var $_tmp_170=(tempDoubleI32[0]=HEAP32[(($_tmp_169)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_169)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_171=(($other+4)|0);
+      var $_tmp_172=(tempDoubleI32[0]=HEAP32[(($_tmp_171)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_171)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_173=_float_mul($_tmp_170, $_tmp_172);
+      var $_tmp_174=(($self+4)|0);
+      var $_tmp_175=(tempDoubleI32[0]=HEAP32[(($_tmp_174)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_174)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_176=(($other+12)|0);
+      var $_tmp_177=(tempDoubleI32[0]=HEAP32[(($_tmp_176)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_176)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_178=_float_mul($_tmp_175, $_tmp_177);
+      var $_tmp_179=_float_sub($_tmp_173, $_tmp_178);
+      var $_tmp_180=(($self+4)|0);
+      var $_tmp_181=(tempDoubleI32[0]=HEAP32[(($_tmp_180)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_180)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_182=(($other+20)|0);
+      var $_tmp_183=(tempDoubleI32[0]=HEAP32[(($_tmp_182)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_182)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_184=_float_mul($_tmp_181, $_tmp_183);
+      var $_tmp_185=(($self+20)|0);
+      var $_tmp_186=(tempDoubleI32[0]=HEAP32[(($_tmp_185)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_185)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_187=(($other+4)|0);
+      var $_tmp_188=(tempDoubleI32[0]=HEAP32[(($_tmp_187)>>2)],tempDoubleI32[1]=HEAP32[((($_tmp_187)+(4))>>2)],tempDoubleF64[0]);
+      var $_tmp_189=_float_mul($_tmp_186, $_tmp_188);
+      var $_tmp_190=_float_sub($_tmp_184, $_tmp_189);
+      var $_tmp_191=_cls1_init();
+      ____init___0($_tmp_191, $_tmp_168, $_tmp_179, $_tmp_190);
+      ;
+      return $_tmp_191;
+    default: assert(0, "bad label: " + __label__);
+  }
+}
+
+
+function __normalized_0($self) {
+  ;
+  var __label__;
+  __label__ = 2; 
+  while(1) switch(__label__) {
+    case 2: 
+      __label__ = 3; break;
+    case 3: 
+      __label__ = 4; break;
+    case 4: 


More information about the pypy-commit mailing list