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:
java-interop/src/Java.Base-ref.cs
Lines 5490 to 5506 in fcad336
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);
}
}