diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs b/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs index 518a4ff53bee20..aa35d57828ee3a 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs @@ -69,6 +69,6 @@ internal static unsafe partial class Runtime [MethodImpl(MethodImplOptions.InternalCall)] public static extern void BindAssemblyExports(IntPtr assemblyNamePtr); [MethodImpl(MethodImplOptions.InternalCall)] - public static extern void GetAssemblyExport(IntPtr assemblyNamePtr, IntPtr namespacePtr, IntPtr classnamePtr, IntPtr methodNamePtr, IntPtr* monoMethodPtrPtr); + public static extern void GetAssemblyExport(IntPtr assemblyNamePtr, IntPtr namespacePtr, IntPtr classnamePtr, IntPtr methodNamePtr, int signatureHash, IntPtr* monoMethodPtrPtr); } } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs index f4653c5e35041f..4780d7c365394f 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs @@ -282,15 +282,21 @@ public static unsafe Task BindAssemblyExports(string? assemblyName) public static unsafe JSFunctionBinding BindManagedFunction(string fullyQualifiedName, int signatureHash, ReadOnlySpan signatures) { var (assemblyName, nameSpace, shortClassName, methodName) = ParseFQN(fullyQualifiedName); - var wrapper_name = $"__Wrapper_{methodName}_{signatureHash}"; + var dllName = assemblyName + ".dll"; IntPtr monoMethod; Interop.Runtime.GetAssemblyExport( + // FIXME: Pass UTF-16 through directly so C can work with it, doing the conversion + // in C# pulls in a bunch of dependencies we don't need this early in startup. + // I tested removing the UTF8 conversion from this specific call, but other parts + // of startup I can't identify still pull in UTF16->UTF8 conversion, so it's not + // worth it to do that yet. Marshal.StringToCoTaskMemUTF8(dllName), Marshal.StringToCoTaskMemUTF8(nameSpace), Marshal.StringToCoTaskMemUTF8(shortClassName), - Marshal.StringToCoTaskMemUTF8(wrapper_name), + Marshal.StringToCoTaskMemUTF8(methodName), + signatureHash, &monoMethod); if (monoMethod == IntPtr.Zero) @@ -327,16 +333,56 @@ public static RuntimeMethodHandle GetMethodHandleFromIntPtr(IntPtr ptr) return temp.methodHandle; } + // The BCL implementations of IndexOf/LastIndexOf/Trim are vectorized & fast, + // but they pull in a bunch of code that is otherwise not necessarily + // useful during early app startup, so we use simple scalar implementations + private static int SmallIndexOf (string s, char ch, int direction = 1) { + if (s.Length < 1) + return -1; + int start_index = (direction > 0) ? 0 : s.Length - 1, + end_index = (direction > 0) ? s.Length - 1 : 0; + for (int i = start_index; i != end_index; i += direction) { + if (s[i] == ch) + return i; + } + return -1; + } + + private static string SmallTrim (string s) { + if (s.Length < 1) + return s; + int head = 0, tail = s.Length - 1; + while (head < s.Length) { + if (s[head] == ' ') + head++; + else + break; + } + while (tail >= 0) { + if (s[tail] == ' ') + tail--; + else + break; + } + if ((head > 0) || (tail < s.Length - 1)) + return s.Substring(head, tail - head + 1); + else + return s; + } + public static (string assemblyName, string nameSpace, string shortClassName, string methodName) ParseFQN(string fqn) { - var assembly = fqn.Substring(fqn.IndexOf('[') + 1, fqn.IndexOf(']') - 1).Trim(); - fqn = fqn.Substring(fqn.IndexOf(']') + 1).Trim(); - var methodName = fqn.Substring(fqn.IndexOf(':') + 1); - var className = fqn.Substring(0, fqn.IndexOf(':')).Trim(); + var assembly = fqn.Substring(SmallIndexOf(fqn, '[') + 1, SmallIndexOf(fqn, ']') - 1); + fqn = SmallTrim(fqn); + fqn = fqn.Substring(SmallIndexOf(fqn, ']') + 1); + fqn = SmallTrim(fqn); + var methodName = fqn.Substring(SmallIndexOf(fqn, ':') + 1); + var className = fqn.Substring(0, SmallIndexOf(fqn, ':')); + className = SmallTrim(className); var nameSpace = ""; var shortClassName = className; - var idx = fqn.LastIndexOf('.'); + var idx = SmallIndexOf(fqn, '.', -1); if (idx != -1) { nameSpace = fqn.Substring(0, idx); diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index 485ba3189af6e2..a6642a06d69fc8 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -34,7 +34,7 @@ typedef void (*background_job_cb)(void); void mono_wasm_bind_assembly_exports (char *assembly_name); void mono_wasm_assembly_get_entry_point (char *assembly_name, int auto_insert_breakpoint, MonoMethod **method_out); -void mono_wasm_get_assembly_export (char *assembly_name, char *namespace, char *classname, char *methodname, MonoMethod **method_out); +void mono_wasm_get_assembly_export (char *assembly_name, char *namespace, char *classname, char *methodname, int signature_hash, MonoMethod **method_out); #ifndef DISABLE_THREADS void mono_wasm_release_cs_owned_object_post (pthread_t target_tid, int js_handle); @@ -230,13 +230,14 @@ void mono_wasm_bind_assembly_exports (char *assembly_name) } } -void mono_wasm_get_assembly_export (char *assembly_name, char *namespace, char *classname, char *methodname, MonoMethod **method_out) +void mono_wasm_get_assembly_export (char *assembly_name, char *namespace, char *classname, char *methodname, int signature_hash, MonoMethod **method_out) { MonoError error; MonoAssembly* assembly; MonoImage *image; MonoClass *klass; MonoMethod *method=NULL; + char real_method_name_buffer[4096]; *method_out = NULL; assert (assembly_name); @@ -247,10 +248,15 @@ void mono_wasm_get_assembly_export (char *assembly_name, char *namespace, char * klass = mono_class_from_name (image, namespace, classname); assert (klass); - method = mono_class_get_method_from_name (klass, methodname, -1); + + snprintf(real_method_name_buffer, 4096, "__Wrapper_%s_%d", methodname, signature_hash); + + method = mono_class_get_method_from_name (klass, real_method_name_buffer, -1); assert (method); *method_out = method; + // This is freed by _mono_wasm_assembly_load for some reason + // free (assembly_name); free (namespace); free (classname); free (methodname);