Repository navigation
Closed
Labels
Area: BindingsIssues in Java Library Binding projects.Issues in Java Library Binding projects.java-interopIssues migrated from dotnet/java-interop / relates to the Java.Interop subtreeIssues migrated from dotnet/java-interop / relates to the Java.Interop subtreeneeds-triageIssues that need to be assigned.Issues that need to be assigned.possibly-staleIssues that are potentially no longer relevant.Issues that are potentially no longer relevant.
Description
Consider the Thread.State enum:
/* partial */ class Thread {
public static final /* partial */ enum State {
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
}
}This "actually" is a class with fields for each enum value:
% javap java.lang.Thread.State
Compiled from "Thread.java"
public final class java.lang.Thread$State extends java.lang.Enum<java.lang.Thread$State> {
public static final java.lang.Thread$State NEW;
public static final java.lang.Thread$State RUNNABLE;
public static final java.lang.Thread$State BLOCKED;
public static final java.lang.Thread$State WAITING;
public static final java.lang.Thread$State TIMED_WAITING;
public static final java.lang.Thread$State TERMINATED;
public static java.lang.Thread$State[] values();
public static java.lang.Thread$State valueOf(java.lang.String);
static {};
}When we bind it, we bind the fields as properties:
However, each of those properties involves a ValueManager lookup:
namespace Java.Lang {
public partial class Thread {
public sealed partial class State : global::Java.Lang.Enum {
public static global::Java.Lang.Thread.State? Runnable {
get {
const string __id = "RUNNABLE.Ljava/lang/Thread$State;";
var __v = _members.StaticFields.GetObjectValue (__id);
return global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<global::Java.Lang.Thread.State? >(ref __v, JniObjectReferenceOptions.Copy);
}
}
}
}
}This is JavaInterop1, not XAJavaInterop1, but .NET for Android isn't much different:
public static Java.Lang.Thread.State? Runnable {
get {
const string __id = "RUNNABLE.Ljava/lang/Thread$State;";
var __v = _members.StaticFields.GetObjectValue (__id);
return global::Java.Lang.Object.GetObject<Java.Lang.Thread.State> (__v.Handle, JniHandleOwnership.TransferLocalRef);
}
}The problem is that value lookup is not fast -- identity hash code needs to be obtained, locks obtained, etc. -- to the point that repeated enum lookups can actually show up in profiles.
TODO: @jonathanpeppers, please provide your profile data. :-D
Suggestion: could we update property generation for all final fields to cache the return value? This means we'd only need to call StaticFields.GetObjectValue() and "GetValue" once, instead of once per-access:
global::Java.Lang.Thread.State? _Runnable_cache;
public static global::Java.Lang.Thread.State? Runnable {
get {
if (_Runnable_cache != null) return _Runnable_cache;
const string __id = "RUNNABLE.Ljava/lang/Thread$State;";
var __v = _members.StaticFields.GetObjectValue (__id);
return _Runnable_cache = global::Java.Interop.JniEnvironment.Runtime.ValueManager.GetValue<global::Java.Lang.Thread.State? >(ref __v, JniObjectReferenceOptions.Copy);
}
}Reacted by Yann Zahringer Ferrando and Amr
Metadata
Metadata
Assignees
Labels
Area: BindingsIssues in Java Library Binding projects.Issues in Java Library Binding projects.java-interopIssues migrated from dotnet/java-interop / relates to the Java.Interop subtreeIssues migrated from dotnet/java-interop / relates to the Java.Interop subtreeneeds-triageIssues that need to be assigned.Issues that need to be assigned.possibly-staleIssues that are potentially no longer relevant.Issues that are potentially no longer relevant.
Activity
jonpryor commentedon Aug 14, 2024
Updated description to mention that we should do caching for all
finalfields, not just fields of enum types. That's whatfinalis for, after all, right?jonathanpeppers commentedon Aug 15, 2024
Here is an example trace:
Search for either
Android.Graphics.Paint.Cap.get_Butt()orAndroid.Graphics.Paint.Join.get_Miter()as an example.I'm doing this for now, which would also help .NET 8:
JoinandCapenum values maui#24248[Java.Interop] ReadOnlyProperty<T>?
[Java.Interop] ReadOnlyProperty<T>?
dotnet-policy-service commentedon Jul 1, 2026
We suspect this issue is stale and no longer relevant. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.
dotnet-policy-service commentedon Jul 15, 2026
This issue will now be closed since it had been marked "possibly-stale" but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.