IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
JNINativeLoader.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2014 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Collections.Generic;
26using System.Runtime.InteropServices;
27
29
30namespace IKVM.Runtime.JNI
31{
32
33#if FIRST_PASS == false && IMPORTER == false && EXPORTER == false
34
35
38 static unsafe class JNINativeLoader
39 {
40
41 delegate int JNI_OnLoadFunc(JavaVM* vm, void* reserved);
42 delegate void JNI_OnUnloadFunc(JavaVM* vm, void* reserved);
43
44 public static readonly object SyncRoot = new object();
45 static readonly List<nint> loaded = new();
46
53 public static long LoadLibrary(string filename, RuntimeJavaType fromClass)
54 {
55 JVM.Context.Diagnostics.GenericJniInfo($"loadLibrary: '{filename}' fromClass '{fromClass}'");
56
57 lock (SyncRoot)
58 {
59 nint p = 0;
60
61 try
62 {
63 // attempt to load the native library
64 if ((p = LibJvm.Instance.JVM_LoadLibrary(filename)) == 0)
65 {
66 JVM.Context.Diagnostics.GenericJniInfo($"Failed to load library: path = '{filename}', message = {"NULL handle returned."}");
67 return 0;
68 }
69
70 // find whether the native library was already loaded
71 foreach (var h in fromClass.ClassLoader.GetNativeLibraries())
72 {
73 if (h == p)
74 {
75 LibJvm.Instance.JVM_UnloadLibrary(p);
76 JVM.Context.Diagnostics.GenericJniWarning("Library was already loaded, returning same reference");
77 return p;
78 }
79 }
80
81 // library was loaded by another classloader, that's a link error
82 if (loaded.Contains(p))
83 {
84 var msg = $"Native library '{filename}' already loaded in another classloader.";
85 JVM.Context.Diagnostics.GenericJniError($"UnsatisfiedLinkError: {msg}");
86 throw new java.lang.UnsatisfiedLinkError(msg);
87 }
88
89 JVM.Context.Diagnostics.GenericJniInfo($"Library loaded: {filename}, handle = 0x{p:X}");
90
91 try
92 {
93 var onload = LibJvm.Instance.JVM_FindLibraryEntry(p, NativeLibrary.MangleExportName("JNI_OnLoad", sizeof(nint) + sizeof(nint)));
94 if (onload != 0)
95 {
96 JVM.Context.Diagnostics.GenericJniInfo($"Calling JNI_OnLoad on: {filename}");
97 var f = new JNIFrame();
98 int v;
99 var w = f.Enter(ikvm.@internal.CallerID.create(fromClass.ClassObject, fromClass.ClassObject.getClassLoader()));
100 try
101 {
102 v = Marshal.GetDelegateForFunctionPointer<JNI_OnLoadFunc>(onload)(JavaVM.pJavaVM, null);
103 JVM.Context.Diagnostics.GenericJniInfo($"JNI_OnLoad returned: 0x{v:X8}");
104 }
105 finally
106 {
107 f.Leave();
108 }
109
110 if (JNIVM.IsSupportedJNIVersion(v) == false)
111 {
112 var msg = $"Unsupported JNI version 0x{v:X} required by {filename}";
113 JVM.Context.Diagnostics.GenericJniError($"UnsatisfiedLinkError: {msg}");
114 throw new java.lang.UnsatisfiedLinkError(msg);
115 }
116 }
117 }
118 catch (EntryPointNotFoundException)
119 {
120 // JNI_OnLoad entry point doesn't exist and isn't required
121 }
122
123 // record addition of native library
124 loaded.Add(p);
125 fromClass.ClassLoader.RegisterNativeLibrary(p);
126 return p;
127 }
128 catch (DllNotFoundException e)
129 {
130 JVM.Context.Diagnostics.GenericJniInfo($"Failed to load library: path = '{filename}', error = DllNotFoundException, message = {e.Message}");
131 return 0;
132 }
133 catch (Exception e)
134 {
135 JVM.Context.Diagnostics.GenericJniInfo($"Failed to load library: path = '{filename}', error = Exception, message = {e.Message}");
136 LibJvm.Instance.JVM_UnloadLibrary(p);
137 throw;
138 }
139 }
140 }
141
147 public static void UnloadLibrary(long handle, RuntimeJavaType fromClass)
148 {
149 var p = (nint)handle;
150
151 lock (SyncRoot)
152 {
153 JVM.Context.Diagnostics.GenericJniInfo($"Unloading library: handle = 0x{handle:X}, class = {fromClass}");
154
155 try
156 {
157 var onunload = LibJvm.Instance.JVM_FindLibraryEntry(p, NativeLibrary.MangleExportName("JNI_OnUnload", sizeof(nint) + sizeof(nint)));
158 if (onunload != 0)
159 {
160 JVM.Context.Diagnostics.GenericJniInfo($"Calling JNI_OnUnload on: handle = 0x{handle:X}");
161
162 var f = new JNIFrame();
163 var w = f.Enter(ikvm.@internal.CallerID.create(fromClass.ClassObject, fromClass.ClassObject.getClassLoader()));
164 try
165 {
166 Marshal.GetDelegateForFunctionPointer<JNI_OnUnloadFunc>(onunload)(JavaVM.pJavaVM, null);
167 }
168 finally
169 {
170 f.Leave();
171 }
172 }
173 }
174 catch (EntryPointNotFoundException)
175 {
176 // JNI_OnUnload entry point doesn't exist and isn't required
177 }
178
179 // remove record of native library
180 loaded.Remove(p);
181 fromClass.ClassLoader.UnregisterNativeLibrary(p);
182 LibJvm.Instance.JVM_UnloadLibrary(p);
183 }
184 }
185
186 }
187
188#endif
189
190}
static void UnloadLibrary(long handle, RuntimeJavaType fromClass)
Initiates an unload of the given native library for the specified class loader.
static long LoadLibrary(string filename, RuntimeJavaType fromClass)
Initiates a load of the given JNI library by the specified class loader.
static readonly object SyncRoot
Main state of the running JVM.
Provides methods to load libraries from standard .NET search locations. This class is not used to loa...
IDiagnosticHandler Diagnostics
Gets the IDiagnosticHandler where events should be sent.
void GenericJniWarning(string arg0)
The 'GenericJniWarning' diagnostic.
void GenericJniError(string arg0)
The 'GenericJniError' diagnostic.
void GenericJniInfo(string arg0)
The 'GenericJniInfo' diagnostic.