Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eng/liveBuilds.targets2
-rw-r--r--src/installer/pkg/projects/netcoreapp/src/netcoreapp.depproj7
-rw-r--r--src/libraries/pretest.proj8
-rw-r--r--src/libraries/restore/runtime/runtime.depproj3
-rw-r--r--src/mono/mono.proj21
-rw-r--r--src/mono/msbuild/WasmAppBuilder/PInvokeTableGenerator.cs146
-rw-r--r--src/mono/msbuild/WasmAppBuilder/WasmAppBuilder.csproj16
-rw-r--r--src/mono/wasm/Makefile100
-rw-r--r--src/mono/wasm/runtime/binding_support.js1277
-rw-r--r--src/mono/wasm/runtime/corebindings.c179
-rw-r--r--src/mono/wasm/runtime/dotnet_support.js96
-rw-r--r--src/mono/wasm/runtime/driver.c759
-rw-r--r--src/mono/wasm/runtime/library_mono.js1000
-rw-r--r--src/mono/wasm/runtime/linker-preserves.xml7
-rw-r--r--src/mono/wasm/wasm.proj46
15 files changed, 3665 insertions, 2 deletions
diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets
index 920392bae32..6462ef23da4 100644
--- a/eng/liveBuilds.targets
+++ b/eng/liveBuilds.targets
@@ -137,6 +137,8 @@
Include="$(MonoArtifactsPath)\cross\*.*" />
<MonoIncludeFiles Condition="'$(TargetsMobile)' == 'true' or '$(TargetOS)' == 'Browser'"
Include="$(MonoArtifactsPath)\include\**\*.*" />
+ <WasmDistFiles Condition="'$(TargetOS)' == 'Browser'"
+ Include="$(MonoArtifactsPath)\wasm\runtimes\**\*.*" />
</ItemGroup>
<Error Condition="'@(RuntimeFiles)' == ''" Text="The '$(RuntimeFlavor)' subset must be built before building this project." />
diff --git a/src/installer/pkg/projects/netcoreapp/src/netcoreapp.depproj b/src/installer/pkg/projects/netcoreapp/src/netcoreapp.depproj
index 29f0b67ea82..7f97f90c9b4 100644
--- a/src/installer/pkg/projects/netcoreapp/src/netcoreapp.depproj
+++ b/src/installer/pkg/projects/netcoreapp/src/netcoreapp.depproj
@@ -71,11 +71,16 @@
Include="@(MonoCrossFiles)">
<TargetPath>runtimes/$(PackageRID)/native/cross</TargetPath>
</RuntimeFiles>
- <RuntimeFiles Condition="'$(TargetsMobile)' == 'true'"
+ <RuntimeFiles Condition="'$(TargetsMobile)' == 'true' or '$(TargetsBrowser)' == 'true'"
Include="@(MonoIncludeFiles)">
<TargetPath>runtimes/$(PackageRID)/native/include/%(RecursiveDir)</TargetPath>
</RuntimeFiles>
+ <RuntimeFiles Condition="'$(TargetsBrowser)' == 'true'"
+ Include="@(WasmDistFiles)">
+ <TargetPath>runtimes/$(PackageRID)/native/wasm/runtimes/%(RecursiveDir)</TargetPath>
+ </RuntimeFiles>
+
<CoreCLRCrossTargetFiles Condition="'%(FileName)' == 'clrjit' or '%(FileName)' == 'libclrjit'">
<TargetPath>runtimes/$(CoreCLRCrossTargetComponentDirName)_$(TargetArchitecture)/native</TargetPath>
</CoreCLRCrossTargetFiles>
diff --git a/src/libraries/pretest.proj b/src/libraries/pretest.proj
index d073141959e..08b8f5ae1ca 100644
--- a/src/libraries/pretest.proj
+++ b/src/libraries/pretest.proj
@@ -72,6 +72,14 @@
TargetRuntimeIdentifier="$(PackageRID)" />
</Target>
+ <!-- Wasm runtimes depend on the mono runtime and libs to be built, so they can only be built here -->
+ <Target Name="BuildWasmPackageDependency"
+ Condition="'$(TargetOS)' == 'Browser'"
+ AfterTargets="RestoreTestHost">
+ <MSBuild Projects="$(MonoProjectRoot)\wasm\wasm.proj"
+ Properties="Configuration=$(Configuration);TargetOS=$(TargetOS);TargetArchitecture=$(TargetArchitecture)"/>
+ </Target>
+
<UsingTask TaskName="CreateFrameworkListFile" AssemblyFile="$(DotNetBuildTasksSharedFrameworkTaskFile)"/>
<Target Name="GenerateFrameworkListFile"
Condition="'$(BinPlaceTestRuntimePack)' == 'true'"
diff --git a/src/libraries/restore/runtime/runtime.depproj b/src/libraries/restore/runtime/runtime.depproj
index 9fb53d1923b..827dec91df7 100644
--- a/src/libraries/restore/runtime/runtime.depproj
+++ b/src/libraries/restore/runtime/runtime.depproj
@@ -94,6 +94,9 @@
<NativeBinPlaceItem Include="@(MonoIncludeFiles)">
<DestinationSubDirectory>include/%(RecursiveDir)</DestinationSubDirectory>
</NativeBinPlaceItem>
+ <NativeBinPlaceItem Include="@(WasmDistFiles)">
+ <DestinationSubDirectory>wasm/%(RecursiveDir)</DestinationSubDirectory>
+ </NativeBinPlaceItem>
</ItemGroup>
<ItemGroup Condition="'$(TargetsMobile)' != 'true'">
<TestHostBinPlaceItem Include="@(RuntimeFiles)" />
diff --git a/src/mono/mono.proj b/src/mono/mono.proj
index c6c35c2adcb..0ac63489b21 100644
--- a/src/mono/mono.proj
+++ b/src/mono/mono.proj
@@ -944,9 +944,16 @@
Targets="Restore;Build" />
</Target>
+ <!-- Need to publish this since it references System.Reflection.MetadataLoadContext -->
+ <Target Name="BuildWasmAppBuilder">
+ <MSBuild Projects="$(MonoProjectRoot)msbuild\WasmAppBuilder\WasmAppBuilder.csproj"
+ Properties="Configuration=$(Configuration);"
+ Targets="Restore;Build;Publish"/>
+ </Target>
+
<!-- Ordering matters! Overwriting the Build target. -->
<!-- General targets -->
- <Target Name="Build" DependsOnTargets="BuildMonoRuntimeUnix;BuildMonoRuntimeWindows;BuildAppleAppBuilder;BuildAndroidAppBuilder">
+ <Target Name="Build" DependsOnTargets="BuildMonoRuntimeUnix;BuildMonoRuntimeWindows;BuildAppleAppBuilder;BuildAndroidAppBuilder;BuildWasmAppBuilder">
<PropertyGroup>
<_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true' and '$(Platform)' == 'x64'">$(MonoObjDir)x64\Bin\$(Configuration)\mono-2.0-sgen.dll</_MonoRuntimeFilePath>
<_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true' and '$(Platform)' == 'x86'">$(MonoObjDir)Win32\Bin\$(Configuration)\mono-2.0-sgen.dll</_MonoRuntimeFilePath>
@@ -981,6 +988,18 @@
<Destination>$(BinDir)cross\opt</Destination>
</_MonoRuntimeArtifacts>
<_MonoIncludeArtifacts Include="$(MonoObjDir)out\include\**" />
+ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-ee-interp.a">
+ <Destination>$(BinDir)libmono-ee-interp.a</Destination>
+ </_MonoRuntimeArtifacts>
+ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-icall-table.a">
+ <Destination>$(BinDir)libmono-icall-table.a</Destination>
+ </_MonoRuntimeArtifacts>
+ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-ilgen.a">
+ <Destination>$(BinDir)libmono-ilgen.a</Destination>
+ </_MonoRuntimeArtifacts>
+ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-profiler-aot.a">
+ <Destination>$(BinDir)libmono-profiler-aot.a</Destination>
+ </_MonoRuntimeArtifacts>
</ItemGroup>
<Copy SourceFiles="@(_MonoRuntimeArtifacts)"
diff --git a/src/mono/msbuild/WasmAppBuilder/PInvokeTableGenerator.cs b/src/mono/msbuild/WasmAppBuilder/PInvokeTableGenerator.cs
new file mode 100644
index 00000000000..dd72774b5d9
--- /dev/null
+++ b/src/mono/msbuild/WasmAppBuilder/PInvokeTableGenerator.cs
@@ -0,0 +1,146 @@
+// -*- indent-tabs-mode: nil -*-
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using System.Reflection;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+public class PInvokeTableGenerator : Task
+{
+ [Required]
+ public ITaskItem[]? Modules { get; set; }
+ [Required]
+ public ITaskItem[]? Assemblies { get; set; }
+ [Required]
+ public string? OutputPath { get; set; }
+
+ public override bool Execute () {
+ GenPInvokeTable (Modules!.Select (item => item.ItemSpec).ToArray (), Assemblies!.Select (item => item.ItemSpec).ToArray ());
+ return true;
+ }
+
+ void GenPInvokeTable (string[] pinvokeModules, string[] assemblies) {
+ var modules = new Dictionary<string, string> ();
+ foreach (var module in pinvokeModules)
+ modules [module] = module;
+
+ var pinvokes = new List<PInvoke> ();
+
+ var resolver = new PathAssemblyResolver (assemblies);
+ var mlc = new MetadataLoadContext (resolver, "System.Private.CoreLib");
+ foreach (var aname in assemblies) {
+ var a = mlc.LoadFromAssemblyPath (aname);
+ foreach (var type in a.GetTypes ())
+ CollectPInvokes (pinvokes, type);
+ }
+
+ Log.LogMessage (MessageImportance.Normal, $"Generating pinvoke table to '{OutputPath}'.");
+
+ using (var w = File.CreateText (OutputPath!)) {
+ EmitPInvokeTable (w, modules, pinvokes);
+ }
+ }
+
+ void CollectPInvokes (List<PInvoke> pinvokes, Type type) {
+ foreach (var method in type.GetMethods (BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance)) {
+ if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0)
+ continue;
+ var dllimport = method.CustomAttributes.First (attr => attr.AttributeType.Name == "DllImportAttribute");
+ var module = (string)dllimport.ConstructorArguments [0].Value!;
+ var entrypoint = (string)dllimport.NamedArguments.First (arg => arg.MemberName == "EntryPoint").TypedValue.Value!;
+ pinvokes.Add (new PInvoke (entrypoint, module, method));
+ }
+ }
+
+ void EmitPInvokeTable (StreamWriter w, Dictionary<string, string> modules, List<PInvoke> pinvokes) {
+ w.WriteLine ("// GENERATED FILE, DO NOT MODIFY");
+ w.WriteLine ("typedef struct {");
+ w.WriteLine ("const char *name;");
+ w.WriteLine ("void *func;");
+ w.WriteLine ("} PinvokeImport;");
+ w.WriteLine ();
+
+ foreach (var pinvoke in pinvokes) {
+ if (modules.ContainsKey (pinvoke.Module))
+ w.WriteLine (GenPInvokeDecl (pinvoke));
+ }
+
+ foreach (var module in modules.Keys) {
+ string symbol = module.Replace (".", "_") + "_imports";
+ w.WriteLine ("static PinvokeImport " + symbol + " [] = {");
+ foreach (var pinvoke in pinvokes) {
+ if (pinvoke.Module == module)
+ w.WriteLine ("{\"" + pinvoke.EntryPoint + "\", " + pinvoke.EntryPoint + "},");
+ }
+ w.WriteLine ("{NULL, NULL}");
+ w.WriteLine ("};");
+ }
+ w.Write ("static void *pinvoke_tables[] = { ");
+ foreach (var module in modules.Keys) {
+ string symbol = module.Replace (".", "_") + "_imports";
+ w.Write (symbol + ",");
+ }
+ w.WriteLine ("};");
+ w.Write ("static char *pinvoke_names[] = { ");
+ foreach (var module in modules.Keys) {
+ w.Write ("\"" + module + "\"" + ",");
+ }
+ w.WriteLine ("};");
+ }
+
+ string MapType (Type t) {
+ string name = t.Name;
+ if (name == "Void")
+ return "void";
+ else if (name == "Double")
+ return "double";
+ else if (name == "Single")
+ return "float";
+ else if (name == "Int64")
+ return "int64_t";
+ else if (name == "UInt64")
+ return "uint64_t";
+ else
+ return "int";
+ }
+
+ string GenPInvokeDecl (PInvoke pinvoke) {
+ var sb = new StringBuilder ();
+ var method = pinvoke.Method;
+ sb.Append (MapType (method.ReturnType));
+ sb.Append ($" {pinvoke.EntryPoint} (");
+ int pindex = 0;
+ var pars = method.GetParameters ();
+ foreach (var p in pars) {
+ if (pindex > 0)
+ sb.Append (",");
+ sb.Append (MapType (pars [pindex].ParameterType));
+ pindex ++;
+ }
+ sb.Append (");");
+ return sb.ToString ();
+ }
+}
+
+class PInvoke
+{
+ public PInvoke (string entry_point, string module, MethodInfo method) {
+ EntryPoint = entry_point;
+ Module = module;
+ Method = method;
+ }
+
+ public string EntryPoint;
+ public string Module;
+ public MethodInfo Method;
+}
diff --git a/src/mono/msbuild/WasmAppBuilder/WasmAppBuilder.csproj b/src/mono/msbuild/WasmAppBuilder/WasmAppBuilder.csproj
new file mode 100644
index 00000000000..271afb933b4
--- /dev/null
+++ b/src/mono/msbuild/WasmAppBuilder/WasmAppBuilder.csproj
@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Library</OutputType>
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
+ <PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />
+ <PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(RefOnlyMicrosoftBuildTasksCoreVersion)" />
+ <PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(RefOnlyMicrosoftBuildUtilitiesCoreVersion)" />
+ <PackageReference Include="System.Reflection.MetadataLoadContext" Version="4.7.1" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="PInvokeTableGenerator.cs" />
+ </ItemGroup>
+</Project>
diff --git a/src/mono/wasm/Makefile b/src/mono/wasm/Makefile
new file mode 100644
index 00000000000..78e6a049d84
--- /dev/null
+++ b/src/mono/wasm/Makefile
@@ -0,0 +1,100 @@
+TOP=$(realpath $(CURDIR)/../../..)
+-include Make.config
+
+#
+# These variables are set by wasm.targets
+#
+EMSDK_PATH?=emsdk
+CONFIG?=Release
+BINDIR?=$(TOP)/artifacts/bin
+OBJDIR?=$(TOP)/artifacts/obj
+PINVOKE_TABLE?=$(TOP)/artifacts/obj/mono/Browser.wasm.$(CONFIG)/wasm/pinvoke-table.h
+MONO_BIN_DIR?=$(BINDIR)/mono/Browser.wasm.$(CONFIG)
+SYS_NATIVE_DIR?=$(BINDIR)/native/net5.0-Browser-$(CONFIG)-wasm/
+
+all: build-native
+
+#
+# EMSCRIPTEN SETUP
+#
+# If EMSDK_PATH is not set by the caller, download and setup a local emsdk install.
+#
+
+EMSCRIPTEN_VERSION=1.39.11
+EMSDK_LOCAL_PATH=emsdk
+EMCC=source $(CURDIR)/emsdk_env.sh && emcc
+
+.stamp-wasm-install-and-select-$(EMSCRIPTEN_VERSION):
+ rm -rf $(EMSDK_LOCAL_PATH)
+ git clone https://github.com/emscripten-core/emsdk.git $(EMSDK_LOCAL_PATH)
+ cd $(EMSDK_LOCAL_PATH) && git checkout $(EMSCRIPTEN_VERSION)
+ cd $(EMSDK_LOCAL_PATH) && ./emsdk install $(EMSCRIPTEN_VERSION)
+ cd $(EMSDK_LOCAL_PATH) && ./emsdk activate --embedded $(EMSCRIPTEN_VERSION)
+ touch $@
+
+ifeq ($(EMSDK_PATH),emsdk)
+provision-wasm: .stamp-wasm-install-and-select-$(EMSCRIPTEN_VERSION)
+else
+provision-wasm:
+endif
+
+# emsdk_env.sh calls emsdk construct_env which is a bit slow so make a copy
+emsdk_env.sh: | provision-wasm
+ cd $(EMSDK_PATH) && ./emsdk construct_env $(CURDIR)/emsdk_env.sh
+
+MONO_OBJ_DIR=$(OBJDIR)/mono/Browser.wasm.$(CONFIG)
+MONO_LIBS = $(MONO_BIN_DIR)/{libmono-ee-interp.a,libmono.a,libmono-ilgen.a,libmono-icall-table.a} ${SYS_NATIVE_DIR}/libSystem.Native.a
+MONO_INCLUDE_DIR=$(MONO_BIN_DIR)/include/mono-2.0
+BUILDS_BIN_DIR=$(MONO_BIN_DIR)/wasm/runtimes
+BUILDS_OBJ_DIR=$(MONO_OBJ_DIR)/wasm/runtimes
+
+EMCC_FLAGS=--profiling-funcs -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s ALIASING_FUNCTION_POINTERS=0 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'FS_createPath', 'FS_createDataFile', 'cwrap', 'setValue', 'getValue', 'UTF8ToString', 'addFunction']" -s "EXPORTED_FUNCTIONS=['_putchar']" --source-map-base http://example.com -s WASM_OBJECT_FILES=0 -s FORCE_FILESYSTEM=1 -s USE_ZLIB=1
+EMCC_DEBUG_FLAGS =-g -Os -s ASSERTIONS=1 -DENABLE_NETCORE=1
+EMCC_RELEASE_FLAGS=-Oz --llvm-opts 2 --llvm-lto 1 -DENABLE_NETCORE=1
+
+#
+# Interpreter builds
+#
+
+# $(1) - name
+# $(2) - runtime dir
+# $(3) - EMCC_FLAGS
+# $(4) - libs
+define InterpBuildTemplate
+
+$(BUILDS_BIN_DIR)/$(1)/:
+ mkdir -p $$@
+
+$(BUILDS_OBJ_DIR)/$(1)/:
+ mkdir -p $$@
+
+$(BUILDS_BIN_DIR)/$(1)/dotnet.js: $(BUILDS_OBJ_DIR)/$(1)/driver.o $(BUILDS_OBJ_DIR)/$(1)/corebindings.o runtime/library_mono.js runtime/binding_support.js runtime/dotnet_support.js $(5) | $(BUILDS_BIN_DIR)/$(1)/ emsdk_env.sh
+ $(EMCC) $(EMCC_FLAGS) $(3) --js-library runtime/library_mono.js --js-library runtime/binding_support.js --js-library runtime/dotnet_support.js $(BUILDS_OBJ_DIR)/$(1)/driver.o $(BUILDS_OBJ_DIR)/$(1)/corebindings.o $(4) -o $(BUILDS_BIN_DIR)/$(1)/dotnet.js
+
+$(BUILDS_OBJ_DIR)/$(1)/pinvoke-table.h: $(PINVOKE_TABLE) | $(BUILDS_OBJ_DIR)/$(1)/
+ if cmp -s $(PINVOKE_TABLE) $$@ ; then : ; else cp $(PINVOKE_TABLE) $$@ ; fi
+
+$(BUILDS_OBJ_DIR)/$(1)/driver.o: runtime/driver.c runtime/corebindings.c $(BUILDS_OBJ_DIR)/$(1)/pinvoke-table.h $(5) | $(BUILDS_OBJ_DIR)/$(1)/ emsdk_env.sh
+ $(EMCC) $(EMCC_FLAGS) $(3) -Oz -DCORE_BINDINGS -I$(BUILDS_OBJ_DIR)/$(1) -I$(MONO_INCLUDE_DIR) runtime/driver.c -c -o $$@
+
+$(BUILDS_OBJ_DIR)/$(1)/corebindings.o: runtime/corebindings.c | $(BUILDS_OBJ_DIR)/$(1)/ emsdk_env.sh
+ $(EMCC) $(3) -Oz -I$(MONO_INCLUDE_DIR) runtime/corebindings.c -c -o $$@
+
+build-native: $(BUILDS_BIN_DIR)/$(1)/dotnet.js
+
+build-interp-$(1): $(BUILDS_BIN_DIR)/$(1)/dotnet.js
+
+endef
+
+$(eval $(call InterpBuildTemplate,debug,,$(EMCC_DEBUG_FLAGS),$(MONO_LIBS)))
+$(eval $(call InterpBuildTemplate,release,,$(EMCC_RELEASE_FLAGS),$(MONO_LIBS)))
+
+build:
+ EMSDK_PATH=$(PWD)/wasm/emsdk ../../../.dotnet/dotnet build /p:TargetArchitecture=wasm /p:TargetOS=Browser /p:Configuration=Release
+
+clean-emsdk:
+ $(RM) -rf $(EMSDK_LOCAL_PATH)
+
+clean:
+ $(RM) -rf $(BUILDS_BIN_DIR) $(BUILDS_OBJ_DIR)
+ $(RM) emsdk_env.sh
diff --git a/src/mono/wasm/runtime/binding_support.js b/src/mono/wasm/runtime/binding_support.js
new file mode 100644
index 00000000000..46b9383373e
--- /dev/null
+++ b/src/mono/wasm/runtime/binding_support.js
@@ -0,0 +1,1277 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+var BindingSupportLib = {
+ $BINDING__postset: 'BINDING.export_functions (Module);',
+ $BINDING: {
+ BINDING_ASM: "[WebAssembly.Bindings]WebAssembly.Runtime",
+ mono_wasm_object_registry: [],
+ mono_wasm_ref_counter: 0,
+ mono_wasm_free_list: [],
+ mono_wasm_marshal_enum_as_int: false,
+ mono_bindings_init: function (binding_asm) {
+ this.BINDING_ASM = binding_asm;
+ },
+
+ export_functions: function (module) {
+ module ["mono_bindings_init"] = BINDING.mono_bindings_init.bind(BINDING);
+ module ["mono_method_invoke"] = BINDING.call_method.bind(BINDING);
+ module ["mono_method_get_call_signature"] = BINDING.mono_method_get_call_signature.bind(BINDING);
+ module ["mono_method_resolve"] = BINDING.resolve_method_fqn.bind(BINDING);
+ module ["mono_bind_static_method"] = BINDING.bind_static_method.bind(BINDING);
+ module ["mono_call_static_method"] = BINDING.call_static_method.bind(BINDING);
+ module ["mono_bind_assembly_entry_point"] = BINDING.bind_assembly_entry_point.bind(BINDING);
+ module ["mono_call_assembly_entry_point"] = BINDING.call_assembly_entry_point.bind(BINDING);
+ },
+
+ bindings_lazy_init: function () {
+ if (this.init)
+ return;
+
+ this.assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']);
+ this.find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']);
+ this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']);
+ this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']);
+ this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']);
+ this.js_string_to_mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']);
+ this.mono_get_obj_type = Module.cwrap ('mono_wasm_get_obj_type', 'number', ['number']);
+ this.mono_unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']);
+ this.mono_unbox_float = Module.cwrap ('mono_wasm_unbox_float', 'number', ['number']);
+ this.mono_array_length = Module.cwrap ('mono_wasm_array_length', 'number', ['number']);
+ this.mono_array_get = Module.cwrap ('mono_wasm_array_get', 'number', ['number', 'number']);
+ this.mono_obj_array_new = Module.cwrap ('mono_wasm_obj_array_new', 'number', ['number']);
+ this.mono_obj_array_set = Module.cwrap ('mono_wasm_obj_array_set', 'void', ['number', 'number', 'number']);
+ this.mono_unbox_enum = Module.cwrap ('mono_wasm_unbox_enum', 'number', ['number']);
+ this.assembly_get_entry_point = Module.cwrap ('mono_wasm_assembly_get_entry_point', 'number', ['number']);
+
+ // receives a byteoffset into allocated Heap with a size.
+ this.mono_typed_array_new = Module.cwrap ('mono_wasm_typed_array_new', 'number', ['number','number','number','number']);
+
+ var binding_fqn_asm = this.BINDING_ASM.substring(this.BINDING_ASM.indexOf ("[") + 1, this.BINDING_ASM.indexOf ("]")).trim();
+ var binding_fqn_class = this.BINDING_ASM.substring (this.BINDING_ASM.indexOf ("]") + 1).trim();
+
+ this.binding_module = this.assembly_load (binding_fqn_asm);
+ if (!this.binding_module)
+ throw "Can't find bindings module assembly: " + binding_fqn_asm;
+
+ if (binding_fqn_class !== null && typeof binding_fqn_class !== "undefined")
+ {
+ var namespace = "WebAssembly";
+ var classname = binding_fqn_class.length > 0 ? binding_fqn_class : "Runtime";
+ if (binding_fqn_class.indexOf(".") != -1) {
+ var idx = binding_fqn_class.lastIndexOf(".");
+ namespace = binding_fqn_class.substring (0, idx);
+ classname = binding_fqn_class.substring (idx + 1);
+ }
+ }
+
+ var wasm_runtime_class = this.find_class (this.binding_module, namespace, classname)
+ if (!wasm_runtime_class)
+ throw "Can't find " + binding_fqn_class + " class";
+
+ var get_method = function(method_name) {
+ var res = BINDING.find_method (wasm_runtime_class, method_name, -1)
+ if (!res)
+ throw "Can't find method " + namespace + "." + classname + ":" + method_name;
+ return res;
+ }
+ this.bind_js_obj = get_method ("BindJSObject");
+ this.bind_core_clr_obj = get_method ("BindCoreCLRObject");
+ this.bind_existing_obj = get_method ("BindExistingObject");
+ this.unbind_js_obj = get_method ("UnBindJSObject");
+ this.unbind_js_obj_and_free = get_method ("UnBindJSObjectAndFree");
+ this.unbind_raw_obj_and_free = get_method ("UnBindRawJSObjectAndFree");
+ this.get_js_id = get_method ("GetJSObjectId");
+ this.get_raw_mono_obj = get_method ("GetMonoObject");
+
+ this.box_js_int = get_method ("BoxInt");
+ this.box_js_double = get_method ("BoxDouble");
+ this.box_js_bool = get_method ("BoxBool");
+ this.is_simple_array = get_method ("IsSimpleArray");
+ this.get_core_type = get_method ("GetCoreType");
+ this.setup_js_cont = get_method ("SetupJSContinuation");
+
+ this.create_tcs = get_method ("CreateTaskSource");
+ this.set_tcs_result = get_method ("SetTaskSourceResult");
+ this.set_tcs_failure = get_method ("SetTaskSourceFailure");
+ this.tcs_get_task_and_bind = get_method ("GetTaskAndBind");
+ this.get_call_sig = get_method ("GetCallSignature");
+
+ this.object_to_string = get_method ("ObjectToString");
+ this.get_date_value = get_method ("GetDateValue");
+ this.create_date_time = get_method ("CreateDateTime");
+ this.create_uri = get_method ("CreateUri");
+
+ this.object_to_enum = get_method ("ObjectToEnum");
+ this.init = true;
+ },
+
+ get_js_obj: function (js_handle) {
+ if (js_handle > 0)
+ return this.mono_wasm_require_handle(js_handle);
+ return null;
+ },
+
+ conv_string: function (mono_obj) {
+ return MONO.string_decoder.copy (mono_obj);
+ },
+
+ is_nested_array: function (ele) {
+ return this.call_method (this.is_simple_array, null, "mi", [ ele ]);
+ },
+
+ mono_array_to_js_array: function (mono_array) {
+ if (mono_array == 0)
+ return null;
+
+ var res = [];
+ var len = this.mono_array_length (mono_array);
+ for (var i = 0; i < len; ++i)
+ {
+ var ele = this.mono_array_get (mono_array, i);
+ if (this.is_nested_array(ele))
+ res.push(this.mono_array_to_js_array(ele));
+ else
+ res.push (this.unbox_mono_obj (ele));
+ }
+
+ return res;
+ },
+
+ js_array_to_mono_array: function (js_array) {
+ var mono_array = this.mono_obj_array_new (js_array.length);
+ for (var i = 0; i < js_array.length; ++i) {
+ this.mono_obj_array_set (mono_array, i, this.js_to_mono_obj (js_array [i]));
+ }
+ return mono_array;
+ },
+
+ unbox_mono_obj: function (mono_obj) {
+ if (mono_obj == 0)
+ return undefined;
+ var type = this.mono_get_obj_type (mono_obj);
+ //See MARSHAL_TYPE_ defines in driver.c
+ switch (type) {
+ case 1: // int
+ return this.mono_unbox_int (mono_obj);
+ case 2: // float
+ return this.mono_unbox_float (mono_obj);
+ case 3: //string
+ return this.conv_string (mono_obj);
+ case 4: //vts
+ throw new Error ("no idea on how to unbox value types");
+ case 5: { // delegate
+ var obj = this.extract_js_obj (mono_obj);
+ return function () {
+ return BINDING.invoke_delegate (obj, arguments);
+ };
+ }
+ case 6: {// Task
+
+ if (typeof Promise === "undefined" || typeof Promise.resolve === "undefined")
+ throw new Error ("Promises are not supported thus C# Tasks can not work in this context.");
+
+ var obj = this.extract_js_obj (mono_obj);
+ var cont_obj = null;
+ var promise = new Promise (function (resolve, reject) {
+ cont_obj = {
+ resolve: resolve,
+ reject: reject
+ };
+ });
+
+ this.call_method (this.setup_js_cont, null, "mo", [ mono_obj, cont_obj ]);
+ obj.__mono_js_cont__ = cont_obj.__mono_gchandle__;
+ cont_obj.__mono_js_task__ = obj.__mono_gchandle__;
+ return promise;
+ }
+
+ case 7: // ref type
+ return this.extract_js_obj (mono_obj);
+
+ case 8: // bool
+ return this.mono_unbox_int (mono_obj) != 0;
+
+ case 9: // enum
+
+ if(this.mono_wasm_marshal_enum_as_int)
+ {
+ return this.mono_unbox_enum (mono_obj);
+ }
+ else
+ {
+ enumValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]);
+ }
+
+ return enumValue;
+
+
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ {
+ throw new Error ("Marshalling of primitive arrays are not supported. Use the corresponding TypedArray instead.");
+ }
+ case 20: // clr .NET DateTime
+ var dateValue = this.call_method(this.get_date_value, null, "md", [ mono_obj ]);
+ return new Date(dateValue);
+ case 21: // clr .NET DateTimeOffset
+ var dateoffsetValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]);
+ return dateoffsetValue;
+ case 22: // clr .NET Uri
+ var uriValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]);
+ return uriValue;
+ default:
+ throw new Error ("no idea on how to unbox object kind " + type);
+ }
+ },
+
+ create_task_completion_source: function () {
+ return this.call_method (this.create_tcs, null, "i", [ -1 ]);
+ },
+
+ set_task_result: function (tcs, result) {
+ tcs.is_mono_tcs_result_set = true;
+ this.call_method (this.set_tcs_result, null, "oo", [ tcs, result ]);
+ if (tcs.is_mono_tcs_task_bound)
+ this.free_task_completion_source(tcs);
+ },
+
+ set_task_failure: function (tcs, reason) {
+ tcs.is_mono_tcs_result_set = true;
+ this.call_method (this.set_tcs_failure, null, "os", [ tcs, reason.toString () ]);
+ if (tcs.is_mono_tcs_task_bound)
+ this.free_task_completion_source(tcs);
+ },
+
+ // https://github.com/Planeshifter/emscripten-examples/blob/master/01_PassingArrays/sum_post.js
+ js_typedarray_to_heap: function(typedArray){
+ var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
+ var ptr = Module._malloc(numBytes);
+ var heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
+ heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, numBytes));
+ return heapBytes;
+ },
+ js_to_mono_obj: function (js_obj) {
+ this.bindings_lazy_init ();
+
+ // determines if the javascript object is a Promise or Promise like which can happen
+ // when using an external Promise library. The javascript object should be marshalled
+ // as managed Task objects.
+ //
+ // Example is when Bluebird is included in a web page using a script tag, it overwrites the
+ // global Promise object by default with its own version of Promise.
+ function isThenable() {
+ // When using an external Promise library the Promise.resolve may not be sufficient
+ // to identify the object as a Promise.
+ return Promise.resolve(js_obj) === js_obj ||
+ ((typeof js_obj === "object" || typeof js_obj === "function") && typeof js_obj.then === "function")
+ }
+
+ switch (true) {
+ case js_obj === null:
+ case typeof js_obj === "undefined":
+ return 0;
+ case typeof js_obj === "number":
+ if (parseInt(js_obj) == js_obj)
+ return this.call_method (this.box_js_int, null, "im", [ js_obj ]);
+ return this.call_method (this.box_js_double, null, "dm", [ js_obj ]);
+ case typeof js_obj === "string":
+ return this.js_string_to_mono_string (js_obj);
+ case typeof js_obj === "boolean":
+ return this.call_method (this.box_js_bool, null, "im", [ js_obj ]);
+ case isThenable() === true:
+ var the_task = this.try_extract_mono_obj (js_obj);
+ if (the_task)
+ return the_task;
+ var tcs = this.create_task_completion_source ();
+ js_obj.then (function (result) {
+ BINDING.set_task_result (tcs, result);
+ }, function (reason) {
+ BINDING.set_task_failure (tcs, reason);
+ })
+ return this.get_task_and_bind (tcs, js_obj);
+ case js_obj.constructor.name === "Date":
+ // We may need to take into account the TimeZone Offset
+ return this.call_method(this.create_date_time, null, "dm", [ js_obj.getTime() ]);
+ default:
+ return this.extract_mono_obj (js_obj);
+ }
+ },
+ js_to_mono_uri: function (js_obj) {
+ this.bindings_lazy_init ();
+
+ switch (true) {
+ case js_obj === null:
+ case typeof js_obj === "undefined":
+ return 0;
+ case typeof js_obj === "string":
+ return this.call_method(this.create_uri, null, "sm", [ js_obj ])
+ default:
+ return this.extract_mono_obj (js_obj);
+ }
+ },
+ js_typed_array_to_array : function (js_obj) {
+
+ // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
+ // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
+ // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
+ // is an object representing a chunk of data; it has no format to speak of, and offers no
+ // mechanism for accessing its contents. In order to access the memory contained in a buffer,
+ // you need to use a view. A view provides a context — that is, a data type, starting offset,
+ // and number of elements — that turns the data into an actual typed array.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
+ if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT))
+ {
+ var arrayType = 0;
+ if (js_obj instanceof Int8Array)
+ arrayType = 11;
+ if (js_obj instanceof Uint8Array)
+ arrayType = 12;
+ if (js_obj instanceof Uint8ClampedArray)
+ arrayType = 12;
+ if (js_obj instanceof Int16Array)
+ arrayType = 13;
+ if (js_obj instanceof Uint16Array)
+ arrayType = 14;
+ if (js_obj instanceof Int32Array)
+ arrayType = 15;
+ if (js_obj instanceof Uint32Array)
+ arrayType = 16;
+ if (js_obj instanceof Float32Array)
+ arrayType = 17;
+ if (js_obj instanceof Float64Array)
+ arrayType = 18;
+
+ var heapBytes = this.js_typedarray_to_heap(js_obj);
+ var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType);
+ Module._free(heapBytes.byteOffset);
+ return bufferArray;
+ }
+ else {
+ throw new Error("Object '" + js_obj + "' is not a typed array");
+ }
+
+
+ },
+ // Copy the existing typed array to the heap pointed to by the pinned array address
+ // typed array memory -> copy to heap -> address of managed pinned array
+ typedarray_copy_to : function (typed_array, pinned_array, begin, end, bytes_per_element) {
+
+ // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
+ // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
+ // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
+ // is an object representing a chunk of data; it has no format to speak of, and offers no
+ // mechanism for accessing its contents. In order to access the memory contained in a buffer,
+ // you need to use a view. A view provides a context — that is, a data type, starting offset,
+ // and number of elements — that turns the data into an actual typed array.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
+ if (!!(typed_array.buffer instanceof ArrayBuffer && typed_array.BYTES_PER_ELEMENT))
+ {
+ // Some sanity checks of what is being asked of us
+ // lets play it safe and throw an error here instead of assuming to much.
+ // Better safe than sorry later
+ if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
+ throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
+
+ // how much space we have to work with
+ var num_of_bytes = (end - begin) * bytes_per_element;
+ // how much typed buffer space are we talking about
+ var view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
+ // only use what is needed.
+ if (num_of_bytes > view_bytes)
+ num_of_bytes = view_bytes;
+
+ // offset index into the view
+ var offset = begin * bytes_per_element;
+
+ // Create a view over the heap pointed to by the pinned array address
+ var heapBytes = new Uint8Array(Module.HEAPU8.buffer, pinned_array + offset, num_of_bytes);
+ // Copy the bytes of the typed array to the heap.
+ heapBytes.set(new Uint8Array(typed_array.buffer, typed_array.byteOffset, num_of_bytes));
+
+ return num_of_bytes;
+ }
+ else {
+ throw new Error("Object '" + typed_array + "' is not a typed array");
+ }
+
+ },
+ // Copy the pinned array address from pinned_array allocated on the heap to the typed array.
+ // adress of managed pinned array -> copy from heap -> typed array memory
+ typedarray_copy_from : function (typed_array, pinned_array, begin, end, bytes_per_element) {
+
+ // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
+ // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
+ // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
+ // is an object representing a chunk of data; it has no format to speak of, and offers no
+ // mechanism for accessing its contents. In order to access the memory contained in a buffer,
+ // you need to use a view. A view provides a context — that is, a data type, starting offset,
+ // and number of elements — that turns the data into an actual typed array.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
+ if (!!(typed_array.buffer instanceof ArrayBuffer && typed_array.BYTES_PER_ELEMENT))
+ {
+ // Some sanity checks of what is being asked of us
+ // lets play it safe and throw an error here instead of assuming to much.
+ // Better safe than sorry later
+ if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
+ throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
+
+ // how much space we have to work with
+ var num_of_bytes = (end - begin) * bytes_per_element;
+ // how much typed buffer space are we talking about
+ var view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
+ // only use what is needed.
+ if (num_of_bytes > view_bytes)
+ num_of_bytes = view_bytes;
+
+ // Create a new view for mapping
+ var typedarrayBytes = new Uint8Array(typed_array.buffer, 0, num_of_bytes);
+ // offset index into the view
+ var offset = begin * bytes_per_element;
+ // Set view bytes to value from HEAPU8
+ typedarrayBytes.set(Module.HEAPU8.subarray(pinned_array + offset, pinned_array + offset + num_of_bytes));
+ return num_of_bytes;
+ }
+ else {
+ throw new Error("Object '" + typed_array + "' is not a typed array");
+ }
+
+ },
+ // Creates a new typed array from pinned array address from pinned_array allocated on the heap to the typed array.
+ // adress of managed pinned array -> copy from heap -> typed array memory
+ typed_array_from : function (pinned_array, begin, end, bytes_per_element, type) {
+
+ // typed array
+ var newTypedArray = 0;
+
+ switch (type)
+ {
+ case 5:
+ newTypedArray = new Int8Array(end - begin);
+ break;
+ case 6:
+ newTypedArray = new Uint8Array(end - begin);
+ break;
+ case 7:
+ newTypedArray = new Int16Array(end - begin);
+ break;
+ case 8:
+ newTypedArray = new Uint16Array(end - begin);
+ break;
+ case 9:
+ newTypedArray = new Int32Array(end - begin);
+ break;
+ case 10:
+ newTypedArray = new Uint32Array(end - begin);
+ break;
+ case 13:
+ newTypedArray = new Float32Array(end - begin);
+ break;
+ case 14:
+ newTypedArray = new Float64Array(end - begin);
+ break;
+ case 15: // This is a special case because the typed array is also byte[]
+ newTypedArray = new Uint8ClampedArray(end - begin);
+ break;
+ }
+
+ this.typedarray_copy_from(newTypedArray, pinned_array, begin, end, bytes_per_element);
+ return newTypedArray;
+ },
+ js_to_mono_enum: function (method, parmIdx, js_obj) {
+ this.bindings_lazy_init ();
+
+ if (js_obj === null || typeof js_obj === "undefined")
+ return 0;
+
+ var monoObj = this.js_to_mono_obj(js_obj);
+ // Check enum contract
+ var monoEnum = this.call_method(this.object_to_enum, null, "iimm", [ method, parmIdx, monoObj ])
+ // return the unboxed enum value.
+ return this.mono_unbox_enum(monoEnum);
+ },
+ wasm_binding_obj_new: function (js_obj_id, type)
+ {
+ return this.call_method (this.bind_js_obj, null, "io", [js_obj_id, type]);
+ },
+ wasm_bind_existing: function (mono_obj, js_id)
+ {
+ return this.call_method (this.bind_existing_obj, null, "mi", [mono_obj, js_id]);
+ },
+
+ wasm_bind_core_clr_obj: function (js_id, gc_handle)
+ {
+ return this.call_method (this.bind_core_clr_obj, null, "ii", [js_id, gc_handle]);
+ },
+
+ wasm_unbind_js_obj: function (js_obj_id)
+ {
+ this.call_method (this.unbind_js_obj, null, "i", [js_obj_id]);
+ },
+
+ wasm_unbind_js_obj_and_free: function (js_obj_id)
+ {
+ this.call_method (this.unbind_js_obj_and_free, null, "i", [js_obj_id]);
+ },
+
+ wasm_get_js_id: function (mono_obj)
+ {
+ return this.call_method (this.get_js_id, null, "m", [mono_obj]);
+ },
+
+ wasm_get_raw_obj: function (gchandle)
+ {
+ return this.call_method (this.get_raw_mono_obj, null, "im", [gchandle]);
+ },
+
+ try_extract_mono_obj:function (js_obj) {
+ if (js_obj === null || typeof js_obj === "undefined" || typeof js_obj.__mono_gchandle__ === "undefined")
+ return 0;
+ return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
+ },
+
+ mono_method_get_call_signature: function(method) {
+ this.bindings_lazy_init ();
+
+ return this.call_method (this.get_call_sig, null, "i", [ method ]);
+ },
+
+ get_task_and_bind: function (tcs, js_obj) {
+ var gc_handle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
+ var task_gchandle = this.call_method (this.tcs_get_task_and_bind, null, "oi", [ tcs, gc_handle + 1 ]);
+ js_obj.__mono_gchandle__ = task_gchandle;
+ this.mono_wasm_object_registry[gc_handle] = js_obj;
+ this.free_task_completion_source(tcs);
+ tcs.is_mono_tcs_task_bound = true;
+ js_obj.__mono_bound_tcs__ = tcs.__mono_gchandle__;
+ tcs.__mono_bound_task__ = js_obj.__mono_gchandle__;
+ return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
+ },
+
+ free_task_completion_source: function (tcs) {
+ if (tcs.is_mono_tcs_result_set)
+ {
+ this.call_method (this.unbind_raw_obj_and_free, null, "ii", [ tcs.__mono_gchandle__ ]);
+ }
+ if (tcs.__mono_bound_task__)
+ {
+ this.call_method (this.unbind_raw_obj_and_free, null, "ii", [ tcs.__mono_bound_task__ ]);
+ }
+ },
+
+ extract_mono_obj: function (js_obj) {
+
+ if (js_obj === null || typeof js_obj === "undefined")
+ return 0;
+
+ if (!js_obj.is_mono_bridged_obj) {
+ var gc_handle = this.mono_wasm_register_obj(js_obj);
+ return this.wasm_get_raw_obj (gc_handle);
+ }
+
+
+ return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
+ },
+
+ extract_js_obj: function (mono_obj) {
+ if (mono_obj == 0)
+ return null;
+
+ var js_id = this.wasm_get_js_id (mono_obj);
+ if (js_id > 0)
+ return this.mono_wasm_require_handle(js_id);
+
+ var gcHandle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
+ var js_obj = {
+ __mono_gchandle__: this.wasm_bind_existing(mono_obj, gcHandle + 1),
+ is_mono_bridged_obj: true
+ };
+
+ this.mono_wasm_object_registry[gcHandle] = js_obj;
+ return js_obj;
+ },
+
+ /*
+ args_marshal is a string with one character per parameter that tells how to marshal it, here are the valid values:
+
+ i: int32
+ j: int32 - Enum with underlying type of int32
+ l: int64
+ k: int64 - Enum with underlying type of int64
+ f: float
+ d: double
+ s: string
+ o: js object will be converted to a C# object (this will box numbers/bool/promises)
+ m: raw mono object. Don't use it unless you know what you're doing
+
+ additionally you can append 'm' to args_marshal beyond `args.length` if you don't want the return value marshaled
+ */
+ call_method: function (method, this_arg, args_marshal, args) {
+ this.bindings_lazy_init ();
+
+ // Allocate memory for error
+ var has_args = args !== null && typeof args !== "undefined" && args.length > 0;
+ var has_args_marshal = args_marshal !== null && typeof args_marshal !== "undefined" && args_marshal.length > 0;
+
+ if (has_args_marshal && (!has_args || args.length > args_marshal.length))
+ throw Error("Parameter count mismatch.");
+
+ var args_start = null;
+ var buffer = null;
+ var exception_out = null;
+
+ // check if the method signature needs argument mashalling
+ if (has_args_marshal && has_args) {
+ var i;
+
+ var converters = this.converters;
+ if (!converters) {
+ converters = new Map ();
+ converters.set ('m', { steps: [{ }], size: 0});
+ converters.set ('s', { steps: [{ convert: this.js_string_to_mono_string.bind (this)}], size: 0});
+ converters.set ('o', { steps: [{ convert: this.js_to_mono_obj.bind (this)}], size: 0});
+ converters.set ('u', { steps: [{ convert: this.js_to_mono_uri.bind (this)}], size: 0});
+ converters.set ('k', { steps: [{ convert: this.js_to_mono_enum.bind (this), indirect: 'i64'}], size: 8});
+ converters.set ('j', { steps: [{ convert: this.js_to_mono_enum.bind (this), indirect: 'i32'}], size: 8});
+ converters.set ('i', { steps: [{ indirect: 'i32'}], size: 8});
+ converters.set ('l', { steps: [{ indirect: 'i64'}], size: 8});
+ converters.set ('f', { steps: [{ indirect: 'float'}], size: 8});
+ converters.set ('d', { steps: [{ indirect: 'double'}], size: 8});
+ this.converters = converters;
+ }
+
+ var converter = converters.get (args_marshal);
+ if (!converter) {
+ var steps = [];
+ var size = 0;
+
+ for (i = 0; i < args_marshal.length; ++i) {
+ var conv = this.converters.get (args_marshal[i]);
+ if (!conv)
+ throw Error ("Unknown parameter type " + type);
+
+ steps.push (conv.steps[0]);
+ size += conv.size;
+ }
+ converter = { steps: steps, size: size };
+ converters.set (args_marshal, converter);
+ }
+
+ // assume at least 8 byte alignment from malloc
+ buffer = Module._malloc (converter.size + (args.length * 4) + 4);
+ var indirect_start = buffer; // buffer + buffer % 8
+ exception_out = indirect_start + converter.size;
+ args_start = exception_out + 4;
+
+ var slot = args_start;
+ var indirect_value = indirect_start;
+ for (i = 0; i < args.length; ++i) {
+ var handler = converter.steps[i];
+ var obj = handler.convert ? handler.convert (args[i], method, i) : args[i];
+
+ if (handler.indirect) {
+ Module.setValue (indirect_value, obj, handler.indirect);
+ obj = indirect_value;
+ indirect_value += 8;
+ }
+
+ Module.setValue (slot, obj, "*");
+ slot += 4;
+ }
+ } else {
+ // only marshal the exception
+ exception_out = buffer = Module._malloc (4);
+ }
+
+ Module.setValue (exception_out, 0, "*");
+
+ var res = this.invoke_method (method, this_arg, args_start, exception_out);
+ var eh_res = Module.getValue (exception_out, "*");
+
+ Module._free (buffer);
+
+ if (eh_res != 0) {
+ var msg = this.conv_string (res);
+ throw new Error (msg); //the convention is that invoke_method ToString () any outgoing exception
+ }
+
+ if (has_args_marshal && has_args) {
+ if (args_marshal.length >= args.length && args_marshal [args.length] === "m")
+ return res;
+ }
+
+ return this.unbox_mono_obj (res);
+ },
+
+ invoke_delegate: function (delegate_obj, js_args) {
+ this.bindings_lazy_init ();
+
+ if (!this.delegate_dynamic_invoke) {
+ if (!this.corlib)
+ this.corlib = this.assembly_load ("mscorlib");
+ if (!this.delegate_class)
+ this.delegate_class = this.find_class (this.corlib, "System", "Delegate");
+ if (!this.delegate_class)
+ {
+ throw new Error("System.Delegate class can not be resolved.");
+ }
+ this.delegate_dynamic_invoke = this.find_method (this.delegate_class, "DynamicInvoke", -1);
+ }
+ var mono_args = this.js_array_to_mono_array (js_args);
+ if (!this.delegate_dynamic_invoke)
+ throw new Error("System.Delegate.DynamicInvoke method can not be resolved.");
+ // Note: the single 'm' passed here is causing problems with AOT. Changed to "mo" again.
+ // This may need more analysis if causes problems again.
+ return this.call_method (this.delegate_dynamic_invoke, this.extract_mono_obj (delegate_obj), "mo", [ mono_args ]);
+ },
+
+ resolve_method_fqn: function (fqn) {
+ var assembly = fqn.substring(fqn.indexOf ("[") + 1, fqn.indexOf ("]")).trim();
+ fqn = fqn.substring (fqn.indexOf ("]") + 1).trim();
+
+ var methodname = fqn.substring(fqn.indexOf (":") + 1);
+ fqn = fqn.substring (0, fqn.indexOf (":")).trim ();
+
+ var namespace = "";
+ var classname = fqn;
+ if (fqn.indexOf(".") != -1) {
+ var idx = fqn.lastIndexOf(".");
+ namespace = fqn.substring (0, idx);
+ classname = fqn.substring (idx + 1);
+ }
+
+ var asm = this.assembly_load (assembly);
+ if (!asm)
+ throw new Error ("Could not find assembly: " + assembly);
+
+ var klass = this.find_class(asm, namespace, classname);
+ if (!klass)
+ throw new Error ("Could not find class: " + namespace + ":" +classname);
+
+ var method = this.find_method (klass, methodname, -1);
+ if (!method)
+ throw new Error ("Could not find method: " + methodname);
+ return method;
+ },
+
+ call_static_method: function (fqn, args, signature) {
+ this.bindings_lazy_init ();
+
+ var method = this.resolve_method_fqn (fqn);
+
+ if (typeof signature === "undefined")
+ signature = Module.mono_method_get_call_signature (method);
+
+ return this.call_method (method, null, signature, args);
+ },
+
+ bind_static_method: function (fqn, signature) {
+ this.bindings_lazy_init ();
+
+ var method = this.resolve_method_fqn (fqn);
+
+ if (typeof signature === "undefined")
+ signature = Module.mono_method_get_call_signature (method);
+
+ return function() {
+ return BINDING.call_method (method, null, signature, arguments);
+ };
+ },
+ bind_assembly_entry_point: function (assembly) {
+ this.bindings_lazy_init ();
+
+ var asm = this.assembly_load (assembly);
+ if (!asm)
+ throw new Error ("Could not find assembly: " + assembly);
+
+ var method = this.assembly_get_entry_point(asm);
+ if (!method)
+ throw new Error ("Could not find entry point for assembly: " + assembly);
+
+ if (typeof signature === "undefined")
+ signature = Module.mono_method_get_call_signature (method);
+
+ return function() {
+ return BINDING.call_method (method, null, signature, arguments);
+ };
+ },
+ call_assembly_entry_point: function (assembly, args, signature) {
+ this.bindings_lazy_init ();
+
+ var asm = this.assembly_load (assembly);
+ if (!asm)
+ throw new Error ("Could not find assembly: " + assembly);
+
+ var method = this.assembly_get_entry_point(asm);
+ if (!method)
+ throw new Error ("Could not find entry point for assembly: " + assembly);
+
+ if (typeof signature === "undefined")
+ signature = Module.mono_method_get_call_signature (method);
+
+ return this.call_method (method, null, signature, args);
+ },
+ wasm_get_core_type: function (obj)
+ {
+ return this.call_method (this.get_core_type, null, "so", [ "WebAssembly.Core."+obj.constructor.name ]);
+ },
+ get_wasm_type: function(obj) {
+ var coreType = obj[Symbol.for("wasm type")];
+ if (typeof coreType === "undefined") {
+ coreType = this.wasm_get_core_type(obj);
+ if (typeof coreType !== "undefined") {
+ obj.constructor.prototype[Symbol.for("wasm type")] = coreType;
+ }
+ }
+ return coreType;
+ },
+ // Object wrapping helper functions to handle reference handles that will
+ // be used in managed code.
+ mono_wasm_register_obj: function(obj) {
+
+ var gc_handle = undefined;
+ if (obj !== null && typeof obj !== "undefined")
+ {
+ gc_handle = obj.__mono_gchandle__;
+
+ if (typeof gc_handle === "undefined") {
+ var handle = this.mono_wasm_free_list.length ?
+ this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
+ obj.__mono_jshandle__ = handle;
+ // Obtain the JS -> C# type mapping.
+ var wasm_type = this.get_wasm_type(obj);
+ gc_handle = obj.__mono_gchandle__ = this.wasm_binding_obj_new(handle + 1, wasm_type);
+ this.mono_wasm_object_registry[handle] = obj;
+
+ }
+ }
+ return gc_handle;
+ },
+ mono_wasm_require_handle: function(handle) {
+ if (handle > 0)
+ return this.mono_wasm_object_registry[handle - 1];
+ return null;
+ },
+ mono_wasm_unregister_obj: function(js_id) {
+ var obj = this.mono_wasm_object_registry[js_id - 1];
+ if (typeof obj !== "undefined" && obj !== null) {
+ // if this is the global object then do not
+ // unregister it.
+ if (typeof ___mono_wasm_global___ !== "undefined" && ___mono_wasm_global___ === obj)
+ return obj;
+
+ var gc_handle = obj.__mono_gchandle__;
+ if (typeof gc_handle !== "undefined") {
+ this.wasm_unbind_js_obj_and_free(js_id);
+
+ obj.__mono_gchandle__ = undefined;
+ obj.__mono_jshandle__ = undefined;
+
+ this.mono_wasm_object_registry[js_id - 1] = undefined;
+ this.mono_wasm_free_list.push(js_id - 1);
+ }
+ }
+ return obj;
+ },
+ mono_wasm_free_handle: function(handle) {
+ this.mono_wasm_unregister_obj(handle);
+ },
+ mono_wasm_free_raw_object: function(js_id) {
+ var obj = this.mono_wasm_object_registry[js_id - 1];
+ if (typeof obj !== "undefined" && obj !== null) {
+ // if this is the global object then do not
+ // unregister it.
+ if (typeof ___mono_wasm_global___ !== "undefined" && ___mono_wasm_global___ === obj)
+ return obj;
+
+ var gc_handle = obj.__mono_gchandle__;
+ if (typeof gc_handle !== "undefined") {
+
+ obj.__mono_gchandle__ = undefined;
+ obj.__mono_jshandle__ = undefined;
+
+ this.mono_wasm_object_registry[js_id - 1] = undefined;
+ this.mono_wasm_free_list.push(js_id - 1);
+ }
+ }
+ return obj;
+ },
+ mono_wasm_get_global: function() {
+ function testGlobal(obj) {
+ obj['___mono_wasm_global___'] = obj;
+ var success = typeof ___mono_wasm_global___ === 'object' && obj['___mono_wasm_global___'] === obj;
+ if (!success) {
+ delete obj['___mono_wasm_global___'];
+ }
+ return success;
+ }
+ if (typeof ___mono_wasm_global___ === 'object') {
+ return ___mono_wasm_global___;
+ }
+ if (typeof global === 'object' && testGlobal(global)) {
+ ___mono_wasm_global___ = global;
+ } else if (typeof window === 'object' && testGlobal(window)) {
+ ___mono_wasm_global___ = window;
+ } else if (testGlobal((function(){return Function;})()('return this')())) {
+
+ ___mono_wasm_global___ = (function(){return Function;})()('return this')();
+
+ }
+ if (typeof ___mono_wasm_global___ === 'object') {
+ return ___mono_wasm_global___;
+ }
+ throw Error('Unable to get mono wasm global object.');
+ },
+
+ },
+
+ mono_wasm_invoke_js_with_args: function(js_handle, method_name, args, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var obj = BINDING.get_js_obj (js_handle);
+ if (!obj) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ var js_name = BINDING.conv_string (method_name);
+ if (!js_name) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid method name object '" + method_name + "'");
+ }
+
+ var js_args = BINDING.mono_array_to_js_array(args);
+
+ var res;
+ try {
+ var m = obj [js_name];
+ if (typeof m === "undefined")
+ throw new Error("Method: '" + js_name + "' not found for: '" + Object.prototype.toString.call(obj) + "'");
+ var res = m.apply (obj, js_args);
+ return BINDING.js_to_mono_obj (res);
+ } catch (e) {
+ var res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || res === undefined)
+ res = "unknown exception";
+ return BINDING.js_string_to_mono_string (res);
+ }
+ },
+ mono_wasm_get_object_property: function(js_handle, property_name, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var obj = BINDING.mono_wasm_require_handle (js_handle);
+ if (!obj) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ var js_name = BINDING.conv_string (property_name);
+ if (!js_name) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid property name object '" + js_name + "'");
+ }
+
+ var res;
+ try {
+ var m = obj [js_name];
+ if (m === Object(m) && obj.__is_mono_proxied__)
+ m.__is_mono_proxied__ = true;
+
+ return BINDING.js_to_mono_obj (m);
+ } catch (e) {
+ var res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || typeof res === "undefined")
+ res = "unknown exception";
+ return BINDING.js_string_to_mono_string (res);
+ }
+ },
+ mono_wasm_set_object_property: function (js_handle, property_name, value, createIfNotExist, hasOwnProperty, is_exception) {
+
+ BINDING.bindings_lazy_init ();
+
+ var requireObject = BINDING.mono_wasm_require_handle (js_handle);
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ var property = BINDING.conv_string (property_name);
+ if (!property) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid property name object '" + property_name + "'");
+ }
+
+ var result = false;
+
+ var js_value = BINDING.unbox_mono_obj(value);
+
+ if (createIfNotExist) {
+ requireObject[property] = js_value;
+ result = true;
+ }
+ else {
+ result = false;
+ if (!createIfNotExist)
+ {
+ if (!requireObject.hasOwnProperty(property))
+ return false;
+ }
+ if (hasOwnProperty === true) {
+ if (requireObject.hasOwnProperty(property)) {
+ requireObject[property] = js_value;
+ result = true;
+ }
+ }
+ else {
+ requireObject[property] = js_value;
+ result = true;
+ }
+
+ }
+ return BINDING.call_method (BINDING.box_js_bool, null, "im", [ result ]);
+ },
+ mono_wasm_get_by_index: function(js_handle, property_index, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var obj = BINDING.mono_wasm_require_handle (js_handle);
+ if (!obj) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ try {
+ var m = obj [property_index];
+ return BINDING.js_to_mono_obj (m);
+ } catch (e) {
+ var res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || typeof res === "undefined")
+ res = "unknown exception";
+ return BINDING.js_string_to_mono_string (res);
+ }
+ },
+ mono_wasm_set_by_index: function(js_handle, property_index, value, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var obj = BINDING.mono_wasm_require_handle (js_handle);
+ if (!obj) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ var js_value = BINDING.unbox_mono_obj(value);
+
+ try {
+ obj [property_index] = js_value;
+ return true;
+ } catch (e) {
+ var res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || typeof res === "undefined")
+ res = "unknown exception";
+ return BINDING.js_string_to_mono_string (res);
+ }
+ },
+ mono_wasm_get_global_object: function(global_name, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var js_name = BINDING.conv_string (global_name);
+
+ var globalObj = undefined;
+
+ if (!js_name) {
+ globalObj = BINDING.mono_wasm_get_global();
+ }
+ else {
+ globalObj = BINDING.mono_wasm_get_global()[js_name];
+ }
+
+ if (globalObj === null || typeof globalObj === undefined) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Global object '" + js_name + "' not found.");
+ }
+
+ return BINDING.js_to_mono_obj (globalObj);
+ },
+ mono_wasm_release_handle: function(js_handle, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ BINDING.mono_wasm_free_handle(js_handle);
+ },
+ mono_wasm_release_object: function(js_handle, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ BINDING.mono_wasm_free_raw_object(js_handle);
+ },
+ mono_wasm_bind_core_object: function(js_handle, gc_handle, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var requireObject = BINDING.mono_wasm_require_handle (js_handle);
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ BINDING.wasm_bind_core_clr_obj(js_handle, gc_handle );
+ requireObject.__mono_gchandle__ = gc_handle;
+ return gc_handle;
+ },
+ mono_wasm_bind_host_object: function(js_handle, gc_handle, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var requireObject = BINDING.mono_wasm_require_handle (js_handle);
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ BINDING.wasm_bind_core_clr_obj(js_handle, gc_handle );
+ requireObject.__mono_gchandle__ = gc_handle;
+ return gc_handle;
+ },
+ mono_wasm_new: function (core_name, args, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var js_name = BINDING.conv_string (core_name);
+
+ if (!js_name) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Core object '" + js_name + "' not found.");
+ }
+
+ var coreObj = BINDING.mono_wasm_get_global()[js_name];
+
+ if (coreObj === null || typeof coreObj === "undefined") {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("JavaScript host object '" + js_name + "' not found.");
+ }
+
+ var js_args = BINDING.mono_array_to_js_array(args);
+
+ try {
+
+ // This is all experimental !!!!!!
+ var allocator = function(constructor, js_args) {
+ // Not sure if we should be checking for anything here
+ var argsList = new Array();
+ argsList[0] = constructor;
+ if (js_args)
+ argsList = argsList.concat(js_args);
+ var obj = new (constructor.bind.apply(constructor, argsList ));
+ return obj;
+ };
+
+ var res = allocator(coreObj, js_args);
+ var gc_handle = BINDING.mono_wasm_free_list.length ? BINDING.mono_wasm_free_list.pop() : BINDING.mono_wasm_ref_counter++;
+ BINDING.mono_wasm_object_registry[gc_handle] = res;
+ return BINDING.js_to_mono_obj (gc_handle + 1);
+ } catch (e) {
+ var res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || res === undefined)
+ res = "Error allocating object.";
+ return BINDING.js_string_to_mono_string (res);
+ }
+
+ },
+ mono_wasm_new_object: function(object_handle_or_function, args, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ if (!object_handle_or_function) {
+ return BINDING.js_to_mono_obj ({});
+ }
+ else {
+
+ var requireObject;
+ if (typeof object_handle_or_function === 'function')
+ requireObject = object_handle_or_function;
+ else
+ requireObject = BINDING.mono_wasm_require_handle (object_handle_or_function);
+
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + object_handle_or_function + "'");
+ }
+
+ var js_args = BINDING.mono_array_to_js_array(args);
+
+ try {
+
+ // This is all experimental !!!!!!
+ var allocator = function(constructor, js_args) {
+ // Not sure if we should be checking for anything here
+ var argsList = new Array();
+ argsList[0] = constructor;
+ if (js_args)
+ argsList = argsList.concat(js_args);
+ var obj = new (constructor.bind.apply(constructor, argsList ));
+ return obj;
+ };
+
+ var res = allocator(requireObject, js_args);
+ return BINDING.extract_mono_obj (res);
+ } catch (e) {
+ var res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || res === undefined)
+ res = "Error allocating object.";
+ return BINDING.js_string_to_mono_string (res);
+ }
+ }
+
+ },
+ mono_wasm_typed_array_to_array: function(js_handle, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var requireObject = BINDING.mono_wasm_require_handle (js_handle);
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ return BINDING.js_typed_array_to_array(requireObject);
+ },
+ mono_wasm_typed_array_copy_to: function(js_handle, pinned_array, begin, end, bytes_per_element, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var requireObject = BINDING.mono_wasm_require_handle (js_handle);
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ var res = BINDING.typedarray_copy_to(requireObject, pinned_array, begin, end, bytes_per_element);
+ return BINDING.js_to_mono_obj (res)
+ },
+ mono_wasm_typed_array_from: function(pinned_array, begin, end, bytes_per_element, type, is_exception) {
+ BINDING.bindings_lazy_init ();
+ var res = BINDING.typed_array_from(pinned_array, begin, end, bytes_per_element, type);
+ return BINDING.js_to_mono_obj (res)
+ },
+ mono_wasm_typed_array_copy_from: function(js_handle, pinned_array, begin, end, bytes_per_element, is_exception) {
+ BINDING.bindings_lazy_init ();
+
+ var requireObject = BINDING.mono_wasm_require_handle (js_handle);
+ if (!requireObject) {
+ setValue (is_exception, 1, "i32");
+ return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
+ }
+
+ var res = BINDING.typedarray_copy_from(requireObject, pinned_array, begin, end, bytes_per_element);
+ return BINDING.js_to_mono_obj (res)
+ },
+
+
+};
+
+autoAddDeps(BindingSupportLib, '$BINDING')
+mergeInto(LibraryManager.library, BindingSupportLib)
diff --git a/src/mono/wasm/runtime/corebindings.c b/src/mono/wasm/runtime/corebindings.c
new file mode 100644
index 00000000000..f4700369585
--- /dev/null
+++ b/src/mono/wasm/runtime/corebindings.c
@@ -0,0 +1,179 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#include <emscripten.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include <mono/jit/jit.h>
+
+//JS funcs
+extern MonoObject* mono_wasm_invoke_js_with_args (int js_handle, MonoString *method, MonoArray *args, int *is_exception);
+extern MonoObject* mono_wasm_get_object_property (int js_handle, MonoString *propertyName, int *is_exception);
+extern MonoObject* mono_wasm_get_by_index (int js_handle, int property_index, int *is_exception);
+extern MonoObject* mono_wasm_set_object_property (int js_handle, MonoString *propertyName, MonoObject *value, int createIfNotExist, int hasOwnProperty, int *is_exception);
+extern MonoObject* mono_wasm_set_by_index (int js_handle, int property_index, MonoObject *value, int *is_exception);
+extern MonoObject* mono_wasm_get_global_object (MonoString *global_name, int *is_exception);
+extern void* mono_wasm_release_handle (int js_handle, int *is_exception);
+extern void* mono_wasm_release_object (int js_handle, int *is_exception);
+extern MonoObject* mono_wasm_new_object (int js_handle, MonoArray *args, int *is_exception);
+extern MonoObject* mono_wasm_new (MonoString *core_name, MonoArray *args, int *is_exception);
+extern int mono_wasm_bind_core_object (int js_handle, int gc_handle, int *is_exception);
+extern int mono_wasm_bind_host_object (int js_handle, int gc_handle, int *is_exception);
+extern MonoObject* mono_wasm_typed_array_to_array (int js_handle, int *is_exception);
+extern MonoObject* mono_wasm_typed_array_copy_to (int js_handle, int ptr, int begin, int end, int bytes_per_element, int *is_exception);
+extern MonoObject* mono_wasm_typed_array_from (int ptr, int begin, int end, int bytes_per_element, int type, int *is_exception);
+extern MonoObject* mono_wasm_typed_array_copy_from (int js_handle, int ptr, int begin, int end, int bytes_per_element, int *is_exception);
+
+// Compiles a JavaScript function from the function data passed.
+// Note: code snippet is not a function definition. Instead it must create and return a function instance.
+EM_JS(MonoObject*, compile_function, (int snippet_ptr, int len, int *is_exception), {
+ try {
+ var data = MONO.string_decoder.decode (snippet_ptr, snippet_ptr + len);
+ var wrapper = '(function () { ' + data + ' })';
+ var funcFactory = eval(wrapper);
+ var func = funcFactory();
+ if (typeof func !== 'function') {
+ throw new Error('Code must return an instance of a JavaScript function. '
+ + 'Please use `return` statement to return a function.');
+ }
+ setValue (is_exception, 0, "i32");
+ return BINDING.js_to_mono_obj (func);
+ }
+ catch (e)
+ {
+ res = e.toString ();
+ setValue (is_exception, 1, "i32");
+ if (res === null || res === undefined)
+ res = "unknown exception";
+ return BINDING.js_to_mono_obj (res);
+ }
+});
+
+static MonoObject*
+mono_wasm_compile_function (MonoString *str, int *is_exception)
+{
+ if (str == NULL)
+ return NULL;
+ //char *native_val = mono_string_to_utf8 (str);
+ mono_unichar2 *native_val = mono_string_chars (str);
+ int native_len = mono_string_length (str) * 2;
+
+ MonoObject* native_res = compile_function((int)native_val, native_len, is_exception);
+ mono_free (native_val);
+ if (native_res == NULL)
+ return NULL;
+ return native_res;
+}
+
+void core_initialize_internals ()
+{
+ mono_add_internal_call ("WebAssembly.Runtime::InvokeJSWithArgs", mono_wasm_invoke_js_with_args);
+ mono_add_internal_call ("WebAssembly.Runtime::GetObjectProperty", mono_wasm_get_object_property);
+ mono_add_internal_call ("WebAssembly.Runtime::GetByIndex", mono_wasm_get_by_index);
+ mono_add_internal_call ("WebAssembly.Runtime::SetObjectProperty", mono_wasm_set_object_property);
+ mono_add_internal_call ("WebAssembly.Runtime::SetByIndex", mono_wasm_set_by_index);
+ mono_add_internal_call ("WebAssembly.Runtime::GetGlobalObject", mono_wasm_get_global_object);
+ mono_add_internal_call ("WebAssembly.Runtime::ReleaseHandle", mono_wasm_release_handle);
+ mono_add_internal_call ("WebAssembly.Runtime::ReleaseObject", mono_wasm_release_object);
+ mono_add_internal_call ("WebAssembly.Runtime::NewObjectJS", mono_wasm_new_object);
+ mono_add_internal_call ("WebAssembly.Runtime::BindCoreObject", mono_wasm_bind_core_object);
+ mono_add_internal_call ("WebAssembly.Runtime::BindHostObject", mono_wasm_bind_host_object);
+ mono_add_internal_call ("WebAssembly.Runtime::New", mono_wasm_new);
+ mono_add_internal_call ("WebAssembly.Runtime::TypedArrayToArray", mono_wasm_typed_array_to_array);
+ mono_add_internal_call ("WebAssembly.Runtime::TypedArrayCopyTo", mono_wasm_typed_array_copy_to);
+ mono_add_internal_call ("WebAssembly.Runtime::TypedArrayFrom", mono_wasm_typed_array_from);
+ mono_add_internal_call ("WebAssembly.Runtime::TypedArrayCopyFrom", mono_wasm_typed_array_copy_from);
+ mono_add_internal_call ("WebAssembly.Runtime::CompileFunction", mono_wasm_compile_function);
+
+}
+
+// Int8Array | int8_t | byte or SByte (signed byte)
+// Uint8Array | uint8_t | byte or Byte (unsigned byte)
+// Uint8ClampedArray| uint8_t | byte or Byte (unsigned byte)
+// Int16Array | int16_t | short (signed short)
+// Uint16Array | uint16_t | ushort (unsigned short)
+// Int32Array | int32_t | int (signed integer)
+// Uint32Array | uint32_t | uint (unsigned integer)
+// Float32Array | float | float
+// Float64Array | double | double
+// typed array marshalling
+#define MARSHAL_ARRAY_BYTE 11
+#define MARSHAL_ARRAY_UBYTE 12
+#define MARSHAL_ARRAY_SHORT 13
+#define MARSHAL_ARRAY_USHORT 14
+#define MARSHAL_ARRAY_INT 15
+#define MARSHAL_ARRAY_UINT 16
+#define MARSHAL_ARRAY_FLOAT 17
+#define MARSHAL_ARRAY_DOUBLE 18
+
+EMSCRIPTEN_KEEPALIVE MonoArray*
+mono_wasm_typed_array_new (char *arr, int length, int size, int type)
+{
+ MonoClass *typeClass = mono_get_byte_class(); // default is Byte
+ switch (type) {
+ case MARSHAL_ARRAY_BYTE:
+ typeClass = mono_get_sbyte_class();
+ break;
+ case MARSHAL_ARRAY_SHORT:
+ typeClass = mono_get_int16_class();
+ break;
+ case MARSHAL_ARRAY_USHORT:
+ typeClass = mono_get_uint16_class();
+ break;
+ case MARSHAL_ARRAY_INT:
+ typeClass = mono_get_int32_class();
+ break;
+ case MARSHAL_ARRAY_UINT:
+ typeClass = mono_get_uint32_class();
+ break;
+ case MARSHAL_ARRAY_FLOAT:
+ typeClass = mono_get_single_class();
+ break;
+ case MARSHAL_ARRAY_DOUBLE:
+ typeClass = mono_get_double_class();
+ break;
+ }
+
+ MonoArray *buffer;
+
+ buffer = mono_array_new (mono_get_root_domain(), typeClass, length);
+ memcpy(mono_array_addr_with_size(buffer, sizeof(char), 0), arr, length * size);
+
+ return buffer;
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_wasm_unbox_enum (MonoObject *obj)
+{
+ if (!obj)
+ return 0;
+
+ MonoType *type = mono_class_get_type (mono_object_get_class(obj));
+
+ void *ptr = mono_object_unbox (obj);
+ switch (mono_type_get_type(mono_type_get_underlying_type (type))) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ return *(unsigned char*)ptr;
+ case MONO_TYPE_I2:
+ return *(short*)ptr;
+ case MONO_TYPE_U2:
+ return *(unsigned short*)ptr;
+ case MONO_TYPE_I4:
+ return *(int*)ptr;
+ case MONO_TYPE_U4:
+ return *(unsigned int*)ptr;
+ // WASM doesn't support returning longs to JS
+ // case MONO_TYPE_I8:
+ // case MONO_TYPE_U8:
+ default:
+ printf ("Invalid type %d to mono_unbox_enum\n", mono_type_get_type(mono_type_get_underlying_type (type)));
+ return 0;
+ }
+}
+
+
diff --git a/src/mono/wasm/runtime/dotnet_support.js b/src/mono/wasm/runtime/dotnet_support.js
new file mode 100644
index 00000000000..e2db502123e
--- /dev/null
+++ b/src/mono/wasm/runtime/dotnet_support.js
@@ -0,0 +1,96 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+var DotNetSupportLib = {
+ $DOTNET: {
+ _dotnet_get_global: function() {
+ function testGlobal(obj) {
+ obj['___dotnet_global___'] = obj;
+ var success = typeof ___dotnet_global___ === 'object' && obj['___dotnet_global___'] === obj;
+ if (!success) {
+ delete obj['___dotnet_global___'];
+ }
+ return success;
+ }
+ if (typeof ___dotnet_global___ === 'object') {
+ return ___dotnet_global___;
+ }
+ if (typeof global === 'object' && testGlobal(global)) {
+ ___dotnet_global___ = global;
+ } else if (typeof window === 'object' && testGlobal(window)) {
+ ___dotnet_global___ = window;
+ }
+ if (typeof ___dotnet_global___ === 'object') {
+ return ___dotnet_global___;
+ }
+ throw Error('unable to get DotNet global object.');
+ },
+ conv_string: function (mono_obj) {
+ return MONO.string_decoder.copy (mono_obj);
+ }
+ },
+ mono_wasm_invoke_js_marshalled: function(exceptionMessage, asyncHandleLongPtr, functionName, argsJson) {
+
+ var mono_string = DOTNET._dotnet_get_global()._mono_string_cached
+ || (DOTNET._dotnet_get_global()._mono_string_cached = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']));
+
+ try {
+ // Passing a .NET long into JS via Emscripten is tricky. The method here is to pass
+ // as pointer to the long, then combine two reads from the HEAPU32 array.
+ // Even though JS numbers can't represent the full range of a .NET long, it's OK
+ // because we'll never exceed Number.MAX_SAFE_INTEGER (2^53 - 1) in this case.
+ //var u32Index = $1 >> 2;
+ var u32Index = asyncHandleLongPtr >> 2;
+ var asyncHandleJsNumber = Module.HEAPU32[u32Index + 1]*4294967296 + Module.HEAPU32[u32Index];
+
+ // var funcNameJsString = UTF8ToString (functionName);
+ // var argsJsonJsString = argsJson && UTF8ToString (argsJson);
+ var funcNameJsString = DOTNET.conv_string(functionName);
+ var argsJsonJsString = argsJson && DOTNET.conv_string (argsJson);
+
+ var dotNetExports = DOTNET._dotnet_get_global().DotNet;
+ if (!dotNetExports) {
+ throw new Error('The Microsoft.JSInterop.js library is not loaded.');
+ }
+
+ if (asyncHandleJsNumber) {
+ dotNetExports.jsCallDispatcher.beginInvokeJSFromDotNet(asyncHandleJsNumber, funcNameJsString, argsJsonJsString);
+ return 0;
+ } else {
+ var resultJson = dotNetExports.jsCallDispatcher.invokeJSFromDotNet(funcNameJsString, argsJsonJsString);
+ return resultJson === null ? 0 : mono_string(resultJson);
+ }
+ } catch (ex) {
+ var exceptionJsString = ex.message + '\n' + ex.stack;
+ var exceptionSystemString = mono_string(exceptionJsString);
+ setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString;
+ return 0;
+ }
+ },
+ mono_wasm_invoke_js_unmarshalled: function(exceptionMessage, funcName, arg0, arg1, arg2) {
+ try {
+ // Get the function you're trying to invoke
+ var funcNameJsString = DOTNET.conv_string(funcName);
+ var dotNetExports = DOTNET._dotnet_get_global().DotNet;
+ if (!dotNetExports) {
+ throw new Error('The Microsoft.JSInterop.js library is not loaded.');
+ }
+ var funcInstance = dotNetExports.jsCallDispatcher.findJSFunction(funcNameJsString);
+
+ return funcInstance.call(null, arg0, arg1, arg2);
+ } catch (ex) {
+ var exceptionJsString = ex.message + '\n' + ex.stack;
+ var mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']); // TODO: Cache
+ var exceptionSystemString = mono_string(exceptionJsString);
+ setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString;
+ return 0;
+ }
+ }
+
+
+};
+
+autoAddDeps(DotNetSupportLib, '$DOTNET')
+mergeInto(LibraryManager.library, DotNetSupportLib)
+
diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c
new file mode 100644
index 00000000000..c55ecba5a4c
--- /dev/null
+++ b/src/mono/wasm/runtime/driver.c
@@ -0,0 +1,759 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#include <emscripten.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <dlfcn.h>
+
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/tokentype.h>
+#include <mono/metadata/threads.h>
+#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-dl-fallback.h>
+#include <mono/jit/jit.h>
+
+#include "pinvoke-table.h"
+
+#ifdef CORE_BINDINGS
+void core_initialize_internals ();
+#endif
+
+// Blazor specific custom routines - see dotnet_support.js for backing code
+extern void* mono_wasm_invoke_js_marshalled (MonoString **exceptionMessage, void *asyncHandleLongPtr, MonoString *funcName, MonoString *argsJson);
+extern void* mono_wasm_invoke_js_unmarshalled (MonoString **exceptionMessage, MonoString *funcName, void* arg0, void* arg1, void* arg2);
+
+void mono_wasm_enable_debugging (int);
+
+void mono_ee_interp_init (const char *opts);
+void mono_marshal_ilgen_init (void);
+void mono_method_builder_ilgen_init (void);
+void mono_sgen_mono_ilgen_init (void);
+void mono_icall_table_init (void);
+void mono_aot_register_module (void **aot_info);
+char *monoeg_g_getenv(const char *variable);
+int monoeg_g_setenv(const char *variable, const char *value, int overwrite);
+void mono_free (void*);
+int32_t mini_parse_debug_option (const char *option);
+
+static MonoClass* datetime_class;
+static MonoClass* datetimeoffset_class;
+static MonoClass* uri_class;
+
+int mono_wasm_enable_gc;
+
+/* Not part of public headers */
+#define MONO_ICALL_TABLE_CALLBACKS_VERSION 2
+
+typedef struct {
+ int version;
+ void* (*lookup) (MonoMethod *method, char *classname, char *methodname, char *sigstart, int32_t *uses_handles);
+ const char* (*lookup_icall_symbol) (void* func);
+} MonoIcallTableCallbacks;
+
+void
+mono_install_icall_table_callbacks (const MonoIcallTableCallbacks *cb);
+
+int mono_regression_test_step (int verbose_level, char *image, char *method_name);
+void mono_trace_init (void);
+
+#define g_new(type, size) ((type *) malloc (sizeof (type) * (size)))
+#define g_new0(type, size) ((type *) calloc (sizeof (type), (size)))
+
+static MonoDomain *root_domain;
+
+static MonoString*
+mono_wasm_invoke_js (MonoString *str, int *is_exception)
+{
+ if (str == NULL)
+ return NULL;
+
+ mono_unichar2 *native_val = mono_string_chars (str);
+ int native_len = mono_string_length (str) * 2;
+
+ mono_unichar2 *native_res = (mono_unichar2*)EM_ASM_INT ({
+ var str = MONO.string_decoder.decode ($0, $0 + $1);
+ try {
+ var res = eval (str);
+ if (res === null || res == undefined)
+ return 0;
+ res = res.toString ();
+ setValue ($2, 0, "i32");
+ } catch (e) {
+ res = e.toString ();
+ setValue ($2, 1, "i32");
+ if (res === null || res === undefined)
+ res = "unknown exception";
+ }
+ var buff = Module._malloc((res.length + 1) * 2);
+ stringToUTF16 (res, buff, (res.length + 1) * 2);
+ return buff;
+ }, (int)native_val, native_len, is_exception);
+
+ if (native_res == NULL)
+ return NULL;
+
+ MonoString *res = mono_string_from_utf16 (native_res);
+ free (native_res);
+ return res;
+}
+
+static void
+wasm_logger (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data)
+{
+ if (fatal) {
+ EM_ASM(
+ var err = new Error();
+ console.log ("Stacktrace: \n");
+ console.log (err.stack);
+ );
+
+ fprintf (stderr, "%s\n", message);
+ fflush (stderr);
+
+ abort ();
+ } else {
+ fprintf (stdout, "L: %s\n", message);
+ }
+}
+
+#ifdef DRIVER_GEN
+#include "driver-gen.c"
+#endif
+
+typedef struct WasmAssembly_ WasmAssembly;
+
+struct WasmAssembly_ {
+ MonoBundledAssembly assembly;
+ WasmAssembly *next;
+};
+
+static WasmAssembly *assemblies;
+static int assembly_count;
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_add_assembly (const char *name, const unsigned char *data, unsigned int size)
+{
+ int len = strlen (name);
+ if (!strcasecmp (".pdb", &name [len - 4])) {
+ char *new_name = strdup (name);
+ //FIXME handle debugging assemblies with .exe extension
+ strcpy (&new_name [len - 3], "dll");
+ mono_register_symfile_for_assembly (new_name, data, size);
+ return;
+ }
+ WasmAssembly *entry = g_new0 (WasmAssembly, 1);
+ entry->assembly.name = strdup (name);
+ entry->assembly.data = data;
+ entry->assembly.size = size;
+ entry->next = assemblies;
+ assemblies = entry;
+ ++assembly_count;
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_setenv (const char *name, const char *value)
+{
+ monoeg_g_setenv (strdup (name), strdup (value), 1);
+}
+
+#ifdef ENABLE_NETCORE
+static void *sysglobal_native_handle;
+#endif
+
+static void*
+wasm_dl_load (const char *name, int flags, char **err, void *user_data)
+{
+ for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) {
+ if (!strcmp (name, pinvoke_names [i]))
+ return pinvoke_tables [i];
+ }
+
+#ifdef ENABLE_NETCORE
+ if (!strcmp (name, "System.Globalization.Native"))
+ return sysglobal_native_handle;
+#endif
+
+#if WASM_SUPPORTS_DLOPEN
+ return dlopen(name, flags);
+#endif
+
+ return NULL;
+}
+
+static mono_bool
+wasm_dl_is_pinvoke_tables (void* handle)
+{
+ for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) {
+ if (pinvoke_tables [i] == handle) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void*
+wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data)
+{
+#ifdef ENABLE_NETCORE
+ if (handle == sysglobal_native_handle)
+ assert (0);
+#endif
+
+#if WASM_SUPPORTS_DLOPEN
+ if (!wasm_dl_is_pinvoke_tables (handle)) {
+ return dlsym (handle, name);
+ }
+#endif
+
+ PinvokeImport *table = (PinvokeImport*)handle;
+ for (int i = 0; table [i].name; ++i) {
+ if (!strcmp (table [i].name, name))
+ return table [i].func;
+ }
+ return NULL;
+}
+
+#ifdef ENABLE_NETCORE
+/* Missing System.Native symbols */
+int SystemNative_CloseNetworkChangeListenerSocket (int a) { return 0; }
+int SystemNative_CreateNetworkChangeListenerSocket (int a) { return 0; }
+void SystemNative_ReadEvents (int a,int b) {}
+int SystemNative_SchedGetAffinity (int a,int b) { return 0; }
+int SystemNative_SchedSetAffinity (int a,int b) { return 0; }
+#endif
+
+#if !defined(ENABLE_AOT) || defined(EE_MODE_LLVMONLY_INTERP)
+#define NEED_INTERP 1
+#ifndef LINK_ICALLS
+// FIXME: llvm+interp mode needs this to call icalls
+#define NEED_NORMAL_ICALL_TABLES 1
+#endif
+#endif
+
+#ifdef LINK_ICALLS
+
+#include "icall-table.h"
+
+static int
+compare_int (const void *k1, const void *k2)
+{
+ return *(int*)k1 - *(int*)k2;
+}
+
+static void*
+icall_table_lookup (MonoMethod *method, char *classname, char *methodname, char *sigstart, int32_t *uses_handles)
+{
+ uint32_t token = mono_method_get_token (method);
+ assert (token);
+ assert ((token & MONO_TOKEN_METHOD_DEF) == MONO_TOKEN_METHOD_DEF);
+ uint32_t token_idx = token - MONO_TOKEN_METHOD_DEF;
+
+ int *indexes = NULL;
+ int indexes_size = 0;
+ uint8_t *handles = NULL;
+ void **funcs = NULL;
+
+ *uses_handles = 0;
+
+ const char *image_name = mono_image_get_name (mono_class_get_image (mono_method_get_class (method)));
+
+#ifdef ICALL_TABLE_mscorlib
+ if (!strcmp (image_name, "mscorlib") || !strcmp (image_name, "System.Private.CoreLib")) {
+ indexes = mscorlib_icall_indexes;
+ indexes_size = sizeof (mscorlib_icall_indexes) / 4;
+ handles = mscorlib_icall_handles;
+ funcs = mscorlib_icall_funcs;
+ assert (sizeof (mscorlib_icall_indexes [0]) == 4);
+ }
+#ifdef ICALL_TABLE_System
+ if (!strcmp (image_name, "System")) {
+ indexes = System_icall_indexes;
+ indexes_size = sizeof (System_icall_indexes) / 4;
+ handles = System_icall_handles;
+ funcs = System_icall_funcs;
+ }
+#endif
+ assert (indexes);
+
+ void *p = bsearch (&token_idx, indexes, indexes_size, 4, compare_int);
+ if (!p) {
+ return NULL;
+ printf ("wasm: Unable to lookup icall: %s\n", mono_method_get_name (method));
+ exit (1);
+ }
+
+ uint32_t idx = (int*)p - indexes;
+ *uses_handles = handles [idx];
+
+ //printf ("ICALL: %s %x %d %d\n", methodname, token, idx, (int)(funcs [idx]));
+
+ return funcs [idx];
+#endif
+}
+
+static const char*
+icall_table_lookup_symbol (void *func)
+{
+ assert (0);
+ return NULL;
+}
+
+#endif
+
+void mono_initialize_internals ()
+{
+ mono_add_internal_call ("WebAssembly.Runtime::InvokeJS", mono_wasm_invoke_js);
+ // TODO: what happens when two types in different assemblies have the same FQN?
+
+ // Blazor specific custom routines - see dotnet_support.js for backing code
+ mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSMarshalled", mono_wasm_invoke_js_marshalled);
+ mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSUnmarshalled", mono_wasm_invoke_js_unmarshalled);
+
+#ifdef CORE_BINDINGS
+ core_initialize_internals();
+#endif
+
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_load_runtime (const char *managed_path, int enable_debugging)
+{
+ const char *interp_opts = "";
+
+ monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0);
+ monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0);
+#ifdef ENABLE_NETCORE
+ monoeg_g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", 0);
+#endif
+
+ mini_parse_debug_option ("top-runtime-invoke-unhandled");
+
+ mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL);
+
+#ifdef ENABLE_AOT
+ // Defined in driver-gen.c
+ register_aot_modules ();
+#ifdef EE_MODE_LLVMONLY_INTERP
+ mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY_INTERP);
+#else
+ mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY);
+#endif
+#else
+ mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_LLVMONLY);
+ if (enable_debugging) {
+ // Disable optimizations which interfere with debugging
+ interp_opts = "-all";
+ mono_wasm_enable_debugging (enable_debugging);
+ }
+#endif
+
+#ifdef LINK_ICALLS
+ /* Link in our own linked icall table */
+ static const MonoIcallTableCallbacks mono_icall_table_callbacks =
+ {
+ MONO_ICALL_TABLE_CALLBACKS_VERSION,
+ icall_table_lookup,
+ icall_table_lookup_symbol
+ };
+ mono_install_icall_table_callbacks (&mono_icall_table_callbacks);
+#endif
+
+#ifdef NEED_NORMAL_ICALL_TABLES
+ mono_icall_table_init ();
+#endif
+#ifdef NEED_INTERP
+ mono_ee_interp_init (interp_opts);
+ mono_marshal_ilgen_init ();
+ mono_method_builder_ilgen_init ();
+ mono_sgen_mono_ilgen_init ();
+#endif
+
+ if (assembly_count) {
+ MonoBundledAssembly **bundle_array = g_new0 (MonoBundledAssembly*, assembly_count + 1);
+ WasmAssembly *cur = assemblies;
+ int i = 0;
+ while (cur) {
+ bundle_array [i] = &cur->assembly;
+ cur = cur->next;
+ ++i;
+ }
+ mono_register_bundled_assemblies ((const MonoBundledAssembly **)bundle_array);
+ }
+
+ mono_trace_init ();
+ mono_trace_set_log_handler (wasm_logger, NULL);
+ root_domain = mono_jit_init_version ("mono", "v4.0.30319");
+
+ mono_initialize_internals();
+
+ mono_thread_set_main (mono_thread_current ());
+}
+
+EMSCRIPTEN_KEEPALIVE MonoAssembly*
+mono_wasm_assembly_load (const char *name)
+{
+ MonoImageOpenStatus status;
+ MonoAssemblyName* aname = mono_assembly_name_new (name);
+ if (!name)
+ return NULL;
+
+ MonoAssembly *res = mono_assembly_load (aname, NULL, &status);
+ mono_assembly_name_free (aname);
+
+ return res;
+}
+
+EMSCRIPTEN_KEEPALIVE MonoClass*
+mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name)
+{
+ return mono_class_from_name (mono_assembly_get_image (assembly), namespace, name);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoMethod*
+mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments)
+{
+ return mono_class_get_method_from_name (klass, name, arguments);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoObject*
+mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[], MonoObject **out_exc)
+{
+ MonoObject *exc = NULL;
+ MonoObject *res;
+
+ if (out_exc)
+ *out_exc = NULL;
+ res = mono_runtime_invoke (method, this_arg, params, &exc);
+ if (exc) {
+ if (out_exc)
+ *out_exc = exc;
+
+ MonoObject *exc2 = NULL;
+ res = (MonoObject*)mono_object_to_string (exc, &exc2);
+ if (exc2)
+ res = (MonoObject*) mono_string_new (root_domain, "Exception Double Fault");
+ return res;
+ }
+
+ MonoMethodSignature *sig = mono_method_signature (method);
+ MonoType *type = mono_signature_get_return_type (sig);
+ // If the method return type is void return null
+ // This gets around a memory access crash when the result return a value when
+ // a void method is invoked.
+ if (mono_type_get_type (type) == MONO_TYPE_VOID)
+ return NULL;
+
+ return res;
+}
+
+EMSCRIPTEN_KEEPALIVE MonoMethod*
+mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
+{
+ MonoImage *image;
+ MonoMethod *method;
+
+ image = mono_assembly_get_image (assembly);
+ uint32_t entry = mono_image_get_entry_point (image);
+ if (!entry)
+ return NULL;
+
+ return mono_get_method (image, entry, NULL);
+}
+
+EMSCRIPTEN_KEEPALIVE char *
+mono_wasm_string_get_utf8 (MonoString *str)
+{
+ return mono_string_to_utf8 (str); //XXX JS is responsible for freeing this
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_string_convert (MonoString *str)
+{
+ if (str == NULL)
+ return;
+
+ mono_unichar2 *native_val = mono_string_chars (str);
+ int native_len = mono_string_length (str) * 2;
+
+ EM_ASM ({
+ MONO.string_decoder.decode($0, $0 + $1, true);
+ }, (int)native_val, native_len);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoString *
+mono_wasm_string_from_js (const char *str)
+{
+ if (str)
+ return mono_string_new (root_domain, str);
+ else
+ return NULL;
+}
+
+static int
+class_is_task (MonoClass *klass)
+{
+ if (!strcmp ("System.Threading.Tasks", mono_class_get_namespace (klass)) &&
+ (!strcmp ("Task", mono_class_get_name (klass)) || !strcmp ("Task`1", mono_class_get_name (klass))))
+ return 1;
+
+ return 0;
+}
+
+MonoClass* mono_get_uri_class(MonoException** exc)
+{
+ MonoAssembly* assembly = mono_wasm_assembly_load ("System");
+ if (!assembly)
+ return NULL;
+ MonoClass* klass = mono_wasm_assembly_find_class(assembly, "System", "Uri");
+ return klass;
+}
+
+#define MARSHAL_TYPE_INT 1
+#define MARSHAL_TYPE_FP 2
+#define MARSHAL_TYPE_STRING 3
+#define MARSHAL_TYPE_VT 4
+#define MARSHAL_TYPE_DELEGATE 5
+#define MARSHAL_TYPE_TASK 6
+#define MARSHAL_TYPE_OBJECT 7
+#define MARSHAL_TYPE_BOOL 8
+#define MARSHAL_TYPE_ENUM 9
+#define MARSHAL_TYPE_DATE 20
+#define MARSHAL_TYPE_DATEOFFSET 21
+#define MARSHAL_TYPE_URI 22
+
+// typed array marshalling
+#define MARSHAL_ARRAY_BYTE 11
+#define MARSHAL_ARRAY_UBYTE 12
+#define MARSHAL_ARRAY_SHORT 13
+#define MARSHAL_ARRAY_USHORT 14
+#define MARSHAL_ARRAY_INT 15
+#define MARSHAL_ARRAY_UINT 16
+#define MARSHAL_ARRAY_FLOAT 17
+#define MARSHAL_ARRAY_DOUBLE 18
+
+EMSCRIPTEN_KEEPALIVE int
+mono_wasm_get_obj_type (MonoObject *obj)
+{
+ if (!obj)
+ return 0;
+
+ if (!datetime_class)
+ datetime_class = mono_class_from_name (mono_get_corlib(), "System", "DateTime");
+ if (!datetimeoffset_class)
+ datetimeoffset_class = mono_class_from_name (mono_get_corlib(), "System", "DateTimeOffset");
+ if (!uri_class) {
+ MonoException** exc = NULL;
+ uri_class = mono_get_uri_class(exc);
+ }
+
+ MonoClass *klass = mono_object_get_class (obj);
+ MonoType *type = mono_class_get_type (klass);
+
+ switch (mono_type_get_type (type)) {
+ // case MONO_TYPE_CHAR: prob should be done not as a number?
+ case MONO_TYPE_BOOLEAN:
+ return MARSHAL_TYPE_BOOL;
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I: // IntPtr
+ return MARSHAL_TYPE_INT;
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ return MARSHAL_TYPE_FP;
+ case MONO_TYPE_STRING:
+ return MARSHAL_TYPE_STRING;
+ case MONO_TYPE_SZARRAY: { // simple zero based one-dim-array
+ MonoClass *eklass = mono_class_get_element_class(klass);
+ MonoType *etype = mono_class_get_type (eklass);
+
+ switch (mono_type_get_type (etype)) {
+ case MONO_TYPE_U1:
+ return MARSHAL_ARRAY_UBYTE;
+ case MONO_TYPE_I1:
+ return MARSHAL_ARRAY_BYTE;
+ case MONO_TYPE_U2:
+ return MARSHAL_ARRAY_USHORT;
+ case MONO_TYPE_I2:
+ return MARSHAL_ARRAY_SHORT;
+ case MONO_TYPE_U4:
+ return MARSHAL_ARRAY_UINT;
+ case MONO_TYPE_I4:
+ return MARSHAL_ARRAY_INT;
+ case MONO_TYPE_R4:
+ return MARSHAL_ARRAY_FLOAT;
+ case MONO_TYPE_R8:
+ return MARSHAL_ARRAY_DOUBLE;
+ default:
+ return MARSHAL_TYPE_OBJECT;
+ }
+ }
+ default:
+ if (klass == datetime_class)
+ return MARSHAL_TYPE_DATE;
+ if (klass == datetimeoffset_class)
+ return MARSHAL_TYPE_DATEOFFSET;
+ if (uri_class && mono_class_is_assignable_from(uri_class, klass))
+ return MARSHAL_TYPE_URI;
+ if (mono_class_is_enum (klass))
+ return MARSHAL_TYPE_ENUM;
+ if (!mono_type_is_reference (type)) //vt
+ return MARSHAL_TYPE_VT;
+ if (mono_class_is_delegate (klass))
+ return MARSHAL_TYPE_DELEGATE;
+ if (class_is_task(klass))
+ return MARSHAL_TYPE_TASK;
+
+ return MARSHAL_TYPE_OBJECT;
+ }
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_unbox_int (MonoObject *obj)
+{
+ if (!obj)
+ return 0;
+ MonoType *type = mono_class_get_type (mono_object_get_class(obj));
+
+ void *ptr = mono_object_unbox (obj);
+ switch (mono_type_get_type (type)) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_BOOLEAN:
+ return *(signed char*)ptr;
+ case MONO_TYPE_U1:
+ return *(unsigned char*)ptr;
+ case MONO_TYPE_I2:
+ return *(short*)ptr;
+ case MONO_TYPE_U2:
+ return *(unsigned short*)ptr;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_I:
+ return *(int*)ptr;
+ case MONO_TYPE_U4:
+ return *(unsigned int*)ptr;
+ // WASM doesn't support returning longs to JS
+ // case MONO_TYPE_I8:
+ // case MONO_TYPE_U8:
+ default:
+ printf ("Invalid type %d to mono_unbox_int\n", mono_type_get_type (type));
+ return 0;
+ }
+}
+
+EMSCRIPTEN_KEEPALIVE double
+mono_wasm_unbox_float (MonoObject *obj)
+{
+ if (!obj)
+ return 0;
+ MonoType *type = mono_class_get_type (mono_object_get_class(obj));
+
+ void *ptr = mono_object_unbox (obj);
+ switch (mono_type_get_type (type)) {
+ case MONO_TYPE_R4:
+ return *(float*)ptr;
+ case MONO_TYPE_R8:
+ return *(double*)ptr;
+ default:
+ printf ("Invalid type %d to mono_wasm_unbox_float\n", mono_type_get_type (type));
+ return 0;
+ }
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_wasm_array_length (MonoArray *array)
+{
+ return mono_array_length (array);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoObject*
+mono_wasm_array_get (MonoArray *array, int idx)
+{
+ return mono_array_get (array, MonoObject*, idx);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoArray*
+mono_wasm_obj_array_new (int size)
+{
+ return mono_array_new (root_domain, mono_get_object_class (), size);
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj)
+{
+ mono_array_setref (array, idx, obj);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoArray*
+mono_wasm_string_array_new (int size)
+{
+ return mono_array_new (root_domain, mono_get_string_class (), size);
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_wasm_exec_regression (int verbose_level, char *image)
+{
+ return mono_regression_test_step (verbose_level, image, NULL) ? 0 : 1;
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_wasm_exit (int exit_code)
+{
+ exit (exit_code);
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_set_main_args (int argc, char* argv[])
+{
+ mono_runtime_set_main_args (argc, argv);
+}
+
+EMSCRIPTEN_KEEPALIVE int
+mono_wasm_strdup (const char *s)
+{
+ return (int)strdup (s);
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_parse_runtime_options (int argc, char* argv[])
+{
+ mono_jit_parse_options (argc, argv);
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_enable_on_demand_gc (void)
+{
+ mono_wasm_enable_gc = 1;
+}
+
+// Returns the local timezone default is UTC.
+EM_JS(size_t, mono_wasm_timezone_get_local_name, (),
+{
+ var res = "UTC";
+ try {
+ res = Intl.DateTimeFormat().resolvedOptions().timeZone;
+ } catch(e) {}
+
+ var buff = Module._malloc((res.length + 1) * 2);
+ stringToUTF16 (res, buff, (res.length + 1) * 2);
+ return buff;
+})
+
+void
+mono_timezone_get_local_name (MonoString **result)
+{
+ // WASM returns back an int pointer to a string UTF16 buffer.
+ // We then cast to `mono_unichar2*`. Returning `mono_unichar2*` from the JavaScript call will
+ // result in cast warnings from the compiler.
+ mono_unichar2 *tzd_local_name = (mono_unichar2*)mono_wasm_timezone_get_local_name ();
+ *result = mono_string_from_utf16 (tzd_local_name);
+ free (tzd_local_name);
+}
diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js
new file mode 100644
index 00000000000..61e6234949d
--- /dev/null
+++ b/src/mono/wasm/runtime/library_mono.js
@@ -0,0 +1,1000 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+var MonoSupportLib = {
+ $MONO__postset: 'MONO.export_functions (Module);',
+ $MONO: {
+ pump_count: 0,
+ timeout_queue: [],
+ _vt_stack: [],
+ mono_wasm_runtime_is_ready : false,
+ mono_wasm_ignore_pdb_load_errors: true,
+ pump_message: function () {
+ if (!this.mono_background_exec)
+ this.mono_background_exec = Module.cwrap ("mono_background_exec", null);
+ while (MONO.timeout_queue.length > 0) {
+ --MONO.pump_count;
+ MONO.timeout_queue.shift()();
+ }
+ while (MONO.pump_count > 0) {
+ --MONO.pump_count;
+ this.mono_background_exec ();
+ }
+ },
+
+ export_functions: function (module) {
+ module ["pump_message"] = MONO.pump_message;
+ module ["mono_load_runtime_and_bcl"] = MONO.mono_load_runtime_and_bcl;
+ },
+
+ mono_text_decoder: undefined,
+ string_decoder: {
+ copy: function (mono_string) {
+ if (mono_string == 0)
+ return null;
+
+ if (!this.mono_wasm_string_convert)
+ this.mono_wasm_string_convert = Module.cwrap ("mono_wasm_string_convert", null, ['number']);
+
+ this.mono_wasm_string_convert (mono_string);
+ var result = this.result;
+ this.result = undefined;
+ return result;
+ },
+ decode: function (start, end, save) {
+ if (!MONO.mono_text_decoder) {
+ MONO.mono_text_decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;
+ }
+
+ var str = "";
+ if (MONO.mono_text_decoder) {
+ // When threading is enabled, TextDecoder does not accept a view of a
+ // SharedArrayBuffer, we must make a copy of the array first.
+ var subArray = typeof SharedArrayBuffer !== 'undefined' && Module.HEAPU8.buffer instanceof SharedArrayBuffer
+ ? Module.HEAPU8.slice(start, end)
+ : Module.HEAPU8.subarray(start, end);
+
+ str = MONO.mono_text_decoder.decode(subArray);
+ } else {
+ for (var i = 0; i < end - start; i+=2) {
+ var char = Module.getValue (start + i, 'i16');
+ str += String.fromCharCode (char);
+ }
+ }
+ if (save)
+ this.result = str;
+
+ return str;
+ },
+ },
+
+ mono_wasm_get_call_stack: function() {
+ if (!this.mono_wasm_current_bp_id)
+ this.mono_wasm_current_bp_id = Module.cwrap ("mono_wasm_current_bp_id", 'number');
+ if (!this.mono_wasm_enum_frames)
+ this.mono_wasm_enum_frames = Module.cwrap ("mono_wasm_enum_frames", null);
+
+ var bp_id = this.mono_wasm_current_bp_id ();
+ this.active_frames = [];
+ this.mono_wasm_enum_frames ();
+
+ var the_frames = this.active_frames;
+ this.active_frames = [];
+ return {
+ "breakpoint_id": bp_id,
+ "frames": the_frames,
+ };
+ },
+
+ _fixup_name_value_objects: function (var_list) {
+ var out_list = [];
+
+ var _fixup_value = function (value) {
+ if (value != null && value != undefined) {
+ var descr = value.description;
+ if (descr == null || descr == undefined)
+ value.description = '' + value.value;
+ }
+ return value;
+ };
+
+ var i = 0;
+ while (i < var_list.length) {
+ var o = var_list [i];
+ var name = o.name;
+ if (name == null || name == undefined) {
+ i ++;
+ o.value = _fixup_value(o.value);
+ out_list.push (o);
+ continue;
+ }
+
+ if (i + 1 < var_list.length)
+ o.value = _fixup_value(var_list[i + 1].value);
+
+ out_list.push (o);
+ i += 2;
+ }
+
+ return out_list;
+ },
+
+ _filter_automatic_properties: function (props) {
+ var names_found = {};
+ var final_var_list = [];
+
+ for (var i in props) {
+ var p = props [i];
+ if (p.name in names_found)
+ continue;
+
+ if (p.name.endsWith ("k__BackingField"))
+ p.name = p.name.replace ("k__BackingField", "")
+ .replace ('<', '')
+ .replace ('>', '');
+
+ names_found [p.name] = p.name;
+ final_var_list.push (p);
+ }
+
+ return final_var_list;
+ },
+
+ mono_wasm_get_variables: function(scope, var_list) {
+ if (!this.mono_wasm_get_var_info)
+ this.mono_wasm_get_var_info = Module.cwrap ("mono_wasm_get_var_info", null, [ 'number', 'number', 'number']);
+
+ this.var_info = [];
+ var numBytes = var_list.length * Int32Array.BYTES_PER_ELEMENT;
+ var ptr = Module._malloc(numBytes);
+ var heapBytes = new Int32Array(Module.HEAP32.buffer, ptr, numBytes);
+ for (let i=0; i<var_list.length; i++) {
+ heapBytes[i] = var_list[i]
+ }
+
+ this._async_method_objectId = 0;
+ this.mono_wasm_get_var_info (scope, heapBytes.byteOffset, var_list.length);
+ Module._free(heapBytes.byteOffset);
+ var res = MONO._fixup_name_value_objects (this.var_info);
+
+ //Async methods are special in the way that local variables can be lifted to generated class fields
+ //value of "this" comes here either
+ for (let i in res) {
+ var name = res [i].name;
+ if (name != undefined && name.indexOf ('>') > 0)
+ res [i].name = name.substring (1, name.indexOf ('>'));
+ }
+
+ if (this._async_method_objectId != 0) {
+ for (let i in res) {
+ if (res [i].value.isValueType != undefined && res [i].value.isValueType)
+ res [i].value.objectId = `dotnet:valuetype:${this._async_method_objectId}:${res [i].fieldOffset}`;
+ }
+ }
+
+ this._post_process_details(res);
+ this.var_info = []
+
+ return res;
+ },
+
+ mono_wasm_get_object_properties: function(objId, expandValueTypes) {
+ if (!this.mono_wasm_get_object_properties_info)
+ this.mono_wasm_get_object_properties_info = Module.cwrap ("mono_wasm_get_object_properties", null, [ 'number', 'bool' ]);
+
+ this.var_info = [];
+ this.mono_wasm_get_object_properties_info (objId, expandValueTypes);
+
+ var res = MONO._filter_automatic_properties (MONO._fixup_name_value_objects (this.var_info));
+ for (var i = 0; i < res.length; i++) {
+ if (res [i].value.isValueType != undefined && res [i].value.isValueType)
+ res [i].value.objectId = `dotnet:valuetype:${objId}:${res [i].fieldOffset}`;
+ }
+
+ this.var_info = [];
+
+ return res;
+ },
+
+ mono_wasm_get_array_values: function(objId) {
+ if (!this.mono_wasm_get_array_values_info)
+ this.mono_wasm_get_array_values_info = Module.cwrap ("mono_wasm_get_array_values", null, [ 'number' ]);
+
+ this.var_info = [];
+ this.mono_wasm_get_array_values_info (objId);
+
+ var res = MONO._fixup_name_value_objects (this.var_info);
+ for (var i = 0; i < res.length; i++) {
+ if (res [i].value.isValueType != undefined && res [i].value.isValueType)
+ res [i].value.objectId = `dotnet:array:${objId}:${i}`;
+ }
+
+ this.var_info = [];
+
+ return res;
+ },
+
+ mono_wasm_get_array_value_expanded: function(objId, idx) {
+ if (!this.mono_wasm_get_array_value_expanded_info)
+ this.mono_wasm_get_array_value_expanded_info = Module.cwrap ("mono_wasm_get_array_value_expanded", null, [ 'number', 'number' ]);
+
+ this.var_info = [];
+ this.mono_wasm_get_array_value_expanded_info (objId, idx);
+
+ var res = MONO._fixup_name_value_objects (this.var_info);
+ // length should be exactly one!
+ if (res [0].value.isValueType != undefined && res [0].value.isValueType)
+ res [0].value.objectId = `dotnet:array:${objId}:${idx}`;
+
+ this.var_info = [];
+
+ return res;
+ },
+
+ _post_process_details: function (details) {
+ if (details == undefined)
+ return {};
+
+ if (details.length > 0)
+ this._extract_and_cache_value_types(details);
+
+ return details;
+ },
+
+ _next_value_type_id: function () {
+ return ++this._next_value_type_id_var;
+ },
+
+ _extract_and_cache_value_types: function (var_list) {
+ if (var_list == undefined || !Array.isArray (var_list) || var_list.length == 0)
+ return var_list;
+
+ for (let i in var_list) {
+ var value = var_list [i].value;
+ if (value == undefined || value.type != "object")
+ continue;
+
+ if (value.isValueType != true || value.expanded != true) // undefined would also give us false
+ continue;
+
+ var objectId = value.objectId;
+ if (objectId == undefined)
+ objectId = `dotnet:valuetype:${this._next_value_type_id ()}`;
+ value.objectId = objectId;
+
+ this._extract_and_cache_value_types (value.members);
+
+ this._value_types_cache [objectId] = value.members;
+ delete value.members;
+ }
+
+ return var_list;
+ },
+
+ _get_details_for_value_type: function (objectId, fetchDetailsFn) {
+ if (objectId in this._value_types_cache)
+ return this._value_types_cache[objectId];
+
+ this._post_process_details (fetchDetailsFn());
+ if (objectId in this._value_types_cache)
+ return this._value_types_cache[objectId];
+
+ // return error
+ throw new Error (`Could not get details for ${objectId}`);
+ },
+
+ _is_object_id_array: function (objectId) {
+ // Keep this in sync with `_get_array_details`
+ return (objectId.startsWith ('dotnet:array:') && objectId.split (':').length == 3);
+ },
+
+ _get_array_details: function (objectId, objectIdParts) {
+ // Keep this in sync with `_is_object_id_array`
+ switch (objectIdParts.length) {
+ case 3:
+ return this._post_process_details (this.mono_wasm_get_array_values(objectIdParts[2]));
+
+ case 4:
+ var arrayObjectId = objectIdParts[2];
+ var arrayIdx = objectIdParts[3];
+ return this._get_details_for_value_type(
+ objectId, () => this.mono_wasm_get_array_value_expanded(arrayObjectId, arrayIdx));
+
+ default:
+ throw new Error (`object id format not supported : ${objectId}`);
+ }
+ },
+
+ mono_wasm_get_details: function (objectId, args) {
+ var parts = objectId.split(":");
+ if (parts[0] != "dotnet")
+ throw new Error ("Can't handle non-dotnet object ids. ObjectId: " + objectId);
+
+ switch (parts[1]) {
+ case "object":
+ if (parts.length != 3)
+ throw new Error(`exception this time: Invalid object id format: ${objectId}`);
+
+ return this._post_process_details(this.mono_wasm_get_object_properties(parts[2], false));
+
+ case "array":
+ return this._get_array_details(objectId, parts);
+
+ case "valuetype":
+ if (parts.length != 3 && parts.length != 4) {
+ // dotnet:valuetype:vtid
+ // dotnet:valuetype:containerObjectId:vtId
+ throw new Error(`Invalid object id format: ${objectId}`);
+ }
+
+ var containerObjectId = parts[2];
+ return this._get_details_for_value_type(objectId, () => this.mono_wasm_get_object_properties(containerObjectId, true));
+
+ case "cfo_res": {
+ if (!(objectId in this._call_function_res_cache))
+ throw new Error(`Could not find any object with id ${objectId}`);
+
+ var real_obj = this._call_function_res_cache [objectId];
+ if (args.accessorPropertiesOnly) {
+ // var val_accessors = JSON.stringify ([
+ // {
+ // name: "__proto__",
+ // get: { type: "function", className: "Function", description: "function get __proto__ () {}", objectId: "dotnet:cfo_res:9999" },
+ // set: { type: "function", className: "Function", description: "function set __proto__ () {}", objectId: "dotnet:cfo_res:8888" },
+ // isOwn: false
+ // }], undefined, 4);
+ return { __value_as_json_string__: "[]" };
+ }
+
+ // behaving as if (args.ownProperties == true)
+ var descriptors = Object.getOwnPropertyDescriptors (real_obj);
+ var own_properties = [];
+ Object.keys (descriptors).forEach (k => {
+ var new_obj;
+ var prop_desc = descriptors [k];
+ if (typeof prop_desc.value == "object") {
+ // convert `{value: { type='object', ... }}`
+ // to `{ name: 'foo', value: { type='object', ... }}
+ new_obj = Object.assign ({ name: k}, prop_desc);
+ } else {
+ // This is needed for values that were not added by us,
+ // thus are like { value: 5 }
+ // instead of { value: { type = 'number', value: 5 }}
+ //
+ // This can happen, for eg., when `length` gets added for arrays
+ // or `__proto__`.
+ new_obj = {
+ name: k,
+ // merge/add `type` and `description` to `d.value`
+ value: Object.assign ({ type: (typeof prop_desc.value), description: '' + prop_desc.value },
+ prop_desc)
+ };
+ }
+
+ own_properties.push (new_obj);
+ });
+
+ return { __value_as_json_string__: JSON.stringify (own_properties) };
+ }
+
+ default:
+ throw new Error(`Unknown object id format: ${objectId}`);
+ }
+ },
+
+ _cache_call_function_res: function (obj) {
+ var id = `dotnet:cfo_res:${this._next_call_function_res_id++}`;
+ this._call_function_res_cache[id] = obj;
+ return id;
+ },
+
+ mono_wasm_release_object: function (objectId) {
+ if (objectId in this._cache_call_function_res)
+ delete this._cache_call_function_res[objectId];
+ },
+
+ mono_wasm_call_function_on: function (request) {
+ var objId = request.objectId;
+ var proxy;
+
+ if (objId in this._call_function_res_cache) {
+ proxy = this._call_function_res_cache [objId];
+ } else if (!objId.startsWith ('dotnet:cfo_res:')) {
+ var details = this.mono_wasm_get_details(objId);
+ var target_is_array = this._is_object_id_array (objId);
+ proxy = target_is_array ? [] : {};
+
+ Object.keys(details).forEach(p => {
+ var prop = details[p];
+ if (target_is_array) {
+ proxy.push(prop.value);
+ } else {
+ if (prop.name != undefined)
+ proxy [prop.name] = prop.value;
+ else // when can this happen??
+ proxy[''+p] = prop.value;
+ }
+ });
+ }
+
+ var fn_args = request.arguments != undefined ? request.arguments.map(a => a.value) : [];
+ var fn_eval_str = `var fn = ${request.functionDeclaration}; fn.call (proxy, ...[${fn_args}]);`;
+
+ var fn_res = eval (fn_eval_str);
+ if (request.returnByValue)
+ return fn_res;
+
+ if (fn_res == undefined)
+ throw Error ('Function returned undefined result');
+
+ var fn_res_id = this._cache_call_function_res (fn_res);
+ if (Object.getPrototypeOf (fn_res) == Array.prototype) {
+ return {
+ type: "object",
+ subtype: "array",
+ className: "Array",
+ description: `Array(${fn_res.length})`,
+ objectId: fn_res_id
+ };
+ } else {
+ return { type: "object", className: "Object", description: "Object", objectId: fn_res_id };
+ }
+ },
+
+ mono_wasm_start_single_stepping: function (kind) {
+ console.log (">> mono_wasm_start_single_stepping " + kind);
+ if (!this.mono_wasm_setup_single_step)
+ this.mono_wasm_setup_single_step = Module.cwrap ("mono_wasm_setup_single_step", 'number', [ 'number']);
+
+ this._next_value_type_id_var = 0;
+ this._value_types_cache = {};
+
+ return this.mono_wasm_setup_single_step (kind);
+ },
+
+ mono_wasm_runtime_ready: function () {
+ this.mono_wasm_runtime_is_ready = true;
+ // DO NOT REMOVE - magic debugger init function
+ console.debug ("mono_wasm_runtime_ready", "fe00e07a-5519-4dfe-b35a-f867dbaf2e28");
+
+ this._next_value_type_id_var = 0;
+ this._value_types_cache = {};
+
+ // FIXME: where should this go?
+ this._next_call_function_res_id = 0;
+ this._call_function_res_cache = {};
+ },
+
+ mono_wasm_set_breakpoint: function (assembly, method_token, il_offset) {
+ if (!this.mono_wasm_set_bp)
+ this.mono_wasm_set_bp = Module.cwrap ('mono_wasm_set_breakpoint', 'number', ['string', 'number', 'number']);
+
+ return this.mono_wasm_set_bp (assembly, method_token, il_offset)
+ },
+
+ mono_wasm_remove_breakpoint: function (breakpoint_id) {
+ if (!this.mono_wasm_del_bp)
+ this.mono_wasm_del_bp = Module.cwrap ('mono_wasm_remove_breakpoint', 'number', ['number']);
+
+ return this.mono_wasm_del_bp (breakpoint_id);
+ },
+
+ // Set environment variable NAME to VALUE
+ // Should be called before mono_load_runtime_and_bcl () in most cases
+ mono_wasm_setenv: function (name, value) {
+ if (!this.wasm_setenv)
+ this.wasm_setenv = Module.cwrap ('mono_wasm_setenv', null, ['string', 'string']);
+ this.wasm_setenv (name, value);
+ },
+
+ mono_wasm_set_runtime_options: function (options) {
+ if (!this.wasm_parse_runtime_options)
+ this.wasm_parse_runtime_options = Module.cwrap ('mono_wasm_parse_runtime_options', null, ['number', 'number']);
+ var argv = Module._malloc (options.length * 4);
+ var wasm_strdup = Module.cwrap ('mono_wasm_strdup', 'number', ['string']);
+ aindex = 0;
+ for (var i = 0; i < options.length; ++i) {
+ Module.setValue (argv + (aindex * 4), wasm_strdup (options [i]), "i32");
+ aindex += 1;
+ }
+ this.wasm_parse_runtime_options (options.length, argv);
+ },
+
+ //
+ // Initialize the AOT profiler with OPTIONS.
+ // Requires the AOT profiler to be linked into the app.
+ // options = { write_at: "<METHODNAME>", send_to: "<METHODNAME>" }
+ // <METHODNAME> should be in the format <CLASS>::<METHODNAME>.
+ // write_at defaults to 'WebAssembly.Runtime::StopProfile'.
+ // send_to defaults to 'WebAssembly.Runtime::DumpAotProfileData'.
+ // DumpAotProfileData stores the data into Module.aot_profile_data.
+ //
+ mono_wasm_init_aot_profiler: function (options) {
+ if (options == null)
+ options = {}
+ if (!('write_at' in options))
+ options.write_at = 'WebAssembly.Runtime::StopProfile';
+ if (!('send_to' in options))
+ options.send_to = 'WebAssembly.Runtime::DumpAotProfileData';
+ var arg = "aot:write-at-method=" + options.write_at + ",send-to-method=" + options.send_to;
+ Module.ccall ('mono_wasm_load_profiler_aot', null, ['string'], [arg]);
+ },
+
+ // options = { write_at: "<METHODNAME>", send_to: "<METHODNAME>" }
+ // <METHODNAME> should be in the format <CLASS>::<METHODNAME>.
+ // write_at defaults to 'WebAssembly.Runtime::StopProfile'.
+ // send_to defaults to 'WebAssembly.Runtime::DumpCoverageProfileData'.
+ // DumpCoverageProfileData stores the data into Module.coverage_profile_data.
+ mono_wasm_init_coverage_profiler: function (options) {
+ if (options == null)
+ options = {}
+ if (!('write_at' in options))
+ options.write_at = 'WebAssembly.Runtime::StopProfile';
+ if (!('send_to' in options))
+ options.send_to = 'WebAssembly.Runtime::DumpCoverageProfileData';
+ var arg = "coverage:write-at-method=" + options.write_at + ",send-to-method=" + options.send_to;
+ Module.ccall ('mono_wasm_load_profiler_coverage', null, ['string'], [arg]);
+ },
+
+ mono_load_runtime_and_bcl: function (vfs_prefix, deploy_prefix, enable_debugging, file_list, loaded_cb, fetch_file_cb) {
+ var pending = file_list.length;
+ var loaded_files = [];
+ var mono_wasm_add_assembly = Module.cwrap ('mono_wasm_add_assembly', null, ['string', 'number', 'number']);
+
+ if (!fetch_file_cb) {
+ if (ENVIRONMENT_IS_NODE) {
+ var fs = require('fs');
+ fetch_file_cb = function (asset) {
+ console.log("MONO_WASM: Loading... " + asset);
+ var binary = fs.readFileSync (asset);
+ var resolve_func2 = function(resolve, reject) {
+ resolve(new Uint8Array (binary));
+ };
+
+ var resolve_func1 = function(resolve, reject) {
+ var response = {
+ ok: true,
+ url: asset,
+ arrayBuffer: function() {
+ return new Promise(resolve_func2);
+ }
+ };
+ resolve(response);
+ };
+
+ return new Promise(resolve_func1);
+ };
+ } else {
+ fetch_file_cb = function (asset) {
+ return fetch (asset, { credentials: 'same-origin' });
+ }
+ }
+ }
+
+ file_list.forEach (function(file_name) {
+
+ var fetch_promise = fetch_file_cb (locateFile(deploy_prefix + "/" + file_name));
+
+ fetch_promise.then (function (response) {
+ if (!response.ok) {
+ // If it's a 404 on a .pdb, we don't want to block the app from starting up.
+ // We'll just skip that file and continue (though the 404 is logged in the console).
+ if (response.status === 404 && file_name.match(/\.pdb$/) && MONO.mono_wasm_ignore_pdb_load_errors) {
+ --pending;
+ throw "MONO-WASM: Skipping failed load for .pdb file: '" + file_name + "'";
+ }
+ else {
+ throw "MONO_WASM: Failed to load file: '" + file_name + "'";
+ }
+ }
+ else {
+ loaded_files.push (response.url);
+ return response ['arrayBuffer'] ();
+ }
+ }).then (function (blob) {
+ var asm = new Uint8Array (blob);
+ var memory = Module._malloc(asm.length);
+ var heapBytes = new Uint8Array(Module.HEAPU8.buffer, memory, asm.length);
+ heapBytes.set (asm);
+ mono_wasm_add_assembly (file_name, memory, asm.length);
+
+ //console.log ("MONO_WASM: Loaded: " + file_name);
+ --pending;
+ if (pending == 0) {
+ MONO.loaded_files = loaded_files;
+ var load_runtime = Module.cwrap ('mono_wasm_load_runtime', null, ['string', 'number']);
+
+ console.log ("MONO_WASM: Initializing mono runtime");
+ if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) {
+ try {
+ load_runtime (vfs_prefix, enable_debugging);
+ } catch (ex) {
+ print ("MONO_WASM: load_runtime () failed: " + ex);
+ var err = new Error();
+ print ("MONO_WASM: Stacktrace: \n");
+ print (err.stack);
+
+ var wasm_exit = Module.cwrap ('mono_wasm_exit', null, ['number']);
+ wasm_exit (1);
+ }
+ } else {
+ load_runtime (vfs_prefix, enable_debugging);
+ }
+ MONO.mono_wasm_runtime_ready ();
+ loaded_cb ();
+ }
+ });
+ });
+ },
+
+ mono_wasm_get_loaded_files: function() {
+ console.log(">>>mono_wasm_get_loaded_files");
+ return this.loaded_files;
+ },
+
+ mono_wasm_clear_all_breakpoints: function() {
+ if (!this.mono_clear_bps)
+ this.mono_clear_bps = Module.cwrap ('mono_wasm_clear_all_breakpoints', null);
+
+ this.mono_clear_bps ();
+ },
+
+ mono_wasm_add_null_var: function(className)
+ {
+ fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className));
+ if (!fixed_class_name) {
+ // Eg, when a @className is passed from js itself, like
+ // mono_wasm_add_null_var ("string")
+ fixed_class_name = className;
+ }
+ MONO.var_info.push ({value: {
+ type: "object",
+ className: fixed_class_name,
+ description: fixed_class_name,
+ subtype: "null"
+ }});
+ },
+
+ _mono_wasm_add_string_var: function(var_value) {
+ if (var_value == 0) {
+ MONO.mono_wasm_add_null_var ("string");
+ return;
+ }
+
+ MONO.var_info.push({
+ value: {
+ type: "string",
+ value: var_value,
+ }
+ });
+ },
+
+ _mono_wasm_add_getter_var: function(className) {
+ fixed_class_name = MONO._mono_csharp_fixup_class_name (className);
+ var value = `${fixed_class_name} { get; }`;
+ MONO.var_info.push({
+ value: {
+ type: "symbol",
+ value: value,
+ description: value
+ }
+ });
+ },
+
+ _mono_wasm_add_array_var: function(className, objectId, length) {
+ fixed_class_name = MONO._mono_csharp_fixup_class_name(className);
+ if (objectId == 0) {
+ MONO.mono_wasm_add_null_var (fixed_class_name);
+ return;
+ }
+
+ MONO.var_info.push({
+ value: {
+ type: "object",
+ subtype: "array",
+ className: fixed_class_name,
+ description: `${fixed_class_name}(${length})`,
+ objectId: "dotnet:array:"+ objectId,
+ }
+ });
+ },
+
+ mono_wasm_add_typed_value: function (type, str_value, value) {
+ var type_str = type;
+ if (typeof type != 'string')
+ type_str = Module.UTF8ToString (type);
+ if (typeof str_value != 'string')
+ str_value = Module.UTF8ToString (str_value);
+
+ switch (type_str) {
+ case "bool":
+ MONO.var_info.push ({
+ value: {
+ type: "boolean",
+ value: value != 0
+ }
+ });
+ break;
+
+ case "char":
+ MONO.var_info.push ({
+ value: {
+ type: "symbol",
+ value: `${value} '${String.fromCharCode (value)}'`
+ }
+ });
+ break;
+
+ case "number":
+ MONO.var_info.push ({
+ value: {
+ type: "number",
+ value: value
+ }
+ });
+ break;
+
+ case "string":
+ MONO._mono_wasm_add_string_var (str_value);
+ break;
+
+ case "getter":
+ MONO._mono_wasm_add_getter_var (str_value);
+ break;
+
+ case "array":
+ MONO._mono_wasm_add_array_var (str_value, value.objectId, value.length);
+ break;
+
+ case "pointer": {
+ MONO.var_info.push ({
+ value: {
+ type: "symbol",
+ value: str_value,
+ description: str_value
+ }
+ });
+ }
+ break;
+
+ default: {
+ var msg = `'${str_value}' ${value}`;
+
+ MONO.var_info.push ({
+ value: {
+ type: "symbol",
+ value: msg,
+ description: msg
+ }
+ });
+ break;
+ }
+ }
+ },
+
+ _mono_csharp_fixup_class_name: function(className)
+ {
+ // Fix up generic names like Foo`2<int, string> to Foo<int, string>
+ // and nested class names like Foo/Bar to Foo.Bar
+ return className.replace(/\//g, '.').replace(/`\d+/g, '');
+ },
+ },
+
+ mono_wasm_add_typed_value: function (type, str_value, value) {
+ MONO.mono_wasm_add_typed_value (type, str_value, value);
+ },
+
+ mono_wasm_add_properties_var: function(name, field_offset) {
+ MONO.var_info.push({
+ name: Module.UTF8ToString (name),
+ fieldOffset: field_offset
+ });
+ },
+
+ mono_wasm_set_is_async_method: function(objectId) {
+ MONO._async_method_objectId = objectId;
+ },
+
+ mono_wasm_begin_value_type_var: function(className, toString) {
+ fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className));
+ var vt_obj = {
+ value: {
+ type: "object",
+ className: fixed_class_name,
+ description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)),
+ // objectId will be generated by MonoProxy
+ expanded: true,
+ isValueType: true,
+ members: []
+ }
+ };
+ if (MONO._vt_stack.length == 0)
+ MONO._old_var_info = MONO.var_info;
+
+ MONO.var_info = vt_obj.value.members;
+ MONO._vt_stack.push (vt_obj);
+ },
+
+ mono_wasm_end_value_type_var: function() {
+ var top_vt_obj_popped = MONO._vt_stack.pop ();
+ top_vt_obj_popped.value.members = MONO._filter_automatic_properties (
+ MONO._fixup_name_value_objects (top_vt_obj_popped.value.members));
+
+ if (MONO._vt_stack.length == 0) {
+ MONO.var_info = MONO._old_var_info;
+ MONO.var_info.push(top_vt_obj_popped);
+ } else {
+ var top_obj = MONO._vt_stack [MONO._vt_stack.length - 1];
+ top_obj.value.members.push (top_vt_obj_popped);
+ MONO.var_info = top_obj.value.members;
+ }
+ },
+
+ mono_wasm_add_value_type_unexpanded_var: function (className, toString) {
+ fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className));
+ MONO.var_info.push({
+ value: {
+ type: "object",
+ className: fixed_class_name,
+ description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)),
+ // objectId added when enumerating object's properties
+ expanded: false,
+ isValueType: true
+ }
+ });
+ },
+
+ mono_wasm_add_enum_var: function(className, members, value) {
+ // FIXME: flags
+ //
+
+ // group0: Monday:0
+ // group1: Monday
+ // group2: 0
+ var re = new RegExp (`[,]?([^,:]+):(${value}(?=,)|${value}$)`, 'g')
+ var members_str = Module.UTF8ToString (members);
+
+ var match = re.exec(members_str);
+ var member_name = match == null ? ('' + value) : match [1];
+
+ fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className));
+ MONO.var_info.push({
+ value: {
+ type: "object",
+ className: fixed_class_name,
+ description: member_name,
+ isEnum: true
+ }
+ });
+ },
+
+ mono_wasm_add_array_item: function(position) {
+ MONO.var_info.push({
+ name: `${position}`
+ });
+ },
+
+ mono_wasm_add_obj_var: function(className, toString, objectId) {
+ if (objectId == 0) {
+ MONO.mono_wasm_add_null_var (className);
+ return;
+ }
+
+ fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className));
+ MONO.var_info.push({
+ value: {
+ type: "object",
+ className: fixed_class_name,
+ description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)),
+ objectId: "dotnet:object:"+ objectId,
+ }
+ });
+ },
+
+ /*
+ * @className, and @targetName are in the following format:
+ *
+ * <ret_type>:[<comma separated list of arg types>]:<method name>
+ */
+ mono_wasm_add_func_var: function (className, targetName, objectId) {
+ if (objectId == 0) {
+ MONO.mono_wasm_add_null_var (
+ MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className)));
+ return;
+ }
+
+ function args_to_sig (args_str) {
+ var parts = args_str.split (":");
+ // TODO: min length = 3?
+ parts = parts.map (a => MONO._mono_csharp_fixup_class_name (a));
+
+ // method name at the end
+ var method_name = parts.pop ();
+
+ // ret type at the beginning
+ var ret_sig = parts [0];
+ var args_sig = parts.splice (1).join (', ');
+ return `${ret_sig} ${method_name} (${args_sig})`;
+ }
+
+ var tgt_sig;
+ if (targetName != 0)
+ tgt_sig = args_to_sig (Module.UTF8ToString (targetName));
+
+ var type_name = MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className));
+
+ if (objectId == -1) {
+ // Target property
+ MONO.var_info.push ({
+ value: {
+ type: "symbol",
+ value: tgt_sig,
+ description: tgt_sig,
+ }
+ });
+ } else {
+ MONO.var_info.push ({
+ value: {
+ type: "object",
+ className: type_name,
+ description: tgt_sig,
+ objectId: "dotnet:object:" + objectId,
+ }
+ });
+ }
+ },
+
+ mono_wasm_add_frame: function(il, method, assembly_name, method_full_name) {
+ var parts = Module.UTF8ToString (method_full_name).split (":", 2);
+ MONO.active_frames.push( {
+ il_pos: il,
+ method_token: method,
+ assembly_name: Module.UTF8ToString (assembly_name),
+ // Extract just the method name from `{class_name}:{method_name}`
+ method_name: parts [parts.length - 1]
+ });
+ },
+
+ schedule_background_exec: function () {
+ ++MONO.pump_count;
+ if (ENVIRONMENT_IS_WEB) {
+ window.setTimeout (MONO.pump_message, 0);
+ } else if (ENVIRONMENT_IS_WORKER) {
+ self.setTimeout (MONO.pump_message, 0);
+ } else if (ENVIRONMENT_IS_NODE) {
+ global.setTimeout (MONO.pump_message, 0);
+ }
+ },
+
+ mono_set_timeout: function (timeout, id) {
+ if (!this.mono_set_timeout_exec)
+ this.mono_set_timeout_exec = Module.cwrap ("mono_set_timeout_exec", null, [ 'number' ]);
+ if (ENVIRONMENT_IS_WEB) {
+ window.setTimeout (function () {
+ this.mono_set_timeout_exec (id);
+ }, timeout);
+ } else if (ENVIRONMENT_IS_WORKER) {
+ self.setTimeout (function () {
+ this.mono_set_timeout_exec (id);
+ }, timeout);
+ } else if (ENVIRONMENT_IS_NODE) {
+ global.setTimeout (function () {
+ global.mono_set_timeout_exec (id);
+ }, timeout);
+ } else {
+ ++MONO.pump_count;
+ MONO.timeout_queue.push(function() {
+ this.mono_set_timeout_exec (id);
+ })
+ }
+ },
+
+ mono_wasm_fire_bp: function () {
+ console.log ("mono_wasm_fire_bp");
+ debugger;
+ }
+};
+
+autoAddDeps(MonoSupportLib, '$MONO')
+mergeInto(LibraryManager.library, MonoSupportLib)
diff --git a/src/mono/wasm/runtime/linker-preserves.xml b/src/mono/wasm/runtime/linker-preserves.xml
new file mode 100644
index 00000000000..2e46279b879
--- /dev/null
+++ b/src/mono/wasm/runtime/linker-preserves.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<linker>
+ <assembly fullname="System">
+ <type fullname="Mono.Util.MonoPInvokeCallbackAttribute"/>
+ </assembly>
+</linker>
+
diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj
new file mode 100644
index 00000000000..3ea7167a8c5
--- /dev/null
+++ b/src/mono/wasm/wasm.proj
@@ -0,0 +1,46 @@
+<Project Sdk="Microsoft.Build.NoTargets" DefaultTargets="BuildWasmRuntimes">
+ <PropertyGroup>
+ <TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
+ </PropertyGroup>
+
+ <UsingTask TaskName="PInvokeTableGenerator"
+ AssemblyFile="$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmAppBuilder', '$(NetCoreAppCurrent)-$(MonoConfiguration)'))publish\WasmAppBuilder.dll"/>
+
+ <PropertyGroup>
+ <WasmPInvokeTablePath>$(MonoObjDir)wasm/pinvoke-table.h</WasmPInvokeTablePath>
+ <RuntimePackDir>$(ArtifactsDir)bin\lib-runtime-packs\runtimes\browser-wasm\lib\$(NetCoreAppCurrent)</RuntimePackDir>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <WasmPInvokeModules Include="libSystem.Native"/>
+ <WasmPInvokeAssemblies Include="$(MonoArtifactsPath)\System.Private.CoreLib.dll"/>
+ <WasmPInvokeAssemblies Include="$(ArtifactsBinDir)\System.Runtime\$(NetCoreAppCurrent)-Unix-$(Configuration)\System.Runtime.dll"/>
+ <WasmPInvokeAssemblies Include="$(ArtifactsBinDir)\System.Console\$(NetCoreAppCurrent)-Unix-$(Configuration)\System.Console.dll"/>
+ </ItemGroup>
+
+ <Target Name="CheckEnv">
+ <Error Condition="'$(TargetArchitecture)' != 'wasm'" Text="Expected TargetArchitecture==wasm, got '$(TargetArchitecture)'"/>
+ <Error Condition="'$(TargetOS)' != 'Browser'" Text="Expected TargetOS==Browser, got '$(TargetOS)'"/>
+ <Error Condition="'$(EMSDK_PATH)' == ''" Text="The EMSDK_PATH environment variable should be set pointing to the emscripten SDK root dir."/>
+ </Target>
+
+ <Target Name="BuildWasmAppBuilder">
+ <MSBuild Projects="$(MonoProjectRoot)mono.proj"
+ Properties="Configuration=$(Configuration)"
+ Targets="BuildWasmAppBuilder"/>
+ </Target>
+
+ <Target Name="BuildPInvokeTable" DependsOnTargets="CheckEnv;BuildWasmAppBuilder">
+ <MakeDir Directories="$(MonoObjDir)wasm"/>
+ <PInvokeTableGenerator
+ Modules="@(WasmPInvokeModules)"
+ Assemblies="@(WasmPInvokeAssemblies)"
+ OutputPath="$(WasmPInvokeTablePath)"
+ />
+ </Target>
+
+ <Target Name="BuildWasmRuntimes" DependsOnTargets="BuildPInvokeTable">
+ <Exec Command="make -C $(MonoProjectRoot)wasm all SHELL=/bin/bash BINDIR=$(ArtifactsBinDir) MONO_BIN_DIR=$(MonoArtifactsPath) OBJDIR=$(ArtifactsObjDir) SYS_NATIVE_DIR=$(ArtifactsBinDir)/native/$(NetCoreAppCurrent)-$(TargetOS)-$(Configuration)-$(TargetArchitecture) CONFIG=$(Configuration) PINVOKE_TABLE=$(WasmPInvokeTablePath)" IgnoreStandardErrorWarningFormat="true"/>
+ </Target>
+
+</Project>