Consider the Thread.State enum:
/* partial */classThread {
publicstaticfinal/* partial */enumState {
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
}
}This "actually" is a class with fields for each enum value:
% javap java.lang.Thread.StateCompiled 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:
https://github.com/dotnet/java-interop/blob/fcad3368815dffd0f38f64384aa21b0b65367d68/src/Java.Base-ref.cs#L5490-L5506
However, each of those properties involves a ValueManager lookup:
namespaceJava.Lang{publicpartialclassThread{publicsealedpartialclassState:global::Java.Lang.Enum{publicstaticglobal::Java.Lang.Thread.State?Runnable{get{conststring__id="RUNNABLE.Ljava/lang/Thread$State;";var__v=_members.StaticFields.GetObjectValue(__id);returnglobal::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:
publicstaticJava.Lang.Thread.State?Runnable{get{conststring__id="RUNNABLE.Ljava/lang/Thread$State;";var__v=_members.StaticFields.GetObjectValue(__id);returnglobal::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;publicstaticglobal::Java.Lang.Thread.State?Runnable{get{if(_Runnable_cache!=null)return_Runnable_cache;conststring__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);}}
Consider the
Thread.Stateenum:This "actually" is a class with fields for each enum value:
When we bind it, we bind the fields as properties:
https://github.com/dotnet/java-interop/blob/fcad3368815dffd0f38f64384aa21b0b65367d68/src/Java.Base-ref.cs#L5490-L5506
However, each of those properties involves a ValueManager lookup:
This is JavaInterop1, not XAJavaInterop1, but .NET for Android isn't much different:
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
finalfields to cache the return value? This means we'd only need to callStaticFields.GetObjectValue()and "GetValue" once, instead of once per-access: