IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
LibJVM.cs
Go to the documentation of this file.
1using System;
2using System.Buffers.Binary;
3using System.IO;
5using System.Runtime.InteropServices;
6using System.Threading;
7
9
10namespace IKVM.Runtime
11{
13
14#if FIRST_PASS == false && IMPORTER == false && EXPORTER == false
15
16 using IKVM.Runtime.JNI;
17
21 internal unsafe class LibJvm
22 {
23
24 static PropertiesAccessor propertiesAccessor;
25
26 static PropertiesAccessor PropertiesAccessor => JVM.Internal.BaseAccessors.Get(ref propertiesAccessor);
27
31 [StructLayout(LayoutKind.Sequential)]
32 unsafe struct JVMInvokeInterface
33 {
34
35 public nint JNI_GetDefaultJavaVMInitArgs;
36 public nint JNI_GetCreatedJavaVMs;
37 public nint JNI_CreateJavaVM;
38
39 public nint JVM_ThrowException;
40 public nint JVM_GetThreadInterruptEvent;
41 public nint JVM_ActiveProcessorCount;
42 public nint JVM_IHashCode;
43 public nint JVM_ArrayCopy;
44 public nint JVM_InitProperties;
45 public nint JVM_RawMonitorCreate;
46 public nint JVM_RawMonitorDestroy;
47 public nint JVM_RawMonitorEnter;
48 public nint JVM_RawMonitorExit;
49 public nint JVM_CopySwapMemory;
50
51 }
52
53 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
54 delegate int JNI_GetDefaultJavaVMInitArgsDelegate(void* vm_args);
55
56 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
57 delegate int JNI_GetCreatedJavaVMsDelegate(JavaVM** vmBuf, int bufLen, int* nVMs);
58
59 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
60 delegate int JNI_CreateJavaVMDelegate(JavaVM** p_vm, void** p_env, void* vm_args);
61
62 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
63 delegate void JVM_ThrowExceptionDelegate([MarshalAs(UnmanagedType.LPUTF8Str)] string name, [MarshalAs(UnmanagedType.LPUTF8Str)] string message);
64
65 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
66 delegate nint JVM_GetThreadInterruptEventDelegate();
67
68 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
69 delegate int JVM_ActiveProcessorCountDelegate();
70
71 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
72 delegate int JVM_IHashCodeDelegate(JNIEnv* env, nint handle);
73
74 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
75 delegate void JVM_ArrayCopyDelegate(JNIEnv* env, nint ignored, nint src, int src_pos, nint dst, int dst_pos, int length);
76
77 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
78 delegate nint JVM_InitPropertiesDelegate(JNIEnv* env, nint props);
79
80 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
81 delegate nint JVM_RawMonitorCreateDelegate();
82
83 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
84 delegate void JVM_RawMonitorDestroyDelegate(nint mon);
85
86 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
87 delegate int JVM_RawMonitorEnterDelegate(nint mon);
88
89 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
90 delegate void JVM_RawMonitorExitDelegate(nint mon);
91
92 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
93 delegate void JVM_CopySwapMemoryDelegate(JNIEnv* env, nint srcObj, long srcOffset, nint dstObj, long dstOffset, long size, long elemSize);
94
95 delegate void JVM_InitDelegate(JVMInvokeInterface* iface);
96
97 delegate nint JVM_LoadLibraryDelegate([MarshalAs(UnmanagedType.LPUTF8Str)] string name);
98
99 delegate void JVM_UnloadLibraryDelegate(nint handle);
100
101 delegate nint JVM_FindLibraryEntryDelegate(nint handle, [MarshalAs(UnmanagedType.LPStr)] string name);
102
106 public static readonly LibJvm Instance = new();
107
108 readonly ikvm.@internal.CallerID callerID = ikvm.@internal.CallerID.create(typeof(LibJvm).TypeHandle);
109 readonly JVMInvokeInterface* jvmii;
110
111 readonly JVM_InitDelegate _JVM_Init;
112 readonly JVM_LoadLibraryDelegate _JVM_LoadLibrary;
113 readonly JVM_UnloadLibraryDelegate _JVM_UnloadLibrary;
114 readonly JVM_FindLibraryEntryDelegate _JVM_FindLibraryEntry;
115
116 readonly JNI_GetDefaultJavaVMInitArgsDelegate _JNI_GetDefaultJavaVMInitArgs;
117 readonly JNI_GetCreatedJavaVMsDelegate _JNI_GetCreatedJavaVMs;
118 readonly JNI_CreateJavaVMDelegate _JNI_CreateJavaVM;
119 readonly JVM_ThrowExceptionDelegate _JVM_ThrowException;
120 readonly JVM_GetThreadInterruptEventDelegate _JVM_GetThreadInterruptEvent;
121 readonly JVM_ActiveProcessorCountDelegate _JVM_ActiveProcessorCount;
122 readonly JVM_IHashCodeDelegate _JVM_IHashCode;
123 readonly JVM_ArrayCopyDelegate _JVM_ArrayCopy;
124 readonly JVM_InitPropertiesDelegate _JVM_InitProperties;
125 readonly JVM_RawMonitorCreateDelegate _JVM_RawMonitorCreate;
126 readonly JVM_RawMonitorDestroyDelegate _JVM_RawMonitorDestroy;
127 readonly JVM_RawMonitorEnterDelegate _JVM_RawMonitorEnter;
128 readonly JVM_RawMonitorExitDelegate _JVM_RawMonitorExit;
129 readonly JVM_CopySwapMemoryDelegate _JVM_CopySwapMemory;
130
134 LibJvm()
135 {
136 // load libjvm through IKVM native library functionality
137 if ((Handle = NativeLibrary.Load(Path.Combine(JVM.Properties.HomePath, "bin", NativeLibrary.MapLibraryName("jvm")))) == null)
138 throw new InternalException("Could not load libjvm.");
139
140 // obtain delegates to functions declared in libjvm
141 _JVM_Init = Marshal.GetDelegateForFunctionPointer<JVM_InitDelegate>(Handle.GetExport("JVM_Init", sizeof(nint)).Handle);
142 _JVM_LoadLibrary = Marshal.GetDelegateForFunctionPointer<JVM_LoadLibraryDelegate>(Handle.GetExport("JVM_LoadLibrary", sizeof(nint)).Handle);
143 _JVM_UnloadLibrary = Marshal.GetDelegateForFunctionPointer<JVM_UnloadLibraryDelegate>(Handle.GetExport("JVM_UnloadLibrary", sizeof(nint)).Handle);
144 _JVM_FindLibraryEntry = Marshal.GetDelegateForFunctionPointer<JVM_FindLibraryEntryDelegate>(Handle.GetExport("JVM_FindLibraryEntry", sizeof(nint) + sizeof(nint)).Handle);
145
146 // initialize invoke interface for calls from libjvm to IKVM
147 jvmii = (JVMInvokeInterface*)Marshal.AllocHGlobal(sizeof(JVMInvokeInterface));
148 jvmii->JNI_GetDefaultJavaVMInitArgs = Marshal.GetFunctionPointerForDelegate(_JNI_GetDefaultJavaVMInitArgs = JNIVM.GetDefaultJavaVMInitArgs);
149 jvmii->JNI_GetCreatedJavaVMs = Marshal.GetFunctionPointerForDelegate(_JNI_GetCreatedJavaVMs = JNIVM.GetCreatedJavaVMs);
150 jvmii->JNI_CreateJavaVM = Marshal.GetFunctionPointerForDelegate(_JNI_CreateJavaVM = JNIVM.CreateJavaVM);
151 jvmii->JVM_ThrowException = Marshal.GetFunctionPointerForDelegate(_JVM_ThrowException = JVM_ThrowException);
152 jvmii->JVM_GetThreadInterruptEvent = Marshal.GetFunctionPointerForDelegate(_JVM_GetThreadInterruptEvent = JVM_GetThreadInterruptEvent);
153 jvmii->JVM_ActiveProcessorCount = Marshal.GetFunctionPointerForDelegate(_JVM_ActiveProcessorCount = JVM_ActiveProcessorCount);
154 jvmii->JVM_IHashCode = Marshal.GetFunctionPointerForDelegate(_JVM_IHashCode = JVM_IHashCode);
155 jvmii->JVM_ArrayCopy = Marshal.GetFunctionPointerForDelegate(_JVM_ArrayCopy = JVM_ArrayCopy);
156 jvmii->JVM_InitProperties = Marshal.GetFunctionPointerForDelegate(_JVM_InitProperties = JVM_InitProperties);
157 jvmii->JVM_RawMonitorCreate = Marshal.GetFunctionPointerForDelegate(_JVM_RawMonitorCreate = JVM_RawMonitorCreate);
158 jvmii->JVM_RawMonitorDestroy = Marshal.GetFunctionPointerForDelegate(_JVM_RawMonitorDestroy = JVM_RawMonitorDestroy);
159 jvmii->JVM_RawMonitorEnter = Marshal.GetFunctionPointerForDelegate(_JVM_RawMonitorEnter = JVM_RawMonitorEnter);
160 jvmii->JVM_RawMonitorExit = Marshal.GetFunctionPointerForDelegate(_JVM_RawMonitorExit = JVM_RawMonitorExit);
161 jvmii->JVM_CopySwapMemory = Marshal.GetFunctionPointerForDelegate(_JVM_CopySwapMemory = JVM_CopySwapMemory);
162 _JVM_Init(jvmii);
163 }
164
168 public NativeLibraryHandle Handle { get; private set; }
169
176 void JVM_ThrowException(string name, string msg)
177 {
178 try
179 {
180 if (name == null)
181 {
182 JVM.Context.Diagnostics.GenericJniError($"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Missing name argument.");
183 return;
184 }
185
186 // find requested exception class
187 var exceptionClass = RuntimeClassLoader.FromCallerID(callerID).TryLoadClassByName(name.Replace('/', '.'));
188 if (exceptionClass == null)
189 {
190 JVM.Context.Diagnostics.GenericJniError($"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Could not find exception class {name}.");
191 return;
192 }
193
194 // find constructor
195 var ctor = exceptionClass.GetMethod("<init>", msg == null ? "()V" : "(Ljava.lang.String;)V", false);
196 if (ctor == null)
197 {
198 JVM.Context.Diagnostics.GenericJniError($"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Exception {name} missing constructor.");
199 return;
200 }
201
202 // invoke the constructor
203 exceptionClass.Finish();
204
205 var ctorMember = (java.lang.reflect.Constructor)ctor.ToMethodOrConstructor(false);
206 var exception = (Exception)ctorMember.newInstance(msg == null ? Array.Empty<object>() : new object[] { msg }, callerID);
207 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Created exception {name} from libjvm.");
208 JVM.SetPendingException(exception);
209 }
210 catch (Exception e)
211 {
212 JVM.Context.Diagnostics.GenericJniError($"{nameof(LibJvm)}.{nameof(JVM_ThrowException)}: Exception occurred creating exception {name}: {e.Message}");
213 JVM.SetPendingException(e);
214 }
215 }
216
221 nint JVM_GetThreadInterruptEvent()
222 {
223 try
224 {
225 return global::java.lang.Thread.currentThread().interruptEvent.SafeWaitHandle.DangerousGetHandle();
226 }
227 catch (global::java.lang.Throwable t)
228 {
229 JVM.SetPendingException(t);
230 return 0;
231 }
232 catch (Exception e)
233 {
234 JVM.Context.Diagnostics.GenericJniError($"{nameof(LibJvm)}.{nameof(JVM_GetThreadInterruptEvent)}: Exception occurred: {e.Message}");
235 JVM.SetPendingException(new global::java.lang.InternalError(e));
236 return 0;
237 }
238 }
239
244 int JVM_ActiveProcessorCount()
245 {
246 return Environment.ProcessorCount;
247 }
248
255 int JVM_IHashCode(JNIEnv* env, nint handle)
256 {
257 return handle == 0 ? 0 : RuntimeHelpers.GetHashCode(env->UnwrapRef(handle));
258 }
259
270 void JVM_ArrayCopy(JNIEnv* env, nint ignored, nint src, int src_pos, nint dst, int dst_pos, int length)
271 {
272 try
273 {
274 if (src == 0 || dst == 0)
275 throw new java.lang.NullPointerException();
276
277 var s = env->UnwrapRef(src) as Array;
278 var d = env->UnwrapRef(dst) as Array;
279 if (s is null || d is null)
280 throw new java.lang.ArrayStoreException();
281
282 if (src_pos < 0 || dst_pos < 0 || length < 0)
283 throw new java.lang.ArrayIndexOutOfBoundsException();
284
285 if (((length + src_pos) > s.Length) || ((length + dst_pos) > d.Length))
286 throw new java.lang.ArrayIndexOutOfBoundsException();
287
288 if (length == 0)
289 return;
290
291 Array.Copy(s, src_pos, d, dst_pos, length);
292 }
293 catch (java.lang.Throwable t)
294 {
295 JVM.SetPendingException(t);
296 }
297 catch (ArrayTypeMismatchException)
298 {
299 JVM.SetPendingException(new java.lang.ArrayStoreException());
300 }
301 catch (Exception e)
302 {
303 JVM.SetPendingException(new java.lang.InternalError(e));
304 }
305 }
306
317 nint JVM_InitProperties(JNIEnv* env, nint props)
318 {
319 try
320 {
321 var p = env->UnwrapRef(props);
322 foreach (var kvp in JVM.Properties.Init)
323 if (kvp.Value is string v)
324 PropertiesAccessor.InvokeSetProperty(p, kvp.Key, v);
325
326 return props;
327 }
328 catch (java.lang.Throwable t)
329 {
330 JVM.SetPendingException(t);
331 return 0;
332 }
333 catch (Exception e)
334 {
335 JVM.SetPendingException(new java.lang.InternalError(e));
336 return 0;
337 }
338 }
339
344 nint JVM_RawMonitorCreate()
345 {
346 try
347 {
348 return (IntPtr)GCHandle.Alloc(new object(), GCHandleType.Normal);
349 }
350 catch (Exception e)
351 {
352 JVM.SetPendingException(new java.lang.InternalError(e));
353 return 0;
354 }
355 }
356
361 void JVM_RawMonitorDestroy(nint mon)
362 {
363 try
364 {
365 GCHandle.FromIntPtr(mon).Free();
366 }
367 catch (Exception e)
368 {
369 JVM.SetPendingException(new java.lang.InternalError(e));
370 }
371 }
372
378 int JVM_RawMonitorEnter(nint mon)
379 {
380 try
381 {
382 Monitor.Enter(GCHandle.FromIntPtr(mon).Target);
383 }
384 catch (Exception e)
385 {
386 JVM.SetPendingException(new java.lang.InternalError(e));
387 }
388
389 return 0;
390 }
391
397 void JVM_RawMonitorExit(nint mon)
398 {
399 try
400 {
401 Monitor.Exit(GCHandle.FromIntPtr(mon).Target);
402 }
403 catch (Exception e)
404 {
405 JVM.SetPendingException(new java.lang.InternalError(e));
406 }
407 }
408
419 unsafe void JVM_CopySwapMemory(JNIEnv* env, nint srcObj, long srcOffset, nint dstObj, long dstOffset, long size, long elemSize)
420 {
421 JVM_CopySwapMemory((Array)env->UnwrapRef(srcObj), srcOffset, (Array)env->UnwrapRef(dstObj), dstOffset, size, elemSize);
422 }
423
433 internal static unsafe void JVM_CopySwapMemory(Array srcObj, long srcOffset, Array dstObj, long dstOffset, long size, long elemSize)
434 {
435 if (size == 0)
436 return;
437
438 try
439 {
440 if (size % elemSize != 0)
441 throw new java.lang.InternalError($"size {size} must be multiple of element size {elemSize}");
442
443 static unsafe Span<T> AsSpan<T>(Array obj, long off, long size) where T : unmanaged
444 {
445 if (obj != null)
446 return new Span<T>(Unsafe.As<T[]>(obj)).Slice((int)(off / sizeof(T)), (int)(size / sizeof(T)));
447 else if (off != 0)
448 return new Span<T>((void*)(nint)off, (int)(size / sizeof(T)));
449 else
450 throw new java.lang.InternalError($"address must not be NULL");
451 }
452
453 switch (elemSize)
454 {
455 case 2:
456 ReverseEndianness(AsSpan<short>(srcObj, srcOffset, size), AsSpan<short>(dstObj, dstOffset, size));
457 break;
458 case 4:
459 ReverseEndianness(AsSpan<int>(srcObj, srcOffset, size), AsSpan<int>(dstObj, dstOffset, size));
460 break;
461 case 8:
462 ReverseEndianness(AsSpan<long>(srcObj, srcOffset, size), AsSpan<long>(dstObj, dstOffset, size));
463 break;
464 default:
465 throw new java.lang.InternalError($"incorrect element size: {elemSize}");
466 }
467 }
468 catch (java.lang.Throwable e)
469 {
470 JVM.SetPendingException(e);
471 }
472 catch (Exception e)
473 {
474 JVM.SetPendingException(new java.lang.InternalError(e));
475 }
476 }
477
483 static void ReverseEndianness(ReadOnlySpan<short> src, Span<short> dst)
484 {
485#if NET7_0_OR_GREATER
486 BinaryPrimitives.ReverseEndianness(src, dst);
487#else
488 ref short srcRef = ref MemoryMarshal.GetReference(src);
489 ref short dstRef = ref MemoryMarshal.GetReference(dst);
490 if (Unsafe.AreSame(ref srcRef, ref dstRef) || !src.Overlaps(dst, out int elementOffset) || elementOffset < 0)
491 for (int i = 0; i < src.Length; i++)
492 dst[i] = BinaryPrimitives.ReverseEndianness(src[i]);
493 else
494 for (int i = src.Length - 1; i >= 0; i--)
495 dst[i] = BinaryPrimitives.ReverseEndianness(src[i]);
496#endif
497 }
498
504 static void ReverseEndianness(ReadOnlySpan<int> src, Span<int> dst)
505 {
506#if NET7_0_OR_GREATER
507 BinaryPrimitives.ReverseEndianness(src, dst);
508#else
509 ref int srcRef = ref MemoryMarshal.GetReference(src);
510 ref int dstRef = ref MemoryMarshal.GetReference(dst);
511 if (Unsafe.AreSame(ref srcRef, ref dstRef) || !src.Overlaps(dst, out int elementOffset) || elementOffset < 0)
512 for (int i = 0; i < src.Length; i++)
513 dst[i] = BinaryPrimitives.ReverseEndianness(src[i]);
514 else
515 for (int i = src.Length - 1; i >= 0; i--)
516 dst[i] = BinaryPrimitives.ReverseEndianness(src[i]);
517#endif
518 }
519
525 static void ReverseEndianness(ReadOnlySpan<long> src, Span<long> dst)
526 {
527#if NET7_0_OR_GREATER
528 BinaryPrimitives.ReverseEndianness(src, dst);
529#else
530 ref long srcRef = ref MemoryMarshal.GetReference(src);
531 ref long dstRef = ref MemoryMarshal.GetReference(dst);
532 if (Unsafe.AreSame(ref srcRef, ref dstRef) || !src.Overlaps(dst, out int elementOffset) || elementOffset < 0)
533 for (int i = 0; i < src.Length; i++)
534 dst[i] = BinaryPrimitives.ReverseEndianness(src[i]);
535 else
536 for (int i = src.Length - 1; i >= 0; i--)
537 dst[i] = BinaryPrimitives.ReverseEndianness(src[i]);
538#endif
539 }
540
546 public nint JVM_LoadLibrary(string name)
547 {
548 try
549 {
550 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_LoadLibrary)}: {name}");
551 var h = _JVM_LoadLibrary(name);
552 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_LoadLibrary)}: {name} => {h}");
553 return h;
554 }
555 finally
556 {
557 JVM.ThrowPendingException();
558 }
559 }
560
565 public void JVM_UnloadLibrary(nint handle)
566 {
567 try
568 {
569 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_UnloadLibrary)}: start {handle}");
570 _JVM_UnloadLibrary(handle);
571 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_UnloadLibrary)}: finish {handle}");
572 }
573 finally
574 {
575 JVM.ThrowPendingException();
576 }
577 }
578
585 public nint JVM_FindLibraryEntry(nint handle, string name)
586 {
587 try
588 {
589 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_FindLibraryEntry)}: {handle} {name}");
590 var h = _JVM_FindLibraryEntry(handle, name);
591 JVM.Context.Diagnostics.GenericJniTrace($"{nameof(LibJvm)}.{nameof(JVM_FindLibraryEntry)}: {handle} {name} => {h}");
592 return h;
593 }
594 finally
595 {
596 JVM.ThrowPendingException();
597 }
598 }
599
603 ~LibJvm()
604 {
605 if (jvmii != null)
606 Marshal.FreeHGlobal((IntPtr)jvmii);
607 }
608
609 }
610
611#endif
612
613}
System.Runtime.InteropServices.CallingConvention CallingConvention
Definition Signature.cs:35
Represents an internal error that occurred within IKVM.
static int GetCreatedJavaVMs(JavaVM **ppvmBuf, jsize bufLen, jsize *nVMs)
Implements the JNI_GetCreatedJavaVMs native function.
Definition JNIVM.cs:146
static int CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args)
Implements the JNI_CreateJavaVM native method.
Definition JNIVM.cs:80
static int GetDefaultJavaVMInitArgs(void *vm_args)
Implements the JNI_GetDefaultJavaVMInitArgs native function.
Definition JNIVM.cs:133
Property values loaded into the JVM from various sources.
Main state of the running JVM.
Provides methods to load libraries from standard .NET search locations. This class is not used to loa...
static NativeLibraryHandle Load(string nameOrPath)
Loads the given library in a platform dependent manner.
static string MapLibraryName(string name)
Returns a version of the library name with the OS specific prefix and suffix.
Runtime support for a class loader.
IDiagnosticHandler Diagnostics
Gets the IDiagnosticHandler where events should be sent.
void GenericJniTrace(string arg0)
The 'GenericJniTrace' diagnostic.
void GenericJniError(string arg0)
The 'GenericJniError' diagnostic.