[
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.gdb_history\nbuild\ndist\nmscorlib.dll\n*.o\n.*.swo\n.*.swp\nmono-wasm\n*.dSYM\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2017 - present Microsoft Corporation\n\nAll rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "MONO_RUNTIME_PATH = ../mono-runtime\nMONO_COMPILER_PATH = ../mono-compiler\nLIBC_PATH = ../libc\nLLVM_PATH = ../llvm-build\n\nCLANG = $(LLVM_PATH)/bin/clang\n\nLIBC_CFLAGS = -fno-stack-protector -nostdinc -I$(LIBC_PATH)/include -I$(LIBC_PATH)/arch/wasm32 -target wasm32 -Wno-shift-op-parentheses -Wno-incompatible-library-redeclaration -Wno-bitwise-op-parentheses\n\nLIBC_INTERNAL_CFLAGS = $(LIBC_CFLAGS) -I$(LIBC_PATH)/src/internal\n\nMONO_CFLAGS = $(LIBC_CFLAGS) -I$(MONO_RUNTIME_PATH) -I$(MONO_RUNTIME_PATH)/mono -I$(MONO_RUNTIME_PATH)/eglib/src -DHAVE_CONFIG_H -D_THREAD_SAFE -DUSE_MMAP -DUSE_MUNMAP -std=gnu99 -fwrapv -DMONO_DLL_EXPORT -Wno-unused-value -Wno-tautological-compare -Wno-bitwise-op-parentheses\n\nall: dist-install\n\nbuild/libmini.bc: $(patsubst %, build/mini/%.bc, abcremoval alias-analysis aot-compiler aot-runtime branch-opts cfgdump cfold debug-mini debugger-agent decompose dominators driver dwarfwriter graph helpers image-writer jit-icalls linear-scan liveness lldb local-propagation memory-access method-to-ir mini-codegen mini-cross-helpers mini-wasm32 mini-exceptions mini-gc mini-generic-sharing mini-native-types mini-posix mini-runtime mini-trampolines mini seq-points simd-intrinsics ssa tasklets trace type-checking unwind xdebug)\n\nbuild/libmetadata.bc: $(patsubst %, build/metadata/%.bc, appdomain assembly attach class-accessors class cominterop console-wasm coree custom-attrs debug-helpers debug-mono-ppdb debug-mono-symfile decimal-ms domain dynamic-image dynamic-stream environment exception file-mmap-posix file-mmap-windows filewatcher gc-stats gc handle icall image jit-info loader locales lock-tracer marshal mempool metadata-cross-helpers metadata-verify metadata method-builder monitor mono-basic-block mono-conc-hash mono-config mono-config-dirs mono-debug mono-endian mono-hash mono-mlist mono-perfcounters mono-route mono-security number-ms object opcodes profiler property-bag rand reflection remoting runtime security-core-clr security-manager seq-points-data sgen-bridge sgen-mono sgen-new-bridge sgen-old-bridge sgen-stw sgen-tarjan-bridge sgen-toggleref sre-encode sre-save sre string-icalls sysmath threadpool-io threadpool-worker-default threadpool threads verify w32error-unix w32event-unix w32file-unix-glob w32file-unix w32file w32handle-namespace w32handle w32mutex-unix w32process-unix-bsd w32process-unix-default w32process-unix-haiku w32process-unix-osx w32process-unix w32process w32semaphore-unix w32socket-unix w32socket)\n\nbuild/libutils.bc: $(patsubst %, build/utils/%.bc, atomic mono-os-mutex bsearch mono-path checked-build mono-poll dlmalloc mono-proclib-windows hazard-pointer mono-proclib json mono-property-hash lock-free-alloc mono-publib lock-free-array-queue mono-rand-windows lock-free-queue mono-rand mono-sha1 mach-support mono-stdlib memfuncs mono-threads-android mono-codeman mono-threads-coop mono-conc-hashtable mono-threads-freebsd mono-context mono-threads-haiku mono-counters mono-threads-linux mono-dl-darwin mono-threads-mach-helper mono-dl-posix mono-threads-mach mono-dl-windows mono-threads-netbsd mono-dl mono-threads-openbsd mono-error mono-threads-posix-signals mono-filemap mono-threads-posix mono-threads-state-machine mono-hwcap mono-hwcap-wasm32 mono-threads-windows mono-internal-hash mono-threads mono-io-portability mono-time mono-linked-list-set mono-tls mono-log-android mono-uri mono-log-common mono-value-hash mono-log-darwin monobitset mono-log-posix networking-fallback mono-log-windows networking-missing mono-logger networking-posix mono-math networking-windows mono-md5 networking mono-mmap-windows os-event-unix mono-mmap parse mono-networkinterfaces strenc)\n\nbuild/libsgen.bc: $(patsubst %, build/sgen/sgen-%.bc, alloc array-list cardtable debug descriptor fin-weak-hash gc gchandles gray hash-table internal layout-stats los marksweep memory-governor nursery-allocator pinning-stats pinning pointer-queue protocol qsort simple-nursery split-nursery thread-pool workers)\n\nbuild/libeglib.bc: $(patsubst %, build/eglib/%.bc, garray goutput gbytearray gpath gdate-unix gpattern gdir-unix gptrarray gerror gqsort gfile-posix gqueue gfile-unix gshell gfile gslist ghashtable gspawn giconv gstr glist gstring gmarkup gtimer-unix gmem gunicode gmisc-unix gutf8 gmodule-unix)\n\nbuild/libmono.bc: build/libmini.bc build/libmetadata.bc build/libutils.bc build/libsgen.bc build/libeglib.bc\n\nbuild/libc.bc: $(patsubst %.c, build/libc/%.bc, $(shell (cd $(LIBC_PATH)/src && ls {ctype,env,errno,exit,internal,ldso,dlmalloc,fcntl,locale,math,prng,signal,stdio,string,stdlib,time,unistd}/*.c | grep -Ev \"(pread|pwrite|sigaltstack|strtok_r)\")) conf/sysconf.c thread/__lock.c misc/getrlimit.c mman/madvise.c stat/stat.c stat/fstat.c)\n\nbuild/libmini.bc build/libmetadata.bc build/libeglib.bc build/libsgen.bc build/libutils.bc build/libmono.bc build/libc.bc:\n\t$(LLVM_PATH)/bin/llvm-link $^ -o $@\n\nbuild/libc/%.bc: $(LIBC_PATH)/src/%.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) $(LIBC_INTERNAL_CFLAGS) $< -c -emit-llvm -o $@\n\nbuild/mini/%.bc : $(MONO_RUNTIME_PATH)/mono/mini/%.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) -I$(MONO_RUNTIME_PATH)/mono/mini $(MONO_CFLAGS) $< -c -emit-llvm -o $@\n\nbuild/metadata/%.bc : $(MONO_RUNTIME_PATH)/mono/metadata/%.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) -I$(MONO_RUNTIME_PATH)/mono/metadata $(MONO_CFLAGS) -DHAVE_SGEN_GC $< -c -emit-llvm -o $@\n\nbuild/utils/%.bc : $(MONO_RUNTIME_PATH)/mono/utils/%.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) -I$(MONO_RUNTIME_PATH)/mono/utils $(MONO_CFLAGS) -DHAVE_SGEN_GC $< -c -emit-llvm -o $@\n\nbuild/sgen/%.bc : $(MONO_RUNTIME_PATH)/mono/sgen/%.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) -I$(MONO_RUNTIME_PATH)/mono/sgen $(MONO_CFLAGS) -DHAVE_SGEN_GC $< -c -emit-llvm -o $@\n\nbuild/eglib/%.bc : $(MONO_RUNTIME_PATH)/eglib/src/%.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) $(MONO_CFLAGS) $< -c -emit-llvm -o $@\n\nmscorlib.dll: $(MONO_COMPILER_PATH)/mcs/class/lib/wasm/mscorlib.dll\n\tcp $< $@\n\nbuild/boot.bc:        boot.c\n\t@/bin/mkdir -p $(dir $@)\n\t$(CLANG) $(MONO_CFLAGS) boot.c -c -emit-llvm -o build/boot.bc\n\nbuild/runtime.bc:     build/boot.bc build/libc.bc build/libmono.bc\n\t@/bin/mkdir -p $(dir $@)\n\t$(LLVM_PATH)/bin/llvm-link build/libc.bc build/libmono.bc build/boot.bc -o build/runtime.bc\n\nMONO_WASM_CXXFLAGS = -Wno-sign-compare -std=c++1y -UNDEBUG -fexceptions\nMONO_WASM_LLVM_COMPONENTS = BitReader BitWriter Core IRReader Linker Object Support TransformUtils IPO webassembly Option\n\njsmin.o:        jsmin.c\n\t/usr/bin/clang -c jsmin.c -o jsmin.o\n\nmono-wasm:      jsmin.o mono-wasm.cpp\n\t/usr/bin/clang++ $(shell $(LLVM_PATH)/bin/llvm-config --cxxflags --ldflags) -Wno-gnu $(MONO_WASM_CXXFLAGS) -I$(shell $(LLVM_PATH)/bin/llvm-config --src-root)/tools/lld/include -g mono-wasm.cpp -o mono-wasm -lncurses -lz jsmin.o $(shell $(LLVM_PATH)/bin/llvm-config --libs $(MONO_WASM_LLVM_COMPONENTS)) -llldCommon -llldCore -llldDriver -llldReaderWriter -llldWasm\n\ndist-install:   mono-wasm build/runtime.bc mscorlib.dll\n\trm -rf dist\n\tmkdir -p dist/bin\n\tcp mono-wasm dist/bin\n\tcp $(MONO_COMPILER_PATH)/mono/mini/mono dist/bin/monoc\n\tmkdir -p dist/lib\n\tcp mscorlib.dll dist/lib\n\tcp mscorlib.xml dist/lib\n\tcp build/runtime.bc dist/lib\n\tcp index.js dist/lib\n\nneed-version:\nifndef VERSION\n    $(error VERSION is undefined)\nendif\n\nmake-dist-dir:\nDIST_DIR = mono-wasm-macos-$(VERSION)\n\nrelease:\tneed-version make-dist-dir dist-install\n\tmkdir -p releases\n\t(cd releases \\\n\t  && mkdir $(DIST_DIR) \\\n\t  && ditto ../dist $(DIST_DIR)/dist \\\n\t  && ditto ../sample $(DIST_DIR)/sample \\\n\t  && for i in `ls $(DIST_DIR)/sample`; do (cd $(DIST_DIR)/sample/$$i && make clean); done \\\n\t  && zip -r $(DIST_DIR).zip $(DIST_DIR))\n\nclean:\n\t/bin/rm -rf build dist mscorlib.dll jsmin.o mono-wasm\n"
  },
  {
    "path": "README.md",
    "content": "# mono-wasm\n\nThis project is a proof-of-concept aiming at building C# applications into WebAssembly, by using Mono and compiling/linking everything statically into one .wasm file that can be easily delivered to browsers.\n\nThe process does not use Emscripten (or Binaryen) but instead uses the experimental WebAssembly backend of LLVM with `clang` and `lld` to generate the final .wasm code. The goal is to use as few dependencies as possible. At the moment the only dependencies are LLVM, `clang` and `lld` trunk.\n\n`mono-wasm` supports 2 build modes: one that links all the LLVM bitcode into one module then performs a WebAssembly codegen on it, and one that compiles project dependencies into WebAssembly incrementally (the runtime and the mscorlib assembly) then uses `lld` to link into a final .wasm file. The later is experimental but will become the default as it allows build times lesser than a second.\n\nThe .wasm file is loaded from JavaScript (see `index.js`), which also exposes proper callbacks for system calls that the C library will be calling into. These syscalls are responsible for heap management, I/O, etc.\n\nThis project is a work in progress. Feel free to ping me if you have questions or feedback: laurent.sansonetti@microsoft.com\n\n## Related repositories\n\n* [mono-wasm-mono](https://github.com/lrz/mono-wasm-mono): a fork of Mono with changes for a wasm32 target, used to build the runtime and compiler.\n* [mono-wasm-libc](https://github.com/lrz/mono-wasm-libc): a fork of the WebAssembly/musl C library with tweaks for our version of Mono and our JS glue.\n\n## Current status\n\nThis is a work in progress, but you can see `sample/hello/hello.cs` running here: www.hipbyte.com/~lrz/mono-wasm-hello\n\n### Binary releases\n\nBinary releases are avalable here (for testing only): https://github.com/lrz/mono-wasm/releases\n\n## How does it work?\n\nAn ASCII graph is worth a thousand words:\n\n```\n+----------------+-------------+  +---------------------+\n|  Mono runtime  |  C library  |  |    C# assemblies    | <-------+\n+----------------+-------------+  +----------+----------+         |\n           clang |                           | mono               |\n  -target=wasm32 |                           | -aot=llvmonly      |\n                 v                           v                    |\n+-------------------------------------------------------+         | load\n|                       LLVM bitcode                    |         | metadata\n+----------------------------+--------------------------+         | (runtime)\n                             | mono-wasm                          |\n                             | (bitcode -> wasm)                  | \n                             v                                    | \n+-------------------------------------------------------+         |\n|                        index.wasm                     |---------+\n+----------------------------------------+--------------+               \n                 ^                       | libc                         \n   load, compile |                       | syscalls                     \n    + run main() |                       v                             \n+----------------+--------------------------------------+         +-----------+ \n|                         index.js                      | <-----> |  Browser  |\n+-------------------------------------------------------+         +-----------+\n```\n\n## Build instructions\n\nWe will assume that you want to build everything in the ~/src/mono-wasm directory.\n\n```\n$ mkdir ~/src/mono-wasm\n$ cd ~/src/mono-wasm\n$ git clone git@github.com:lrz/mono-wasm.git build\n```\n\n### LLVM+clang+lld with WebAssembly target\n\nWe need a copy of the LLVM tooling (clang and lld included) with the experimental WebAssembly target enabled. Make sure to build a Release build (as indicated below) otherwise the WASM codegen will be significantly slower.\n\n```\n$ cd ~/src/mono-wasm\n$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm\n$ cd llvm/tools\n$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang\n$ svn co http://llvm.org/svn/llvm-project/lld/trunk lld\n$ cd ../..\n$ mkdir llvm-build\n$ cd llvm-build\n$ cmake -G \"Unix Makefiles\" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../llvm\n$ make\n```\n\nAfter you did this you should have the LLVM static libraries for the WebAssembly target:\n\n```\n$ ls ~/src/mono-wasm/llvm-build/lib | grep WebAssembly\nlibLLVMWebAssemblyAsmPrinter.a\nlibLLVMWebAssemblyCodeGen.a\nlibLLVMWebAssemblyDesc.a\nlibLLVMWebAssemblyDisassembler.a\nlibLLVMWebAssemblyInfo.a\n```\n\nYou should also have the `~/src/mono-wasm/llvm-build/bin/clang` program built with the wasm32 target:\n\n```\n$ ~/src/mono-wasm/llvm-build/bin/clang --version\nclang version 5.0.0 (trunk 306818)\nTarget: x86_64-apple-darwin15.6.0\nThread model: posix\nInstalledDir: /Users/lrz/src/mono-wasm/llvm-build/bin\n\n  Registered Targets:\n[...]\n    wasm32     - WebAssembly 32-bit\n    wasm64     - WebAssembly 64-bit\n```\n\nYou should also have the wasm lld (linker) library:\n\n```\n$ ls ~/src/mono-wasm/llvm-build/lib/liblldWasm.a\n/Users/lrz/src/mono-wasm/llvm-build/lib/liblldWasm.a\n```\n\n### Mono compiler\n\nWe need a build a copy of the Mono compiler that we will use to generate LLVM bitcode from assemblies. We are building this for 32-bit Intel (i386) because the Mono compiler assumes way too many things from the host environment when generating the bitcode, so we want to match the target architecture (which is also 32-bit).\n\nFirst, you need to build a copy of the Mono fork of LLVM. We are building it for both 32-bit and 64-bit Intel so that we can easily switch the Mono compiler back to 64-bit later, and we manually have to copy the headers to the build directory as the Mono build system doesn't support external LLVM builds.\n\n```\n$ cd ~/src/mono-wasm\n$ git clone git@github.com:mono/llvm.git llvm-mono\n$ mkdir llvm-mono-build\n$ cd llvm-mono-build\n$ cmake -G \"Unix Makefiles\" -DCMAKE_OSX_ARCHITECTURES=\"i386;x86_64\" ../llvm-mono\n$ ditto ../llvm-mono/include include\n$ make\n```\n\nNow, we can now build the Mono compiler itself.\n\n```\n$ cd ~/src/mono-wasm\n$ git clone git@github.com:lrz/mono-wasm-mono.git mono-compiler\n$ cd mono-compiler\n$ ./autogen.sh --host=i386-darwin --with-cross-offsets=offsets-wasm32.h CFLAGS=\"-DCOMPILE_WASM32 -DMONO_CROSS_COMPILE\" CXXFLAGS=\"-DCOMPILE_WASM32 -DMONO_CROSS_COMPILE\" --disable-boehm --with-sigaltstack=no --enable-llvm --enable-llvm-runtime --with-llvm=../llvm-mono-build --disable-btls --with-runtime_preset=testing_aot_full\n$ cd eglib\n$ make\n$ cd ../mono\n$ make\n```\n\nAt the end of this process you should have a `mono` executable installed as `~/src/mono-wasm/mono-compiler/mono/mini/mono` built for the i386 architecture.\n\n```\n$ file ~/src/mono-wasm/mono-compiler/mono/mini/mono\nmono/mini/mono: Mach-O executable i386\n```\n\nNow let's build the `mscorlib.dll` assembly for the WebAssembly profile. We can't use the mono runtime we just built as it's full AOT, so we use assume you have a normal `mono` runtime in your PATH that we can use. Clearly a hack, but in the meantime it works.\n\n```\n$ cd ~/src/mono-wasm/mono-compiler/mcs/class/corlib\n$ make V=1 PROFILE=wasm RUNTIME=mono STRING_REPLACER=true SN=true\n```\n\nAfter this you should have the assembly file created in the proper location:\n\n```\n$ file ~/src/mono-wasm/mono-compiler/mcs/class/lib/wasm/mscorlib.dll \n/Users/lrz/src/mono-wasm/mono-compiler/mcs/class/lib/wasm/mscorlib.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows\n```\n\n### Mono runtime\n\nNow we can prepare the Mono runtime. We have to clone a new copy of the source code. We are not building the runtime code using the Mono autotools system, so we have to copy header files that are normally generated.\n\n```\n$ cd ~/src/mono-wasm\n$ git clone git@github.com:lrz/mono-wasm-mono.git mono-runtime\n$ cd mono-runtime\n$ cp config-wasm32.h config.h\n$ cp eglib/src/eglib-config-wasm32.h eglib/src/eglib-config.h\n```\n\n### C library\n\nSimilarly as above, we clone a copy of the C library that we will be using.\n\n```\n$ cd ~/src/mono-wasm\n$ git clone git@github.com:lrz/mono-wasm-libc.git libc\n```\n\n### OK ready!\n\nWe are ready to build our Hello World.\n\nFirst, we need to build everything into the `dist` directory:\n\n```\n$ cd ~/src/mono-wasm/build\n$ vi Makefile               # make sure the *_PATH variables point to proper locations, should be the case if you followed these instructions\n$ make\n```\n\nThis will build the mono runtime and the libc as LLVM bitcode using our version of clang, then link everything into a `runtime.bc` file. This will also build the `mono-wasm` tool which links against the LLVM and lld libraries. Finally, we will copy the Mono compiler and its `mscorlib.dll` file.\n\n```\n$ find dist -type f\ndist/bin/monoc\ndist/bin/mono-wasm\ndist/lib/runtime.bc\ndist/lib/index.js\ndist/lib/mscorlib.dll\ndist/lib/mscorlib.xml\n```\n\nOnce done, you can build the Hello World sample:\n\n```\n$ cd sample/hello\n$ make\n```\n\n## TODO\n\nTODO (now):\n\n* fix garbage collection (need to figure out how to scan the stack)\n* ship a first 'alpha' release\n\nTODO (later):\n\n* put mscorlib on a diet (currently 'hello world' is 10MB) by removing more functionality within the `wasm.make` profile and doing more aggressive IL linking\n* work on patches for mono based on the changes made in the fork\n* merge the WebAssembly LLVM code into the mono/llvm fork so that the Mono compiler can target wasm32 directly, and that we can merge the code into `mono-wasm` (we won't have to ship the Mono compiler separately as `monoc`)\n* improve the C# -> JS interop by doing a full C# API replication in JS like embeddinator 4000\n* investigate: threads, sockets, debugger, stack unwinding, simd and atomic operations, etc.\n\n## License\n\nThis work is distributed under the terms of the MIT license. See the LICENSE.txt file for more information.\n"
  },
  {
    "path": "boot.c",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See the LICENSE.txt file in the project root\n// for the license information.\n\n#include <mono/mini/mini.h>\n#include <mono/metadata/assembly.h>\n#include <locale.h>\n\nvoid mono_wasm_aot_init(void);\n\n__attribute__ ((__visibility__ (\"default\")))\nint\nmono_wasm_main(char *main_assembly_name, int debug)\n{\n    g_log(\"mono-wasm\", G_LOG_LEVEL_INFO, \"booting main()\");\n\n    setlocale(LC_ALL, \"\");\n\n    g_setenv(\"LANG\", \"en_US\", 1);\n    g_setenv(\"MONO_PATH\", \".\", 1);\n    g_setenv(\"MONO_LOG_LEVEL\", debug ? \"debug\" : \"error\", 1);\n\n    g_log_set_always_fatal(G_LOG_LEVEL_ERROR);\n    g_log_set_fatal_mask(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);\n\n    g_set_prgname(\"hello\");\n\n    mono_wasm_aot_init();\n\n    g_log(\"mono-wasm\", G_LOG_LEVEL_INFO, \"initializing mono runtime\");\n    mono_jit_set_aot_mode(MONO_AOT_MODE_LLVMONLY);\n    MonoDomain *domain = mono_jit_init_version(\"hello\", \"v4.0.30319\");\n\n    g_log(\"mono-wasm\", G_LOG_LEVEL_INFO, \"opening main assembly `%s'\",\n            main_assembly_name);\n    MonoAssembly *assembly = mono_assembly_open(main_assembly_name, NULL);\n    g_assert(assembly != NULL);\n\n    g_log(\"mono-wasm\", G_LOG_LEVEL_INFO, \"running Main()\");\n    int mono_argc = 1;\n    char *mono_argv[] = { main_assembly_name, NULL };\n    return mono_jit_exec(domain, assembly, mono_argc, mono_argv);\n}\n"
  },
  {
    "path": "index.js",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See the LICENSE.txt file in the project root\n// for the license information.\n\n// JavaScript WASM support for libc+mono. Inspired from WebAssembly/musl's\n// wasm.js file.\n\nError.stackTraceLimit = Infinity; // print the entire callstack on errors\n\nvar dump_cross_offsets = false;\nvar debug_logs = false;\nvar functions = { env: {} };\nvar instance;\nvar heap;\nvar heap_size;\n\nvar browser_environment = (typeof window != \"undefined\");\n\nfunction heap_get_short(ptr) {\n  var d = 0;\n  d += (heap[ptr + 0] << 0);\n  d += (heap[ptr + 1] << 8);\n  return d;\n}\n\nfunction heap_get_int(ptr) {\n  var d = 0;\n  d += (heap[ptr + 0] << 0);\n  d += (heap[ptr + 1] << 8);\n  d += (heap[ptr + 2] << 16);\n  d += (heap[ptr + 3] << 24);\n  return d;\n}\n\nfunction heap_get_long(ptr) {\n  var d = 0;\n  d += (heap[ptr + 0] << 0);\n  d += (heap[ptr + 1] << 8);\n  d += (heap[ptr + 2] << 16);\n  d += (heap[ptr + 3] << 24);\n  d += (heap[ptr + 4] << 32);\n  d += (heap[ptr + 5] << 40);\n  d += (heap[ptr + 6] << 48);\n  d += (heap[ptr + 7] << 56);\n  return d;\n}\n\nfunction heap_set_int(ptr, d) {\n  heap[ptr + 0] = ((d & 0x000000ff) >> 0);\n  heap[ptr + 1] = ((d & 0x0000ff00) >> 8);\n  heap[ptr + 2] = ((d & 0x00ff0000) >> 16);\n  heap[ptr + 3] = ((d & 0xff000000) >> 24);\n  return d;\n}\n\nfunction heap_set_long(ptr, d) {\n  heap[ptr + 0] = ((d & 0x00000000000000ff) >> 0);\n  heap[ptr + 1] = ((d & 0x000000000000ff00) >> 8);\n  heap[ptr + 2] = ((d & 0x0000000000ff0000) >> 16);\n  heap[ptr + 3] = ((d & 0x00000000ff000000) >> 24);\n  heap[ptr + 4] = ((d & 0x000000ff00000000) >> 32);\n  heap[ptr + 5] = ((d & 0x0000ff0000000000) >> 40);\n  heap[ptr + 6] = ((d & 0x00ff000000000000) >> 48);\n  heap[ptr + 7] = ((d & 0xff00000000000000) >> 56);\n  return d;\n}\n\nfunction heap_get_string(ptr, len=-1) {\n  var str = '';\n  var i = 0;\n  while (true) {\n    var c = heap[ptr + i];\n    if (c == 0) {\n      break;\n    }\n    if (i == len) {\n      break;\n    }\n    str += String.fromCharCode(c);\n    i++;\n  }\n  return str;\n}\n\nfunction heap_get_mono_string(ptr)\n{\n  var str_length = heap_get_int(ptr + 8)\n  var str_chars = ptr + 12\n  var str = ''\n  for (var i = 0; i < str_length; i++) {\n    var c = heap_get_short(str_chars + (i * 2))\n    str += String.fromCharCode(c);\n  }\n  return str;\n}\n\nfunction heap_set_string(ptr, str) {\n  for (var i = 0; i < str.length; i++) {\n    heap[ptr + i] = str.charCodeAt(i);\n  }\n  heap[ptr + str.length] = 0\n}\n\nfunction heap_malloc_string(str) {\n  var ptr = instance.exports.malloc(str.length + 1)\n  heap_set_string(ptr, str)\n  return ptr\n}\n\nfunction heap_human(size) {\n  var suffixes = ['B', 'K', 'M', 'G']\n  var suffix;\n  for (var i in suffixes) {\n    suffix = suffixes[i]\n    if (size < 1000) {\n      break\n    }\n    size /= 1000\n  }\n  return size.toFixed(2) + suffix\n}\n\nfunction log(str) {\n  browser_environment ? console.log(str) : print(str)\n}\n\nfunction debug(str) {\n  if (debug_logs) {\n    log(\">> \" + str);\n  }\n}\n\nfunction error(str) {\n  log(\"!! \" + str + \": \" + new Error().stack);\n}\n\nfunction TerminateWasmException(value) {\n  this.message = 'Terminating WebAssembly';\n  this.value = value;\n  this.toString = function() { return this.message + ': ' + this.value; };\n}\n\nfunction NotYetImplementedException(what) {\n  this.message = 'Not yet implemented';\n  this.what = what;\n  this.toString = function() { return this.message + ': ' + this.what; };\n}\n\n// TODO: these missing (imported) functions shouldn't be called from the runtime.\nvar missing_functions=[\"__addtf3\",\"__clone\",\"__divdc3\",\"__divtf3\",\"__eqtf2\",\"__extenddftf2\",\"__extendsftf2\",\"__fixtfdi\",\"__fixtfsi\",\"__fixunstfsi\",\"__floatsitf\",\"__floatunsitf\",\"__getf2\",\"__lsysinfo\",\"__lttf2\",\"__mmap\",\"__multf3\",\"__munmap\",\"__netf2\",\"__randname\",\"__set_thread_area\",\"__subtf3\",\"__synccall\",\"__syscall\",\"__syscall0\",\"__syscall1\",\"__syscall2\",\"__syscall3\",\"__syscall4\",\"__syscall5\",\"__syscall6\",\"__syscall_cp\",\"__trunctfdf2\",\"__trunctfsf2\",\"__unordtf2\",\"__wait\",\"_pthread_cleanup_pop\",\"_pthread_cleanup_push\",\"accept\",\"bind\",\"btowc\",\"cabs\",\"chmod\",\"closedir\",\"closelog\",\"connect\",\"execv\",\"execve\",\"execvp\",\"feclearexcept\",\"fegetround\",\"feraiseexcept\",\"fesetround\",\"fetestexcept\",\"fork\",\"freeaddrinfo\",\"getaddrinfo\",\"getgrgid_r\",\"getgrnam_r\",\"getnameinfo\",\"getpeername\",\"getpriority\",\"getprotobyname\",\"getpwnam_r\",\"getpwuid_r\",\"getrusage\",\"getsockname\",\"getsockopt\",\"htons\",\"ioctl\",\"listen\",\"longjmp\",\"lstat\",\"mbrtowc\",\"mbsinit\",\"mbsnrtowcs\",\"mbstowcs\",\"mbtowc\",\"mincore\",\"mkdir\",\"mkdtemp\",\"mkstemp\",\"mmap\",\"mono_arch_cleanup\",\"mono_arch_context_get_int_reg\",\"mono_arch_create_generic_trampoline\",\"mono_arch_create_rgctx_lazy_fetch_trampoline\",\"mono_arch_create_specific_trampoline\",\"mono_arch_find_imt_method\",\"mono_arch_find_static_call_vtable\",\"mono_arch_flush_register_windows\",\"mono_arch_free_jit_tls_data\",\"mono_arch_get_argument_info\",\"mono_arch_get_call_filter\",\"mono_arch_get_delegate_invoke_impl\",\"mono_arch_get_delegate_virtual_invoke_impl\",\"mono_arch_get_gsharedvt_arg_trampoline\",\"mono_arch_get_gsharedvt_call_info\",\"mono_arch_get_gsharedvt_trampoline\",\"mono_arch_get_restore_context\",\"mono_arch_get_rethrow_exception\",\"mono_arch_get_static_rgctx_trampoline\",\"mono_arch_get_this_arg_from_call\",\"mono_arch_get_throw_corlib_exception\",\"mono_arch_get_throw_exception\",\"mono_arch_get_unbox_trampoline\",\"mono_arch_handle_exception\",\"mono_arch_ip_from_context\",\"mono_arch_patch_callsite\",\"mono_arch_patch_plt_entry\",\"mono_arch_regname\",\"mono_arch_unwind_frame\",\"mono_interp_frame_iter_init\",\"mono_interp_frame_iter_next\",\"mono_interp_run_finally\",\"mono_interp_set_resume_state\",\"mono_monoctx_to_sigctx\",\"mono_mprotect\",\"mono_sigctx_to_monoctx\",\"mono_vfree\",\"mono_w32file_get_volume_information\",\"mono_wasm_js_eval_imp\",\"mono_wasm_throw_exception\",\"msync\",\"munmap\",\"opendir\",\"openlog\",\"posix_spawn\",\"posix_spawn_file_actions_adddup2\",\"posix_spawn_file_actions_destroy\",\"posix_spawn_file_actions_init\",\"pthread_attr_destroy\",\"pthread_attr_getstacksize\",\"pthread_attr_init\",\"pthread_attr_setdetachstate\",\"pthread_attr_setstacksize\",\"pthread_barrier_init\",\"pthread_barrier_wait\",\"pthread_cond_broadcast\",\"pthread_cond_destroy\",\"pthread_cond_init\",\"pthread_cond_signal\",\"pthread_cond_timedwait\",\"pthread_cond_wait\",\"pthread_condattr_destroy\",\"pthread_condattr_init\",\"pthread_condattr_setclock\",\"pthread_create\",\"pthread_exit\",\"pthread_getschedparam\",\"pthread_getspecific\",\"pthread_join\",\"pthread_key_create\",\"pthread_key_delete\",\"pthread_kill\",\"pthread_mutex_destroy\",\"pthread_mutex_init\",\"pthread_mutex_lock\",\"pthread_mutex_trylock\",\"pthread_mutex_unlock\",\"pthread_mutexattr_destroy\",\"pthread_mutexattr_init\",\"pthread_mutexattr_settype\",\"pthread_once\",\"pthread_self\",\"pthread_setcancelstate\",\"pthread_setschedparam\",\"pthread_setspecific\",\"pthread_sigmask\",\"readdir\",\"recvfrom\",\"recvmsg\",\"sched_get_priority_max\",\"sched_yield\",\"select\",\"sem_destroy\",\"sem_init\",\"sem_post\",\"sem_timedwait\",\"sem_trywait\",\"sem_wait\",\"send\",\"sendmsg\",\"sendto\",\"setjmp\",\"setpriority\",\"setsockopt\",\"shutdown\",\"socket\",\"statvfs\",\"syslog\",\"uname\",\"utimensat\",\"waitpid\",\"wcsrtombs\",\"wctomb\",\"mono_arch_build_imt_trampoline\"];\n// TODO: these missing (imported) globals should also be removed from the runtime.\nvar missing_globals=[\"_ZTIPi\"];\n\n// variables generated by `mono-wasm':\n//   files: an array of IL assemblies files\nif (typeof files == \"undefined\") {\n  var files = [];\n}\n\nfor (var i in missing_functions) {\n  f = missing_functions[i];\n  functions['env'][f] = (function(f) { \n    return function() {\n      error(\"Not Yet Implemented: \" + f)\n      throw new NotYetImplementedException(f);\n    }\n  })(f);\n}\n\nvar do_nothing_functions = ['pthread_mutexattr_init', 'pthread_mutexattr_settype', 'pthread_mutex_init', 'pthread_mutexattr_destroy', 'pthread_mutex_lock', 'pthread_mutex_unlock', 'pthread_condattr_init', 'pthread_condattr_setclock', 'pthread_cond_init', 'pthread_condattr_destroy', 'pthread_sigmask', '_pthread_cleanup_push', '_pthread_cleanup_pop', 'pthread_self', 'pthread_create', 'pthread_mutex_trylock', 'pthread_attr_init', 'pthread_attr_setstacksize', 'pthread_attr_getstacksize', 'pthread_attr_destroy', 'sem_init', 'sem_wait', 'sem_post', 'mono_console_init', '__munmap', 'pthread_cond_broadcast', 'pthread_mutex_destroy', 'pthread_cond_destroy', 'mono_mprotect', 'sched_yield']\n\nfor (var i in do_nothing_functions) {\n  f = do_nothing_functions[i];\n  functions['env'][f] = function() { }\n}\n\n// A (way too) simple implementation for thread-local variables. Should be\n// removed once we enable the relevant code in the libc.\nvar tls_variables = {}\n\nfunctions['env']['pthread_key_create'] = function(key_ptr, destructor) {\n  key = Object.keys(tls_variables).length;\n  tls_variables[key] = 0;\n  heap_set_int(key_ptr, key);\n  return 0;\n}\n\nfunctions['env']['pthread_getspecific'] = function(key) {\n  var value = tls_variables[key];\n  debug('pthread_getspecific(' + key + ') -> ' + value);\n  return value;\n}\n\nfunctions['env']['pthread_setspecific'] = function(key, value) {\n  debug('pthread_setspecific(' + key + ', ' + value + ')');\n  tls_variables[key] = value;\n  return 0;\n}\n\nfor (var i in missing_globals) {\n  g = missing_globals[i];\n  functions['env'][g] = 0;\n}\n\n// Temporary entry-point for exceptions raised by Mono. We assume that all\n// exceptions are fatal at this point.\n\nfunctions['env']['mono_wasm_throw_exception'] = function(exc) {\n  var class_str = heap_get_mono_string(heap_get_int(exc + 8))\n  var message_str = heap_get_mono_string(heap_get_int(exc + 12))\n  msg = ('Mono Exception: ' + (class_str.length > 0 ? class_str + ': ' : '')\n          + message_str)\n  error(msg)\n  throw new TerminateWasmException(msg)\n}\n\n// Implementation of the C# WebAssembly API.\n\nfunctions['env']['mono_wasm_js_eval_imp'] = function(expr, exception_raised) {\n  var str = heap_get_string(expr);\n  var res = undefined;\n  try {\n    res = eval(str);\n  }\n  catch (e) {\n    heap_set_int(exception_raised, 1);\n    res = e;\n  }\n  return heap_malloc_string(String(res));\n}\n\nvar mono_wasm_refs = {};\nvar mono_wasm_ref_counter = 0;\n\nObject.defineProperty(Object.prototype, \"__mono_wasm_ref__\", {\n  writable: true\n});\n\nfunction mono_wasm_wrap_obj(obj) {\n  var ref = undefined;\n  if (obj != null) {\n    ref = obj.__mono_wasm_ref__;\n    if (ref == undefined) {\n      obj.__mono_wasm_ref__ = ref = mono_wasm_ref_counter++;\n    }\n    mono_wasm_refs[ref] = obj;\n  }\n  return ref;\n}\n\nfunction mono_wasm_unwrap_obj(ref) {\n  return mono_wasm_refs[ref];\n}\n\n// Implementation of the JS/Mono API.\n\nfunction _MonoDomain() {\n  return instance.exports.mono_domain_get();\n}\n\nfunction _MonoGPtrToArray(ptr) {\n  var pdata = heap_get_int(ptr + 0);\n  var plen = heap_get_int(ptr + 4);\n  var ary = [];\n  for (var i = 0; i < plen; i++) {\n    ary.push(heap_get_int(pdata + (i * 4)));\n  }\n  return ary;\n}\n\nfunction _MonoAssemblies() {\n  var ptr = instance.exports.mono_domain_get_assemblies(_MonoDomain(), false);\n  return _MonoGPtrToArray(ptr);\n}\n\nfunction _MonoImage(assembly) {\n  return instance.exports.mono_assembly_get_image(assembly);\n}\n\nfunction MonoClass(namespace, name) {\n  var namespace_str = heap_malloc_string(namespace);\n  var name_str = heap_malloc_string(name);\n  var assemblies = _MonoAssemblies();\n  var klass = undefined;\n  for (var i in assemblies) {\n    var assembly = assemblies[i];\n    var image = _MonoImage(assembly);\n    var klass = instance.exports.mono_class_from_name(image, namespace_str,\n            name_str);\n    if (klass) {\n      break;\n    }\n  }\n  instance.exports.free(namespace_str);\n  instance.exports.free(name_str);\n  return klass;\n}\n\nfunction MonoMethod(klass, name, is_static) {\n  var flags = (is_static ? 0x10 : 0);\n  var name_str = heap_malloc_string(name);\n  var method = instance.exports.mono_class_get_method_from_name_flags(klass,\n          name_str, -1, flags);\n  instance.exports.free(name_str);\n  return method;\n}\n\nfunction MonoInvoke(obj, method, params) {\n  var sig = instance.exports.mono_method_signature(method);\n  var argc = instance.exports.mono_signature_get_param_count(sig);\n  if (params.length != argc) {\n    throw \"invalid number of parameters\";\n  }\n  var argv = 0;\n  if (argc > 0) {\n    argv = instance.exports.malloc(4 * argc);\n    for (var i in params) {\n      var param = params[i];\n      var arg = undefined;\n      if (Number.isInteger(param)) {\n        arg = instance.exports.malloc(4);\n        heap_set_int(arg, param);\n      }\n      else if (typeof param === 'string') {\n        var param_str = heap_malloc_string(param);        \n        arg = instance.exports.mono_string_new(_MonoDomain(), param_str)\n        instance.exports.free(param_str);\n      }\n      else {\n        throw \"unsupported param type\";\n      }\n      heap_set_int(argv + (i * 4), arg);\n    }\n  }\n  var res = instance.exports.mono_runtime_invoke(method, obj, argv);\n  if (argc > 0) {\n    //for (var i = 0; i < argc; i++) {\n    //  instance.exports.free(heap_get_int(argv + (i * 4)))\n    //}\n    instance.exports.free(argv);\n  }\n  //if (res) {\n  //  res = instance.exports.mono_object_unbox(res);\n  //}\n  return res;\n}\n\n// System calls.\n\nvar fds = {}\nfds[0] = undefined\nfds[1] = undefined\nfds[2] = undefined\n\nvar out_buffer = '';\n\nfunction out_buffer_add(ptr, len) {\n  out_buffer += heap_get_string(ptr, len)\n}\n\nfunction out_buffer_flush() {\n  if (out_buffer.charAt(out_buffer.length - 1) == '\\n') {\n    log(out_buffer.substr(0, out_buffer.length - 1))\n    out_buffer = ''\n  }\n}\n\nvar files_content = {}\nvar syscalls = {}\n\nsyscalls[3] = function SYS_read(fd, buf, len) {\n  var obj = fds[fd]\n  if (obj) {\n    debug('read(' + fd + ') -> ' + len) \n    offset = obj['offset']\n    buffer = obj['content']\n    heap.set(buffer.subarray(offset, offset + len), buf)   \n    return len\n  }\n  error('read() called with invalid fd ' + fd)\n  return -1\n}\n\nsyscalls[4] = function SYS_write(fd, buf, len) {\n  if (fd == 1 || fd == 2) {\n    out_buffer_add(buf, len)\n    out_buffer_flush()\n    return len\n  }\n  error('write() called with invalid fd ' + fd)\n}\n\nsyscalls[6] = function SYS_close(fd) {\n  var obj = fds[fd]\n  if (obj) {\n    fds[fd] = undefined\n    return 0\n  }\n  error('close() called with invalid fd ' + fd)\n  return -1\n}\n\nsyscalls[20] = function SYS_getpid() {\n  return 42\n}\n\nvar brk_current = 0\nsyscalls[45] = function SYS_brk(inc) {\n  if (inc == 0) {\n    brk_current = heap_size;\n    debug(\"brk: current heap \" + heap_human(brk_current))\n    return brk_current;\n  }\n  if (brk_current + inc > heap_size) {\n    var delta = inc - (heap_size - brk_current)\n    brk_current += inc\n    var new_pages_needed = Math.ceil(delta / 65536.0)\n    var memory = instance.exports.memory\n    var n = memory.grow(new_pages_needed);\n    var new_heap_size = memory.buffer.byteLength\n    debug(\"brk: pages \" + n + \" -> \" + (n + new_pages_needed) + \" (+\" + new_pages_needed + \"), heap \" + heap_human(heap_size) + \" -> \" + heap_human(new_heap_size) + \" (+\" + heap_human(new_heap_size - heap_size) + \")\")\n    heap = new Uint8Array(memory.buffer)\n    heap_size = new_heap_size\n  }\n  return inc\n}\n\nsyscalls[54] = function SYS_ioctl(fd, req, arg) {\n  // TODO\n  return 0\n}\n\nsyscalls[55] = function SYS_fcntl(fd, cmd, arg) {\n  if (cmd == 3) {\n    // F_GETFL\n    if (fd == 1 || fd == 2) {\n      return 1 // O_WRONLY\n    }\n    if (fd == 0 || fds[fd]) {\n      return 0 // O_RDONLY\n    }\n  }\n  error('fcntl() called with invalid fd ' + fd + ' and/or cmd ' + cmd)\n  return -1\n}\n\nsyscalls[76] = function SYS_getrlimit(resource, rlim) {\n  // TODO\n  return 0\n}\n\nsyscalls[85] = function SYS_readlink(path, buf, buflen) {\n  // TODO\n  debug('readlink(\"' + heap_get_string(path) + '\")')\n  return -1\n}\n\nsyscalls[146] = function SYS_writev(fd, iovs, iov_count) {\n  if (fd == 1 || fd == 2) {\n    var all_lens = 0\n    for (var i = 0; i < iov_count; i++) {\n      var base = heap_get_int(iovs + (i * 8))\n      var len = heap_get_int(iovs + 4 + (i * 8))\n      debug(\"write fd: \" + fd + \", base: \" + base + \", len: \" + len)\n      out_buffer_add(base, len)\n      all_lens += len\n    }\n    out_buffer_flush()\n    return all_lens\n  }\n  error(\"can only write on stdout and stderr\") \n  return -1\n}\n\nvar sizeof_k_sigaction = 20\nvar signals = {} // maps signal numbers to k_sigaction UInt8Array\nsyscalls[174] = function SYS_sigaction(sig, act, oact, mask_len) {\n  if (mask_len != 8) {\n    error('mask_len should be 8 (is ' + mask_len + ')')\n    mask_len = 8\n  }\n  sig_act = (signals[sig] || new Uint8Array(sizeof_k_sigaction))\n  if (oact != 0) {\n    heap.set(sig_act, oact)    \n  }\n  if (act != 0) {\n    sig_act.set(heap.slice(act, sizeof_k_sigaction)) \n  }\n  return 0\n}\n\nsyscalls[106] = function SYS_stat(path, s) {\n  var path_str = heap_get_string(path)\n  debug('stat(\"' + path_str + '\")')\n  if (path_str == \"/\") {\n    heap_set_int(s + 16, 0040000)   // st_mode -> S_IFDIR\n    return 0\n  }\n  for (var i in files) {\n    var file = \"/\" + files[i];\n    if (path_str == file) {\n      heap_set_int(s + 16, 0100000)   // st_mode -> S_IFREG\n      return 0\n    }\n  }\n  return -1\n}\n\nsyscalls[108] = function SYS_fstat(fd, s) {\n  var obj = fds[fd]\n  if (obj) {\n    var st_size = obj['content'].length\n    debug('fstat(' + fd + ') -> { st_size: ' + st_size + ' }')\n    heap_set_int(s + 40, st_size) // st_size\n    return 0\n  }\n  error('fstat() called with invalid fd ' + fd)\n  return -1\n}\n\nsyscalls[140] = function SYS_lseek(fd, unused, offset, result, whence) {\n  var obj = fds[fd]\n  if (obj) {\n    if (whence == 0) {\n      // SEEK_SET\n      obj['offset'] = offset\n    }\n    else if (whence == 1) {\n      // SEEK_CUR\n      offset = obj['offset']\n    }\n    else {\n      error('lseek() called with invalid whence ' + whence)\n      return -1\n    }\n    debug('lseek(' + fd + ', ...) -> ' + offset)\n    heap_set_long(result, offset)\n    return 0\n  }\n  error('lseek() called with invalid fd ' + fd)\n  return -1\n}\n\nsyscalls[175] = function SYS_sigprocmask(action, mask, set, sig_n) {\n  // TODO\n  return 0\n}\n\nsyscalls[183] = function SYS_getcwd(buf, buflen) {\n  if (buflen > 1) {\n    heap_set_string(buf, \"/\")\n    return 0\n  }\n  error('getcwd() called with buflen ' + buflen)\n  return -1\n}\n\nvar process_tid = 42 // Should fix this once we get multithreading\nsyscalls[224] = function SYS_gettid() {\n  return process_tid\n}\n\nsyscalls[219] = function SYS_madvise(addr, len, advice) {\n  if (advice == 4) {\n    // TODO\n    return 0\n  }\n  return -1\n}\n\nsyscalls[238] = function SYS_tkill(tid, signal) {\n  if (tid == process_tid) {\n    if (signal == 6) {\n      // SIGABRT\n      error(\"received SIGABRT\")\n      throw new TerminateWasmException('SIGABRT');\n    }\n    error('tkill() with unsupported signal: ' + signal)\n  }\n  else {\n    error('tkill() with wrong tid: ' + tid)\n  }\n  return -1\n}\n\nsyscalls[252] = function SYS_exit(code) {\n  log(\"exit(\" + code + \"): \" + new Error().stack)\n  throw new TerminateWasmException('exit(' + code + ')');\n}\n\nsyscalls[265] = function SYS_clock_gettime(clock_id, timespec) {\n  // TODO should switch to something else with a higher resolution + support\n  // the different CLOCK_ ids.\n  if (timespec) {\n    var ms = new Date().getTime()\n    var sec = Math.floor(ms / 1000)\n    var nsec = (ms % 1000) * 1000000\n    debug(\"clock_gettime: msec: \" + ms + \" -> sec: \" + sec + \", nsec: \"\n            + nsec)\n    heap_set_int(timespec, sec)        // tv_sec\n    heap_set_int(timespec + 4, nsec)   // tv_nsec\n  }\n  return 0;\n}\n\nsyscalls[266] = function SYS_clock_getred(clock_id, timespec) {\n  if (timespec) {\n    // Our gettime JS implementation has a 1ms resolution.\n    heap_set_int(timespec, 0)           // tv_sec\n    heap_set_int(timespec + 4, 1000000) // tv_nsec\n  }\n  return 0\n}\n\nsyscalls[295] = function SYS_openat(at, filename, flags, mode) {\n  if (at == -100) {\n    // AT_FDCWD\n    if (flags == 0100000) {\n      var filename_str = heap_get_string(filename)\n      var fd = -1\n      if (filename_str.charAt(0) == '/') {\n          filename_str = filename_str.substr(1)\n      }\n      if (files.indexOf(filename_str) != -1) {\n        var obj = {};\n        obj['offset'] = 0;\n        obj['path'] = filename_str;\n        var buf = files_content[filename_str]\n        if (!buf) {\n          buf = new Uint8Array(readbuffer(filename_str))\n          files_content[filename_str] = buf\n        } \n        obj['content'] = buf\n        fd = Object.keys(fds).length;\n        fds[fd] = obj;\n      }\n      debug('open(\"' + filename_str + '\") -> ' + fd);\n      return fd\n    }\n  }\n  error('openat() called with at ' + at + ' and flags ' + flags)\n  return -1\n}\n\nsyscalls[340] = function SYS_prlimit64(pid, resource, new_rlim, old_rlim) {\n  // TODO\n  return 0\n}\n\nsyscalls[375] = function SYS_membarrier() {\n  return 0\n}\n\nfunction route_syscall() {\n  n = arguments[0]\n  argv = [].slice.call(arguments, 1)\n  f = syscalls[n]\n  name = f ? f.name : n\n  debug('syscall(' + name + (argv.length > 0 ? ', ' + argv.join(', ') : '')\n              + ')')\n  if (!f) {\n    error('unimplemented syscall ' + n + ' called')\n    return -1\n  }\n  return f.apply(this, argv)\n}\n\nfor (var i in [0, 1, 2, 3, 4, 5, 6]) {\n  functions['env']['__syscall' + i] = route_syscall\n}\nfunctions['env']['__syscall_cp'] = route_syscall\n\nfunction run_wasm_code() {\n  heap = new Uint8Array(instance.exports.memory.buffer);\n  heap_size = instance.exports.memory.buffer.byteLength;\n  \n  if (dump_cross_offsets) {\n    // We don't care about freeing the memory as we exit soon after.\n    instance.exports.setenv(heap_malloc_string('DUMP_CROSS_OFFSETS'),\n            heap_malloc_string('1'), 1)\n  }\n \n  debug(\"running main()\")\n  var ret = instance.exports.mono_wasm_main(heap_malloc_string(files[0]),\n          debug_logs);\n  debug('main() returned: ' + ret);\n}\n\nif (browser_environment) {\n  fetch('index.wasm').then(function(response) {\n    return response.arrayBuffer()\n  }).then(function(buf) {\n    return WebAssembly.compile(buf)\n  }).then(function(mod) {\n    return WebAssembly.instantiate(mod, functions)\n  }).then(function(i) {\n    instance = i\n    var files_promises = [];\n    files.forEach(function(url, i) {\n      files_promises.push(\n        fetch(url).then(function(res){\n          return res.arrayBuffer();\n        }).then(function(buf){\n          files_content[url] = new Uint8Array(buf)\n        })\n      );\n    });\n    Promise.all(files_promises).then(function() {\n      run_wasm_code();\n      document.dispatchEvent(new Event('WebAssemblyContentLoaded'));\n    });\n  })\n}\nelse {\n  var module = new WebAssembly.Module(read('index.wasm', 'binary'))\n  instance = new WebAssembly.Instance(module, functions)\n  run_wasm_code()\n}\n"
  },
  {
    "path": "jsmin.c",
    "content": "/* jsmin.c\n   2013-03-29\n\nCopyright (c) 2002 Douglas Crockford  (www.crockford.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nThe Software shall be used for Good, not Evil.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#include <stdlib.h>\n#include <stdio.h>\n\nFILE *jsmin_in = NULL;\nFILE *jsmin_out = NULL;\n\nstatic int   theA;\nstatic int   theB;\nstatic int   theLookahead = EOF;\nstatic int   theX = EOF;\nstatic int   theY = EOF;\n\n\nstatic void\nerror(const char* s)\n{\n    fputs(\"JSMIN Error: \", stderr);\n    fputs(s, stderr);\n    fputc('\\n', stderr);\n    exit(1);\n}\n\n/* isAlphanum -- return true if the character is a letter, digit, underscore,\n        dollar sign, or non-ASCII character.\n*/\n\nstatic int\nisAlphanum(int c)\n{\n    return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||\n        (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\\\' ||\n        c > 126);\n}\n\n\n/* get -- return the next character from stdin. Watch out for lookahead. If\n        the character is a control character, translate it to a space or\n        linefeed.\n*/\n\nstatic int\nget()\n{\n    int c = theLookahead;\n    theLookahead = EOF;\n    if (c == EOF) {\n        c = getc(jsmin_in);\n    }\n    if (c >= ' ' || c == '\\n' || c == EOF) {\n        return c;\n    }\n    if (c == '\\r') {\n        return '\\n';\n    }\n    return ' ';\n}\n\n\n/* peek -- get the next character without getting it.\n*/\n\nstatic int\npeek()\n{\n    theLookahead = get();\n    return theLookahead;\n}\n\n\n/* next -- get the next character, excluding comments. peek() is used to see\n        if a '/' is followed by a '/' or '*'.\n*/\n\nstatic int\nnext()\n{\n    int c = get();\n    if  (c == '/') {\n        switch (peek()) {\n        case '/':\n            for (;;) {\n                c = get();\n                if (c <= '\\n') {\n                    break;\n                }\n            }\n            break;\n        case '*':\n            get();\n            while (c != ' ') {\n                switch (get()) {\n                case '*':\n                    if (peek() == '/') {\n                        get();\n                        c = ' ';\n                    }\n                    break;\n                case EOF:\n                    error(\"Unterminated comment.\");\n                }\n            }\n            break;\n        }\n    }\n    theY = theX;\n    theX = c;\n    return c;\n}\n\n\n/* action -- do something! What you do is determined by the argument:\n        1   Output A. Copy B to A. Get the next B.\n        2   Copy B to A. Get the next B. (Delete A).\n        3   Get the next B. (Delete B).\n   action treats a string as a single character. Wow!\n   action recognizes a regular expression if it is preceded by ( or , or =.\n*/\n\nstatic void\naction(int d)\n{\n    switch (d) {\n    case 1:\n        putc(theA, jsmin_out);\n        if (\n            (theY == '\\n' || theY == ' ') &&\n            (theA == '+' || theA == '-' || theA == '*' || theA == '/') &&\n            (theB == '+' || theB == '-' || theB == '*' || theB == '/')\n        ) {\n            putc(theY, jsmin_out);\n        }\n    case 2:\n        theA = theB;\n        if (theA == '\\'' || theA == '\"' || theA == '`') {\n            for (;;) {\n                putc(theA, jsmin_out);\n                theA = get();\n                if (theA == theB) {\n                    break;\n                }\n                if (theA == '\\\\') {\n                    putc(theA, jsmin_out);\n                    theA = get();\n                }\n                if (theA == EOF) {\n                    error(\"Unterminated string literal.\");\n                }\n            }\n        }\n    case 3:\n        theB = next();\n        if (theB == '/' && (\n            theA == '(' || theA == ',' || theA == '=' || theA == ':' ||\n            theA == '[' || theA == '!' || theA == '&' || theA == '|' ||\n            theA == '?' || theA == '+' || theA == '-' || theA == '~' ||\n            theA == '*' || theA == '/' || theA == '{' || theA == '\\n'\n        )) {\n            putc(theA, jsmin_out);\n            if (theA == '/' || theA == '*') {\n                putc(' ', jsmin_out);\n            }\n            putc(theB, jsmin_out);\n            for (;;) {\n                theA = get();\n                if (theA == '[') {\n                    for (;;) {\n                        putc(theA, jsmin_out);\n                        theA = get();\n                        if (theA == ']') {\n                            break;\n                        }\n                        if (theA == '\\\\') {\n                            putc(theA, jsmin_out);\n                            theA = get();\n                        }\n                        if (theA == EOF) {\n                            error(\"Unterminated set in Regular Expression literal.\");\n                        }\n                    }\n                } else if (theA == '/') {\n                    switch (peek()) {\n                    case '/':\n                    case '*':\n                        error(\"Unterminated set in Regular Expression literal.\");\n                    }\n                    break;\n                } else if (theA =='\\\\') {\n                    putc(theA, jsmin_out);\n                    theA = get();\n                }\n                if (theA == EOF) {\n                    error(\"Unterminated Regular Expression literal.\");\n                }\n                putc(theA, jsmin_out);\n            }\n            theB = next();\n        }\n    }\n}\n\n\n/* jsmin -- Copy the input to the output, deleting the characters which are\n        insignificant to JavaScript. Comments will be removed. Tabs will be\n        replaced with spaces. Carriage returns will be replaced with linefeeds.\n        Most spaces and linefeeds will be removed.\n*/\n\nvoid\njsmin(void)\n{\n    if (peek() == 0xEF) {\n        get();\n        get();\n        get();\n    }\n    theA = '\\n';\n    action(3);\n    while (theA != EOF) {\n        switch (theA) {\n        case ' ':\n            action(isAlphanum(theB) ? 1 : 2);\n            break;\n        case '\\n':\n            switch (theB) {\n            case '{':\n            case '[':\n            case '(':\n            case '+':\n            case '-':\n            case '!':\n            case '~':\n                action(1);\n                break;\n            case ' ':\n                action(3);\n                break;\n            default:\n                action(isAlphanum(theB) ? 1 : 2);\n            }\n            break;\n        default:\n            switch (theB) {\n            case ' ':\n                action(isAlphanum(theA) ? 1 : 3);\n                break;\n            case '\\n':\n                switch (theA) {\n                case '}':\n                case ']':\n                case ')':\n                case '+':\n                case '-':\n                case '\"':\n                case '\\'':\n                case '`':\n                    action(1);\n                    break;\n                default:\n                    action(isAlphanum(theA) ? 1 : 3);\n                }\n                break;\n            default:\n                action(1);\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "mono-wasm.cpp",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License. See the LICENSE.txt file in the project root\n// for the license information.\n\n#include <mach/mach_time.h>\n#include <sys/stat.h>\n#include <dirent.h>\n#include <libgen.h>\n\n#include <string>\n#include <vector>\n#include <memory>\n\n#include \"llvm/Analysis/TargetLibraryInfo.h\"\n#include \"llvm/ADT/STLExtras.h\"\n#include \"llvm/Bitcode/BitcodeReader.h\"\n#include \"llvm/Bitcode/BitcodeWriter.h\"\n#include \"llvm/IR/AutoUpgrade.h\"\n#include \"llvm/IR/DiagnosticInfo.h\"\n#include \"llvm/IR/DiagnosticPrinter.h\"\n#include \"llvm/IR/LegacyPassManager.h\"\n#include \"llvm/IR/LLVMContext.h\"\n#include \"llvm/IR/Module.h\"\n#include \"llvm/IR/ModuleSummaryIndex.h\"\n#include \"llvm/IR/Verifier.h\"\n#include \"llvm/IRReader/IRReader.h\"\n#include \"llvm/Linker/Linker.h\"\n#include \"llvm/Support/CommandLine.h\"\n#include \"llvm/Support/FileSystem.h\"\n#include \"llvm/Support/ManagedStatic.h\"\n#include \"llvm/Support/Path.h\"\n#include \"llvm/Support/PrettyStackTrace.h\"\n#include \"llvm/Support/Signals.h\"\n#include \"llvm/Support/SourceMgr.h\"\n#include \"llvm/Support/SystemUtils.h\"\n#include \"llvm/Support/TargetRegistry.h\"\n#include \"llvm/Support/TargetSelect.h\"\n#include \"llvm/Support/ToolOutputFile.h\"\n#include \"llvm/Target/TargetMachine.h\"\n#include \"llvm/Transforms/IPO/FunctionImport.h\"\n#include \"llvm/Transforms/IPO/Internalize.h\"\n#include \"llvm/Transforms/Utils/FunctionImportUtils.h\"\n\n#include \"lld/Common/Driver.h\"\n\n#define ERROR(...) \\\n    do { \\\n        fprintf(stderr, __VA_ARGS__); \\\n        exit(1); \\\n    } \\\n    while (0)\n\n#define _PATH_CHECK(path, iftype, what, must_exist) \\\n    ({ \\\n        struct stat s; \\\n        bool exists = false; \\\n        if (stat(path, &s) != 0) { \\\n            if (must_exist) { \\\n                ERROR(\"path `%s' does not exist\\n\", path); \\\n            } \\\n        } \\\n        else { \\\n            if ((s.st_mode & S_IFMT) != iftype) { \\\n                ERROR(\"path `%s' is not a %s\\n\", path, what); \\\n            } \\\n            exists = true; \\\n        } \\\n        exists; \\\n    })\n\n#define _FILE_CHECK(path, must_exist) \\\n    _PATH_CHECK(path, S_IFREG, \"file\", must_exist)\n#define FILE_MUST_EXIST(path) _FILE_CHECK(path, true)\n#define FILE_MAY_EXIST(path) _FILE_CHECK(path, false)\n\n#define _DIR_CHECK(path, must_exist) \\\n    _PATH_CHECK(path, S_IFDIR, \"directory\", must_exist)\n#define DIR_MUST_EXIST(path) _DIR_CHECK(path, true)\n#define DIR_MAY_EXIST(path) _DIR_CHECK(path, false)\n\nstatic int\ntimespec_cmp (struct timespec a, struct timespec b)\n{\n    return a.tv_sec < b.tv_sec\n        ? -1\n        : (a.tv_sec > b.tv_sec\n                ? 1 : a.tv_nsec - b.tv_nsec);\n}\n\n#define FILE_IS_OLDER(source_path, dest_path) \\\n    ({ \\\n        struct stat source_s; \\\n        assert(stat(source_path, &source_s) == 0); \\\n        struct stat dest_s; \\\n        stat(dest_path, &dest_s) == 0 \\\n            ? timespec_cmp(source_s.st_mtimespec, dest_s.st_mtimespec) > 0 \\\n            : true; \\\n    })\n\nstatic char libdir_path[PATH_MAX] = { 0 };\nstatic char bindir_path[PATH_MAX] = { 0 };\n\nstatic void\nsetup_paths(const char *arg0)\n{\n    char path[PATH_MAX];\n    snprintf(path, sizeof path, \"%s/../../lib\", arg0);\n    if (realpath(path, libdir_path) == NULL) {\n        ERROR(\"can't resolve `lib' directory\\n\");\n    }\n    DIR_MUST_EXIST(libdir_path);\n\n    snprintf(path, sizeof path, \"%s/..\", arg0);\n    if (realpath(path, bindir_path) == NULL) {\n        ERROR(\"can't resolve `bin' directory\\n\");\n    }\n    DIR_MUST_EXIST(bindir_path);\n}\n\nstatic void\ndiagnostic_handler(const llvm::DiagnosticInfo &DI, void *ctx)\n{\n    switch (DI.getSeverity()) {\n        case llvm::DS_Error:\n            llvm::errs() << \"ERROR: \";\n            break;\n        case llvm::DS_Warning:\n            llvm::errs() << \"WARNING: \";\n            break;\n        default:\n            break;\n    }\n\n    llvm::DiagnosticPrinterRawOStream DP(llvm::errs());\n    DI.print(DP);\n    llvm::errs() << '\\n';\n}\n\nstatic void\nassembly_link(std::vector<std::string> &assembly_paths,\n        const char *output_path)\n{\n    auto dest_base = std::string(output_path) + \"/\";\n\n    if (DIR_MAY_EXIST(output_path)) {\n        bool need_link = false;\n        for (auto assembly_path : assembly_paths) {\n            auto linked_path = dest_base + assembly_path;\n            if (FILE_IS_OLDER(assembly_path.c_str(), linked_path.c_str())) {\n                need_link = true;\n                break;\n            }\n        }\n        if (!need_link) {\n            goto skip_link;\n        }\n    }\n\n    char cmd[PATH_MAX];\n    snprintf(cmd, sizeof cmd, \"monolinker -d %s -c link -l none -o %s\",\n            libdir_path, output_path);\n\n    for (auto assembly_path : assembly_paths) {\n        strlcat(cmd, \" -a \", sizeof cmd);\n        strlcat(cmd, assembly_path.c_str(), sizeof cmd);\n    }\n\n    if (system(cmd) != 0) {\n        ERROR(\"monolinker pass failed (command was: %s)\\n\", cmd);\n    }\n\nskip_link:\n    char *first_assembly = strdup(basename((char *)assembly_paths[0].c_str()));\n    assert(first_assembly != NULL);\n    assembly_paths.clear();\n    DIR *dir = opendir(output_path);\n    assert(dir != NULL);\n    struct dirent *entry;\n    int i = 0, first_assembly_i = -1;\n    while ((entry = readdir(dir)) != NULL) {\n        const char *s = entry->d_name;\n        size_t sl = strlen(s);\n        if (sl > 4) {\n            const char *sp = s + sl - 4;\n            if (strcmp(sp, \".exe\") == 0 || strcmp(sp, \".dll\") == 0) {\n                auto linked_path = dest_base + s;\n                assembly_paths.push_back(linked_path);\n                if (strcmp(s, first_assembly) == 0) {\n                    first_assembly_i = i;\n                }\n                i++;\n            }\n        }\n    }\n    closedir(dir);\n    // The first assembly path must remain the same given to the command line.\n    assert (first_assembly_i >= 0);\n    if (first_assembly_i > 0) {\n        std::iter_swap(assembly_paths.begin() + first_assembly_i,\n                assembly_paths.begin());\n    }\n    free(first_assembly);\n}\n\nstatic std::string\nassembly_compile(std::string assembly_path, const char *build_dir,\n        std::string bitcode_path)\n{\n    static char monoc_path[PATH_MAX] = { '\\0' };\n    if (monoc_path[0] == '\\0') {\n        snprintf(monoc_path, sizeof monoc_path, \"%s/monoc\", bindir_path);\n        FILE_MUST_EXIST(monoc_path);\n    }\n\n    if (FILE_IS_OLDER(assembly_path.c_str(), bitcode_path.c_str())) {\n        char cmd[PATH_MAX];\n        snprintf(cmd, sizeof cmd,\n                \"MONO_PATH=\\\"%s\\\" MONO_ENABLE_COOP=1 \" \\\n                \"%s --aot=asmonly,llvmonly,static,llvm-outfile=%s %s \" \\\n                \">& /dev/null\",\n                build_dir, monoc_path, bitcode_path.c_str(),\n                assembly_path.c_str());\n\n        if (system(cmd) != 0) {\n            ERROR(\"bitcode compilation for `%s' failed \" \\\n                    \"(command was: %s)\\n\", assembly_path.c_str(), cmd);\n        }\n    }\n\n    return bitcode_path;\n}\n\nstatic std::unique_ptr<llvm::Module>\nbitcode_link(std::vector<std::string> &paths, llvm::LLVMContext &context)\n{\n    auto module = llvm::make_unique<llvm::Module>(\"index.bc\", context);\n    llvm::Linker linker(*module);\n\n    for (auto path : paths) {\n        llvm::SMDiagnostic err;\n        auto file_module = llvm::parseIRFile(path, err, context);\n        if (!file_module) {\n            ERROR(\"bitcode parsing error: %s:%d: %s\\n\",\n                    err.getFilename().str().c_str(), err.getLineNo(),\n                    err.getMessage().str().c_str());\n        }\n\n        if (linker.linkInModule(std::move(file_module),\n                    llvm::Linker::Flags::OverrideFromSrc)) {\n            ERROR(\"linking %s failed\\n\", path.c_str());\n        }\n    }\n\n    return module;\n}\n\nstatic llvm::Module *\naot_init_gen(std::vector<std::string> &assembly_paths, llvm::Module *module,\n        llvm::LLVMContext &context)\n{\n    if (module == NULL) {\n        module = new llvm::Module(\"aot_init.bc\", context);\n    }\n\n    auto ptr_ty = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(context));\n\n    auto register_f = module->getFunction(\"mono_aot_register_module\");\n    if (register_f == NULL) {\n        std::vector<llvm::Type *> types;\n        types.push_back(ptr_ty);\n        auto c = module->getOrInsertFunction(\"mono_aot_register_module\",\n                llvm::FunctionType::get(llvm::Type::getVoidTy(context),\n                    types, false));\n        register_f = llvm::cast<llvm::Function>(c);\n    }\n\n    auto c = module->getOrInsertFunction(\"mono_wasm_aot_init\",\n            llvm::FunctionType::get(llvm::Type::getVoidTy(context), false));\n    auto f = llvm::cast<llvm::Function>(c);\n    auto bb = llvm::BasicBlock::Create(context, \"entry\", f);\n\n    for (auto path : assembly_paths) {\n        // /<build-dir>/foo.{exe,dll} -> mono_aot_module_foo_info\n        assert(path.size() > 4);\n        assert(path[path.size() - 4] == '.');\n        size_t beg = path.rfind('/');\n        assert(beg != std::string::npos);\n        beg++;\n\n        auto name = std::string(\"mono_aot_module_\")\n            + path.substr(beg, path.size() - beg - 4) + \"_info\";\n\n        auto aot_info = module->getGlobalVariable(name.c_str());\n        if (aot_info == NULL) {\n            auto c = module->getOrInsertGlobal(name.c_str(), ptr_ty);\n            aot_info = llvm::cast<llvm::GlobalVariable>(c);\n        }\n\n        llvm::CallInst::Create(register_f,\n                new llvm::LoadInst(aot_info, \"\", bb), \"\", bb);\n    }\n\n    llvm::ReturnInst::Create(context, bb);\n\n    return module;\n}\n\nstatic void\nwasm_codegen(llvm::Module *module, llvm::CodeGenOpt::Level opt_level,\n        llvm::LLVMContext &context, std::string wasm_path)\n{\n    static bool init_done = false;\n    if (!init_done) {\n        LLVMInitializeWebAssemblyTarget();\n        LLVMInitializeWebAssemblyTargetMC();\n        LLVMInitializeWebAssemblyTargetInfo();\n        LLVMInitializeWebAssemblyAsmPrinter();\n        init_done = true;\n    }\n\n    // Important to generate a proper wasm object file.\n    module->setTargetTriple(\"wasm32-unknown-unknown-wasm\");\n\n    std::string err;\n    auto triple = llvm::Triple(module->getTargetTriple());\n    auto target = llvm::TargetRegistry::lookupTarget(\"wasm32\", triple, err);\n    if (target == NULL) {\n        ERROR(\"can't lookup wasm32 target: %s\\n\", err.c_str());\n    }\n\n    std::string cpu_str = \"\";\n    std::string features_str = \"\";\n    llvm::TargetOptions options;\n    options.MCOptions.AsmVerbose = false;\n\n    auto target_machine = target->createTargetMachine(triple.getTriple(),\n            cpu_str, features_str, options, llvm::None,\n            llvm::CodeModel::Large, opt_level);\n\n    if (target_machine == NULL) {\n        ERROR(\"couldn't allocate target machine\\n\");\n    }\n\n    llvm::legacy::PassManager pm;\n    pm.add(new llvm::TargetLibraryInfoWrapperPass(\n                llvm::TargetLibraryInfoImpl(triple)));\n\n    module->setDataLayout(target_machine->createDataLayout());\n\n    std::error_code EC;\n    llvm::raw_fd_ostream dest(wasm_path, EC, llvm::sys::fs::F_None);\n    if (EC) {\n        ERROR(\"error when opening file %s: %s\\n\", wasm_path.c_str(),\n                EC.message().c_str());\n    }\n\n    if (target_machine->addPassesToEmitFile(pm, dest,\n                llvm::TargetMachine::CGFT_ObjectFile)) {\n        ERROR(\"target does not support assembly generation\\n\");\n    }\n\n    pm.run(*module);\n    dest.flush();\n}\n\nstatic void\nwasm_codegen2(std::string &bitcode_path, llvm::CodeGenOpt::Level opt,\n        llvm::LLVMContext &context, std::string wasm_path)\n{\n    if (FILE_IS_OLDER(bitcode_path.c_str(), wasm_path.c_str())) {\n        llvm::SMDiagnostic err;\n        auto module = llvm::parseIRFile(bitcode_path, err, context);\n        if (!module) {\n            ERROR(\"parsing bitcode file `%s' failed: %s:%d: %s\\n\",\n                    bitcode_path.c_str(), err.getFilename().str().c_str(),\n                    err.getLineNo(), err.getMessage().str().c_str());\n        }\n\n        wasm_codegen(module.get(), opt, context, wasm_path);\n    }\n}\n\nstatic void\nwasm_link(std::vector<std::string> &paths, std::string output,\n        bool strip_debug_info)\n{\n    std::vector<const char *> args;\n    args.push_back(\"wasm-lld\");\n    for (auto path : paths) {\n        args.push_back(strdup(path.c_str()));\n    }\n    args.push_back(\"-o\");\n    args.push_back(output.c_str());\n    args.push_back(\"--allow-undefined\");\n    args.push_back(\"--no-entry\");\n    if (strip_debug_info) {\n        args.push_back(\"--strip-debug\");\n    }\n\n    if (!lld::wasm::link(args, false)) {\n        ERROR(\"failed to link wasm files\\n\");\n    }\n\n    for (int i = 0; i < paths.size(); i++) {\n        free((char *)args[i + 1]);\n    }\n}\n\nstatic void\nassembly_strip(std::vector<std::string> &paths, const char *output_path)\n{\n    for (auto path : paths) {\n        const char *base = strrchr(path.c_str(), '/');\n        assert(base != NULL);\n\n        char cmd[PATH_MAX];\n        snprintf(cmd, sizeof cmd, \"mono-cil-strip %s %s%s >& /dev/null\",\n                path.c_str(), output_path, base);\n\n        if (system(cmd) != 0) {\n            ERROR(\"IL strip for `%s' failed (command was: %s)\\n\",\n                    path.c_str(), cmd);\n        }\n    }\n}\n\nextern \"C\" {\n    extern FILE *jsmin_in;\n    extern FILE *jsmin_out;\n    void jsmin(void);\n}\n\nstatic void\njs_gen(std::vector<std::string> &assembly_paths, const char *output_path)\n{\n    auto index_js = std::string(libdir_path) + \"/index.js\";\n    FILE_MUST_EXIST(index_js.c_str());\n\n    auto output_index_js = std::string(output_path) + \"/index.js\";\n    FILE *output = fopen(output_index_js.c_str(), \"w+\");\n    if (output == NULL) {\n        ERROR(\"can't open `%s': %s\\n\", output_index_js.c_str(),\n                strerror(errno));\n    }\n\n    fprintf(output, \"var files=[\");\n    for (auto path : assembly_paths) {\n        const char *base = strrchr(path.c_str(), '/');\n        assert(base != NULL);\n        fprintf(output, \"\\\"%s\\\",\", base + 1);\n    }\n    fprintf(output, \"];\");\n\n    jsmin_in = fopen(index_js.c_str(), \"r\");\n    jsmin_out = output;\n\n    jsmin();\n\n    fclose(jsmin_in);\n    fclose(output);\n\n    jsmin_in = NULL;\n    jsmin_out = NULL;\n}\n\nstatic std::string\nswap_extension(std::string path, const char *new_extension)\n{\n    auto pos = path.rfind('.');\n    if (pos != std::string::npos) {\n        assert(pos > 0);\n        path = path.substr(0, pos);\n    }\n    return path + new_extension;\n}\n\nint\nmain(int argc, char **argv)\n{\n    if (argc < 2) {\n        ERROR(\"Usage: %s [options] <input files>\\n\\n\" \\\n                \"Options:\\n\" \\\n                \"    -b <directory>        Specify build directory\\n\" \\\n                \"                          (default is `./build')\\n\" \\\n                \"    -o <directory>        Specify output directory\\n\" \\\n                \"    -On                   Specify optimization level\\n\" \\\n                \"                          (0, 1, 2, 3, default is 2)\\n\" \\\n                \"    --strip-debug         Strip debugging information\\n\" \\\n                \"    -v                    Verbose output\\n\" \\\n                \"    -i                    Incremental build (experimental)\\n\",\n                argv[0]);\n    }\n\n    const char *build_path = \"./build\";\n    const char *output_path = NULL;\n    llvm::CodeGenOpt::Level opt = llvm::CodeGenOpt::Default;\n    bool strip_debug_info = false;\n    bool verbose = false;\n    bool incremental = false;\n    std::vector<std::string> assembly_paths, bitcode_paths, wasm_paths;\n    for (int i = 1; i < argc; i++) {\n        const char *arg = argv[i];\n        if (arg[0] == '-') {\n            if (arg[1] == 'b' && arg[2] == '\\0') {\n                i++;\n                if (i >= argc) {\n                    ERROR(\"expected value for `-b' option\\n\");\n                }\n                build_path = argv[i];\n            }\n            else if (arg[1] == 'o' && arg[2] == '\\0') {\n                i++;\n                if (i >= argc) {\n                    ERROR(\"expected value for `-o' option\\n\");\n                }\n                output_path = argv[i];\n            }\n            else if (arg[1] == 'v' && arg[2] == '\\0') {\n                verbose = true;\n            }\n            else if (arg[1] == 'i' && arg[2] == '\\0') {\n                incremental = true;\n            }\n            else if (arg[1] == 'O' && arg[3] == '\\0') {\n                switch (arg[2]) {\n                    case '0':\n                        opt = llvm::CodeGenOpt::None;\n                        break;\n                    case '1':\n                        opt = llvm::CodeGenOpt::Less;\n                        break;\n                    case '2':\n                        opt = llvm::CodeGenOpt::Default;\n                        break;\n                    case '3':\n                        opt = llvm::CodeGenOpt::Aggressive;\n                        break;\n                    default:\n                        ERROR(\"malformed `-On' option\\n\");\n                }\n            }\n            else if (strcmp(arg, \"--strip-debug\") == 0) {\n                strip_debug_info = true;\n            }\n            else {\n                ERROR(\"invalid `%s' option\\n\", arg);\n            }\n        }\n        else {\n            assembly_paths.push_back(arg);\n        }\n    }\n    if (output_path == NULL) {\n        ERROR(\"`-o' option required\\n\");\n    }\n    if (assembly_paths.size() == 0) {\n        ERROR(\"at least one input file is required\\n\");\n    }\n\n    setup_paths(argv[0]);\n\n    if (!DIR_MAY_EXIST(output_path)) {\n        if (mkdir(output_path, 0755) != 0) {\n            ERROR(\"can't create output directory `%s': %s\\n\",\n                    output_path, strerror(errno));\n        }\n    }\n\n    auto output_wasm = std::string(output_path) + \"/index.wasm\";\n\n    llvm::LLVMContext context;\n    context.setDiagnosticHandlerCallBack(diagnostic_handler, NULL, true);\n\n    uint64_t start = 0, total = 0, delta = 0;\n    mach_timebase_info_data_t timebase_info;\n    mach_timebase_info(&timebase_info);\n\n#define T_MEASURE(what, code) \\\n    start = mach_absolute_time(); \\\n    if (verbose) { \\\n        std::string _what = what; \\\n        printf(\"%s ... \", _what.c_str()); \\\n    } \\\n    code; \\\n    delta = mach_absolute_time() - start; \\\n    total += delta; \\\n    if (verbose) { \\\n        printf(\"%.3fs\\n\", (((double)(delta) * timebase_info.numer) \\\n                    / (timebase_info.denom * 1000000000))); \\\n    }\n\n    T_MEASURE(\"IL link\", assembly_link(assembly_paths, build_path));\n\n    bitcode_paths.push_back(std::string(libdir_path) + \"/runtime.bc\");\n    for (auto assembly_path : assembly_paths) {\n        auto bitcode_path = swap_extension(assembly_path, \".bc\");\n        T_MEASURE(std::string(\"IL/IR compile \") + assembly_path,\n                assembly_compile(assembly_path, build_path, bitcode_path));\n        bitcode_paths.push_back(bitcode_path);\n    }\n\n    if (incremental) {\n        for (auto bitcode_path : bitcode_paths) {\n            auto wasm_path = swap_extension(bitcode_path, \".wasm\");\n            T_MEASURE(std::string(\"IR/WASM codegen \")\n                    + bitcode_path.c_str(),\n                    wasm_codegen2(bitcode_path, opt, context, wasm_path));\n            wasm_paths.push_back(wasm_path);\n        }\n\n        auto path = std::string(build_path) + \"/aot_init.wasm\";\n        auto aot_init_mod = aot_init_gen(assembly_paths, NULL, context);\n        wasm_codegen(aot_init_mod, opt, context, path);\n        wasm_paths.push_back(path);\n        delete aot_init_mod;\n    }\n    else {\n        T_MEASURE(\"IR link\",\n                auto module = bitcode_link(bitcode_paths, context));\n\n        aot_init_gen(assembly_paths, module.get(), context);\n\n        auto path = std::string(build_path) + \"/index.wasm\";\n        T_MEASURE(\"IR/WASM codegen\",\n                wasm_codegen(module.get(), opt, context, path));\n        wasm_paths.push_back(path);\n    }\n\n    T_MEASURE(\"WASM link\",\n            wasm_link(wasm_paths, output_wasm, strip_debug_info));\n\n    T_MEASURE(\"IL strip\", assembly_strip(assembly_paths, output_path));\n\n    T_MEASURE(\"JS gen\", js_gen(assembly_paths, output_path));\n\n#undef T_MEASURE\n\n    return 0;\n}\n"
  },
  {
    "path": "mscorlib.xml",
    "content": "<linker>\n  <assembly fullname=\"mscorlib\">\n  </assembly>\n</linker>\n"
  },
  {
    "path": "sample/hello/.gitignore",
    "content": "build\noutput\nhello.exe\n"
  },
  {
    "path": "sample/hello/Makefile",
    "content": "all: hello.exe output/index.wasm output/index.html\n\nhello.exe:      hello.cs\n\tmcs -nostdlib -noconfig -r:../../dist/lib/mscorlib.dll hello.cs -out:hello.exe\n\noutput/index.wasm:      hello.exe\n\t../../dist/bin/mono-wasm -i hello.exe -o output\n\noutput/index.html:      index.html\n\tcp index.html output\n\nclean:\n\trm -rf build output hello.exe\n"
  },
  {
    "path": "sample/hello/hello.cs",
    "content": "class Hello {\n  static int Main(string[] args) {\n    System.Console.WriteLine(\"hello world!\");\n    return 0;\n  }\n}\n"
  },
  {
    "path": "sample/hello/index.html",
    "content": "<!DOCTYPE html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title>WebAssembly Example</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" href=\"styles.css\">\n  </head>\n  <body>\n    <script src=\"index.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "sample/hello2/.gitignore",
    "content": "build\noutput\nhello.exe\n"
  },
  {
    "path": "sample/hello2/Makefile",
    "content": "all: hello.exe output/index.wasm output/index.html\n\nhello.exe:      hello.cs\n\tmcs -nostdlib -noconfig -r:../../dist/lib/mscorlib.dll hello.cs -out:hello.exe\n\noutput/index.wasm:      hello.exe\n\t../../dist/bin/mono-wasm -i hello.exe -o output\n\noutput/index.html:      index.html\n\tcp index.html output\n\nclean:\n\trm -rf build output hello.exe\n"
  },
  {
    "path": "sample/hello2/hello.cs",
    "content": "using Mono.WebAssembly;\nusing System;\n\nclass Hello\n{\n    static int Factorial(int n)\n    {\n        if (n == 0) {\n            return 1;\n        }\n        return n * Factorial(n - 1);\n    }\n\n    // This function is called from the browser by JavaScript.\n    // Here we calculate the factorial of the given number then use the\n    // Mono.WebAssembly API to retrieve the element from the DOM and set its\n    // innerText property to the factorial result.\n    static void FactorialInElement(int n, string element_id)\n    {\n        Console.WriteLine(\n                \"Calculating factorial of {0} into DOM element {1}\",\n                n, element_id);\n\n        int f = Factorial(n);\n\n        var elem = HtmlPage.Document.GetElementById(element_id);\n        elem.InnerText = f.ToString();\n    }\n\n    static void PrintHtmlElements(HtmlElement elem, int level)\n    {\n        string str = \"\";\n        for (int i = 0; i < level; i++) {\n            str += \"  \";\n        }\n\n        str += $\"<{elem.TagName}\";\n\n        foreach (var name in elem.AttributeNames) {\n            var value = elem.GetAttribute(name);\n            str += $\" {name}='{value}'\";\n        }\n\n        str += \">\";\n\n        Console.WriteLine(str);\n\n        var list = elem.Children;\n        for (int i = 0; i < list.Count; i++) {\n            var child = list[i];\n            PrintHtmlElements(child, level + 1);\n        }\n    }\n\n    static int Main(string[] args)\n    {\n        int f = Factorial(6);\n        HtmlPage.Window.Alert($\"Hello world! factorial(6) -> {f}\");\n\n        var bi = HtmlPage.BrowserInformation;\n        Console.WriteLine($\"BrowserInformation: Name {bi.Name} BrowserVersion {bi.BrowserVersion} UserAgent {bi.UserAgent} Platform {bi.Platform} CookiesEnabled {bi.CookiesEnabled} ProductName {bi.ProductName}\");\n\n        var d = HtmlPage.Document;\n        Console.WriteLine($\"Document Location: {d.Location}\");\n\n        PrintHtmlElements(d.DocumentElement, 0);\n\n        var p = d.CreateElement(\"p\");\n        p.InnerText = \"This text was added at runtime.\";\n        d.Body.AppendChild(p);\n\n        if (args.Length > 0) FactorialInElement(0, \"\"); // this is a hack so that the linker does not remove the FactorialInElement() method\n\n        return f;\n    }\n}\n"
  },
  {
    "path": "sample/hello2/index.html",
    "content": "<!DOCTYPE html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title>WebAssembly Example</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" href=\"styles.css\">\n  </head>\n  <body>\n    <p>\n      <form name=\"factorial_form\" onSubmit=\"return factorial_submit()\">\n        Number: <input type=\"text\" name=\"input\" value=\"6\"/>\n        <br/><br/>\n        Result: <span id=\"factorial_result\">...</span>\n        <br/><br/>\n        <input name=\"Submit\"  type=\"submit\" value=\"Calculate\"/>\n      </form>\n    </p>\n    <script src=\"index.js\"></script>\n    <script>\n      function factorial_submit() {\n        // This function is called by the form. We now call into the\n        // Hello.FactorialInElement() C# method, passing the input (a number)\n        // and the element ID which should be set with the result (here, the\n        // <span> element defined above. \n        var input = document.forms[\"factorial_form\"][\"input\"].value;\n        var klass = MonoClass(\"\", \"Hello\");\n        if (klass) {\n          var method = MonoMethod(klass, \"FactorialInElement\", true);\n          if (method) {\n            MonoInvoke(0, method, [parseInt(input), \"factorial_result\"]);\n          }\n        }\n        return false;\n      }\n\n      document.addEventListener('WebAssemblyContentLoaded', function() {\n        // Calculate the initial form value.\n        factorial_submit();\n      }, false);\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "tests/Mono.WebAssembly/Makefile",
    "content": "all: run\n\ntest.exe:      test.cs\n\tmcs -nostdlib -noconfig -r:../../dist/lib/mscorlib.dll test.cs -out:test.exe\n\noutput/index.wasm:      test.exe\n\t../../dist/bin/mono-wasm -g test.exe -o output\n\nrun:    output/index.wasm\n\tcp index.html output\n\t(cd output && python -m SimpleHTTPServer 9000)\n"
  },
  {
    "path": "tests/Mono.WebAssembly/index.html",
    "content": "<!DOCTYPE html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <title>WebAssembly Example</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" href=\"styles.css\">\n  </head>\n  <body>\n    <script src=\"index.js\"></script>\n    <span id=\"span-id\">span-id text</span>\n    <div class=\"my-class container\">\n      <div class=\"my-class\">my-class-container</div>\n      <span>text</span>\n    </div>\n    <p/>\n    <div class=\"my-class\"></div>\n    <p/>\n    <div class=\"my-class\"></div>\n    <p/>\n  </body>\n</html>\n\n"
  },
  {
    "path": "tests/Mono.WebAssembly/test.cs",
    "content": "using Mono.WebAssembly;\nusing System;\n\nclass Test\n{\n    int count = 0;\n    int failures = 0;\n\n    void _assert(bool condition, string msg)\n    {\n        if (condition) {\n            count++;        \n        }\n        else {\n            Console.WriteLine(msg);\n            failures++;\n        }\n    }\n\n    void assert(bool condition)\n    {\n        _assert(condition, $\"assertion {count} failed\");\n    }\n\n    void assert_Equals(object obj1, object obj2)\n    {\n        _assert(((obj1 == null && obj2 == null) || obj1.Equals(obj2)),\n                $\"assertion {count} failed: `{obj1}' should be equal to `{obj2}'\");\n    }\n\n    void test_Runtime()\n    {\n        assert_Equals(Runtime.JavaScriptEval(\"1+2\") , \"3\");\n\n        assert_Equals(Runtime.JavaScriptEval(\"var x = 42; x\"), \"42\");\n\n        assert_Equals(Runtime.JavaScriptEval(\n                    \"(function(x, y) { return x + y; })(40, 2);\"), \"42\");\n    }\n\n    void test_BrowserInformation()\n    {\n        var bi = HtmlPage.BrowserInformation;\n\n        assert_Equals(bi.Name, \"Netscape\");\n        assert(bi.BrowserVersion.Contains(\"5.0\"));\n        assert(bi.UserAgent.Contains(\"Firefox\")\n                || bi.UserAgent.Contains(\"Chrome\")\n                || bi.UserAgent.Contains(\"Safari\"));\n        assert_Equals(bi.Platform, \"MacIntel\");\n        assert_Equals(bi.CookiesEnabled, true);\n        assert_Equals(bi.ProductName, \"Mozilla\");\n    }\n\n    void test_HtmlDocument()\n    {\n        var doc = HtmlPage.Document;\n\n        var root = doc.DocumentElement;\n        assert_Equals(root.TagName, \"HTML\");\n        assert_Equals(doc.GetElementsByTagName(\"html\")[0], root);\n        assert_Equals(root.Parent, null);\n\n        var body = doc.Body;\n        assert_Equals(body.TagName, \"BODY\");\n        assert_Equals(doc.GetElementsByTagName(\"body\")[0], body);\n        assert_Equals(body.Parent, root);\n\n        // We can't use `Contains()' or even `foreach' yet due to a compiler\n        // limitation.\n        bool found_body_in_root_children = false;\n        var root_children = root.Children;\n        for (int i = 0, len = root_children.Count; i < len; i++) {\n            var child = root_children[i];\n            if (child.Equals(body)) {\n                found_body_in_root_children = true;\n                break;\n            }\n        }\n        assert(found_body_in_root_children);\n\n        var span_id = doc.GetElementById(\"span-id\");\n        assert(span_id != null);\n        assert_Equals(span_id.TagName, \"SPAN\");\n        assert_Equals(span_id.Id, \"span-id\");\n        assert_Equals(span_id.Parent, body);\n        assert_Equals(span_id.InnerText, \"span-id text\");\n\n        assert_Equals(doc.GetElementById(\"does-not-exist\"), null);\n\n        var elem = doc.CreateElement(\"span\");\n        elem.Id = \"span-id2\";\n        assert_Equals(elem.TagName, \"SPAN\");\n        assert_Equals(elem.Parent, null);\n        body.AppendChild(elem);\n        assert_Equals(elem.Parent, body);\n        assert_Equals(doc.GetElementById(\"span-id2\"), elem);\n        body.RemoveChild(elem);\n        assert_Equals(elem.Parent, null);\n        assert_Equals(doc.GetElementById(\"span-id2\"), null);\n    }\n\n    void test_HtmlNode()\n    {\n        var doc = HtmlPage.Document;\n\n        assert_Equals(doc.GetElementsByTagName(\"does-not-exist\").Count, 0);\n        assert_Equals(doc.Body.GetElementsByTagName(\"does-not-exist\").Count, 0);\n\n        assert_Equals(doc.GetElementsByTagName(\"p\").Count, 3);\n        assert_Equals(doc.Body.GetElementsByTagName(\"p\").Count, 3);\n\n        assert_Equals(doc.GetElementsByClassName(\"my-class\").Count, 4);\n        assert_Equals(doc.Body.GetElementsByClassName(\"my-class\").Count, 4);\n        var ary = doc.GetElementsByClassName(\"container\");\n        var ary2 = doc.Body.GetElementsByClassName(\"container\");\n        assert_Equals(ary.Count, 1);\n        assert_Equals(ary2.Count, 1);\n        var container = ary[0];\n        assert_Equals(container, ary2[0]);\n        assert_Equals(container.GetElementsByClassName(\"my-class\").Count, 1);\n        assert_Equals(container.InnerText, \"my-class-container\\ntext\");\n\n        var ary3 = container.GetElementsByTagName(\"span\");\n        assert_Equals(ary3.Count, 1);\n        ary3[0].InnerText = \"42\";\n        assert_Equals(container.InnerText, \"my-class-container\\n42\");\n\n        assert_Equals(doc.QuerySelector(\".does-not-exist\"), null);\n        assert_Equals(doc.Body.QuerySelector(\".does-not-exist\"), null);\n\n        var elem = doc.QuerySelector(\".my-class\");\n        assert(elem != null);\n        assert_Equals(elem, doc.QuerySelector(\".container\"));\n        assert_Equals(elem, doc.Body.QuerySelector(\".my-class\"));\n        assert_Equals(elem, doc.Body.QuerySelector(\".container\"));\n\n        var ary4 = doc.QuerySelectorAll(\".my-class\");\n        var ary5 = doc.Body.QuerySelectorAll(\".my-class\");\n        assert_Equals(ary4.Count, 4);\n        assert_Equals(ary5.Count, 4);\n        assert_Equals(ary4[0], elem);\n        assert_Equals(ary5[0], elem);\n\n        assert_Equals(doc.QuerySelector(\".container span\"), ary3[0]);\n    }\n\n    void test_HtmlElement()\n    {\n        var doc = HtmlPage.Document;\n\n        var elem = doc.CreateElement(\"div\");\n        assert_Equals(elem.TagName, \"DIV\");\n        assert_Equals(elem.ClassName, \"\");\n        assert_Equals(elem.Id, \"\");\n        assert_Equals(elem.Parent, null);\n        assert_Equals(elem.Children.Count, 0);\n        assert_Equals(elem.AttributeNames.Length, 0);\n        assert_Equals(elem.InnerText, \"\");\n\n        elem.InnerText = \"foo\";\n        assert_Equals(elem.InnerText, \"foo\");\n\n        assert_Equals(elem.GetAttribute(\"does-not-exist\"), null);\n\n        elem.ClassName = \"my-class\";\n        assert_Equals(elem.ClassName, \"my-class\");\n        assert_Equals(elem.AttributeNames.Length, 1);\n        assert_Equals(elem.AttributeNames[0], \"class\");\n        assert_Equals(elem.GetAttribute(\"class\"), \"my-class\");\n\n        elem.SetAttribute(\"id\", \"my-id\");\n        assert_Equals(elem.Id, \"my-id\");\n        assert_Equals(elem.AttributeNames.Length, 2);\n\n        elem.RemoveAttribute(\"id\");\n        assert_Equals(elem.Id, \"\");\n        assert_Equals(elem.AttributeNames.Length, 1);\n\n        var ary = doc.GetElementsByTagName(\"script\");\n        assert_Equals(ary.Count, 1);\n        var elem2 = ary[0];\n        assert_Equals(elem2.AttributeNames.Length, 1);\n        assert_Equals(elem.AttributeNames[0], \"src\");\n        assert_Equals(elem.GetAttribute(\"src\"), \"index.js\");\n    }\n\n    void run_tests()\n    {\n        test_Runtime();\n        test_BrowserInformation();\n        test_HtmlDocument();\n        test_HtmlNode();\n        test_HtmlElement();\n\n        if (failures == 0) {\n            Console.WriteLine(\"All tests ({0}) successful\", count);\n        }\n        else {\n            Console.WriteLine(\"Tests ran with {0} failures\", failures);\n        }\n    }\n\n    static void Main()\n    {\n        var r = new Test();\n        r.run_tests();\n    }\n}\n"
  }
]