15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.loader.BootLoader;
29 import jdk.internal.org.objectweb.asm.ClassWriter;
30 import jdk.internal.org.objectweb.asm.FieldVisitor;
31 import jdk.internal.org.objectweb.asm.MethodVisitor;
32 import jdk.internal.vm.annotation.Stable;
33 import sun.invoke.util.BytecodeName;
34
35 import java.lang.reflect.*;
36 import java.security.AccessController;
37 import java.security.PrivilegedAction;
38 import java.security.ProtectionDomain;
39 import java.util.*;
40 import java.util.concurrent.ConcurrentHashMap;
41 import java.util.concurrent.ConcurrentMap;
42 import java.util.function.Function;
43
44 import static java.lang.invoke.LambdaForm.*;
45 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
46 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;
47 import static java.lang.invoke.MethodHandleStatics.*;
48 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
49 import static jdk.internal.org.objectweb.asm.Opcodes.*;
50
51 /**
52 * Class specialization code.
53 * @param <T> top class under which species classes are created.
54 * @param <K> key which identifies individual specializations.
55 * @param <S> species data type.
56 */
57 /*non-public*/
58 abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesData> {
59 private final Class<T> topClass;
60 private final Class<K> keyType;
61 private final Class<S> metaType;
62 private final MemberName sdAccessor;
63 private final String sdFieldName;
64 private final List<MemberName> transformMethods;
65 private final MethodType baseConstructorType;
66 private final S topSpecies;
67 private final ConcurrentMap<K, S> cache = new ConcurrentHashMap<>();
68 private final Factory factory;
69 private @Stable boolean topClassIsSuper;
70
71 /** Return the top type mirror, for type {@code T} */
72 public final Class<T> topClass() { return topClass; }
73
74 /** Return the key type mirror, for type {@code K} */
75 public final Class<K> keyType() { return keyType; }
76
77 /** Return the species metadata type mirror, for type {@code S} */
78 public final Class<S> metaType() { return metaType; }
79
80 /** Report the leading arguments (if any) required by every species factory.
81 * Every species factory adds its own field types as additional arguments,
82 * but these arguments always come first, in every factory method.
83 */
84 protected MethodType baseConstructorType() { return baseConstructorType; }
85
86 /** Return the trivial species for the null sequence of arguments. */
87 protected final S topSpecies() { return topSpecies; }
96 * Constructor for this class specializer.
97 * @param topClass type mirror for T
98 * @param keyType type mirror for K
99 * @param metaType type mirror for S
100 * @param baseConstructorType principal constructor type
101 * @param sdAccessor the method used to get the speciesData
102 * @param sdFieldName the name of the species data field, inject the speciesData object
103 * @param transformMethods optional list of transformMethods
104 */
105 protected ClassSpecializer(Class<T> topClass,
106 Class<K> keyType,
107 Class<S> metaType,
108 MethodType baseConstructorType,
109 MemberName sdAccessor,
110 String sdFieldName,
111 List<MemberName> transformMethods) {
112 this.topClass = topClass;
113 this.keyType = keyType;
114 this.metaType = metaType;
115 this.sdAccessor = sdAccessor;
116 // FIXME: use List.copyOf once 8177290 is in
117 this.transformMethods = List.of(transformMethods.toArray(new MemberName[transformMethods.size()]));
118 this.sdFieldName = sdFieldName;
119 this.baseConstructorType = baseConstructorType.changeReturnType(void.class);
120 this.factory = makeFactory();
121 K tsk = topSpeciesKey();
122 S topSpecies = null;
123 if (tsk != null && topSpecies == null) {
124 // if there is a key, build the top species if needed:
125 topSpecies = findSpecies(tsk);
126 }
127 this.topSpecies = topSpecies;
128 }
129
130 // Utilities for subclass constructors:
131 protected static <T> Constructor<T> reflectConstructor(Class<T> defc, Class<?>... ptypes) {
132 try {
133 return defc.getDeclaredConstructor(ptypes);
134 } catch (NoSuchMethodException ex) {
135 throw newIAE(defc.getName()+"("+MethodType.methodType(void.class, ptypes)+")", ex);
136 }
137 }
138
139 protected static Field reflectField(Class<?> defc, String name) {
140 try {
141 return defc.getDeclaredField(name);
142 } catch (NoSuchFieldException ex) {
143 throw newIAE(defc.getName()+"."+name, ex);
144 }
145 }
146
147 private static RuntimeException newIAE(String message, Throwable cause) {
148 return new IllegalArgumentException(message, cause);
149 }
150
151 public final S findSpecies(K key) {
152 S speciesData = cache.computeIfAbsent(key, new Function<>() {
153 @Override
154 public S apply(K key1) {
155 return factory.loadSpecies(newSpeciesData(key1));
156 }
157 });
158 // Note: Species instantiation may throw VirtualMachineError because of
159 // code cache overflow. If this happens the species bytecode may be
160 // loaded but not linked to its species metadata (with MH's etc).
161 // That will cause a throw out of CHM.computeIfAbsent,
162 // which will shut down the caller thread.
163 //
164 // In a latter attempt to get the same species, the already-loaded
165 // class will be present in the system dictionary, causing an
166 // error when the species generator tries to reload it.
167 // We try to detect this case and link the pre-existing code.
168 //
169 // Although it would be better to start fresh by loading a new
170 // copy, we have to salvage the previously loaded but broken code.
171 // (As an alternative, we might spin a new class with a new name,
172 // or use the anonymous class mechanism.)
173 //
174 // In the end, as long as everybody goes through the same CHM,
175 // CHM.computeIfAbsent will ensure only one SpeciesData will be set
176 // successfully on a concrete class if ever.
177 // The concrete class is published via SpeciesData instance
178 // returned here only after the class and species data are linked together.
179 assert(speciesData != null);
180 return speciesData;
181 }
182
183 /**
184 * Meta-data wrapper for concrete subtypes of the top class.
185 * Each concrete subtype corresponds to a given sequence of basic field types (LIJFD).
186 * The fields are immutable; their values are fully specified at object construction.
187 * Each species supplies an array of getter functions which may be used in lambda forms.
188 * A concrete value is always constructed from the full tuple of its field values,
189 * accompanied by the required constructor parameters.
190 * There *may* also be transforms which cloning a species instance and
191 * either replace a constructor parameter or add one or more new field values.
192 * The shortest possible species has zero fields.
193 * Subtypes are not interrelated among themselves by subtyping, even though
194 * it would appear that a shorter species could serve as a supertype of a
195 * longer one which extends it.
196 */
197 public abstract class SpeciesData {
198 // Bootstrapping requires circular relations Class -> SpeciesData -> Class
199 // Therefore, we need non-final links in the chain. Use @Stable fields.
200 private final K key;
201 private final List<Class<?>> fieldTypes;
202 @Stable private Class<? extends T> speciesCode;
203 @Stable private List<MethodHandle> factories;
204 @Stable private List<MethodHandle> getters;
205 @Stable private List<LambdaForm.NamedFunction> nominalGetters;
206 @Stable private final MethodHandle[] transformHelpers = new MethodHandle[transformMethods.size()];
207
208 protected SpeciesData(K key) {
209 this.key = keyType.cast(Objects.requireNonNull(key));
210 List<Class<?>> types = deriveFieldTypes(key);
211 // TODO: List.copyOf
212 int arity = types.size();
213 this.fieldTypes = List.of(types.toArray(new Class<?>[arity]));
214 }
215
216 public final K key() {
217 return key;
218 }
219
220 protected final List<Class<?>> fieldTypes() {
221 return fieldTypes;
222 }
223
224 protected final int fieldCount() {
225 return fieldTypes.size();
226 }
227
228 protected ClassSpecializer<T,K,S> outer() {
229 return ClassSpecializer.this;
230 }
231
232 protected final boolean isResolved() {
233 return speciesCode != null && factories != null && !factories.isEmpty();
441 */
442 S loadSpecies(S speciesData) {
443 String className = speciesData.deriveClassName();
444 assert(className.indexOf('/') < 0) : className;
445 Class<?> salvage = null;
446 try {
447 salvage = BootLoader.loadClassOrNull(className);
448 if (TRACE_RESOLVE && salvage != null) {
449 // Used by jlink species pregeneration plugin, see
450 // jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin
451 System.out.println("[SPECIES_RESOLVE] " + className + " (salvaged)");
452 }
453 } catch (Error ex) {
454 if (TRACE_RESOLVE) {
455 System.out.println("[SPECIES_FRESOLVE] " + className + " (Error) " + ex.getMessage());
456 }
457 }
458 final Class<? extends T> speciesCode;
459 if (salvage != null) {
460 speciesCode = salvage.asSubclass(topClass());
461 factory.linkSpeciesDataToCode(speciesData, speciesCode);
462 factory.linkCodeToSpeciesData(speciesCode, speciesData, true);
463 } else {
464 // Not pregenerated, generate the class
465 try {
466 speciesCode = generateConcreteSpeciesCode(className, speciesData);
467 if (TRACE_RESOLVE) {
468 // Used by jlink species pregeneration plugin, see
469 // jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin
470 System.out.println("[SPECIES_RESOLVE] " + className + " (generated)");
471 }
472 // This operation causes a lot of churn:
473 linkSpeciesDataToCode(speciesData, speciesCode);
474 // This operation commits the relation, but causes little churn:
475 linkCodeToSpeciesData(speciesCode, speciesData, false);
476 } catch (Error ex) {
477 if (TRACE_RESOLVE) {
478 System.out.println("[SPECIES_RESOLVE] " + className + " (Error #2)" );
479 }
480 // We can get here if there is a race condition loading a class.
481 // Or maybe we are out of resources. Back out of the CHM.get and retry.
482 throw ex;
483 }
484 }
485
486 if (!speciesData.isResolved()) {
487 throw newInternalError("bad species class linkage for " + className + ": " + speciesData);
488 }
489 assert(speciesData == factory.loadSpeciesDataFromCode(speciesCode));
490 return speciesData;
491 }
492
493 /**
494 * Generate a concrete subclass of the top class for a given combination of bound types.
495 *
496 * A concrete species subclass roughly matches the following schema:
497 *
498 * <pre>
499 * class Species_[[types]] extends [[T]] {
500 * final [[S]] speciesData() { return ... }
501 * static [[T]] make([[fields]]) { return ... }
502 * [[fields]]
503 * final [[T]] transform([[args]]) { return ... }
504 * }
505 * </pre>
506 *
507 * The {@code [[types]]} signature is precisely the key for the species.
508 *
509 * The {@code [[fields]]} section consists of one field definition per character in
|
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.loader.BootLoader;
29 import jdk.internal.org.objectweb.asm.ClassWriter;
30 import jdk.internal.org.objectweb.asm.FieldVisitor;
31 import jdk.internal.org.objectweb.asm.MethodVisitor;
32 import jdk.internal.vm.annotation.Stable;
33 import sun.invoke.util.BytecodeName;
34
35 import java.lang.reflect.Constructor;
36 import java.lang.reflect.Field;
37 import java.lang.reflect.Modifier;
38 import java.security.AccessController;
39 import java.security.PrivilegedAction;
40 import java.security.ProtectionDomain;
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Objects;
45 import java.util.concurrent.ConcurrentHashMap;
46 import java.util.function.Function;
47
48 import static java.lang.invoke.LambdaForm.*;
49 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
50 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;
51 import static java.lang.invoke.MethodHandleStatics.*;
52 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
53 import static jdk.internal.org.objectweb.asm.Opcodes.*;
54
55 /**
56 * Class specialization code.
57 * @param <T> top class under which species classes are created.
58 * @param <K> key which identifies individual specializations.
59 * @param <S> species data type.
60 */
61 /*non-public*/
62 abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesData> {
63 private final Class<T> topClass;
64 private final Class<K> keyType;
65 private final Class<S> metaType;
66 private final MemberName sdAccessor;
67 private final String sdFieldName;
68 private final List<MemberName> transformMethods;
69 private final MethodType baseConstructorType;
70 private final S topSpecies;
71 private final ConcurrentHashMap<K, S> cache = new ConcurrentHashMap<>();
72 private final Factory factory;
73 private @Stable boolean topClassIsSuper;
74
75 /** Return the top type mirror, for type {@code T} */
76 public final Class<T> topClass() { return topClass; }
77
78 /** Return the key type mirror, for type {@code K} */
79 public final Class<K> keyType() { return keyType; }
80
81 /** Return the species metadata type mirror, for type {@code S} */
82 public final Class<S> metaType() { return metaType; }
83
84 /** Report the leading arguments (if any) required by every species factory.
85 * Every species factory adds its own field types as additional arguments,
86 * but these arguments always come first, in every factory method.
87 */
88 protected MethodType baseConstructorType() { return baseConstructorType; }
89
90 /** Return the trivial species for the null sequence of arguments. */
91 protected final S topSpecies() { return topSpecies; }
100 * Constructor for this class specializer.
101 * @param topClass type mirror for T
102 * @param keyType type mirror for K
103 * @param metaType type mirror for S
104 * @param baseConstructorType principal constructor type
105 * @param sdAccessor the method used to get the speciesData
106 * @param sdFieldName the name of the species data field, inject the speciesData object
107 * @param transformMethods optional list of transformMethods
108 */
109 protected ClassSpecializer(Class<T> topClass,
110 Class<K> keyType,
111 Class<S> metaType,
112 MethodType baseConstructorType,
113 MemberName sdAccessor,
114 String sdFieldName,
115 List<MemberName> transformMethods) {
116 this.topClass = topClass;
117 this.keyType = keyType;
118 this.metaType = metaType;
119 this.sdAccessor = sdAccessor;
120 this.transformMethods = List.copyOf(transformMethods);
121 this.sdFieldName = sdFieldName;
122 this.baseConstructorType = baseConstructorType.changeReturnType(void.class);
123 this.factory = makeFactory();
124 K tsk = topSpeciesKey();
125 S topSpecies = null;
126 if (tsk != null && topSpecies == null) {
127 // if there is a key, build the top species if needed:
128 topSpecies = findSpecies(tsk);
129 }
130 this.topSpecies = topSpecies;
131 }
132
133 // Utilities for subclass constructors:
134 protected static <T> Constructor<T> reflectConstructor(Class<T> defc, Class<?>... ptypes) {
135 try {
136 return defc.getDeclaredConstructor(ptypes);
137 } catch (NoSuchMethodException ex) {
138 throw newIAE(defc.getName()+"("+MethodType.methodType(void.class, ptypes)+")", ex);
139 }
140 }
141
142 protected static Field reflectField(Class<?> defc, String name) {
143 try {
144 return defc.getDeclaredField(name);
145 } catch (NoSuchFieldException ex) {
146 throw newIAE(defc.getName()+"."+name, ex);
147 }
148 }
149
150 private static RuntimeException newIAE(String message, Throwable cause) {
151 return new IllegalArgumentException(message, cause);
152 }
153
154 public final S findSpecies(K key) {
155 // Note: Species instantiation may throw VirtualMachineError because of
156 // code cache overflow. If this happens the species bytecode may be
157 // loaded but not linked to its species metadata (with MH's etc).
158 // That will cause a throw out of CHM.computeIfAbsent,
159 // which will shut down the caller thread.
160 //
161 // In a latter attempt to get the same species, the already-loaded
162 // class will be present in the system dictionary, causing an
163 // error when the species generator tries to reload it.
164 // We try to detect this case and link the pre-existing code.
165 //
166 // Although it would be better to start fresh by loading a new
167 // copy, we have to salvage the previously loaded but broken code.
168 // (As an alternative, we might spin a new class with a new name,
169 // or use the anonymous class mechanism.)
170 //
171 // In the end, as long as everybody goes through the same CHM,
172 // CHM.computeIfAbsent will ensure only one SpeciesData will be set
173 // successfully on a concrete class if ever.
174 // The concrete class is published via SpeciesData instance
175 // returned here only after the class and species data are linked together.
176 S speciesData = cache.computeIfAbsent(key, new Function<>() {
177 @Override
178 public S apply(K key1) {
179 return newSpeciesData(key1);
180 }
181 });
182 // Separating the creation of a placeholder SpeciesData instance above
183 // from the loading and linking a real one below ensures we can never
184 // accidentally call computeIfAbsent recursively. Replacing rather than
185 // updating the placeholder is done to ensure safe publication.
186 if (!speciesData.isResolved()) {
187 synchronized (speciesData) {
188 S existingSpeciesData = cache.get(key);
189 if (existingSpeciesData == speciesData) { // won the race
190 // create a new SpeciesData...
191 speciesData = newSpeciesData(key);
192 // load and link it...
193 speciesData = factory.loadSpecies(speciesData);
194 if (!cache.replace(key, existingSpeciesData, speciesData)) {
195 throw newInternalError("Concurrent loadSpecies");
196 }
197 } else { // lost the race; the retrieved existingSpeciesData is the final
198 speciesData = existingSpeciesData;
199 }
200 }
201 }
202 assert(speciesData != null && speciesData.isResolved());
203 return speciesData;
204 }
205
206 /**
207 * Meta-data wrapper for concrete subtypes of the top class.
208 * Each concrete subtype corresponds to a given sequence of basic field types (LIJFD).
209 * The fields are immutable; their values are fully specified at object construction.
210 * Each species supplies an array of getter functions which may be used in lambda forms.
211 * A concrete value is always constructed from the full tuple of its field values,
212 * accompanied by the required constructor parameters.
213 * There *may* also be transforms which cloning a species instance and
214 * either replace a constructor parameter or add one or more new field values.
215 * The shortest possible species has zero fields.
216 * Subtypes are not interrelated among themselves by subtyping, even though
217 * it would appear that a shorter species could serve as a supertype of a
218 * longer one which extends it.
219 */
220 public abstract class SpeciesData {
221 // Bootstrapping requires circular relations Class -> SpeciesData -> Class
222 // Therefore, we need non-final links in the chain. Use @Stable fields.
223 private final K key;
224 private final List<Class<?>> fieldTypes;
225 @Stable private Class<? extends T> speciesCode;
226 @Stable private List<MethodHandle> factories;
227 @Stable private List<MethodHandle> getters;
228 @Stable private List<LambdaForm.NamedFunction> nominalGetters;
229 @Stable private final MethodHandle[] transformHelpers = new MethodHandle[transformMethods.size()];
230
231 protected SpeciesData(K key) {
232 this.key = keyType.cast(Objects.requireNonNull(key));
233 List<Class<?>> types = deriveFieldTypes(key);
234 this.fieldTypes = List.copyOf(types);
235 }
236
237 public final K key() {
238 return key;
239 }
240
241 protected final List<Class<?>> fieldTypes() {
242 return fieldTypes;
243 }
244
245 protected final int fieldCount() {
246 return fieldTypes.size();
247 }
248
249 protected ClassSpecializer<T,K,S> outer() {
250 return ClassSpecializer.this;
251 }
252
253 protected final boolean isResolved() {
254 return speciesCode != null && factories != null && !factories.isEmpty();
462 */
463 S loadSpecies(S speciesData) {
464 String className = speciesData.deriveClassName();
465 assert(className.indexOf('/') < 0) : className;
466 Class<?> salvage = null;
467 try {
468 salvage = BootLoader.loadClassOrNull(className);
469 if (TRACE_RESOLVE && salvage != null) {
470 // Used by jlink species pregeneration plugin, see
471 // jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin
472 System.out.println("[SPECIES_RESOLVE] " + className + " (salvaged)");
473 }
474 } catch (Error ex) {
475 if (TRACE_RESOLVE) {
476 System.out.println("[SPECIES_FRESOLVE] " + className + " (Error) " + ex.getMessage());
477 }
478 }
479 final Class<? extends T> speciesCode;
480 if (salvage != null) {
481 speciesCode = salvage.asSubclass(topClass());
482 linkSpeciesDataToCode(speciesData, speciesCode);
483 linkCodeToSpeciesData(speciesCode, speciesData, true);
484 } else {
485 // Not pregenerated, generate the class
486 try {
487 speciesCode = generateConcreteSpeciesCode(className, speciesData);
488 if (TRACE_RESOLVE) {
489 // Used by jlink species pregeneration plugin, see
490 // jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin
491 System.out.println("[SPECIES_RESOLVE] " + className + " (generated)");
492 }
493 // This operation causes a lot of churn:
494 linkSpeciesDataToCode(speciesData, speciesCode);
495 // This operation commits the relation, but causes little churn:
496 linkCodeToSpeciesData(speciesCode, speciesData, false);
497 } catch (Error ex) {
498 if (TRACE_RESOLVE) {
499 System.out.println("[SPECIES_RESOLVE] " + className + " (Error #2)" );
500 }
501 // We can get here if there is a race condition loading a class.
502 // Or maybe we are out of resources. Back out of the CHM.get and retry.
503 throw ex;
504 }
505 }
506
507 if (!speciesData.isResolved()) {
508 throw newInternalError("bad species class linkage for " + className + ": " + speciesData);
509 }
510 assert(speciesData == loadSpeciesDataFromCode(speciesCode));
511 return speciesData;
512 }
513
514 /**
515 * Generate a concrete subclass of the top class for a given combination of bound types.
516 *
517 * A concrete species subclass roughly matches the following schema:
518 *
519 * <pre>
520 * class Species_[[types]] extends [[T]] {
521 * final [[S]] speciesData() { return ... }
522 * static [[T]] make([[fields]]) { return ... }
523 * [[fields]]
524 * final [[T]] transform([[args]]) { return ... }
525 * }
526 * </pre>
527 *
528 * The {@code [[types]]} signature is precisely the key for the species.
529 *
530 * The {@code [[fields]]} section consists of one field definition per character in
|