| File: System\Runtime\InteropServices\JavaScript\JSHostImplementation.CoreCLR.cs | Web Access |
| Project: src\runtime\src\libraries\System.Runtime.InteropServices.JavaScript\src\System.Runtime.InteropServices.JavaScript.csproj (System.Runtime.InteropServices.JavaScript) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Loader; using System.Threading; using System.Threading.Tasks; namespace System.Runtime.InteropServices.JavaScript { internal static partial class JSHostImplementation { [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "It's kept from trimming by ModuleInitializerAttribute in the generated code.")] [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "It's kept from trimming by ModuleInitializerAttribute in the generated code.")] public static Task BindAssemblyExports(string? assemblyName) { ArgumentException.ThrowIfNullOrEmpty(assemblyName); Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); Type? generatedInitializerType = assembly.GetType("System.Runtime.InteropServices.JavaScript.__GeneratedInitializer", throwOnError: true); if (generatedInitializerType == null) { throw new ArithmeticException($"BindAssemblyExports: __GeneratedInitializer type not found in assembly '{assemblyName}'"); } MethodInfo? registerMethod = generatedInitializerType.GetMethod("__Register_", BindingFlags.NonPublic | BindingFlags.Static, binder: null, Type.EmptyTypes, modifiers: null); if (registerMethod == null) { throw new ArithmeticException($"BindAssemblyExports: __Register_ method not found in type '{generatedInitializerType.FullName}' in assembly '{assemblyName}'"); } registerMethod.Invoke(null, null); return Task.CompletedTask; } // this reflection based approach is used by JSExport assemblies generated by Net10 or below [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "It's kept from trimming by DynamicDependencyAttribute in the generated code.")] [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "It's kept from trimming by DynamicDependencyAttribute in the generated code.")] public static unsafe JSFunctionBinding BindManagedFunction(string fullyQualifiedName, int signatureHash, ReadOnlySpan<JSMarshalerType> signatures) { var ctx = JSProxyContext.CurrentThreadContext; var (assemblyName, nameSpace, shortClassName, methodName) = ParseFQN(fullyQualifiedName); var wrapperName = $"__Wrapper_{methodName}_{signatureHash}"; shortClassName = shortClassName.Replace('/', '+'); // get MethodInfo from the fully qualified name var assembly = Assembly.Load(new AssemblyName(assemblyName)); var clazz = string.IsNullOrEmpty(nameSpace) ? assembly.GetType(shortClassName) : assembly.GetType(nameSpace + "." + shortClassName); if (clazz == null) { Environment.FailFast($"Can't find {nameSpace}{shortClassName} in {assemblyName} assembly"); } var wrapperInfo = clazz.GetMethod(wrapperName, BindingFlags.Static | BindingFlags.NonPublic); if (wrapperInfo == null) { Environment.FailFast($"Can't find method wrapper {wrapperName} in {nameSpace}.{shortClassName} in {assemblyName} assembly"); } Action<IntPtr> wrapper = (IntPtr args) => { object boxedLegacyArgs = Pointer.Box((void*)args, typeof(JSMarshalerArgument*)); // real signature is void (JSMarshalerArgument* args) wrapperInfo.Invoke(null, new object?[] { boxedLegacyArgs }); }; int methodHandle = ctx.NextJSExportHandle++; ctx.JSExportByHandle[methodHandle] = wrapper; var signature = GetMethodSignature(signatures, null, null); // this will hit JS side possibly on another thread, depending on JSProxyContext.CurrentThreadContext JavaScriptImports.BindCSFunction(methodHandle, assemblyName, nameSpace, shortClassName, methodName, signatureHash, (IntPtr)signature.Header); FreeMethodSignatureBuffer(signature); return signature; } } }