镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Java enumerations should *cache* the field values #11856

Closed

Description

@jonpryor

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:

https://github.com/dotnet/java-interop/blob/fcad3368815dffd0f38f64384aa21b0b65367d68/src/Java.Base-ref.cs#L5490-L5506

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);
				}
			}

Activity

  1. jonpryor commented on Aug 14, 2024

    @jonpryor
    ContributorAuthor

    Updated description to mention that we should do caching for all final fields, not just fields of enum types. That's what final is for, after all, right?

  2. jonathanpeppers commented on Aug 15, 2024

    @jonathanpeppers
    Member

    Here is an example trace:

    Search for either Android.Graphics.Paint.Cap.get_Butt() or Android.Graphics.Paint.Join.get_Miter() as an example.

    I'm doing this for now, which would also help .NET 8:

  3. added this to the .NET 10 milestone on Sep 11, 2024
  4. added theissue type on Apr 29, 2025
  5. removed
    enhancementProposed change to current functionality.
    on Apr 29, 2025
  6. added
    java-interopIssues migrated from dotnet/java-interop / relates to the Java.Interop subtree
    needs-triageIssues that need to be assigned.
    Area: BindingsIssues in Java Library Binding projects.
    on Jul 1, 2026
  7. dotnet-policy-service commented on Jul 1, 2026

    @dotnet-policy-service

    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.

  8. dotnet-policy-service commented on Jul 15, 2026

    @dotnet-policy-service

    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.

  9. removed this from the .NET 10 milestone on Jul 15, 2026
  10. locked and limited conversation to collaborators on Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: BindingsIssues in Java Library Binding projects.java-interopIssues migrated from dotnet/java-interop / relates to the Java.Interop subtreeneeds-triageIssues that need to be assigned.possibly-staleIssues that are potentially no longer relevant.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions