This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Commit b881d21

Browse files
[Java.Interop] Remove JniObjectReference SafeHandle backend (#1446)
Related to #1448 ## Summary Remove the unsupported `JniObjectReference` SafeHandle backend and make the existing `IntPtr` representation the only implementation: - remove `FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES` / `FEATURE_JNIOBJECTREFERENCE_INTPTRS` branching from `Java.Interop` - delete the unused `JniReferenceSafeHandle`, `JniLocalReference`, `JniGlobalReference`, `JniWeakGlobalReference`, and `JniAllocObjectRef` types - delete the excluded SafeHandle-specific test - remove the obsolete SafeHandle invocation strategy from `jnienv-gen` and regenerate `tests/invocation-overhead/jni.cs` - update docs to describe the SafeHandle path as a historical experiment, not a supported backend ## Decision record The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an `IntPtr` representation. That experiment has been rejected for the current runtime model: - the active project build always used the `IntPtr`-backed `JniObjectReference` path - trying to enable the SafeHandle object-reference symbol conflicts with the default `FEATURE_JNIOBJECTREFERENCE_INTPTRS` define - the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project - the SafeHandle branch had stale code and was not maintained as a buildable configuration - historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs - Android now depends on the `JniObjectReferenceControlBlock`/`IntPtr` model for runtime and GC-bridge integration Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a2b83e3 commit b881d21

22 files changed

Lines changed: 56 additions & 5600 deletions

‎Documentation/Architecture.md‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,12 @@ they don't require cleanup *anyway*. Furthermore, these values should be
237237
*cached* -- see `JniPeerMembers` -- so making them GC objects shouldn't be
238238
a long-term problem.
239239

240-
By doing so, we allow Java.Interop to have *two separate implementations*,
241-
controlled by build-time `#define`s:
242-
243-
*`FEATURE_HANDLES_ARE_SAFE_HANDLES`: Causes `JniObjectReference` to
244-
contain a `SafeHandle` wrapping the underlying JNI handle.
245-
*`FEATURE_HANDLES_ARE_INTPTRS`: Causes `JniObjectReference` to contain
246-
an `IntPtr` for the underlying JNI handle.
247-
248-
The rationale for this is twofold:
249-
250-
1. It allows swapping out "safer" `SafeHandle` and "less safe" `IntPtr`
251-
implementations, permitting easier performance comparisons.
252-
2. It allows migrating the existing code, as some of the existing
253-
tests may assume that JNI handles are garbage collected, which
254-
won't be the case when `FEATURE_HANDLES_ARE_INTPTRS` is set.
240+
Historically, `JniObjectReference` retained an optional `SafeHandle`
241+
implementation behind a build-time feature switch so the safer but slower
242+
representation could be compared with the `IntPtr` representation during the
243+
migration. That experiment is no longer active: the supported implementation is
244+
the `IntPtr`-backed `JniObjectReference` struct, with explicit ownership
245+
transfer and disposal via `JniObjectReference.Dispose (ref reference)`.
255246

256247

257248
## Naming Conventions
@@ -289,4 +280,3 @@ I halted the above loop after reaching 25686556 instances.
289280
I'm not sure when the JDK would stop handing out references, but it's probably
290281
bound to process heap limits (e.g. depends on 32-bit vs. 64-bit process).
291282

292-

‎build-tools/jnienv-gen/Generator.cs‎

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,19 @@ static void GenerateFile (TextWriter o)
8888
o.WriteLine("// To make changes, edit monodroid/tools/jnienv-gen-interop and rerun");
8989
o.WriteLine("#nullable enable");
9090
o.WriteLine();
91-
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
91+
o.WriteLine("#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9292
o.WriteLine("#define FEATURE_JNIENVIRONMENT_JI_PINVOKES");
93-
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS");
93+
o.WriteLine("#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
9494
o.WriteLine();
95-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
95+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9696
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
97-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_INTPTRS");
98-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
97+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
98+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
9999
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
100-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_JI_PINVOKES");
101-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
100+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_PINVOKES && (FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)");
101+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
102102
o.WriteLine("#define _NAMESPACE_PER_HANDLE");
103-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES && FEATURE_JNIENVIRONMENT_XA_INTPTRS");
103+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_XA_INTPTRS && FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
104104
o.WriteLine();
105105
o.WriteLine("using System;");
106106
o.WriteLine("using System.Linq;");
@@ -123,7 +123,6 @@ static void GenerateFile (TextWriter o)
123123
o.WriteLine("namespace Java.Interop {");
124124
GenerateJniNativeInterface(o);
125125
o.WriteLine("}");
126-
WriteSection(o,HandleStyle.SafeHandle,"FEATURE_JNIENVIRONMENT_SAFEHANDLES","Java.Interop.SafeHandles");
127126
WriteSection(o,HandleStyle.JIIntPtr,"FEATURE_JNIENVIRONMENT_JI_INTPTRS","Java.Interop.JIIntPtrs");
128127
WriteSection(o,HandleStyle.JIIntPtrPinvokeWithErrors,"FEATURE_JNIENVIRONMENT_JI_PINVOKES","Java.Interop.JIPinvokes");
129128
WriteSection(o,HandleStyle.XAIntPtr,"FEATURE_JNIENVIRONMENT_XA_INTPTRS","Java.Interop.XAIntPtrs");
@@ -149,7 +148,6 @@ static void WriteSection (TextWriter o, HandleStyle style, string define, string
149148
o.WriteLine();
150149
switch(style){
151150
caseHandleStyle.JIIntPtr:
152-
caseHandleStyle.SafeHandle:
153151
caseHandleStyle.XAIntPtr:
154152
GenerateJniNativeInterfaceInvoker(o,style);
155153
break;
@@ -172,7 +170,7 @@ static void GenerateJniNativeInterface (TextWriter o)
172170
o.WriteLine("#pragma warning disable 0169 // Field never used; ignore since these fields make the structure have the right layout.");
173171
o.WriteLine();
174172

175-
o.WriteLine("#if FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
173+
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
176174
o.WriteLine("\t[StructLayout (LayoutKind.Sequential)]");
177175
o.WriteLine("\tpartial struct JniNativeInterfaceStruct {");
178176
o.WriteLine();
@@ -186,7 +184,7 @@ static void GenerateJniNativeInterface (TextWriter o)
186184
o.WriteLine("\t\tpublic IntPtr {0};{1} // {2}",e.Name,newstring(' ',maxName-e.Name.Length),e.Prototype);
187185
}
188186
o.WriteLine("\t}");
189-
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_SAFEHANDLES || FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
187+
o.WriteLine("#endif // FEATURE_JNIENVIRONMENT_JI_INTPTRS || FEATURE_JNIENVIRONMENT_XA_INTPTRS");
190188
o.WriteLine();
191189

192190
o.WriteLine("#if FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS");
@@ -961,7 +959,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
961959
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
962960
{
963961
switch(style){
964-
caseHandleStyle.SafeHandle:
965962
caseHandleStyle.XAIntPtr:
966963
returnnew[]{
967964
string.Format("JniEnvironment.LogCreateLocalRef ({0});",variable),
@@ -1070,7 +1067,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
10701067
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
10711068
{
10721069
switch(style){
1073-
caseHandleStyle.SafeHandle:
10741070
caseHandleStyle.JIIntPtr:
10751071
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10761072
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1084,7 +1080,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
10841080
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
10851081
{
10861082
switch(style){
1087-
caseHandleStyle.SafeHandle:
10881083
caseHandleStyle.JIIntPtr:
10891084
caseHandleStyle.JIIntPtrPinvokeWithErrors:
10901085
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1099,7 +1094,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
10991094
?variable.Substring(1)
11001095
:variable;
11011096
switch(style){
1102-
caseHandleStyle.SafeHandle:
11031097
caseHandleStyle.JIIntPtr:
11041098
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11051099
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1122,7 +1116,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
11221116
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
11231117
{
11241118
switch(style){
1125-
caseHandleStyle.SafeHandle:
11261119
caseHandleStyle.JIIntPtr:
11271120
caseHandleStyle.JIIntPtrPinvokeWithErrors:
11281121
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1186,20 +1179,17 @@ protected override bool IsStatic {
11861179

11871180
abstractclassObjectReferenceTypeInfo:TypeInfo{
11881181

1189-
stringsafeType,refType;
1182+
stringrefType;
11901183

1191-
publicObjectReferenceTypeInfo(stringjni,stringsafeType,stringrefType)
1184+
publicObjectReferenceTypeInfo(stringjni,stringrefType)
11921185
:base(jni)
11931186
{
1194-
this.safeType=safeType;
11951187
this.refType=refType;
11961188
}
11971189

11981190
publicoverridestringGetMarshalType(HandleStylestyle,boolisReturn,boolisPinvoke)
11991191
{
12001192
switch(style){
1201-
caseHandleStyle.SafeHandle:
1202-
returnisReturn?safeType:"JniReferenceSafeHandle";
12031193
caseHandleStyle.JIIntPtr:
12041194
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12051195
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1212,7 +1202,6 @@ public override string GetMarshalType (HandleStyle style, bool isReturn, bool is
12121202
publicoverridestringGetManagedType(HandleStylestyle,boolisReturn,boolisPinvoke)
12131203
{
12141204
switch(style){
1215-
caseHandleStyle.SafeHandle:
12161205
caseHandleStyle.JIIntPtr:
12171206
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12181207
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1226,8 +1215,6 @@ public override string GetManagedType (HandleStyle style, bool isReturn, bool is
12261215
publicoverridestringGetManagedToMarshalExpression(HandleStylestyle,stringvariable)
12271216
{
12281217
switch(style){
1229-
caseHandleStyle.SafeHandle:
1230-
returnstring.Format("{0}.SafeHandle",variable);
12311218
caseHandleStyle.JIIntPtr:
12321219
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12331220
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1241,7 +1228,6 @@ public override string GetManagedToMarshalExpression (HandleStyle style, string
12411228
publicoverridestring[]GetMarshalToManagedStatements(HandleStylestyle,stringvariable,JniFunctionentry)
12421229
{
12431230
switch(style){
1244-
caseHandleStyle.SafeHandle:
12451231
caseHandleStyle.JIIntPtr:
12461232
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12471233
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1262,7 +1248,6 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12621248
?variable.Substring(1)
12631249
:variable;
12641250
switch(style){
1265-
caseHandleStyle.SafeHandle:
12661251
caseHandleStyle.JIIntPtr:
12671252
caseHandleStyle.JIIntPtrPinvokeWithErrors:
12681253
caseHandleStyle.JIFunctionPtrWithErrors:
@@ -1283,7 +1268,7 @@ public override string[] VerifyParameter (HandleStyle style, string variable)
12831268
classLocalReferenceTypeInfo:ObjectReferenceTypeInfo{
12841269

12851270
publicLocalReferenceTypeInfo(stringjni)
1286-
:base(jni,"JniLocalReference","JniObjectReferenceType.Local")
1271+
:base(jni,"JniObjectReferenceType.Local")
12871272
{
12881273
}
12891274

@@ -1300,15 +1285,15 @@ public override string[] GetHandleCreationLogStatements (HandleStyle style, stri
13001285
classWeakGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13011286

13021287
publicWeakGlobalReferenceTypeInfo(stringjni)
1303-
:base(jni,"JniWeakGlobalReference","JniObjectReferenceType.WeakGlobal")
1288+
:base(jni,"JniObjectReferenceType.WeakGlobal")
13041289
{
13051290
}
13061291
}
13071292

13081293
classGlobalReferenceTypeInfo:ObjectReferenceTypeInfo{
13091294

13101295
publicGlobalReferenceTypeInfo(stringjni)
1311-
:base(jni,"JniGlobalReference","JniObjectReferenceType.Global")
1296+
:base(jni,"JniObjectReferenceType.Global")
13121297
{
13131298
}
13141299
}
@@ -1399,11 +1384,9 @@ enum Modifier {
13991384
}
14001385

14011386
enumHandleStyle{
1402-
SafeHandle,
14031387
JIIntPtr,
14041388
JIIntPtrPinvokeWithErrors,
14051389
XAIntPtr,
14061390
JIFunctionPtrWithErrors,
14071391
}
14081392
}
1409-

‎src/Java.Interop/Java.Interop.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ImportProject="..\..\TargetFrameworkDependentValues.props" />
2323
<ImportProject="..\..\build-tools\trim-analyzers\trim-analyzers.props" />
2424
<PropertyGroup>
25-
<DefineConstants>INTEROP;FEATURE_JNIOBJECTREFERENCE_INTPTRS;$(JavaInteropDefineConstants)</DefineConstants>
25+
<DefineConstants>INTEROP;$(JavaInteropDefineConstants)</DefineConstants>
2626
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
2727
<OutputPath>$(ToolOutputFullPath)</OutputPath>
2828
<DocumentationFile>$(ToolOutputFullPath)Java.Interop.xml</DocumentationFile>

‎src/Java.Interop/Java.Interop/JavaException.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ unsafe public partial class JavaException : Exception, IJavaPeerable
1414
publicintJniIdentityHashCode{get;privateset;}
1515
publicJniManagedPeerStatesJniManagedPeerState{get;privateset;}
1616

17-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
18-
JniObjectReferencereference;
19-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
20-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2117
unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
22-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
2318

2419
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
2520

@@ -96,16 +91,11 @@ protected void Construct (ref JniObjectReference reference, JniObjectReferenceOp
9691

9792
publicJniObjectReferencePeerReference{
9893
get{
99-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
100-
returnreference;
101-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
102-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
10394
varc=jniObjectReferenceControlBlock;
10495
if(c==null){
10596
returndefault;
10697
}
10798
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
108-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10999
}
110100
}
111101

@@ -131,10 +121,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
131121
return;
132122
}
133123

134-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135-
this.reference=reference;
136-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
137-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
138124
varc=jniObjectReferenceControlBlock;
139125
if(c==null){
140126
c=jniObjectReferenceControlBlock=
@@ -143,7 +129,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
143129
c->handle=reference.Handle;
144130
c->handle_type=(int)reference.Type;
145131
}
146-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
147132

148133
JniObjectReference.Dispose(refreference,options);
149134
}
@@ -287,15 +272,12 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
287272
voidIJavaPeerable.SetPeerReference(JniObjectReferencereference)
288273
{
289274
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
290-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
291275
if(!reference.IsValid&&JniManagedPeerState.HasFlag(Disposed)){
292276
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
293277
}
294-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
295278
}
296279

297280
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
298281
(IntPtr)jniObjectReferenceControlBlock;
299282
}
300283
}
301-

‎src/Java.Interop/Java.Interop/JavaObject.cs‎

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ unsafe public partial class JavaObject : IJavaPeerable
2121

2222
publicJniManagedPeerStatesJniManagedPeerState=>managedPeerState;
2323

24-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
25-
[NonSerialized]JniObjectReferencereference;
26-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
27-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
2824
[NonSerialized]unsafeJniObjectReferenceControlBlock*jniObjectReferenceControlBlock;
29-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3025

3126
protectedstaticreadonlyJniObjectReference*InvalidJniObjectReference=null;
3227

@@ -37,16 +32,11 @@ unsafe public partial class JavaObject : IJavaPeerable
3732

3833
publicunsafeJniObjectReferencePeerReference{
3934
get{
40-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
41-
returnreference;
42-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
43-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
4435
varc=jniObjectReferenceControlBlock;
4536
if(c==null){
4637
returndefault;
4738
}
4839
returnnewJniObjectReference(c->handle,(JniObjectReferenceType)c->handle_type);
49-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5040
}
5141
}
5242

@@ -86,10 +76,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
8676
return;
8777
}
8878

89-
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
90-
this.reference=reference;
91-
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
92-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
9379
varc=jniObjectReferenceControlBlock;
9480
if(c==null){
9581
c=jniObjectReferenceControlBlock=
@@ -98,7 +84,6 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9884
c->handle=reference.Handle;
9985
c->handle_type=(int)reference.Type;
10086
}
101-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
10287

10388
JniObjectReference.Dispose(refreference,options);
10489
}
@@ -176,15 +161,12 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
176161
{
177162
SetPeerReference(refreference,JniObjectReferenceOptions.Copy);
178163

179-
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
180164
if(!reference.IsValid&&managedPeerState.HasFlag(Disposed)){
181165
Java.Interop.JniObjectReferenceControlBlock.Free(refjniObjectReferenceControlBlock);
182166
}
183-
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
184167
}
185168

186169
IntPtrIJavaPeerable.JniObjectReferenceControlBlock=>
187170
(IntPtr)jniObjectReferenceControlBlock;
188171
}
189172
}
190-

‎src/Java.Interop/Java.Interop/JniAllocObjectRef.cs‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)