Proposal: java.lang.runtime.Carrier

Brian Goetz brian.goetz at oracle.com
Thu Mar 3 15:29:51 UTC 2022


Thanks Jim.

As background, (some form of) this code originated in a prototype for 
pattern matching, where we needed a carrier for a tuple (T, U, V) to 
carry the results of a match from a deconstruction pattern (or other 
declared pattern) on the stack as a return value.  We didn't want to 
spin a custom class per pattern, and we didn't want to commit to the 
actual layout, because we wanted to preserve the ability to switch later 
to a value class.  So the idea is you describe the carrier you want as a 
MethodType, and there's a condy that gives you an MH that maps that 
shape of arguments to an opaque carrier (the constructor), and other 
condys that give you MHs that map from the carrier to the individual 
bindings.  So pattern matching will stick those MHs in CP slots.

The carrier might be some bespoke thing (e.g., record anon(T t, U u, V 
v)), or something that holds an Object[], or something with three int 
fields and two ref fields, or whatever the runtime decides to serve up.

The template mechanism wants almost exactly the same thing for bundling 
the parameters for uninterprted template strings.

Think of it as a macro-box; instead of boxing primitives to Object and 
Objects to varargs, there's a single boxing operation from a tuple to an 
opaque type.



On 3/3/2022 8:57 AM, Jim Laskey wrote:
>
> We propose to provide a runtime /anonymous carrier class object 
> generator/; *java.lang.runtime.Carrier*. This generator class is 
> designed to share /anonymous classes/ when shapes are similar. For 
> example, if several clients require objects containing two integer 
> fields, then *Carrier* will ensure that each client generates carrier 
> objects using the same underlying anonymous class.
>
> Providing this mechanism decouples the strategy for carrier class 
> generation from the client facility. One could implement one class per 
> shape; one class for all shapes (with an Object[]), or something in 
> the middle; having this decision behind a bootstrap means that it can 
> be evolved at runtime, and optimized differently for different situations.
>
>
>       Motivation
>
> The String Templates JEP draft 
> <https://bugs.openjdk.java.net/browse/JDK-8273943> proposes the 
> introduction of a /TemplatedString/ object for the primary purpose of 
> /carrying/ the /template/ and associated /values/ derived from a 
> /template literal/. To avoid value boxing, early prototypes described 
> these /carrier/objects using /per-callsite/ anonymous classes shaped 
> by value types, The use of distinct anonymous classes here is 
> overkill, especially considering that many of these classes are 
> similar; containing one or two object fields and/or one or two 
> integral fields. /Pattern matching/ has a similar issue when carrying 
> the values for the /holes/ of a pattern. With potentially hundreds 
> (thousands?) of template literals or patterns per application, we need 
> to find an alternate approach for these /value carriers/.
>
>
>       Description
>
> In general terms, the *Carrier* class simply caches anonymous classes 
> keyed on shape. To further increase similarity in shape, the ordering 
> of value types is handled by the API and not in the underlying 
> anonymous class. If one client requires an object with one object 
> value and one integer value and a second client requires an object 
> with one integer value and one object value, then both clients will 
> use the same underlying anonymous class. Further, types are folded as 
> either integer (byte, short, int, boolean, char, float), long (long, 
> double) or object. [We've seen that performance hit by folding the 
> long group into the integer group is significant, hence the separate 
> group.]
>
> The *Carrier* API uses MethodType parameter types to describe the 
> shape of a carrier. This incorporates with the primary use case where 
> bootstrap methods need to capture indy non-static arguments. The API 
> has three static methods;
>
> |// Return a constructor MethodHandle for a carrier with components // 
> aligning with the parameter types of the supplied methodType. static 
> MethodHandle constructor(MethodType methodType) // Return a component 
> getter MethodHandle for component i. static MethodHandle 
> component(MethodType methodType, int i) // Return component getter 
> MethodHandles for all the carrier's components. static MethodHandle[] 
> components(MethodType methodType)|
>
>
>       Examples
>
> |import java.lang.runtime.Carrier; ... // Define the carrier 
> description. MethodType methodType = 
> MethodType.methodType(Object.class, byte.class, short.class, 
> char.class, int.class, long.class, float.class, double.class, 
> boolean.class, String.class); // Fetch the carrier constructor. 
> MethodHandle constructor = Carrier.constructor(methodType); // Create 
> a carrier object. Object object = 
> (Object)constructor.invokeExact((byte)0xFF, (short)0xFFFF, 'C', 
> 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFFL, 1.0f / 3.0f, 1.0 / 3.0, true, 
> "abcde"); // Get an array of accessors for the carrier object. 
> MethodHandle[] components = Carrier.components(methodType); // Access 
> fields. byte b = (byte)components[0].invokeExact(object); short s = 
> (short)components[1].invokeExact(object); char c 
> =(char)components[2].invokeExact(object); int i = 
> (int)components[3].invokeExact(object); long l = 
> (long)components[4].invokeExact(object); float f 
> =(float)components[5].invokeExact(object); double d = 
> (double)components[6].invokeExact(object); boolean tf 
> (boolean)components[7].invokeExact(object); String s = 
> (String)components[8].invokeExact(object)); // Access a specific 
> field. MethodHandle component = Carrier.component(methodType, 3); int 
> ii = (int)component.invokeExact(object);|
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20220303/520c9193/attachment.htm>


More information about the amber-spec-experts mailing list