1
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
61
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, Object> cache = new ConcurrentHashMap<>();
72 private final Factory factory;
73 private @Stable boolean topClassIsSuper;
74
75
76 public final Class<T> topClass() { return topClass; }
77
78
79 public final Class<K> keyType() { return keyType; }
80
81
82 public final Class<S> metaType() { return metaType; }
83
84
88 protected MethodType baseConstructorType() { return baseConstructorType; }
89
90
91 protected final S topSpecies() { return topSpecies; }
92
93
94 protected final List<MemberName> transformMethods() { return transformMethods; }
95
96
97 protected final Factory factory() { return factory; }
98
99
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
128 topSpecies = findSpecies(tsk);
129 }
130 this.topSpecies = topSpecies;
131 }
132
133
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 private static final Function<Object, Object> CREATE_RESERVATION = new Function<>() {
155 @Override
156 public Object apply(Object key) {
157 return new Object();
158 }
159 };
160
161 public final S findSpecies(K key) {
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 Object speciesDataOrReservation = cache.computeIfAbsent(key, CREATE_RESERVATION);
183
184
185
186 S speciesData;
187 if (speciesDataOrReservation.getClass() == Object.class) {
188 synchronized (speciesDataOrReservation) {
189 Object existingSpeciesData = cache.get(key);
190 if (existingSpeciesData == speciesDataOrReservation) {
191
192 speciesData = newSpeciesData(key);
193
194 speciesData = factory.loadSpecies(speciesData);
195 if (!cache.replace(key, existingSpeciesData, speciesData)) {
196 throw newInternalError("Concurrent loadSpecies");
197 }
198 } else {
199 speciesData = metaType.cast(existingSpeciesData);
200 }
201 }
202 } else {
203 speciesData = metaType.cast(speciesDataOrReservation);
204 }
205 assert(speciesData != null && speciesData.isResolved());
206 return speciesData;
207 }
208
209
223 public abstract class SpeciesData {
224
225
226 private final K key;
227 private final List<Class<?>> fieldTypes;
228 @Stable private Class<? extends T> speciesCode;
229 @Stable private List<MethodHandle> factories;
230 @Stable private List<MethodHandle> getters;
231 @Stable private List<LambdaForm.NamedFunction> nominalGetters;
232 @Stable private final MethodHandle[] transformHelpers = new MethodHandle[transformMethods.size()];
233
234 protected SpeciesData(K key) {
235 this.key = keyType.cast(Objects.requireNonNull(key));
236 List<Class<?>> types = deriveFieldTypes(key);
237 this.fieldTypes = List.copyOf(types);
238 }
239
240 public final K key() {
241 return key;
242 }
243
244 protected final List<Class<?>> fieldTypes() {
245 return fieldTypes;
246 }
247
248 protected final int fieldCount() {
249 return fieldTypes.size();
250 }
251
252 protected ClassSpecializer<T,K,S> outer() {
253 return ClassSpecializer.this;
254 }
255
256 protected final boolean isResolved() {
257 return speciesCode != null && factories != null && !factories.isEmpty();
258 }
259
260 @Override public String toString() {
261 return metaType.getSimpleName() + "[" + key.toString() + " => " + (isResolved() ? speciesCode.getSimpleName() : "UNRESOLVED") + "]";
262 }
263
264 @Override
265 public int hashCode() {
266 return key.hashCode();
267 }
268
269 @Override
270 public boolean equals(Object obj) {
271 if (!(obj instanceof ClassSpecializer.SpeciesData)) {
272 return false;
273 }
274 @SuppressWarnings("rawtypes")
275 ClassSpecializer.SpeciesData that = (ClassSpecializer.SpeciesData) obj;
276 return this.outer() == that.outer() && this.key.equals(that.key);
277 }
278
279
280 protected final Class<? extends T> speciesCode() {
281 return Objects.requireNonNull(speciesCode);
282 }
283
284
289 protected MethodHandle getter(int i) {
290 return getters.get(i);
291 }
292
293
298 protected LambdaForm.NamedFunction getterFunction(int i) {
299 LambdaForm.NamedFunction nf = nominalGetters.get(i);
300 assert(nf.memberDeclaringClassOrNull() == speciesCode());
301 assert(nf.returnType() == BasicType.basicType(fieldTypes.get(i)));
302 return nf;
303 }
304
305 protected List<LambdaForm.NamedFunction> getterFunctions() {
306 return nominalGetters;
307 }
308
309 protected List<MethodHandle> getters() {
310 return getters;
311 }
312
313 protected MethodHandle factory() {
314 return factories.get(0);
315 }
316
317 protected MethodHandle transformHelper(int whichtm) {
318 MethodHandle mh = transformHelpers[whichtm];
319 if (mh != null) return mh;
320 mh = deriveTransformHelper(transformMethods().get(whichtm), whichtm);
321
322
323 final MethodType mt = transformHelperType(whichtm);
324 mh = mh.asType(mt);
325 return transformHelpers[whichtm] = mh;
326 }
327
328 private final MethodType transformHelperType(int whichtm) {
329 MemberName tm = transformMethods().get(whichtm);
330 ArrayList<Class<?>> args = new ArrayList<>();
331 ArrayList<Class<?>> fields = new ArrayList<>();
332 Collections.addAll(args, tm.getParameterTypes());
333 fields.addAll(fieldTypes());
334 List<Class<?>> helperArgs = deriveTransformHelperArguments(tm, whichtm, args, fields);
335 return MethodType.methodType(tm.getReturnType(), helperArgs);
336 }
337
338
339
340
344 protected abstract List<Class<?>> deriveFieldTypes(K key);
345
346
362 protected abstract MethodHandle deriveTransformHelper(MemberName transform, int whichtm);
363
364
381 protected abstract <X> List<X> deriveTransformHelperArguments(MemberName transform, int whichtm,
382 List<X> args, List<X> fields);
383
384
389 protected String deriveClassName() {
390 return outer().topClass().getName() + "$Species_" + deriveTypeString();
391 }
392
393
400 protected String deriveTypeString() {
401 List<Class<?>> types = fieldTypes();
402 StringBuilder buf = new StringBuilder();
403 StringBuilder end = new StringBuilder();
404 for (Class<?> type : types) {
405 BasicType basicType = BasicType.basicType(type);
406 if (basicType.basicTypeClass() == type) {
407 buf.append(basicType.basicTypeChar());
408 } else {
409 buf.append('V');
410 end.append(classSig(type));
411 }
412 }
413 String typeString;
414 if (end.length() > 0) {
415 typeString = BytecodeName.toBytecodeName(buf.append("_").append(end).toString());
416 } else {
417 typeString = buf.toString();
418 }
419 return LambdaForm.shortenSignature(typeString);
420 }
421
422
430 protected Class<? extends T> deriveSuperClass() {
431 final Class<T> topc = topClass();
432 if (!topClassIsSuper) {
433 try {
434 final Constructor<T> con = reflectConstructor(topc, baseConstructorType().parameterArray());
435 if (!topc.isInterface() && !Modifier.isPrivate(con.getModifiers())) {
436 topClassIsSuper = true;
437 }
438 } catch (Exception|InternalError ex) {
439
440 }
441 if (!topClassIsSuper) {
442 throw newInternalError("must override if the top class cannot serve as a super class");
443 }
444 }
445 return topc;
446 }
447 }
448
449 protected abstract S newSpeciesData(K key);
450
451 protected K topSpeciesKey() {
452 return null;
453 }
454
455
459 public class Factory {
460
466 S loadSpecies(S speciesData) {
467 String className = speciesData.deriveClassName();
468 assert(className.indexOf('/') < 0) : className;
469 Class<?> salvage = null;
470 try {
471 salvage = BootLoader.loadClassOrNull(className);
472 if (TRACE_RESOLVE && salvage != null) {
473
474
475 System.out.println("[SPECIES_RESOLVE] " + className + " (salvaged)");
476 }
477 } catch (Error ex) {
478 if (TRACE_RESOLVE) {
479 System.out.println("[SPECIES_FRESOLVE] " + className + " (Error) " + ex.getMessage());
480 }
481 }
482 final Class<? extends T> speciesCode;
483 if (salvage != null) {
484 speciesCode = salvage.asSubclass(topClass());
485 linkSpeciesDataToCode(speciesData, speciesCode);
486 linkCodeToSpeciesData(speciesCode, speciesData, true);
487 } else {
488
489 try {
490 speciesCode = generateConcreteSpeciesCode(className, speciesData);
491 if (TRACE_RESOLVE) {
492
493
494 System.out.println("[SPECIES_RESOLVE] " + className + " (generated)");
495 }
496
497 linkSpeciesDataToCode(speciesData, speciesCode);
498
499 linkCodeToSpeciesData(speciesCode, speciesData, false);
500 } catch (Error ex) {
501 if (TRACE_RESOLVE) {
502 System.out.println("[SPECIES_RESOLVE] " + className + " (Error #2)" );
503 }
504
505
506 throw ex;
507 }
508 }
509
510 if (!speciesData.isResolved()) {
511 throw newInternalError("bad species class linkage for " + className + ": " + speciesData);
512 }
513 assert(speciesData == loadSpeciesDataFromCode(speciesCode));
514 return speciesData;
515 }
516
517
574 Class<? extends T> generateConcreteSpeciesCode(String className, ClassSpecializer<T,K,S>.SpeciesData speciesData) {
575 byte[] classFile = generateConcreteSpeciesCodeFile(className, speciesData);
576
577
578 InvokerBytecodeGenerator.maybeDump(classBCName(className), classFile);
579 Class<?> speciesCode;
580
581 ClassLoader cl = topClass().getClassLoader();
582 ProtectionDomain pd = null;
583 if (cl != null) {
584 pd = AccessController.doPrivileged(
585 new PrivilegedAction<>() {
586 @Override
587 public ProtectionDomain run() {
588 return topClass().getProtectionDomain();
589 }
590 });
591 }
592 try {
593 speciesCode = UNSAFE.defineClass(className, classFile, 0, classFile.length, cl, pd);
594 } catch (Exception ex) {
595 throw newInternalError(ex);
596 }
597
598 return speciesCode.asSubclass(topClass());
599 }
600
601
602 private final String SPECIES_DATA = classBCName(metaType);
603 private final String SPECIES_DATA_SIG = classSig(SPECIES_DATA);
604 private final String SPECIES_DATA_NAME = sdAccessor.getName();
605 private final int SPECIES_DATA_MODS = sdAccessor.getModifiers();
606 private final List<String> TRANSFORM_NAMES;
607 private final List<MethodType> TRANSFORM_TYPES;
608 private final List<Integer> TRANSFORM_MODS;
609 {
610
611 List<String> tns = new ArrayList<>();
612 List<MethodType> tts = new ArrayList<>();
613 List<Integer> tms = new ArrayList<>();
614 for (int i = 0; i < transformMethods.size(); i++) {
615 MemberName tm = transformMethods.get(i);
616 tns.add(tm.getName());
617 final MethodType tt = tm.getMethodType();
618 tts.add(tt);
619 tms.add(tm.getModifiers());
620 }
621 TRANSFORM_NAMES = List.of(tns.toArray(new String[0]));
622 TRANSFORM_TYPES = List.of(tts.toArray(new MethodType[0]));
623 TRANSFORM_MODS = List.of(tms.toArray(new Integer[0]));
624 }
625 private static final int ACC_PPP = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED;
626
627 byte[] generateConcreteSpeciesCodeFile(String className0, ClassSpecializer<T,K,S>.SpeciesData speciesData) {
628 final String className = classBCName(className0);
629 final String superClassName = classBCName(speciesData.deriveSuperClass());
630
631 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
632 final int NOT_ACC_PUBLIC = 0;
633 cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, superClassName, null);
634
635 final String sourceFile = className.substring(className.lastIndexOf('.')+1);
636 cw.visitSource(sourceFile, null);
637
638
639 FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, sdFieldName, SPECIES_DATA_SIG, null, null);
640 fw.visitAnnotation(STABLE_SIG, true);
641 fw.visitEnd();
642
643
644 class Var {
645 final int index;
646 final String name;
647 final Class<?> type;
648 final String desc;
649 final BasicType basicType;
650 final int slotIndex;
651 Var(int index, int slotIndex) {
652 this.index = index;
653 this.slotIndex = slotIndex;
654 name = null; type = null; desc = null;
655 basicType = BasicType.V_TYPE;
656 }
657 Var(String name, Class<?> type, Var prev) {
658 int slotIndex = prev.nextSlotIndex();
659 int index = prev.nextIndex();
660 if (name == null) name = "x";
661 if (name.endsWith("#"))
662 name = name.substring(0, name.length()-1) + index;
663 assert(!type.equals(void.class));
664 String desc = classSig(type);
665 BasicType basicType = BasicType.basicType(type);
666 this.index = index;
667 this.name = name;
668 this.type = type;
669 this.desc = desc;
670 this.basicType = basicType;
671 this.slotIndex = slotIndex;
672 }
673 Var lastOf(List<Var> vars) {
674 int n = vars.size();
675 return (n == 0 ? this : vars.get(n-1));
676 }
677 <X> List<Var> fromTypes(List<X> types) {
678 Var prev = this;
679 ArrayList<Var> result = new ArrayList<>(types.size());
680 int i = 0;
681 for (X x : types) {
682 String vn = name;
683 Class<?> vt;
684 if (x instanceof Class) {
685 vt = (Class<?>) x;
686
687 assert((vn = vn + "_" + (i++)) != null);
688 } else {
689 @SuppressWarnings("unchecked")
690 Var v = (Var) x;
691 vn = v.name;
692 vt = v.type;
693 }
694 prev = new Var(vn, vt, prev);
695 result.add(prev);
696 }
697 return result;
698 }
699
700 int slotSize() { return basicType.basicTypeSlots(); }
701 int nextIndex() { return index + (slotSize() == 0 ? 0 : 1); }
702 int nextSlotIndex() { return slotIndex >= 0 ? slotIndex + slotSize() : slotIndex; }
703 boolean isInHeap() { return slotIndex < 0; }
704 void emitVarInstruction(int asmop, MethodVisitor mv) {
705 if (asmop == ALOAD)
706 asmop = typeLoadOp(basicType.basicTypeChar());
707 else
708 throw new AssertionError("bad op="+asmop+" for desc="+desc);
709 mv.visitVarInsn(asmop, slotIndex);
710 }
711 public void emitFieldInsn(int asmop, MethodVisitor mv) {
712 mv.visitFieldInsn(asmop, className, name, desc);
713 }
714 }
715
716 final Var NO_THIS = new Var(0, 0),
717 AFTER_THIS = new Var(0, 1),
718 IN_HEAP = new Var(0, -1);
719
720
721 final List<Class<?>> fieldTypes = speciesData.fieldTypes();
722 final List<Var> fields = new ArrayList<>(fieldTypes.size());
723 {
724 Var nextF = IN_HEAP;
725 for (Class<?> ft : fieldTypes) {
726 String fn = chooseFieldName(ft, nextF.nextIndex());
727 nextF = new Var(fn, ft, nextF);
728 fields.add(nextF);
729 }
730 }
731
732
733 for (Var field : fields) {
734 cw.visitField(ACC_FINAL, field.name, field.desc, null, null).visitEnd();
735 }
736
737 MethodVisitor mv;
738
739
740 mv = cw.visitMethod((SPECIES_DATA_MODS & ACC_PPP) + ACC_FINAL,
741 SPECIES_DATA_NAME, "()" + SPECIES_DATA_SIG, null, null);
742 mv.visitCode();
743 mv.visitFieldInsn(GETSTATIC, className, sdFieldName, SPECIES_DATA_SIG);
744 mv.visitInsn(ARETURN);
745 mv.visitMaxs(0, 0);
746 mv.visitEnd();
747
748
749 MethodType superCtorType = ClassSpecializer.this.baseConstructorType();
750 MethodType thisCtorType = superCtorType.appendParameterTypes(fieldTypes);
751
752
753 {
754 mv = cw.visitMethod(ACC_PRIVATE,
755 "<init>", methodSig(thisCtorType), null, null);
756 mv.visitCode();
757 mv.visitVarInsn(ALOAD, 0);
758
759 final List<Var> ctorArgs = AFTER_THIS.fromTypes(superCtorType.parameterList());
760 for (Var ca : ctorArgs) {
761 ca.emitVarInstruction(ALOAD, mv);
762 }
763
764
765 mv.visitMethodInsn(INVOKESPECIAL, superClassName,
766 "<init>", methodSig(superCtorType), false);
767
768
769 Var lastFV = AFTER_THIS.lastOf(ctorArgs);
770 for (Var f : fields) {
771
772 mv.visitVarInsn(ALOAD, 0);
773 lastFV = new Var(f.name, f.type, lastFV);
774 lastFV.emitVarInstruction(ALOAD, mv);
775 f.emitFieldInsn(PUTFIELD, mv);
776 }
777
778 mv.visitInsn(RETURN);
779 mv.visitMaxs(0, 0);
780 mv.visitEnd();
781 }
782
783
784 {
785 MethodType ftryType = thisCtorType.changeReturnType(topClass());
786 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC,
787 "make", methodSig(ftryType), null, null);
788 mv.visitCode();
789
790 mv.visitTypeInsn(NEW, className);
791 mv.visitInsn(DUP);
792
793 for (Var v : NO_THIS.fromTypes(ftryType.parameterList())) {
794 v.emitVarInstruction(ALOAD, mv);
795 }
796
797
798 mv.visitMethodInsn(INVOKESPECIAL, className,
799 "<init>", methodSig(thisCtorType), false);
800 mv.visitInsn(ARETURN);
801 mv.visitMaxs(0, 0);
802 mv.visitEnd();
803 }
804
805
806
807
808
809
810
811 for (int whichtm = 0; whichtm < TRANSFORM_NAMES.size(); whichtm++) {
812 final String TNAME = TRANSFORM_NAMES.get(whichtm);
813 final MethodType TTYPE = TRANSFORM_TYPES.get(whichtm);
814 final int TMODS = TRANSFORM_MODS.get(whichtm);
815 mv = cw.visitMethod((TMODS & ACC_PPP) | ACC_FINAL,
816 TNAME, TTYPE.toMethodDescriptorString(), null, E_THROWABLE);
817 mv.visitCode();
818
819
820 mv.visitFieldInsn(GETSTATIC, className,
821 sdFieldName, SPECIES_DATA_SIG);
822 emitIntConstant(whichtm, mv);
823 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA,
824 "transformHelper", "(I)" + MH_SIG, false);
825
826 List<Var> targs = AFTER_THIS.fromTypes(TTYPE.parameterList());
827 List<Var> tfields = new ArrayList<>(fields);
828
829 List<Var> helperArgs = speciesData.deriveTransformHelperArguments(transformMethods.get(whichtm), whichtm, targs, tfields);
830 List<Class<?>> helperTypes = new ArrayList<>(helperArgs.size());
831 for (Var ha : helperArgs) {
832 helperTypes.add(ha.basicType.basicTypeClass());
833 if (ha.isInHeap()) {
834 assert(tfields.contains(ha));
835 mv.visitVarInsn(ALOAD, 0);
836 ha.emitFieldInsn(GETFIELD, mv);
837 } else {
838 assert(targs.contains(ha));
839 ha.emitVarInstruction(ALOAD, mv);
840 }
841 }
842
843
844 final Class<?> rtype = TTYPE.returnType();
845 final BasicType rbt = BasicType.basicType(rtype);
846 MethodType invokeBasicType = MethodType.methodType(rbt.basicTypeClass(), helperTypes);
847 mv.visitMethodInsn(INVOKEVIRTUAL, MH,
848 "invokeBasic", methodSig(invokeBasicType), false);
849 if (rbt == BasicType.L_TYPE) {
850 mv.visitTypeInsn(CHECKCAST, classBCName(rtype));
851 mv.visitInsn(ARETURN);
852 } else {
853 throw newInternalError("NYI: transform of type "+rtype);
854 }
855 mv.visitMaxs(0, 0);
856 mv.visitEnd();
857 }
858
859 cw.visitEnd();
860
861 return cw.toByteArray();
862 }
863
864 private int typeLoadOp(char t) {
865 switch (t) {
866 case 'L': return ALOAD;
867 case 'I': return ILOAD;
868 case 'J': return LLOAD;
869 case 'F': return FLOAD;
870 case 'D': return DLOAD;
871 default : throw newInternalError("unrecognized type " + t);
872 }
873 }
874
875 private void emitIntConstant(int con, MethodVisitor mv) {
876 if (ICONST_M1 - ICONST_0 <= con && con <= ICONST_5 - ICONST_0)
877 mv.visitInsn(ICONST_0 + con);
878 else if (con == (byte) con)
879 mv.visitIntInsn(BIPUSH, con);
880 else if (con == (short) con)
881 mv.visitIntInsn(SIPUSH, con);
882 else {
883 mv.visitLdcInsn(con);
884 }
885
886 }
887
888
889
890
891
892 private MethodHandle findGetter(Class<?> speciesCode, List<Class<?>> types, int index) {
893 Class<?> fieldType = types.get(index);
894 String fieldName = chooseFieldName(fieldType, index);
895 try {
896 return IMPL_LOOKUP.findGetter(speciesCode, fieldName, fieldType);
897 } catch (NoSuchFieldException | IllegalAccessException e) {
898 throw newInternalError(e);
899 }
900 }
901
902 private List<MethodHandle> findGetters(Class<?> speciesCode, List<Class<?>> types) {
903 MethodHandle[] mhs = new MethodHandle[types.size()];
904 for (int i = 0; i < mhs.length; ++i) {
905 mhs[i] = findGetter(speciesCode, types, i);
906 assert(mhs[i].internalMemberName().getDeclaringClass() == speciesCode);
907 }
908 return List.of(mhs);
909 }
910
911 private List<MethodHandle> findFactories(Class<? extends T> speciesCode, List<Class<?>> types) {
912 MethodHandle[] mhs = new MethodHandle[1];
913 mhs[0] = findFactory(speciesCode, types);
914 return List.of(mhs);
915 }
916
917 List<LambdaForm.NamedFunction> makeNominalGetters(List<Class<?>> types, List<MethodHandle> getters) {
918 LambdaForm.NamedFunction[] nfs = new LambdaForm.NamedFunction[types.size()];
919 for (int i = 0; i < nfs.length; ++i) {
920 nfs[i] = new LambdaForm.NamedFunction(getters.get(i));
921 }
922 return List.of(nfs);
923 }
924
925
926
927
928
929 protected void linkSpeciesDataToCode(ClassSpecializer<T,K,S>.SpeciesData speciesData, Class<? extends T> speciesCode) {
930 speciesData.speciesCode = speciesCode.asSubclass(topClass);
931 final List<Class<?>> types = speciesData.fieldTypes;
932 speciesData.factories = this.findFactories(speciesCode, types);
933 speciesData.getters = this.findGetters(speciesCode, types);
934 speciesData.nominalGetters = this.makeNominalGetters(types, speciesData.getters);
935 }
936
937 private Field reflectSDField(Class<? extends T> speciesCode) {
938 final Field field = reflectField(speciesCode, sdFieldName);
939 assert(field.getType() == metaType);
940 assert(Modifier.isStatic(field.getModifiers()));
941 return field;
942 }
943
944 private S readSpeciesDataFromCode(Class<? extends T> speciesCode) {
945 try {
946 MemberName sdField = IMPL_LOOKUP.resolveOrFail(REF_getStatic, speciesCode, sdFieldName, metaType);
947 Object base = MethodHandleNatives.staticFieldBase(sdField);
948 long offset = MethodHandleNatives.staticFieldOffset(sdField);
949 UNSAFE.loadFence();
950 return metaType.cast(UNSAFE.getObject(base, offset));
951 } catch (Error err) {
952 throw err;
953 } catch (Exception ex) {
954 throw newInternalError("Failed to load speciesData from speciesCode: " + speciesCode.getName(), ex);
955 } catch (Throwable t) {
956 throw uncaughtException(t);
957 }
958 }
959
960 protected S loadSpeciesDataFromCode(Class<? extends T> speciesCode) {
961 if (speciesCode == topClass()) {
962 return topSpecies;
963 }
964 S result = readSpeciesDataFromCode(speciesCode);
965 if (result.outer() != ClassSpecializer.this) {
966 throw newInternalError("wrong class");
967 }
968 return result;
969 }
970
971 protected void linkCodeToSpeciesData(Class<? extends T> speciesCode, ClassSpecializer<T,K,S>.SpeciesData speciesData, boolean salvage) {
972 try {
973 assert(readSpeciesDataFromCode(speciesCode) == null ||
974 (salvage && readSpeciesDataFromCode(speciesCode).equals(speciesData)));
975
976 MemberName sdField = IMPL_LOOKUP.resolveOrFail(REF_putStatic, speciesCode, sdFieldName, metaType);
977 Object base = MethodHandleNatives.staticFieldBase(sdField);
978 long offset = MethodHandleNatives.staticFieldOffset(sdField);
979 UNSAFE.storeFence();
980 UNSAFE.putObject(base, offset, speciesData);
981 UNSAFE.storeFence();
982 } catch (Error err) {
983 throw err;
984 } catch (Exception ex) {
985 throw newInternalError("Failed to link speciesData to speciesCode: " + speciesCode.getName(), ex);
986 } catch (Throwable t) {
987 throw uncaughtException(t);
988 }
989 }
990
991
997 protected String chooseFieldName(Class<?> type, int index) {
998 BasicType bt = BasicType.basicType(type);
999 return "" + bt.basicTypeChar() + index;
1000 }
1001
1002 MethodHandle findFactory(Class<? extends T> speciesCode, List<Class<?>> types) {
1003 final MethodType type = baseConstructorType().changeReturnType(topClass()).appendParameterTypes(types);
1004 try {
1005 return IMPL_LOOKUP.findStatic(speciesCode, "make", type);
1006 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
1007 throw newInternalError(e);
1008 }
1009 }
1010 }
1011
1012
1013 protected Factory makeFactory() {
1014 return new Factory();
1015 }
1016
1017
1018
1019 private static final String MH = "java/lang/invoke/MethodHandle";
1020 private static final String MH_SIG = "L" + MH + ";";
1021 private static final String STABLE = "jdk/internal/vm/annotation/Stable";
1022 private static final String STABLE_SIG = "L" + STABLE + ";";
1023 private static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
1024 static {
1025 assert(MH_SIG.equals(classSig(MethodHandle.class)));
1026 assert(MH.equals(classBCName(MethodHandle.class)));
1027 }
1028
1029 static String methodSig(MethodType mt) {
1030 return mt.toMethodDescriptorString();
1031 }
1032 static String classSig(Class<?> cls) {
1033 if (cls.isPrimitive() || cls.isArray())
1034 return MethodType.methodType(cls).toMethodDescriptorString().substring(2);
1035 return classSig(classBCName(cls));
1036 }
1037 static String classSig(String bcName) {
1038 assert(bcName.indexOf('.') < 0);
1039 assert(!bcName.endsWith(";"));
1040 assert(!bcName.startsWith("["));
1041 return "L" + bcName + ";";
1042 }
1043 static String classBCName(Class<?> cls) {
1044 return classBCName(className(cls));
1045 }
1046 static String classBCName(String str) {
1047 assert(str.indexOf('/') < 0) : str;
1048 return str.replace('.', '/');
1049 }
1050 static String className(Class<?> cls) {
1051 assert(!cls.isArray() && !cls.isPrimitive());
1052 return cls.getName();
1053 }
1054 }
1055