/// <inheritdoc/> public ulong DefaultSymbolResolver(string name, IntPtr ctx) { try { // Workaround OrcJit+Windows/COFF bug/limitation where functions in the generated obj are // not marked as exported, so the official llvm-c API doesn't see the symbol to get the address // LibLLVM variant takes the additional bool so that is used on Windows to find non-exported symbols. bool exportedOnly = Environment.OSVersion.Platform != PlatformID.Win32NT; var err = LibLLVMOrcGetSymbolAddress(JitStackHandle, out ulong retAddr, name, exportedOnly); if (!err.IsInvalid) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.Unresolved_Symbol_0_1, name, LLVMOrcGetErrorMsg(JitStackHandle))); } if (retAddr != 0) { return(retAddr); } return(GlobalInteropFunctions.TryGetValue(name, out WrappedNativeCallback callBack) ? ( ulong )callBack.ToIntPtr( ).ToInt64( ) : 0); } #pragma warning disable CA1031 // Do not catch general exception types catch { // Allowing exceptions outside this call is not helpful as the LLVM // native JIT engine is what calls this function and it doesn't know // how to deal with a managed exception. Any exceptions are at least // logged in a debugger before being swallowed here. return(0); } #pragma warning restore CA1031 // Do not catch general exception types }
/// <summary>Adds or replaces an interop callback for a global symbol</summary> /// <typeparam name="T">Delegate type for the callback</typeparam> /// <param name="symbolName">Symbol name of the global</param> /// <param name="delegate">Delegate for the callback</param> /// <remarks> /// <note type="warning"> /// The delegate is made available to native code as a callback, and therefore it /// must have a lifetime that is at least as long as the callback is registered or /// the lifetime of the JIT engine itself. The direct delegate and any instance /// it may be a member of are handled automatically in the internal implementation /// of this function. However, any data the delegate may rely on is not. (e.g. if /// the object the delegate is a method on a class implementing IDisposable and the /// Dispose method was called on that instance, then the callback could end up operating /// on a disposed object) /// </note> /// <note type="warning"> /// The callback **MUST NOT** throw any exceptions out of the callback, as the /// JIT engine doesn't know how to handle them and neither does the JIT'd code. /// </note> /// </remarks> public void AddInteropCallback <T>(string symbolName, T @delegate) where T : Delegate { LLVMOrcGetMangledSymbol(JitStackHandle, out string mangledName, symbolName); if (GlobalInteropFunctions.TryGetValue(mangledName, out WrappedNativeCallback existingCallback)) { GlobalInteropFunctions.Remove(mangledName); existingCallback.Dispose( ); } GlobalInteropFunctions.Add(mangledName, new WrappedNativeCallback <T>(@delegate)); }