25using System.Diagnostics;
34#if FIRST_PASS == false && IMPORTER == false && EXPORTER == false
39 internal sealed unsafe
class JNIEnvContext
43 static JNIEnvContext current;
48 internal static JNIEnvContext Current
50 [MethodImpl(MethodImplOptions.NoOptimization)]
get => current;
51 [MethodImpl(MethodImplOptions.NoOptimization)]
set => current = value;
54 internal const int JNI_OK = 0;
55 internal const int JNI_ERR = -1;
56 internal const int JNI_EDETACHED = -2;
57 internal const int JNI_EVERSION = -3;
58 internal const int JNI_COMMIT = 1;
59 internal const int JNI_ABORT = 2;
60 internal const jboolean JNI_TRUE = 1;
61 internal const jboolean JNI_FALSE = 0;
66 const int LOCAL_REF_INITIAL_BUCKET_SIZE = 32;
67 const int LOCAL_REF_SHIFT = 10;
68 const int LOCAL_REF_MAX_BUCKET_SIZE = (1 << LOCAL_REF_SHIFT);
69 const int LOCAL_REF_MASK = (LOCAL_REF_MAX_BUCKET_SIZE - 1);
71 internal readonly RuntimeContext context;
72 internal readonly JNIEnv* pJNIEnv;
73 internal RuntimeClassLoader classLoader;
84 internal JNIEnvContext(RuntimeContext context)
86 this.context = context ??
throw new ArgumentNullException(nameof(context));
88 pJNIEnv = (JNIEnv*)JNIMemory.Alloc(
sizeof(JNIEnv));
89 localRefs =
new object[32][];
90 active = localRefs[0] =
new object[LOCAL_REF_INITIAL_BUCKET_SIZE];
102 if (Environment.HasShutdownStarted ==
false)
104 if (pJNIEnv->context.IsAllocated)
105 pJNIEnv->context.Free();
107 for (
int i = 0; i < pJNIEnv->pinHandleMaxCount; i++)
108 if (pJNIEnv->pinHandles[i].IsAllocated)
109 pJNIEnv->pinHandles[i].Free();
111 JNIMemory.Free((nint)(
void*)pJNIEnv);
115 internal readonly
struct FrameState
119 internal readonly
int localRefSlot;
120 internal readonly
int localRefIndex;
128 internal FrameState(ikvm.@
internal.CallerID callerID,
int localRefSlot,
int localRefIndex)
130 this.callerID = callerID;
131 this.localRefSlot = localRefSlot;
132 this.localRefIndex = localRefIndex;
137 internal FrameState Enter(ikvm.@
internal.CallerID newCallerID)
139 var prev =
new FrameState(callerID, localRefSlot, localRefIndex);
140 callerID = newCallerID;
142 if (localRefSlot >= localRefs.Length)
144 var tmp =
new object[localRefs.Length * 2][];
145 Array.Copy(localRefs, 0, tmp, 0, localRefs.Length);
150 active = localRefs[localRefSlot];
151 active ??= localRefs[localRefSlot] =
new object[LOCAL_REF_INITIAL_BUCKET_SIZE];
156 internal void Leave(FrameState prev)
158 for (
int i = 0; i < localRefIndex; i++)
161 while (--localRefSlot != prev.localRefSlot)
163 if (localRefs[localRefSlot] !=
null)
165 if (localRefs[localRefSlot].Length == LOCAL_REF_MAX_BUCKET_SIZE)
168 localRefs[localRefSlot] =
null;
172 Array.Clear(localRefs[localRefSlot], 0, localRefs[localRefSlot].Length);
177 active = localRefs[localRefSlot];
178 localRefIndex = prev.localRefIndex;
179 callerID = prev.callerID;
182 internal nint MakeLocalRef(
object obj)
188 if (localRefIndex == active.Length)
190 index = FindFreeIndex();
194 index = localRefIndex++;
198 return (nint)((localRefSlot << LOCAL_REF_SHIFT) + index);
203 for (
int i = 0; i < active.Length; i++)
205 if (active[i] ==
null)
207 while (localRefIndex - 1 > i && active[localRefIndex - 1] ==
null)
217 return localRefIndex++;
220 void GrowActiveSlot()
222 if (active.Length < LOCAL_REF_MAX_BUCKET_SIZE)
224 var tmp =
new object[active.Length * 2];
225 Array.Copy(active, tmp, active.Length);
226 active = localRefs[localRefSlot] = tmp;
237 if (localRefSlot == localRefs.Length)
239 var tmp =
new object[localRefSlot * 2][];
240 Array.Copy(localRefs, 0, tmp, 0, localRefSlot);
244 active = localRefs[localRefSlot];
245 active ??= localRefs[localRefSlot] =
new object[LOCAL_REF_MAX_BUCKET_SIZE];
248 internal object UnwrapLocalRef(nint i)
250 return localRefs[i >> LOCAL_REF_SHIFT][i & LOCAL_REF_MASK];
253 internal int PushLocalFrame(
jint capacity)
256 if (localRefSlot >= localRefs.Length)
258 var tmp =
new object[localRefs.Length * 2][];
259 Array.Copy(localRefs, 0, tmp, 0, localRefs.Length);
264 localRefs[localRefSlot - 1] =
null;
265 if (localRefs[localRefSlot] ==
null)
270 capacity = Math.Min(capacity, LOCAL_REF_MAX_BUCKET_SIZE);
274 localRefs[localRefSlot] =
new object[r];
278 active = localRefs[localRefSlot];
282 internal jobject PopLocalFrame(
object res)
284 while (localRefs[localRefSlot] !=
null)
286 localRefs[localRefSlot] =
null;
291 localRefIndex = localRefs[localRefSlot].Length;
292 active = localRefs[localRefSlot];
293 return MakeLocalRef(res);
296 internal void DeleteLocalRef(
jobject obj)
298 int i = obj.ToInt32();
301 localRefs[i >> LOCAL_REF_SHIFT][i & LOCAL_REF_MASK] =
null;
307 Debug.Assert(
false,
"bogus localref in DeleteLocalRef");