We need a VM-level API point for running a constructor of an inline (by-value) type, which is distinct from the current way of running constructors. Currently, constructors are invoked by running invokespecial on a special internal method named <init>, passing a blank fresh instance of the required class. The blankness of the fresh instance is tracked by the verifier using very special rules which are triggered by the mention of the very special name <init>.
We can't use this mechanism for constructing value types because there is no way to perform side effects on a value type instance, blank or not. The most natural way to create a value type instance, in the JVM, is to run invokestatic on an appropriately named static factory method. The name of this method is a convention which is known to various parties, notably the static compiler (javac) and reflection (jlr.Constructor). After some prototyping, I can say that it is a reasonable and simple thing to do to re-use the string "<init>" for the target of an invokestatic which translates a constructor of an inline type. For example: ``` inline class Point { int x, y; Point(int x1, int y1) { x=x1; y=y1; } } // static Point.<init>(II)Point { vdefault[Point] … } class Client { static Point myPoint() { return new Point(3,4); } } // Client.myPoint() { … invokestatic[Point.<init>(II)Point] … } ``` To do this, we will need to make some changes to the JVM specification (and implementations). Here are the changes I propose: * Relax constraints on CONSTANT_Methodref and CONSTANT_NameAndType allowing free use of <init> as if it were a regular method name. * Retain all restrictions on use of <init> via invokespecial. * Allow an invokestatic to mention <init> (but no other bytecodes). * Retain all restrictions on definition of <init> methods *in regular non-inline classfiles* * Allow an inline classfile to define a <init> method, only with ACC_STATIC * Require that the type returned by such an <init> method is the containing class. (Extra rider: If the class is non-denotable, aka. hidden, returned class must be Object.) These changes ensure that there are only two kinds of methods named <init>, classic by-reference object constructors, and new by-value "static init factories". The specification ensures that these two kinds of methods, both named <init>, can never be confused. The basic mechanism for ensuring this is that one kind of method is defined as non-static and the other is defined as static, and there is no way to accidentally invoke a static method via invokespecial, and vice versa for invokestatic. Note that CONSTANT_Methodrefs can refer to either kind of descriptor. This is not ambiguous, since every use of such a constant is coupled with an indicator (an opcode or ref-kind) which tells if the use is of a static method or not. Note also that there can be "crazy" references to the name <init> such as under the type "()I" (no args returning int). These references are harmless because they will never link to a definition of that signature. This is true not because there are limitations on the form of uses of <init>, but because there are strong limitations on the possible definitions of <init>. A "crazy" use has no impact, other than causing an eventual linkage error. We could try to add more limits against crazy uses of <init>, but that does not seem to be necessary, except perhaps as a "defense in depth" move. Additional changes are needed for reflection: * Allow new static init factories to be wrapped in `jlr.Constructor`s. * Ensure that `Constructor::newInstance` uses the right calling sequence for static init factories. * Ensure that `Lookup::findConstructor` can find static init factories. * Allow `Lookup::findStatic` to find static init factories. (This step simplifies mapping between invokestatic and method handle constants. It could be dropped.) * Ensure that resolution of `CONSTANT_MethodHandle` continues to use the reference-kind option correctly. (No actual spec change.) The low-level user model has a twist in it: At the level of bytecodes, a static init factory is just a vanilla static method, albeit with a funny name. But at the level of reflection, a static init factory appears to be a constructor. This is reasonable since a static init factory translates an actual constructor in source code. A `Constructor` which wraps a static init factory will have its `ACC_STATIC` method set, allowing users who care to distinguish the two uses of the name <init>. The query method `Class::getDeclaredMethods` will not expose static init factories. Only `Class::getDeclaredConstructors` will. A similar rule applies to related API points such as `getMethod`. The purpose of this restriction (which is optional) is to avoid having overlaps in the reflected lists of constructors and methods. Because the `java.lang.invoke` API is lower-level than `java.lang.reflect`, it should (probably) be willing to treat static init factories as vanilla static methods. Thus `findStatic` can return a handle to such a factory. Because `java.lang.invoke` also integrates (via "unreflection") with `java.lang.reflect`, `findConstructor` should be willing to treat static init factories as constructors. Perhaps one of these methods can be suppressed, but it seems reasonable to allow both in `java.lang.invoke`, because of the two-sided positioning of that API layer. I posted a HotSpot POC implementation here: http://cr.openjdk.java.net/~jrose/jvm/JDK-8222787/ Comments, please? — John