1.1 --- a/rt/emul/compact/pom.xml Sun Aug 10 06:21:50 2014 +0200
1.2 +++ b/rt/emul/compact/pom.xml Sun Aug 10 07:02:12 2014 +0200
1.3 @@ -55,8 +55,8 @@
1.4 <compilerArguments>
1.5 <bootclasspath>netbeans.ignore.jdk.bootclasspath</bootclasspath>
1.6 </compilerArguments>
1.7 - <source>1.7</source>
1.8 - <target>1.7</target>
1.9 + <source>1.8</source>
1.10 + <target>1.8</target>
1.11 </configuration>
1.12 </plugin>
1.13 <plugin>
2.1 --- a/rt/emul/compact/src/main/java/java/lang/ClassValue.java Sun Aug 10 06:21:50 2014 +0200
2.2 +++ b/rt/emul/compact/src/main/java/java/lang/ClassValue.java Sun Aug 10 07:02:12 2014 +0200
2.3 @@ -186,7 +186,7 @@
2.4 /** Return the cache, if it exists, else a dummy empty cache. */
2.5 private static Entry<?>[] getCacheCarefully(Class<?> type) {
2.6 // racing type.classValueMap{.cacheArray} : null => new Entry[X] <=> new Entry[Y]
2.7 - ClassValueMap map = type.classValueMap;
2.8 + ClassValueMap map = (ClassValueMap) type.classValueMap;
2.9 if (map == null) return EMPTY_CACHE;
2.10 Entry<?>[] cache = map.getCache();
2.11 return cache;
2.12 @@ -364,7 +364,7 @@
2.13 // racing type.classValueMap : null (blank) => unique ClassValueMap
2.14 // if a null is observed, a map is created (lazily, synchronously, uniquely)
2.15 // all further access to that map is synchronized
2.16 - ClassValueMap map = type.classValueMap;
2.17 + ClassValueMap map = (ClassValueMap)type.classValueMap;
2.18 if (map != null) return map;
2.19 return initializeMap(type);
2.20 }
2.21 @@ -374,7 +374,7 @@
2.22 ClassValueMap map;
2.23 synchronized (CRITICAL_SECTION) { // private object to avoid deadlocks
2.24 // happens about once per type
2.25 - if ((map = type.classValueMap) == null)
2.26 + if ((map = (ClassValueMap)type.classValueMap) == null)
2.27 type.classValueMap = map = new ClassValueMap(type);
2.28 }
2.29 return map;
3.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/BoundMethodHandle.java Sun Aug 10 06:21:50 2014 +0200
3.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/BoundMethodHandle.java Sun Aug 10 07:02:12 2014 +0200
3.3 @@ -25,24 +25,16 @@
3.4
3.5 package java.lang.invoke;
3.6
3.7 -import static jdk.internal.org.objectweb.asm.Opcodes.*;
3.8 import static java.lang.invoke.LambdaForm.basicTypes;
3.9 -import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
3.10 import static java.lang.invoke.MethodHandleStatics.*;
3.11
3.12 import java.lang.invoke.LambdaForm.Name;
3.13 import java.lang.invoke.LambdaForm.NamedFunction;
3.14 import java.lang.invoke.MethodHandles.Lookup;
3.15 -import java.lang.reflect.Field;
3.16 import java.util.Arrays;
3.17 import java.util.HashMap;
3.18
3.19 import sun.invoke.util.ValueConversions;
3.20 -import sun.invoke.util.Wrapper;
3.21 -
3.22 -import jdk.internal.org.objectweb.asm.ClassWriter;
3.23 -import jdk.internal.org.objectweb.asm.MethodVisitor;
3.24 -import jdk.internal.org.objectweb.asm.Type;
3.25
3.26 /**
3.27 * The flavor of method handle which emulates an invoke instruction
3.28 @@ -373,8 +365,9 @@
3.29 this.constructor = new MethodHandle[1];
3.30 this.getters = new MethodHandle[types.length()];
3.31 } else {
3.32 - this.constructor = Factory.makeCtors(clazz, types, null);
3.33 - this.getters = Factory.makeGetters(clazz, types, null);
3.34 + throw new IllegalStateException("bound method handle");
3.35 +// this.constructor = Factory.makeCtors(clazz, types, null);
3.36 +// this.getters = Factory.makeGetters(clazz, types, null);
3.37 }
3.38 this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
3.39 }
3.40 @@ -382,8 +375,8 @@
3.41 private void initForBootstrap() {
3.42 assert(!INIT_DONE);
3.43 if (constructor[0] == null) {
3.44 - Factory.makeCtors(clazz, types, this.constructor);
3.45 - Factory.makeGetters(clazz, types, this.getters);
3.46 +// Factory.makeCtors(clazz, types, this.constructor);
3.47 +// Factory.makeGetters(clazz, types, this.getters);
3.48 }
3.49 }
3.50
3.51 @@ -425,7 +418,7 @@
3.52 // Use synch. on the placeholder to prevent multiple instantiation of one species.
3.53 // Creating this class forces a recursive call to getForClass.
3.54 if (lookupCache(types).isPlaceholder())
3.55 - Factory.generateConcreteBMHClass(types);
3.56 + throw new IllegalStateException("Cannot generate anything");
3.57 }
3.58 // Reacquire cache lock.
3.59 d = lookupCache(types);
3.60 @@ -459,6 +452,7 @@
3.61 SpeciesData d0 = BoundMethodHandle.SPECIES_DATA; // trigger class init
3.62 assert(d0 == null || d0 == lookupCache("")) : d0;
3.63 try {
3.64 + /*
3.65 for (Class<?> c : rootCls.getDeclaredClasses()) {
3.66 if (rootCls.isAssignableFrom(c)) {
3.67 final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
3.68 @@ -468,6 +462,7 @@
3.69 assert(d == lookupCache(d.types));
3.70 }
3.71 }
3.72 + */
3.73 } catch (Throwable e) {
3.74 throw newInternalError(e);
3.75 }
3.76 @@ -485,375 +480,7 @@
3.77 return SpeciesData.get(types);
3.78 }
3.79
3.80 - /**
3.81 - * Generation of concrete BMH classes.
3.82 - *
3.83 - * A concrete BMH species is fit for binding a number of values adhering to a
3.84 - * given type pattern. Reference types are erased.
3.85 - *
3.86 - * BMH species are cached by type pattern.
3.87 - *
3.88 - * A BMH species has a number of fields with the concrete (possibly erased) types of
3.89 - * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
3.90 - * which can be included as names in lambda forms.
3.91 - */
3.92 - static class Factory {
3.93
3.94 - static final String JLO_SIG = "Ljava/lang/Object;";
3.95 - static final String JLS_SIG = "Ljava/lang/String;";
3.96 - static final String JLC_SIG = "Ljava/lang/Class;";
3.97 - static final String MH = "java/lang/invoke/MethodHandle";
3.98 - static final String MH_SIG = "L"+MH+";";
3.99 - static final String BMH = "java/lang/invoke/BoundMethodHandle";
3.100 - static final String BMH_SIG = "L"+BMH+";";
3.101 - static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
3.102 - static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
3.103 -
3.104 - static final String SPECIES_PREFIX_NAME = "Species_";
3.105 - static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
3.106 -
3.107 - static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
3.108 - static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
3.109 - static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
3.110 - static final String VOID_SIG = "()V";
3.111 -
3.112 - static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
3.113 -
3.114 - static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
3.115 -
3.116 - static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
3.117 -
3.118 - /**
3.119 - * Generate a concrete subclass of BMH for a given combination of bound types.
3.120 - *
3.121 - * A concrete BMH species adheres to the following schema:
3.122 - *
3.123 - * <pre>
3.124 - * class Species_[[types]] extends BoundMethodHandle {
3.125 - * [[fields]]
3.126 - * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
3.127 - * }
3.128 - * </pre>
3.129 - *
3.130 - * The {@code [[types]]} signature is precisely the string that is passed to this
3.131 - * method.
3.132 - *
3.133 - * The {@code [[fields]]} section consists of one field definition per character in
3.134 - * the type signature, adhering to the naming schema described in the definition of
3.135 - * {@link #makeFieldName}.
3.136 - *
3.137 - * For example, a concrete BMH species for two reference and one integral bound values
3.138 - * would have the following shape:
3.139 - *
3.140 - * <pre>
3.141 - * class BoundMethodHandle { ... private static
3.142 - * final class Species_LLI extends BoundMethodHandle {
3.143 - * final Object argL0;
3.144 - * final Object argL1;
3.145 - * final int argI2;
3.146 - * public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
3.147 - * super(mt, lf);
3.148 - * this.argL0 = argL0;
3.149 - * this.argL1 = argL1;
3.150 - * this.argI2 = argI2;
3.151 - * }
3.152 - * public final SpeciesData speciesData() { return SPECIES_DATA; }
3.153 - * public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
3.154 - * public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
3.155 - * return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
3.156 - * }
3.157 - * public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
3.158 - * return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
3.159 - * }
3.160 - * public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
3.161 - * return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
3.162 - * }
3.163 - * public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
3.164 - * return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
3.165 - * }
3.166 - * public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
3.167 - * return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
3.168 - * }
3.169 - * public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
3.170 - * return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
3.171 - * }
3.172 - * }
3.173 - * </pre>
3.174 - *
3.175 - * @param types the type signature, wherein reference types are erased to 'L'
3.176 - * @return the generated concrete BMH class
3.177 - */
3.178 - static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
3.179 - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
3.180 -
3.181 - final String className = SPECIES_PREFIX_PATH + types;
3.182 - final String sourceFile = SPECIES_PREFIX_NAME + types;
3.183 - cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
3.184 - cw.visitSource(sourceFile, null);
3.185 -
3.186 - // emit static types and SPECIES_DATA fields
3.187 - cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
3.188 -
3.189 - // emit bound argument fields
3.190 - for (int i = 0; i < types.length(); ++i) {
3.191 - final char t = types.charAt(i);
3.192 - final String fieldName = makeFieldName(types, i);
3.193 - final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
3.194 - cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
3.195 - }
3.196 -
3.197 - MethodVisitor mv;
3.198 -
3.199 - // emit constructor
3.200 - mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
3.201 - mv.visitCode();
3.202 - mv.visitVarInsn(ALOAD, 0);
3.203 - mv.visitVarInsn(ALOAD, 1);
3.204 - mv.visitVarInsn(ALOAD, 2);
3.205 -
3.206 - mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
3.207 -
3.208 - for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
3.209 - // i counts the arguments, j counts corresponding argument slots
3.210 - char t = types.charAt(i);
3.211 - mv.visitVarInsn(ALOAD, 0);
3.212 - mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
3.213 - mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
3.214 - if (t == 'J' || t == 'D') {
3.215 - ++j; // adjust argument register access
3.216 - }
3.217 - }
3.218 -
3.219 - mv.visitInsn(RETURN);
3.220 - mv.visitMaxs(0, 0);
3.221 - mv.visitEnd();
3.222 -
3.223 - // emit implementation of reinvokerTarget()
3.224 - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
3.225 - mv.visitCode();
3.226 - mv.visitVarInsn(ALOAD, 0);
3.227 - mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG);
3.228 - mv.visitTypeInsn(CHECKCAST, MH);
3.229 - mv.visitInsn(ARETURN);
3.230 - mv.visitMaxs(0, 0);
3.231 - mv.visitEnd();
3.232 -
3.233 - // emit implementation of speciesData()
3.234 - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
3.235 - mv.visitCode();
3.236 - mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
3.237 - mv.visitInsn(ARETURN);
3.238 - mv.visitMaxs(0, 0);
3.239 - mv.visitEnd();
3.240 -
3.241 - // emit clone()
3.242 - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
3.243 - mv.visitCode();
3.244 - // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
3.245 - // obtain constructor
3.246 - mv.visitVarInsn(ALOAD, 0);
3.247 - mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
3.248 - mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
3.249 - mv.visitInsn(ICONST_0);
3.250 - mv.visitInsn(AALOAD);
3.251 - // load mt, lf
3.252 - mv.visitVarInsn(ALOAD, 1);
3.253 - mv.visitVarInsn(ALOAD, 2);
3.254 - // put fields on the stack
3.255 - emitPushFields(types, className, mv);
3.256 - // finally, invoke the constructor and return
3.257 - mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
3.258 - mv.visitInsn(ARETURN);
3.259 - mv.visitMaxs(0, 0);
3.260 - mv.visitEnd();
3.261 -
3.262 - // for each type, emit cloneExtendT()
3.263 - for (Class<?> c : TYPES) {
3.264 - char t = Wrapper.basicTypeChar(c);
3.265 - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
3.266 - mv.visitCode();
3.267 - // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
3.268 - // obtain constructor
3.269 - mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
3.270 - int iconstInsn = ICONST_0 + extensionIndex(t);
3.271 - assert(iconstInsn <= ICONST_5);
3.272 - mv.visitInsn(iconstInsn);
3.273 - mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG);
3.274 - mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
3.275 - mv.visitInsn(ICONST_0);
3.276 - mv.visitInsn(AALOAD);
3.277 - // load mt, lf
3.278 - mv.visitVarInsn(ALOAD, 1);
3.279 - mv.visitVarInsn(ALOAD, 2);
3.280 - // put fields on the stack
3.281 - emitPushFields(types, className, mv);
3.282 - // put narg on stack
3.283 - mv.visitVarInsn(typeLoadOp(t), 3);
3.284 - // finally, invoke the constructor and return
3.285 - mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false));
3.286 - mv.visitInsn(ARETURN);
3.287 - mv.visitMaxs(0, 0);
3.288 - mv.visitEnd();
3.289 - }
3.290 -
3.291 - // emit class initializer
3.292 - mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
3.293 - mv.visitCode();
3.294 - mv.visitLdcInsn(types);
3.295 - mv.visitLdcInsn(Type.getObjectType(className));
3.296 - mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG);
3.297 - mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
3.298 - mv.visitInsn(RETURN);
3.299 - mv.visitMaxs(0, 0);
3.300 - mv.visitEnd();
3.301 -
3.302 - cw.visitEnd();
3.303 -
3.304 - // load class
3.305 - final byte[] classFile = cw.toByteArray();
3.306 - InvokerBytecodeGenerator.maybeDump(className, classFile);
3.307 - Class<? extends BoundMethodHandle> bmhClass =
3.308 - //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
3.309 - UNSAFE.defineClass(className, classFile, 0, classFile.length,
3.310 - BoundMethodHandle.class.getClassLoader(), null)
3.311 - .asSubclass(BoundMethodHandle.class);
3.312 - UNSAFE.ensureClassInitialized(bmhClass);
3.313 -
3.314 - return bmhClass;
3.315 - }
3.316 -
3.317 - private static int typeLoadOp(char t) {
3.318 - switch (t) {
3.319 - case 'L': return ALOAD;
3.320 - case 'I': return ILOAD;
3.321 - case 'J': return LLOAD;
3.322 - case 'F': return FLOAD;
3.323 - case 'D': return DLOAD;
3.324 - default : throw new InternalError("unrecognized type " + t);
3.325 - }
3.326 - }
3.327 -
3.328 - private static void emitPushFields(String types, String className, MethodVisitor mv) {
3.329 - for (int i = 0; i < types.length(); ++i) {
3.330 - char tc = types.charAt(i);
3.331 - mv.visitVarInsn(ALOAD, 0);
3.332 - mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
3.333 - }
3.334 - }
3.335 -
3.336 - static String typeSig(char t) {
3.337 - return t == 'L' ? JLO_SIG : String.valueOf(t);
3.338 - }
3.339 -
3.340 - //
3.341 - // Getter MH generation.
3.342 - //
3.343 -
3.344 - private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
3.345 - String fieldName = makeFieldName(types, index);
3.346 - Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
3.347 - try {
3.348 - return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
3.349 - } catch (NoSuchFieldException | IllegalAccessException e) {
3.350 - throw newInternalError(e);
3.351 - }
3.352 - }
3.353 -
3.354 - static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
3.355 - if (mhs == null) mhs = new MethodHandle[types.length()];
3.356 - for (int i = 0; i < mhs.length; ++i) {
3.357 - mhs[i] = makeGetter(cbmhClass, types, i);
3.358 - assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
3.359 - }
3.360 - return mhs;
3.361 - }
3.362 -
3.363 - static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
3.364 - if (mhs == null) mhs = new MethodHandle[1];
3.365 - mhs[0] = makeCbmhCtor(cbmh, types);
3.366 - return mhs;
3.367 - }
3.368 -
3.369 - //
3.370 - // Auxiliary methods.
3.371 - //
3.372 -
3.373 - static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
3.374 - try {
3.375 - Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
3.376 - return (SpeciesData) F_SPECIES_DATA.get(null);
3.377 - } catch (ReflectiveOperationException ex) {
3.378 - throw newInternalError(ex);
3.379 - }
3.380 - }
3.381 -
3.382 - /**
3.383 - * Field names in concrete BMHs adhere to this pattern:
3.384 - * arg + type + index
3.385 - * where type is a single character (L, I, J, F, D).
3.386 - */
3.387 - private static String makeFieldName(String types, int index) {
3.388 - assert index >= 0 && index < types.length();
3.389 - return "arg" + types.charAt(index) + index;
3.390 - }
3.391 -
3.392 - private static String makeSignature(String types, boolean ctor) {
3.393 - StringBuilder buf = new StringBuilder(SIG_INCIPIT);
3.394 - for (char c : types.toCharArray()) {
3.395 - buf.append(typeSig(c));
3.396 - }
3.397 - return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
3.398 - }
3.399 -
3.400 - static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
3.401 - try {
3.402 - return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
3.403 - } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
3.404 - throw newInternalError(e);
3.405 - }
3.406 - }
3.407 -
3.408 - /**
3.409 - * Wrap a constructor call in a {@link LambdaForm}.
3.410 - *
3.411 - * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
3.412 - * are turned into bytecode, because the call to the allocator is routed through an MH, and the
3.413 - * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
3.414 - * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
3.415 - * {@link MethodHandle#linkToSpecial}.
3.416 - *
3.417 - * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
3.418 - * result of the {@code <init>} invocation. This entry is replaced.
3.419 - */
3.420 - private static MethodHandle linkConstructor(MethodHandle cmh) {
3.421 - final LambdaForm lf = cmh.form;
3.422 - final int initNameIndex = lf.names.length - 1;
3.423 - final Name initName = lf.names[initNameIndex];
3.424 - final MemberName ctorMN = initName.function.member;
3.425 - final MethodType ctorMT = ctorMN.getInvocationType();
3.426 -
3.427 - // obtain function member (call target)
3.428 - // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
3.429 - final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
3.430 - MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
3.431 - try {
3.432 - linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
3.433 - assert(linkerMN.isStatic());
3.434 - } catch (ReflectiveOperationException ex) {
3.435 - throw newInternalError(ex);
3.436 - }
3.437 - // extend arguments array
3.438 - Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
3.439 - newArgs[newArgs.length - 1] = ctorMN;
3.440 - // replace function
3.441 - final NamedFunction nf = new NamedFunction(linkerMN);
3.442 - final Name linkedCtor = new Name(nf, newArgs);
3.443 - linkedCtor.initIndex(initNameIndex);
3.444 - lf.names[initNameIndex] = linkedCtor;
3.445 - return cmh;
3.446 - }
3.447 -
3.448 - }
3.449
3.450 private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
3.451
4.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/DirectMethodHandle.java Sun Aug 10 06:21:50 2014 +0200
4.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/DirectMethodHandle.java Sun Aug 10 07:02:12 2014 +0200
4.3 @@ -25,7 +25,6 @@
4.4
4.5 package java.lang.invoke;
4.6
4.7 -import sun.misc.Unsafe;
4.8 import java.lang.reflect.Method;
4.9 import java.util.Arrays;
4.10 import sun.invoke.util.VerifyAccess;
4.11 @@ -326,19 +325,19 @@
4.12 VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
4.13 // It is a system class. It is probably in the process of
4.14 // being initialized, but we will help it along just to be safe.
4.15 - if (UNSAFE.shouldBeInitialized(cls)) {
4.16 - UNSAFE.ensureClassInitialized(cls);
4.17 + if (shouldBeInitialized(cls)) {
4.18 + ensureClassInitialized(cls);
4.19 }
4.20 return false;
4.21 }
4.22 - return UNSAFE.shouldBeInitialized(cls);
4.23 + return shouldBeInitialized(cls);
4.24 }
4.25
4.26 private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
4.27 @Override
4.28 protected WeakReference<Thread> computeValue(Class<?> type) {
4.29 - UNSAFE.ensureClassInitialized(type);
4.30 - if (UNSAFE.shouldBeInitialized(type))
4.31 + ensureClassInitialized(type);
4.32 + if (shouldBeInitialized(type))
4.33 // If the previous call didn't block, this can happen.
4.34 // We are executing inside <clinit>.
4.35 return new WeakReference<>(Thread.currentThread());
4.36 @@ -366,14 +365,14 @@
4.37 // Somebody may still be running defc.<clinit>.
4.38 if (clinitThread == Thread.currentThread()) {
4.39 // If anybody is running defc.<clinit>, it is this thread.
4.40 - if (UNSAFE.shouldBeInitialized(defc))
4.41 + if (shouldBeInitialized(defc))
4.42 // Yes, we are running it; keep the barrier for now.
4.43 return false;
4.44 } else {
4.45 // We are in a random thread. Block.
4.46 - UNSAFE.ensureClassInitialized(defc);
4.47 + ensureClassInitialized(defc);
4.48 }
4.49 - assert(!UNSAFE.shouldBeInitialized(defc));
4.50 + assert(!shouldBeInitialized(defc));
4.51 // put it into the final state
4.52 EnsureInitialized.INSTANCE.remove(defc);
4.53 return true;
4.54 @@ -423,7 +422,12 @@
4.55
4.56 /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
4.57 Constructor dmh = (Constructor)mh;
4.58 - return UNSAFE.allocateInstance(dmh.instanceClass);
4.59 + try {
4.60 + return dmh.instanceClass.newInstance();
4.61 +// return UNSAFE.allocateInstance(dmh.instanceClass);
4.62 + } catch (IllegalAccessException ex) {
4.63 + throw (InstantiationException)new InstantiationException().initCause(ex);
4.64 + }
4.65 }
4.66
4.67 /** This subclass handles non-static field references. */
4.68 @@ -603,7 +607,7 @@
4.69 linkerType = MethodType.methodType(ft, Object.class, long.class);
4.70 else
4.71 linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
4.72 - MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
4.73 + MemberName linker = null;//new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
4.74 try {
4.75 linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
4.76 } catch (ReflectiveOperationException ex) {
4.77 @@ -642,7 +646,7 @@
4.78 names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
4.79 Object[] outArgs = new Object[1 + linkerType.parameterCount()];
4.80 assert(outArgs.length == (isGetter ? 3 : 4));
4.81 - outArgs[0] = UNSAFE;
4.82 +// outArgs[0] = UNSAFE;
4.83 if (isStatic) {
4.84 outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
4.85 outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
4.86 @@ -707,7 +711,7 @@
4.87 };
4.88 for (NamedFunction nf : nfs) {
4.89 // Each nf must be statically invocable or we get tied up in our bootstraps.
4.90 - assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
4.91 +// assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
4.92 nf.resolve();
4.93 }
4.94 } catch (ReflectiveOperationException ex) {
4.95 @@ -715,4 +719,12 @@
4.96 }
4.97 }
4.98 }
4.99 +
4.100 + private static boolean shouldBeInitialized(Class<?> c) {
4.101 + return false;
4.102 + }
4.103 +
4.104 + private static void ensureClassInitialized(Class<?> c) {
4.105 + c.getName();
4.106 + }
4.107 }
5.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java Sun Aug 10 06:21:50 2014 +0200
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,551 +0,0 @@
5.4 -/*
5.5 - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
5.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5.7 - *
5.8 - * This code is free software; you can redistribute it and/or modify it
5.9 - * under the terms of the GNU General Public License version 2 only, as
5.10 - * published by the Free Software Foundation. Oracle designates this
5.11 - * particular file as subject to the "Classpath" exception as provided
5.12 - * by Oracle in the LICENSE file that accompanied this code.
5.13 - *
5.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
5.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5.17 - * version 2 for more details (a copy is included in the LICENSE file that
5.18 - * accompanied this code).
5.19 - *
5.20 - * You should have received a copy of the GNU General Public License version
5.21 - * 2 along with this work; if not, write to the Free Software Foundation,
5.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5.23 - *
5.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5.25 - * or visit www.oracle.com if you need additional information or have any
5.26 - * questions.
5.27 - */
5.28 -
5.29 -package java.lang.invoke;
5.30 -
5.31 -import jdk.internal.org.objectweb.asm.*;
5.32 -import sun.invoke.util.BytecodeDescriptor;
5.33 -import sun.misc.Unsafe;
5.34 -import sun.security.action.GetPropertyAction;
5.35 -
5.36 -import java.io.FilePermission;
5.37 -import java.io.Serializable;
5.38 -import java.lang.reflect.Constructor;
5.39 -import java.security.AccessController;
5.40 -import java.security.PrivilegedAction;
5.41 -import java.util.LinkedHashSet;
5.42 -import java.util.concurrent.atomic.AtomicInteger;
5.43 -import java.util.PropertyPermission;
5.44 -import java.util.Set;
5.45 -
5.46 -import static jdk.internal.org.objectweb.asm.Opcodes.*;
5.47 -
5.48 -/**
5.49 - * Lambda metafactory implementation which dynamically creates an
5.50 - * inner-class-like class per lambda callsite.
5.51 - *
5.52 - * @see LambdaMetafactory
5.53 - */
5.54 -/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
5.55 - private static final Unsafe UNSAFE = Unsafe.getUnsafe();
5.56 -
5.57 - private static final int CLASSFILE_VERSION = 52;
5.58 - private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
5.59 - private static final String JAVA_LANG_OBJECT = "java/lang/Object";
5.60 - private static final String NAME_CTOR = "<init>";
5.61 - private static final String NAME_FACTORY = "get$Lambda";
5.62 -
5.63 - //Serialization support
5.64 - private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
5.65 - private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
5.66 - private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
5.67 - private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
5.68 - private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
5.69 - private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
5.70 - private static final String NAME_METHOD_READ_OBJECT = "readObject";
5.71 - private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
5.72 - private static final String DESCR_CTOR_SERIALIZED_LAMBDA
5.73 - = MethodType.methodType(void.class,
5.74 - Class.class,
5.75 - String.class, String.class, String.class,
5.76 - int.class, String.class, String.class, String.class,
5.77 - String.class,
5.78 - Object[].class).toMethodDescriptorString();
5.79 - private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION
5.80 - = MethodType.methodType(void.class, String.class).toMethodDescriptorString();
5.81 - private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
5.82 -
5.83 -
5.84 - private static final String[] EMPTY_STRING_ARRAY = new String[0];
5.85 -
5.86 - // Used to ensure that each spun class name is unique
5.87 - private static final AtomicInteger counter = new AtomicInteger(0);
5.88 -
5.89 -
5.90 - // See context values in AbstractValidatingLambdaMetafactory
5.91 - private final String implMethodClassName; // Name of type containing implementation "CC"
5.92 - private final String implMethodName; // Name of implementation method "impl"
5.93 - private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;"
5.94 - private final Class<?> implMethodReturnClass; // class for implementaion method return type "Ljava/lang/String;"
5.95 - private final MethodType constructorType; // Generated class constructor type "(CC)void"
5.96 - private final ClassWriter cw; // ASM class writer
5.97 - private final String[] argNames; // Generated names for the constructor arguments
5.98 - private final String[] argDescs; // Type descriptors for the constructor arguments
5.99 - private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
5.100 -
5.101 - /**
5.102 - * General meta-factory constructor, supporting both standard cases and
5.103 - * allowing for uncommon options such as serialization or bridging.
5.104 - *
5.105 - * @param caller Stacked automatically by VM; represents a lookup context
5.106 - * with the accessibility privileges of the caller.
5.107 - * @param invokedType Stacked automatically by VM; the signature of the
5.108 - * invoked method, which includes the expected static
5.109 - * type of the returned lambda object, and the static
5.110 - * types of the captured arguments for the lambda. In
5.111 - * the event that the implementation method is an
5.112 - * instance method, the first argument in the invocation
5.113 - * signature will correspond to the receiver.
5.114 - * @param samMethodName Name of the method in the functional interface to
5.115 - * which the lambda or method reference is being
5.116 - * converted, represented as a String.
5.117 - * @param samMethodType Type of the method in the functional interface to
5.118 - * which the lambda or method reference is being
5.119 - * converted, represented as a MethodType.
5.120 - * @param implMethod The implementation method which should be called (with
5.121 - * suitable adaptation of argument types, return types,
5.122 - * and adjustment for captured arguments) when methods of
5.123 - * the resulting functional interface instance are invoked.
5.124 - * @param instantiatedMethodType The signature of the primary functional
5.125 - * interface method after type variables are
5.126 - * substituted with their instantiation from
5.127 - * the capture site
5.128 - * @param isSerializable Should the lambda be made serializable? If set,
5.129 - * either the target type or one of the additional SAM
5.130 - * types must extend {@code Serializable}.
5.131 - * @param markerInterfaces Additional interfaces which the lambda object
5.132 - * should implement.
5.133 - * @param additionalBridges Method types for additional signatures to be
5.134 - * bridged to the implementation method
5.135 - * @throws LambdaConversionException If any of the meta-factory protocol
5.136 - * invariants are violated
5.137 - */
5.138 - public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
5.139 - MethodType invokedType,
5.140 - String samMethodName,
5.141 - MethodType samMethodType,
5.142 - MethodHandle implMethod,
5.143 - MethodType instantiatedMethodType,
5.144 - boolean isSerializable,
5.145 - Class<?>[] markerInterfaces,
5.146 - MethodType[] additionalBridges)
5.147 - throws LambdaConversionException {
5.148 - super(caller, invokedType, samMethodName, samMethodType,
5.149 - implMethod, instantiatedMethodType,
5.150 - isSerializable, markerInterfaces, additionalBridges);
5.151 - implMethodClassName = implDefiningClass.getName().replace('.', '/');
5.152 - implMethodName = implInfo.getName();
5.153 - implMethodDesc = implMethodType.toMethodDescriptorString();
5.154 - implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
5.155 - ? implDefiningClass
5.156 - : implMethodType.returnType();
5.157 - constructorType = invokedType.changeReturnType(Void.TYPE);
5.158 - lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
5.159 - cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
5.160 - int parameterCount = invokedType.parameterCount();
5.161 - if (parameterCount > 0) {
5.162 - argNames = new String[parameterCount];
5.163 - argDescs = new String[parameterCount];
5.164 - for (int i = 0; i < parameterCount; i++) {
5.165 - argNames[i] = "arg$" + (i + 1);
5.166 - argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
5.167 - }
5.168 - } else {
5.169 - argNames = argDescs = EMPTY_STRING_ARRAY;
5.170 - }
5.171 - }
5.172 -
5.173 - /**
5.174 - * Build the CallSite. Generate a class file which implements the functional
5.175 - * interface, define the class, if there are no parameters create an instance
5.176 - * of the class which the CallSite will return, otherwise, generate handles
5.177 - * which will call the class' constructor.
5.178 - *
5.179 - * @return a CallSite, which, when invoked, will return an instance of the
5.180 - * functional interface
5.181 - * @throws ReflectiveOperationException
5.182 - * @throws LambdaConversionException If properly formed functional interface
5.183 - * is not found
5.184 - */
5.185 - @Override
5.186 - CallSite buildCallSite() throws LambdaConversionException {
5.187 - final Class<?> innerClass = spinInnerClass();
5.188 - if (invokedType.parameterCount() == 0) {
5.189 - final Constructor[] ctrs = AccessController.doPrivileged(
5.190 - new PrivilegedAction<Constructor[]>() {
5.191 - @Override
5.192 - public Constructor[] run() {
5.193 - Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
5.194 - if (ctrs.length == 1) {
5.195 - // The lambda implementing inner class constructor is private, set
5.196 - // it accessible (by us) before creating the constant sole instance
5.197 - ctrs[0].setAccessible(true);
5.198 - }
5.199 - return ctrs;
5.200 - }
5.201 - });
5.202 - if (ctrs.length != 1) {
5.203 - throw new LambdaConversionException("Expected one lambda constructor for "
5.204 - + innerClass.getCanonicalName() + ", got " + ctrs.length);
5.205 - }
5.206 -
5.207 - try {
5.208 - Object inst = ctrs[0].newInstance();
5.209 - return new ConstantCallSite(MethodHandles.constant(samBase, inst));
5.210 - }
5.211 - catch (ReflectiveOperationException e) {
5.212 - throw new LambdaConversionException("Exception instantiating lambda object", e);
5.213 - }
5.214 - } else {
5.215 - try {
5.216 - UNSAFE.ensureClassInitialized(innerClass);
5.217 - return new ConstantCallSite(
5.218 - MethodHandles.Lookup.IMPL_LOOKUP
5.219 - .findStatic(innerClass, NAME_FACTORY, invokedType));
5.220 - }
5.221 - catch (ReflectiveOperationException e) {
5.222 - throw new LambdaConversionException("Exception finding constructor", e);
5.223 - }
5.224 - }
5.225 - }
5.226 -
5.227 - /**
5.228 - * Generate a class file which implements the functional
5.229 - * interface, define and return the class.
5.230 - *
5.231 - * @implNote The class that is generated does not include signature
5.232 - * information for exceptions that may be present on the SAM method.
5.233 - * This is to reduce classfile size, and is harmless as checked exceptions
5.234 - * are erased anyway, no one will ever compile against this classfile,
5.235 - * and we make no guarantees about the reflective properties of lambda
5.236 - * objects.
5.237 - *
5.238 - * @return a Class which implements the functional interface
5.239 - * @throws LambdaConversionException If properly formed functional interface
5.240 - * is not found
5.241 - */
5.242 - private Class<?> spinInnerClass() throws LambdaConversionException {
5.243 - String[] interfaces;
5.244 - String samIntf = samBase.getName().replace('.', '/');
5.245 - boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
5.246 - if (markerInterfaces.length == 0) {
5.247 - interfaces = new String[]{samIntf};
5.248 - } else {
5.249 - // Assure no duplicate interfaces (ClassFormatError)
5.250 - Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
5.251 - itfs.add(samIntf);
5.252 - for (Class<?> markerInterface : markerInterfaces) {
5.253 - itfs.add(markerInterface.getName().replace('.', '/'));
5.254 - accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
5.255 - }
5.256 - interfaces = itfs.toArray(new String[itfs.size()]);
5.257 - }
5.258 -
5.259 - cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
5.260 - lambdaClassName, null,
5.261 - JAVA_LANG_OBJECT, interfaces);
5.262 -
5.263 - // Generate final fields to be filled in by constructor
5.264 - for (int i = 0; i < argDescs.length; i++) {
5.265 - FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
5.266 - argNames[i],
5.267 - argDescs[i],
5.268 - null, null);
5.269 - fv.visitEnd();
5.270 - }
5.271 -
5.272 - generateConstructor();
5.273 -
5.274 - if (invokedType.parameterCount() != 0) {
5.275 - generateFactory();
5.276 - }
5.277 -
5.278 - // Forward the SAM method
5.279 - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
5.280 - samMethodType.toMethodDescriptorString(), null, null);
5.281 - new ForwardingMethodGenerator(mv).generate(samMethodType);
5.282 -
5.283 - // Forward the bridges
5.284 - if (additionalBridges != null) {
5.285 - for (MethodType mt : additionalBridges) {
5.286 - mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
5.287 - mt.toMethodDescriptorString(), null, null);
5.288 - new ForwardingMethodGenerator(mv).generate(mt);
5.289 - }
5.290 - }
5.291 -
5.292 - if (isSerializable)
5.293 - generateSerializationFriendlyMethods();
5.294 - else if (accidentallySerializable)
5.295 - generateSerializationHostileMethods();
5.296 -
5.297 - cw.visitEnd();
5.298 -
5.299 - // Define the generated class in this VM.
5.300 -
5.301 - final byte[] classBytes = cw.toByteArray();
5.302 -
5.303 - // If requested, dump out to a file for debugging purposes
5.304 - if (dumper != null) {
5.305 - AccessController.doPrivileged(new PrivilegedAction<Void>() {
5.306 - @Override
5.307 - public Void run() {
5.308 - dumper.dumpClass(lambdaClassName, classBytes);
5.309 - return null;
5.310 - }
5.311 - }, null,
5.312 - new FilePermission("<<ALL FILES>>", "read, write"),
5.313 - // createDirectories may need it
5.314 - new PropertyPermission("user.dir", "read"));
5.315 - }
5.316 -
5.317 - return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
5.318 - }
5.319 -
5.320 - /**
5.321 - * Generate the factory method for the class
5.322 - */
5.323 - private void generateFactory() {
5.324 - MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
5.325 - m.visitCode();
5.326 - m.visitTypeInsn(NEW, lambdaClassName);
5.327 - m.visitInsn(Opcodes.DUP);
5.328 - int parameterCount = invokedType.parameterCount();
5.329 - for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
5.330 - Class<?> argType = invokedType.parameterType(typeIndex);
5.331 - m.visitVarInsn(getLoadOpcode(argType), varIndex);
5.332 - varIndex += getParameterSize(argType);
5.333 - }
5.334 - m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString());
5.335 - m.visitInsn(ARETURN);
5.336 - m.visitMaxs(-1, -1);
5.337 - m.visitEnd();
5.338 - }
5.339 -
5.340 - /**
5.341 - * Generate the constructor for the class
5.342 - */
5.343 - private void generateConstructor() {
5.344 - // Generate constructor
5.345 - MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
5.346 - constructorType.toMethodDescriptorString(), null, null);
5.347 - ctor.visitCode();
5.348 - ctor.visitVarInsn(ALOAD, 0);
5.349 - ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
5.350 - METHOD_DESCRIPTOR_VOID);
5.351 - int parameterCount = invokedType.parameterCount();
5.352 - for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
5.353 - ctor.visitVarInsn(ALOAD, 0);
5.354 - Class<?> argType = invokedType.parameterType(i);
5.355 - ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
5.356 - lvIndex += getParameterSize(argType);
5.357 - ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
5.358 - }
5.359 - ctor.visitInsn(RETURN);
5.360 - // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
5.361 - ctor.visitMaxs(-1, -1);
5.362 - ctor.visitEnd();
5.363 - }
5.364 -
5.365 - /**
5.366 - * Generate a writeReplace method that supports serialization
5.367 - */
5.368 - private void generateSerializationFriendlyMethods() {
5.369 - TypeConvertingMethodAdapter mv
5.370 - = new TypeConvertingMethodAdapter(
5.371 - cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
5.372 - NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
5.373 - null, null));
5.374 -
5.375 - mv.visitCode();
5.376 - mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
5.377 - mv.visitInsn(DUP);
5.378 - mv.visitLdcInsn(Type.getType(targetClass));
5.379 - mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
5.380 - mv.visitLdcInsn(samMethodName);
5.381 - mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
5.382 - mv.visitLdcInsn(implInfo.getReferenceKind());
5.383 - mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
5.384 - mv.visitLdcInsn(implInfo.getName());
5.385 - mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
5.386 - mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
5.387 - mv.iconst(argDescs.length);
5.388 - mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
5.389 - for (int i = 0; i < argDescs.length; i++) {
5.390 - mv.visitInsn(DUP);
5.391 - mv.iconst(i);
5.392 - mv.visitVarInsn(ALOAD, 0);
5.393 - mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
5.394 - mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
5.395 - mv.visitInsn(AASTORE);
5.396 - }
5.397 - mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
5.398 - DESCR_CTOR_SERIALIZED_LAMBDA);
5.399 - mv.visitInsn(ARETURN);
5.400 - // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
5.401 - mv.visitMaxs(-1, -1);
5.402 - mv.visitEnd();
5.403 - }
5.404 -
5.405 - /**
5.406 - * Generate a readObject/writeObject method that is hostile to serialization
5.407 - */
5.408 - private void generateSerializationHostileMethods() {
5.409 - MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
5.410 - NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
5.411 - null, SER_HOSTILE_EXCEPTIONS);
5.412 - mv.visitCode();
5.413 - mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
5.414 - mv.visitInsn(DUP);
5.415 - mv.visitLdcInsn("Non-serializable lambda");
5.416 - mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
5.417 - DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
5.418 - mv.visitInsn(ATHROW);
5.419 - mv.visitMaxs(-1, -1);
5.420 - mv.visitEnd();
5.421 -
5.422 - mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
5.423 - NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
5.424 - null, SER_HOSTILE_EXCEPTIONS);
5.425 - mv.visitCode();
5.426 - mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
5.427 - mv.visitInsn(DUP);
5.428 - mv.visitLdcInsn("Non-serializable lambda");
5.429 - mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
5.430 - DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
5.431 - mv.visitInsn(ATHROW);
5.432 - mv.visitMaxs(-1, -1);
5.433 - mv.visitEnd();
5.434 - }
5.435 -
5.436 - /**
5.437 - * This class generates a method body which calls the lambda implementation
5.438 - * method, converting arguments, as needed.
5.439 - */
5.440 - private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
5.441 -
5.442 - ForwardingMethodGenerator(MethodVisitor mv) {
5.443 - super(mv);
5.444 - }
5.445 -
5.446 - void generate(MethodType methodType) {
5.447 - visitCode();
5.448 -
5.449 - if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
5.450 - visitTypeInsn(NEW, implMethodClassName);
5.451 - visitInsn(DUP);
5.452 - }
5.453 - for (int i = 0; i < argNames.length; i++) {
5.454 - visitVarInsn(ALOAD, 0);
5.455 - visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
5.456 - }
5.457 -
5.458 - convertArgumentTypes(methodType);
5.459 -
5.460 - // Invoke the method we want to forward to
5.461 - visitMethodInsn(invocationOpcode(), implMethodClassName,
5.462 - implMethodName, implMethodDesc,
5.463 - implDefiningClass.isInterface());
5.464 -
5.465 - // Convert the return value (if any) and return it
5.466 - // Note: if adapting from non-void to void, the 'return'
5.467 - // instruction will pop the unneeded result
5.468 - Class<?> samReturnClass = methodType.returnType();
5.469 - convertType(implMethodReturnClass, samReturnClass, samReturnClass);
5.470 - visitInsn(getReturnOpcode(samReturnClass));
5.471 - // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
5.472 - visitMaxs(-1, -1);
5.473 - visitEnd();
5.474 - }
5.475 -
5.476 - private void convertArgumentTypes(MethodType samType) {
5.477 - int lvIndex = 0;
5.478 - boolean samIncludesReceiver = implIsInstanceMethod &&
5.479 - invokedType.parameterCount() == 0;
5.480 - int samReceiverLength = samIncludesReceiver ? 1 : 0;
5.481 - if (samIncludesReceiver) {
5.482 - // push receiver
5.483 - Class<?> rcvrType = samType.parameterType(0);
5.484 - visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
5.485 - lvIndex += getParameterSize(rcvrType);
5.486 - convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
5.487 - }
5.488 - int samParametersLength = samType.parameterCount();
5.489 - int argOffset = implMethodType.parameterCount() - samParametersLength;
5.490 - for (int i = samReceiverLength; i < samParametersLength; i++) {
5.491 - Class<?> argType = samType.parameterType(i);
5.492 - visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
5.493 - lvIndex += getParameterSize(argType);
5.494 - convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
5.495 - }
5.496 - }
5.497 -
5.498 - private int invocationOpcode() throws InternalError {
5.499 - switch (implKind) {
5.500 - case MethodHandleInfo.REF_invokeStatic:
5.501 - return INVOKESTATIC;
5.502 - case MethodHandleInfo.REF_newInvokeSpecial:
5.503 - return INVOKESPECIAL;
5.504 - case MethodHandleInfo.REF_invokeVirtual:
5.505 - return INVOKEVIRTUAL;
5.506 - case MethodHandleInfo.REF_invokeInterface:
5.507 - return INVOKEINTERFACE;
5.508 - case MethodHandleInfo.REF_invokeSpecial:
5.509 - return INVOKESPECIAL;
5.510 - default:
5.511 - throw new InternalError("Unexpected invocation kind: " + implKind);
5.512 - }
5.513 - }
5.514 - }
5.515 -
5.516 - static int getParameterSize(Class<?> c) {
5.517 - if (c == Void.TYPE) {
5.518 - return 0;
5.519 - } else if (c == Long.TYPE || c == Double.TYPE) {
5.520 - return 2;
5.521 - }
5.522 - return 1;
5.523 - }
5.524 -
5.525 - static int getLoadOpcode(Class<?> c) {
5.526 - if(c == Void.TYPE) {
5.527 - throw new InternalError("Unexpected void type of load opcode");
5.528 - }
5.529 - return ILOAD + getOpcodeOffset(c);
5.530 - }
5.531 -
5.532 - static int getReturnOpcode(Class<?> c) {
5.533 - if(c == Void.TYPE) {
5.534 - return RETURN;
5.535 - }
5.536 - return IRETURN + getOpcodeOffset(c);
5.537 - }
5.538 -
5.539 - private static int getOpcodeOffset(Class<?> c) {
5.540 - if (c.isPrimitive()) {
5.541 - if (c == Long.TYPE) {
5.542 - return 1;
5.543 - } else if (c == Float.TYPE) {
5.544 - return 2;
5.545 - } else if (c == Double.TYPE) {
5.546 - return 3;
5.547 - }
5.548 - return 0;
5.549 - } else {
5.550 - return 4;
5.551 - }
5.552 - }
5.553 -
5.554 -}
6.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/InvokerBytecodeGenerator.java Sun Aug 10 06:21:50 2014 +0200
6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
6.3 @@ -1,1052 +0,0 @@
6.4 -/*
6.5 - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
6.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6.7 - *
6.8 - * This code is free software; you can redistribute it and/or modify it
6.9 - * under the terms of the GNU General Public License version 2 only, as
6.10 - * published by the Free Software Foundation. Oracle designates this
6.11 - * particular file as subject to the "Classpath" exception as provided
6.12 - * by Oracle in the LICENSE file that accompanied this code.
6.13 - *
6.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
6.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6.17 - * version 2 for more details (a copy is included in the LICENSE file that
6.18 - * accompanied this code).
6.19 - *
6.20 - * You should have received a copy of the GNU General Public License version
6.21 - * 2 along with this work; if not, write to the Free Software Foundation,
6.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
6.23 - *
6.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
6.25 - * or visit www.oracle.com if you need additional information or have any
6.26 - * questions.
6.27 - */
6.28 -
6.29 -package java.lang.invoke;
6.30 -
6.31 -import sun.invoke.util.VerifyAccess;
6.32 -import java.lang.invoke.LambdaForm.Name;
6.33 -import java.lang.invoke.MethodHandles.Lookup;
6.34 -
6.35 -import sun.invoke.util.Wrapper;
6.36 -
6.37 -import java.io.*;
6.38 -import java.util.*;
6.39 -
6.40 -import jdk.internal.org.objectweb.asm.*;
6.41 -
6.42 -import java.lang.reflect.*;
6.43 -import static java.lang.invoke.MethodHandleStatics.*;
6.44 -import static java.lang.invoke.MethodHandleNatives.Constants.*;
6.45 -import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
6.46 -import sun.invoke.util.ValueConversions;
6.47 -import sun.invoke.util.VerifyType;
6.48 -
6.49 -/**
6.50 - * Code generation backend for LambdaForm.
6.51 - * <p>
6.52 - * @author John Rose, JSR 292 EG
6.53 - */
6.54 -class InvokerBytecodeGenerator {
6.55 - /** Define class names for convenience. */
6.56 - private static final String MH = "java/lang/invoke/MethodHandle";
6.57 - private static final String BMH = "java/lang/invoke/BoundMethodHandle";
6.58 - private static final String LF = "java/lang/invoke/LambdaForm";
6.59 - private static final String LFN = "java/lang/invoke/LambdaForm$Name";
6.60 - private static final String CLS = "java/lang/Class";
6.61 - private static final String OBJ = "java/lang/Object";
6.62 - private static final String OBJARY = "[Ljava/lang/Object;";
6.63 -
6.64 - private static final String LF_SIG = "L" + LF + ";";
6.65 - private static final String LFN_SIG = "L" + LFN + ";";
6.66 - private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
6.67 -
6.68 - /** Name of its super class*/
6.69 - private static final String superName = LF;
6.70 -
6.71 - /** Name of new class */
6.72 - private final String className;
6.73 -
6.74 - /** Name of the source file (for stack trace printing). */
6.75 - private final String sourceFile;
6.76 -
6.77 - private final LambdaForm lambdaForm;
6.78 - private final String invokerName;
6.79 - private final MethodType invokerType;
6.80 - private final int[] localsMap;
6.81 -
6.82 - /** ASM bytecode generation. */
6.83 - private ClassWriter cw;
6.84 - private MethodVisitor mv;
6.85 -
6.86 - private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
6.87 - private static final Class<?> HOST_CLASS = LambdaForm.class;
6.88 -
6.89 - private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
6.90 - String className, String invokerName, MethodType invokerType) {
6.91 - if (invokerName.contains(".")) {
6.92 - int p = invokerName.indexOf(".");
6.93 - className = invokerName.substring(0, p);
6.94 - invokerName = invokerName.substring(p+1);
6.95 - }
6.96 - if (DUMP_CLASS_FILES) {
6.97 - className = makeDumpableClassName(className);
6.98 - }
6.99 - this.className = superName + "$" + className;
6.100 - this.sourceFile = "LambdaForm$" + className;
6.101 - this.lambdaForm = lambdaForm;
6.102 - this.invokerName = invokerName;
6.103 - this.invokerType = invokerType;
6.104 - this.localsMap = new int[localsMapSize];
6.105 - }
6.106 -
6.107 - private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
6.108 - this(null, invokerType.parameterCount(),
6.109 - className, invokerName, invokerType);
6.110 - // Create an array to map name indexes to locals indexes.
6.111 - for (int i = 0; i < localsMap.length; i++) {
6.112 - localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
6.113 - }
6.114 - }
6.115 -
6.116 - private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
6.117 - this(form, form.names.length,
6.118 - className, form.debugName, invokerType);
6.119 - // Create an array to map name indexes to locals indexes.
6.120 - Name[] names = form.names;
6.121 - for (int i = 0, index = 0; i < localsMap.length; i++) {
6.122 - localsMap[i] = index;
6.123 - index += Wrapper.forBasicType(names[i].type).stackSlots();
6.124 - }
6.125 - }
6.126 -
6.127 -
6.128 - /** instance counters for dumped classes */
6.129 - private final static HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
6.130 - /** debugging flag for saving generated class files */
6.131 - private final static File DUMP_CLASS_FILES_DIR;
6.132 -
6.133 - static {
6.134 - if (DUMP_CLASS_FILES) {
6.135 - DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
6.136 - try {
6.137 - File dumpDir = new File("DUMP_CLASS_FILES");
6.138 - if (!dumpDir.exists()) {
6.139 - dumpDir.mkdirs();
6.140 - }
6.141 - DUMP_CLASS_FILES_DIR = dumpDir;
6.142 - System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
6.143 - } catch (Exception e) {
6.144 - throw newInternalError(e);
6.145 - }
6.146 - } else {
6.147 - DUMP_CLASS_FILES_COUNTERS = null;
6.148 - DUMP_CLASS_FILES_DIR = null;
6.149 - }
6.150 - }
6.151 -
6.152 - static void maybeDump(final String className, final byte[] classFile) {
6.153 - if (DUMP_CLASS_FILES) {
6.154 - System.out.println("dump: " + className);
6.155 - java.security.AccessController.doPrivileged(
6.156 - new java.security.PrivilegedAction<Void>() {
6.157 - public Void run() {
6.158 - try {
6.159 - String dumpName = className;
6.160 - //dumpName = dumpName.replace('/', '-');
6.161 - File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
6.162 - dumpFile.getParentFile().mkdirs();
6.163 - FileOutputStream file = new FileOutputStream(dumpFile);
6.164 - file.write(classFile);
6.165 - file.close();
6.166 - return null;
6.167 - } catch (IOException ex) {
6.168 - throw newInternalError(ex);
6.169 - }
6.170 - }
6.171 - });
6.172 - }
6.173 -
6.174 - }
6.175 -
6.176 - private static String makeDumpableClassName(String className) {
6.177 - Integer ctr;
6.178 - synchronized (DUMP_CLASS_FILES_COUNTERS) {
6.179 - ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
6.180 - if (ctr == null) ctr = 0;
6.181 - DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
6.182 - }
6.183 - String sfx = ctr.toString();
6.184 - while (sfx.length() < 3)
6.185 - sfx = "0"+sfx;
6.186 - className += sfx;
6.187 - return className;
6.188 - }
6.189 -
6.190 - class CpPatch {
6.191 - final int index;
6.192 - final String placeholder;
6.193 - final Object value;
6.194 - CpPatch(int index, String placeholder, Object value) {
6.195 - this.index = index;
6.196 - this.placeholder = placeholder;
6.197 - this.value = value;
6.198 - }
6.199 - public String toString() {
6.200 - return "CpPatch/index="+index+",placeholder="+placeholder+",value="+value;
6.201 - }
6.202 - }
6.203 -
6.204 - Map<Object, CpPatch> cpPatches = new HashMap<>();
6.205 -
6.206 - int cph = 0; // for counting constant placeholders
6.207 -
6.208 - String constantPlaceholder(Object arg) {
6.209 - String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
6.210 - if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + arg.toString() + ">>"; // debugging aid
6.211 - if (cpPatches.containsKey(cpPlaceholder)) {
6.212 - throw new InternalError("observed CP placeholder twice: " + cpPlaceholder);
6.213 - }
6.214 - // insert placeholder in CP and remember the patch
6.215 - int index = cw.newConst((Object) cpPlaceholder); // TODO check if aready in the constant pool
6.216 - cpPatches.put(cpPlaceholder, new CpPatch(index, cpPlaceholder, arg));
6.217 - return cpPlaceholder;
6.218 - }
6.219 -
6.220 - Object[] cpPatches(byte[] classFile) {
6.221 - int size = getConstantPoolSize(classFile);
6.222 - Object[] res = new Object[size];
6.223 - for (CpPatch p : cpPatches.values()) {
6.224 - if (p.index >= size)
6.225 - throw new InternalError("in cpool["+size+"]: "+p+"\n"+Arrays.toString(Arrays.copyOf(classFile, 20)));
6.226 - res[p.index] = p.value;
6.227 - }
6.228 - return res;
6.229 - }
6.230 -
6.231 - /**
6.232 - * Extract the number of constant pool entries from a given class file.
6.233 - *
6.234 - * @param classFile the bytes of the class file in question.
6.235 - * @return the number of entries in the constant pool.
6.236 - */
6.237 - private static int getConstantPoolSize(byte[] classFile) {
6.238 - // The first few bytes:
6.239 - // u4 magic;
6.240 - // u2 minor_version;
6.241 - // u2 major_version;
6.242 - // u2 constant_pool_count;
6.243 - return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
6.244 - }
6.245 -
6.246 - /**
6.247 - * Extract the MemberName of a newly-defined method.
6.248 - */
6.249 - private MemberName loadMethod(byte[] classFile) {
6.250 - Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
6.251 - return resolveInvokerMember(invokerClass, invokerName, invokerType);
6.252 - }
6.253 -
6.254 - /**
6.255 - * Define a given class as anonymous class in the runtime system.
6.256 - */
6.257 - private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
6.258 - Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
6.259 - UNSAFE.ensureClassInitialized(invokerClass); // Make sure the class is initialized; VM might complain.
6.260 - return invokerClass;
6.261 - }
6.262 -
6.263 - private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
6.264 - MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
6.265 - //System.out.println("resolveInvokerMember => "+member);
6.266 - //for (Method m : invokerClass.getDeclaredMethods()) System.out.println(" "+m);
6.267 - try {
6.268 - member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
6.269 - } catch (ReflectiveOperationException e) {
6.270 - throw newInternalError(e);
6.271 - }
6.272 - //System.out.println("resolveInvokerMember => "+member);
6.273 - return member;
6.274 - }
6.275 -
6.276 - /**
6.277 - * Set up class file generation.
6.278 - */
6.279 - private void classFilePrologue() {
6.280 - cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
6.281 - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
6.282 - cw.visitSource(sourceFile, null);
6.283 -
6.284 - String invokerDesc = invokerType.toMethodDescriptorString();
6.285 - mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
6.286 - }
6.287 -
6.288 - /**
6.289 - * Tear down class file generation.
6.290 - */
6.291 - private void classFileEpilogue() {
6.292 - mv.visitMaxs(0, 0);
6.293 - mv.visitEnd();
6.294 - }
6.295 -
6.296 - /*
6.297 - * Low-level emit helpers.
6.298 - */
6.299 - private void emitConst(Object con) {
6.300 - if (con == null) {
6.301 - mv.visitInsn(Opcodes.ACONST_NULL);
6.302 - return;
6.303 - }
6.304 - if (con instanceof Integer) {
6.305 - emitIconstInsn((int) con);
6.306 - return;
6.307 - }
6.308 - if (con instanceof Long) {
6.309 - long x = (long) con;
6.310 - if (x == (short) x) {
6.311 - emitIconstInsn((int) x);
6.312 - mv.visitInsn(Opcodes.I2L);
6.313 - return;
6.314 - }
6.315 - }
6.316 - if (con instanceof Float) {
6.317 - float x = (float) con;
6.318 - if (x == (short) x) {
6.319 - emitIconstInsn((int) x);
6.320 - mv.visitInsn(Opcodes.I2F);
6.321 - return;
6.322 - }
6.323 - }
6.324 - if (con instanceof Double) {
6.325 - double x = (double) con;
6.326 - if (x == (short) x) {
6.327 - emitIconstInsn((int) x);
6.328 - mv.visitInsn(Opcodes.I2D);
6.329 - return;
6.330 - }
6.331 - }
6.332 - if (con instanceof Boolean) {
6.333 - emitIconstInsn((boolean) con ? 1 : 0);
6.334 - return;
6.335 - }
6.336 - // fall through:
6.337 - mv.visitLdcInsn(con);
6.338 - }
6.339 -
6.340 - private void emitIconstInsn(int i) {
6.341 - int opcode;
6.342 - switch (i) {
6.343 - case 0: opcode = Opcodes.ICONST_0; break;
6.344 - case 1: opcode = Opcodes.ICONST_1; break;
6.345 - case 2: opcode = Opcodes.ICONST_2; break;
6.346 - case 3: opcode = Opcodes.ICONST_3; break;
6.347 - case 4: opcode = Opcodes.ICONST_4; break;
6.348 - case 5: opcode = Opcodes.ICONST_5; break;
6.349 - default:
6.350 - if (i == (byte) i) {
6.351 - mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
6.352 - } else if (i == (short) i) {
6.353 - mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
6.354 - } else {
6.355 - mv.visitLdcInsn(i);
6.356 - }
6.357 - return;
6.358 - }
6.359 - mv.visitInsn(opcode);
6.360 - }
6.361 -
6.362 - /*
6.363 - * NOTE: These load/store methods use the localsMap to find the correct index!
6.364 - */
6.365 - private void emitLoadInsn(char type, int index) {
6.366 - int opcode;
6.367 - switch (type) {
6.368 - case 'I': opcode = Opcodes.ILOAD; break;
6.369 - case 'J': opcode = Opcodes.LLOAD; break;
6.370 - case 'F': opcode = Opcodes.FLOAD; break;
6.371 - case 'D': opcode = Opcodes.DLOAD; break;
6.372 - case 'L': opcode = Opcodes.ALOAD; break;
6.373 - default:
6.374 - throw new InternalError("unknown type: " + type);
6.375 - }
6.376 - mv.visitVarInsn(opcode, localsMap[index]);
6.377 - }
6.378 - private void emitAloadInsn(int index) {
6.379 - emitLoadInsn('L', index);
6.380 - }
6.381 -
6.382 - private void emitStoreInsn(char type, int index) {
6.383 - int opcode;
6.384 - switch (type) {
6.385 - case 'I': opcode = Opcodes.ISTORE; break;
6.386 - case 'J': opcode = Opcodes.LSTORE; break;
6.387 - case 'F': opcode = Opcodes.FSTORE; break;
6.388 - case 'D': opcode = Opcodes.DSTORE; break;
6.389 - case 'L': opcode = Opcodes.ASTORE; break;
6.390 - default:
6.391 - throw new InternalError("unknown type: " + type);
6.392 - }
6.393 - mv.visitVarInsn(opcode, localsMap[index]);
6.394 - }
6.395 - private void emitAstoreInsn(int index) {
6.396 - emitStoreInsn('L', index);
6.397 - }
6.398 -
6.399 - /**
6.400 - * Emit a boxing call.
6.401 - *
6.402 - * @param type primitive type class to box.
6.403 - */
6.404 - private void emitBoxing(Class<?> type) {
6.405 - Wrapper wrapper = Wrapper.forPrimitiveType(type);
6.406 - String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
6.407 - String name = "valueOf";
6.408 - String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
6.409 - mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc);
6.410 - }
6.411 -
6.412 - /**
6.413 - * Emit an unboxing call (plus preceding checkcast).
6.414 - *
6.415 - * @param type wrapper type class to unbox.
6.416 - */
6.417 - private void emitUnboxing(Class<?> type) {
6.418 - Wrapper wrapper = Wrapper.forWrapperType(type);
6.419 - String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
6.420 - String name = wrapper.primitiveSimpleName() + "Value";
6.421 - String desc = "()" + wrapper.basicTypeChar();
6.422 - mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
6.423 - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
6.424 - }
6.425 -
6.426 - /**
6.427 - * Emit an implicit conversion.
6.428 - *
6.429 - * @param ptype type of value present on stack
6.430 - * @param pclass type of value required on stack
6.431 - */
6.432 - private void emitImplicitConversion(char ptype, Class<?> pclass) {
6.433 - switch (ptype) {
6.434 - case 'L':
6.435 - if (VerifyType.isNullConversion(Object.class, pclass))
6.436 - return;
6.437 - if (isStaticallyNameable(pclass)) {
6.438 - mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
6.439 - } else {
6.440 - mv.visitLdcInsn(constantPlaceholder(pclass));
6.441 - mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
6.442 - mv.visitInsn(Opcodes.SWAP);
6.443 - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG);
6.444 - if (pclass.isArray())
6.445 - mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
6.446 - }
6.447 - return;
6.448 - case 'I':
6.449 - if (!VerifyType.isNullConversion(int.class, pclass))
6.450 - emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
6.451 - return;
6.452 - case 'J':
6.453 - assert(pclass == long.class);
6.454 - return;
6.455 - case 'F':
6.456 - assert(pclass == float.class);
6.457 - return;
6.458 - case 'D':
6.459 - assert(pclass == double.class);
6.460 - return;
6.461 - }
6.462 - throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
6.463 - }
6.464 -
6.465 - /**
6.466 - * Emits an actual return instruction conforming to the given return type.
6.467 - */
6.468 - private void emitReturnInsn(Class<?> type) {
6.469 - int opcode;
6.470 - switch (Wrapper.basicTypeChar(type)) {
6.471 - case 'I': opcode = Opcodes.IRETURN; break;
6.472 - case 'J': opcode = Opcodes.LRETURN; break;
6.473 - case 'F': opcode = Opcodes.FRETURN; break;
6.474 - case 'D': opcode = Opcodes.DRETURN; break;
6.475 - case 'L': opcode = Opcodes.ARETURN; break;
6.476 - case 'V': opcode = Opcodes.RETURN; break;
6.477 - default:
6.478 - throw new InternalError("unknown return type: " + type);
6.479 - }
6.480 - mv.visitInsn(opcode);
6.481 - }
6.482 -
6.483 - private static String getInternalName(Class<?> c) {
6.484 - assert(VerifyAccess.isTypeVisible(c, Object.class));
6.485 - return c.getName().replace('.', '/');
6.486 - }
6.487 -
6.488 - /**
6.489 - * Generate customized bytecode for a given LambdaForm.
6.490 - */
6.491 - static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
6.492 - InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
6.493 - return g.loadMethod(g.generateCustomizedCodeBytes());
6.494 - }
6.495 -
6.496 - /**
6.497 - * Generate an invoker method for the passed {@link LambdaForm}.
6.498 - */
6.499 - private byte[] generateCustomizedCodeBytes() {
6.500 - classFilePrologue();
6.501 -
6.502 - // Suppress this method in backtraces displayed to the user.
6.503 - mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
6.504 -
6.505 - // Mark this method as a compiled LambdaForm
6.506 - mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
6.507 -
6.508 - // Force inlining of this invoker method.
6.509 - mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
6.510 -
6.511 - // iterate over the form's names, generating bytecode instructions for each
6.512 - // start iterating at the first name following the arguments
6.513 - for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
6.514 - Name name = lambdaForm.names[i];
6.515 - MemberName member = name.function.member();
6.516 -
6.517 - if (isSelectAlternative(member)) {
6.518 - // selectAlternative idiom
6.519 - // FIXME: make sure this idiom is really present!
6.520 - emitSelectAlternative(name, lambdaForm.names[i + 1]);
6.521 - i++; // skip MH.invokeBasic of the selectAlternative result
6.522 - } else if (isStaticallyInvocable(member)) {
6.523 - emitStaticInvoke(member, name);
6.524 - } else {
6.525 - emitInvoke(name);
6.526 - }
6.527 -
6.528 - // store the result from evaluating to the target name in a local if required
6.529 - // (if this is the last value, i.e., the one that is going to be returned,
6.530 - // avoid store/load/return and just return)
6.531 - if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
6.532 - // return value - do nothing
6.533 - } else if (name.type != 'V') {
6.534 - // non-void: actually assign
6.535 - emitStoreInsn(name.type, name.index());
6.536 - }
6.537 - }
6.538 -
6.539 - // return statement
6.540 - emitReturn();
6.541 -
6.542 - classFileEpilogue();
6.543 - bogusMethod(lambdaForm);
6.544 -
6.545 - final byte[] classFile = cw.toByteArray();
6.546 - maybeDump(className, classFile);
6.547 - return classFile;
6.548 - }
6.549 -
6.550 - /**
6.551 - * Emit an invoke for the given name.
6.552 - */
6.553 - void emitInvoke(Name name) {
6.554 - if (true) {
6.555 - // push receiver
6.556 - MethodHandle target = name.function.resolvedHandle;
6.557 - assert(target != null) : name.exprString();
6.558 - mv.visitLdcInsn(constantPlaceholder(target));
6.559 - mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
6.560 - } else {
6.561 - // load receiver
6.562 - emitAloadInsn(0);
6.563 - mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
6.564 - mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
6.565 - mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
6.566 - // TODO more to come
6.567 - }
6.568 -
6.569 - // push arguments
6.570 - for (int i = 0; i < name.arguments.length; i++) {
6.571 - emitPushArgument(name, i);
6.572 - }
6.573 -
6.574 - // invocation
6.575 - MethodType type = name.function.methodType();
6.576 - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString());
6.577 - }
6.578 -
6.579 - static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
6.580 - // Sample classes from each package we are willing to bind to statically:
6.581 - java.lang.Object.class,
6.582 - java.util.Arrays.class,
6.583 - sun.misc.Unsafe.class
6.584 - //MethodHandle.class already covered
6.585 - };
6.586 -
6.587 - static boolean isStaticallyInvocable(MemberName member) {
6.588 - if (member == null) return false;
6.589 - if (member.isConstructor()) return false;
6.590 - Class<?> cls = member.getDeclaringClass();
6.591 - if (cls.isArray() || cls.isPrimitive())
6.592 - return false; // FIXME
6.593 - if (cls.isAnonymousClass() || cls.isLocalClass())
6.594 - return false; // inner class of some sort
6.595 - if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
6.596 - return false; // not on BCP
6.597 - MethodType mtype = member.getMethodOrFieldType();
6.598 - if (!isStaticallyNameable(mtype.returnType()))
6.599 - return false;
6.600 - for (Class<?> ptype : mtype.parameterArray())
6.601 - if (!isStaticallyNameable(ptype))
6.602 - return false;
6.603 - if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
6.604 - return true; // in java.lang.invoke package
6.605 - if (member.isPublic() && isStaticallyNameable(cls))
6.606 - return true;
6.607 - return false;
6.608 - }
6.609 -
6.610 - static boolean isStaticallyNameable(Class<?> cls) {
6.611 - while (cls.isArray())
6.612 - cls = cls.getComponentType();
6.613 - if (cls.isPrimitive())
6.614 - return true; // int[].class, for example
6.615 - // could use VerifyAccess.isClassAccessible but the following is a safe approximation
6.616 - if (cls.getClassLoader() != Object.class.getClassLoader())
6.617 - return false;
6.618 - if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
6.619 - return true;
6.620 - if (!Modifier.isPublic(cls.getModifiers()))
6.621 - return false;
6.622 - for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
6.623 - if (VerifyAccess.isSamePackage(pkgcls, cls))
6.624 - return true;
6.625 - }
6.626 - return false;
6.627 - }
6.628 -
6.629 - /**
6.630 - * Emit an invoke for the given name, using the MemberName directly.
6.631 - */
6.632 - void emitStaticInvoke(MemberName member, Name name) {
6.633 - assert(member.equals(name.function.member()));
6.634 - String cname = getInternalName(member.getDeclaringClass());
6.635 - String mname = member.getName();
6.636 - String mtype;
6.637 - byte refKind = member.getReferenceKind();
6.638 - if (refKind == REF_invokeSpecial) {
6.639 - // in order to pass the verifier, we need to convert this to invokevirtual in all cases
6.640 - assert(member.canBeStaticallyBound()) : member;
6.641 - refKind = REF_invokeVirtual;
6.642 - }
6.643 -
6.644 - if (member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual) {
6.645 - // Methods from Object declared in an interface can be resolved by JVM to invokevirtual kind.
6.646 - // Need to convert it back to invokeinterface to pass verification and make the invocation works as expected.
6.647 - refKind = REF_invokeInterface;
6.648 - }
6.649 -
6.650 - // push arguments
6.651 - for (int i = 0; i < name.arguments.length; i++) {
6.652 - emitPushArgument(name, i);
6.653 - }
6.654 -
6.655 - // invocation
6.656 - if (member.isMethod()) {
6.657 - mtype = member.getMethodType().toMethodDescriptorString();
6.658 - mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype,
6.659 - member.getDeclaringClass().isInterface());
6.660 - } else {
6.661 - mtype = MethodType.toFieldDescriptorString(member.getFieldType());
6.662 - mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
6.663 - }
6.664 - }
6.665 - int refKindOpcode(byte refKind) {
6.666 - switch (refKind) {
6.667 - case REF_invokeVirtual: return Opcodes.INVOKEVIRTUAL;
6.668 - case REF_invokeStatic: return Opcodes.INVOKESTATIC;
6.669 - case REF_invokeSpecial: return Opcodes.INVOKESPECIAL;
6.670 - case REF_invokeInterface: return Opcodes.INVOKEINTERFACE;
6.671 - case REF_getField: return Opcodes.GETFIELD;
6.672 - case REF_putField: return Opcodes.PUTFIELD;
6.673 - case REF_getStatic: return Opcodes.GETSTATIC;
6.674 - case REF_putStatic: return Opcodes.PUTSTATIC;
6.675 - }
6.676 - throw new InternalError("refKind="+refKind);
6.677 - }
6.678 -
6.679 - /**
6.680 - * Check if MemberName is a call to MethodHandleImpl.selectAlternative.
6.681 - */
6.682 - private boolean isSelectAlternative(MemberName member) {
6.683 - return member != null &&
6.684 - member.getDeclaringClass() == MethodHandleImpl.class &&
6.685 - member.getName().equals("selectAlternative");
6.686 - }
6.687 -
6.688 - /**
6.689 - * Emit bytecode for the selectAlternative idiom.
6.690 - *
6.691 - * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
6.692 - * <blockquote><pre>{@code
6.693 - * Lambda(a0:L,a1:I)=>{
6.694 - * t2:I=foo.test(a1:I);
6.695 - * t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
6.696 - * t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
6.697 - * }</pre></blockquote>
6.698 - */
6.699 - private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
6.700 - MethodType type = selectAlternativeName.function.methodType();
6.701 -
6.702 - Name receiver = (Name) invokeBasicName.arguments[0];
6.703 -
6.704 - Label L_fallback = new Label();
6.705 - Label L_done = new Label();
6.706 -
6.707 - // load test result
6.708 - emitPushArgument(selectAlternativeName, 0);
6.709 - mv.visitInsn(Opcodes.ICONST_1);
6.710 -
6.711 - // if_icmpne L_fallback
6.712 - mv.visitJumpInsn(Opcodes.IF_ICMPNE, L_fallback);
6.713 -
6.714 - // invoke selectAlternativeName.arguments[1]
6.715 - MethodHandle target = (MethodHandle) selectAlternativeName.arguments[1];
6.716 - emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative
6.717 - emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
6.718 - emitInvoke(invokeBasicName);
6.719 -
6.720 - // goto L_done
6.721 - mv.visitJumpInsn(Opcodes.GOTO, L_done);
6.722 -
6.723 - // L_fallback:
6.724 - mv.visitLabel(L_fallback);
6.725 -
6.726 - // invoke selectAlternativeName.arguments[2]
6.727 - MethodHandle fallback = (MethodHandle) selectAlternativeName.arguments[2];
6.728 - emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative
6.729 - emitAstoreInsn(receiver.index()); // store the MH in the receiver slot
6.730 - emitInvoke(invokeBasicName);
6.731 -
6.732 - // L_done:
6.733 - mv.visitLabel(L_done);
6.734 - }
6.735 -
6.736 - private void emitPushArgument(Name name, int paramIndex) {
6.737 - Object arg = name.arguments[paramIndex];
6.738 - char ptype = name.function.parameterType(paramIndex);
6.739 - MethodType mtype = name.function.methodType();
6.740 - if (arg instanceof Name) {
6.741 - Name n = (Name) arg;
6.742 - emitLoadInsn(n.type, n.index());
6.743 - emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
6.744 - } else if ((arg == null || arg instanceof String) && ptype == 'L') {
6.745 - emitConst(arg);
6.746 - } else {
6.747 - if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
6.748 - emitConst(arg);
6.749 - } else {
6.750 - mv.visitLdcInsn(constantPlaceholder(arg));
6.751 - emitImplicitConversion('L', mtype.parameterType(paramIndex));
6.752 - }
6.753 - }
6.754 - }
6.755 -
6.756 - /**
6.757 - * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
6.758 - */
6.759 - private void emitReturn() {
6.760 - // return statement
6.761 - if (lambdaForm.result == -1) {
6.762 - // void
6.763 - mv.visitInsn(Opcodes.RETURN);
6.764 - } else {
6.765 - LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
6.766 - char rtype = Wrapper.basicTypeChar(invokerType.returnType());
6.767 -
6.768 - // put return value on the stack if it is not already there
6.769 - if (lambdaForm.result != lambdaForm.names.length - 1) {
6.770 - emitLoadInsn(rn.type, lambdaForm.result);
6.771 - }
6.772 -
6.773 - // potentially generate cast
6.774 - // rtype is the return type of the invoker - generated code must conform to this
6.775 - // rn.type is the type of the result Name in the LF
6.776 - if (rtype != rn.type) {
6.777 - // need cast
6.778 - if (rtype == 'L') {
6.779 - // possibly cast the primitive to the correct type for boxing
6.780 - char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
6.781 - if (boxedType != rn.type) {
6.782 - emitPrimCast(rn.type, boxedType);
6.783 - }
6.784 - // cast primitive to reference ("boxing")
6.785 - emitBoxing(invokerType.returnType());
6.786 - } else {
6.787 - // to-primitive cast
6.788 - if (rn.type != 'L') {
6.789 - // prim-to-prim cast
6.790 - emitPrimCast(rn.type, rtype);
6.791 - } else {
6.792 - // ref-to-prim cast ("unboxing")
6.793 - throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
6.794 - }
6.795 - }
6.796 - }
6.797 -
6.798 - // generate actual return statement
6.799 - emitReturnInsn(invokerType.returnType());
6.800 - }
6.801 - }
6.802 -
6.803 - /**
6.804 - * Emit a type conversion bytecode casting from "from" to "to".
6.805 - */
6.806 - private void emitPrimCast(char from, char to) {
6.807 - // Here's how.
6.808 - // - indicates forbidden
6.809 - // <-> indicates implicit
6.810 - // to ----> boolean byte short char int long float double
6.811 - // from boolean <-> - - - - - - -
6.812 - // byte - <-> i2s i2c <-> i2l i2f i2d
6.813 - // short - i2b <-> i2c <-> i2l i2f i2d
6.814 - // char - i2b i2s <-> <-> i2l i2f i2d
6.815 - // int - i2b i2s i2c <-> i2l i2f i2d
6.816 - // long - l2i,i2b l2i,i2s l2i,i2c l2i <-> l2f l2d
6.817 - // float - f2i,i2b f2i,i2s f2i,i2c f2i f2l <-> f2d
6.818 - // double - d2i,i2b d2i,i2s d2i,i2c d2i d2l d2f <->
6.819 - if (from == to) {
6.820 - // no cast required, should be dead code anyway
6.821 - return;
6.822 - }
6.823 - Wrapper wfrom = Wrapper.forBasicType(from);
6.824 - Wrapper wto = Wrapper.forBasicType(to);
6.825 - if (wfrom.isSubwordOrInt()) {
6.826 - // cast from {byte,short,char,int} to anything
6.827 - emitI2X(to);
6.828 - } else {
6.829 - // cast from {long,float,double} to anything
6.830 - if (wto.isSubwordOrInt()) {
6.831 - // cast to {byte,short,char,int}
6.832 - emitX2I(from);
6.833 - if (wto.bitWidth() < 32) {
6.834 - // targets other than int require another conversion
6.835 - emitI2X(to);
6.836 - }
6.837 - } else {
6.838 - // cast to {long,float,double} - this is verbose
6.839 - boolean error = false;
6.840 - switch (from) {
6.841 - case 'J':
6.842 - if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
6.843 - else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
6.844 - else error = true;
6.845 - break;
6.846 - case 'F':
6.847 - if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
6.848 - else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
6.849 - else error = true;
6.850 - break;
6.851 - case 'D':
6.852 - if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
6.853 - else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
6.854 - else error = true;
6.855 - break;
6.856 - default:
6.857 - error = true;
6.858 - break;
6.859 - }
6.860 - if (error) {
6.861 - throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
6.862 - }
6.863 - }
6.864 - }
6.865 - }
6.866 -
6.867 - private void emitI2X(char type) {
6.868 - switch (type) {
6.869 - case 'B': mv.visitInsn(Opcodes.I2B); break;
6.870 - case 'S': mv.visitInsn(Opcodes.I2S); break;
6.871 - case 'C': mv.visitInsn(Opcodes.I2C); break;
6.872 - case 'I': /* naught */ break;
6.873 - case 'J': mv.visitInsn(Opcodes.I2L); break;
6.874 - case 'F': mv.visitInsn(Opcodes.I2F); break;
6.875 - case 'D': mv.visitInsn(Opcodes.I2D); break;
6.876 - case 'Z':
6.877 - // For compatibility with ValueConversions and explicitCastArguments:
6.878 - mv.visitInsn(Opcodes.ICONST_1);
6.879 - mv.visitInsn(Opcodes.IAND);
6.880 - break;
6.881 - default: throw new InternalError("unknown type: " + type);
6.882 - }
6.883 - }
6.884 -
6.885 - private void emitX2I(char type) {
6.886 - switch (type) {
6.887 - case 'J': mv.visitInsn(Opcodes.L2I); break;
6.888 - case 'F': mv.visitInsn(Opcodes.F2I); break;
6.889 - case 'D': mv.visitInsn(Opcodes.D2I); break;
6.890 - default: throw new InternalError("unknown type: " + type);
6.891 - }
6.892 - }
6.893 -
6.894 - private static String basicTypeCharSignature(String prefix, MethodType type) {
6.895 - StringBuilder buf = new StringBuilder(prefix);
6.896 - for (Class<?> ptype : type.parameterList())
6.897 - buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
6.898 - buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
6.899 - return buf.toString();
6.900 - }
6.901 -
6.902 - /**
6.903 - * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
6.904 - */
6.905 - static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
6.906 - assert(LambdaForm.isValidSignature(sig));
6.907 - //System.out.println("generateExactInvoker "+sig);
6.908 - // compute method type
6.909 - // first parameter and return type
6.910 - char tret = LambdaForm.signatureReturn(sig);
6.911 - MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
6.912 - // other parameter types
6.913 - int arity = LambdaForm.signatureArity(sig);
6.914 - for (int i = 1; i < arity; i++) {
6.915 - type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
6.916 - }
6.917 - InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
6.918 - return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
6.919 - }
6.920 -
6.921 - private byte[] generateLambdaFormInterpreterEntryPointBytes() {
6.922 - classFilePrologue();
6.923 -
6.924 - // Suppress this method in backtraces displayed to the user.
6.925 - mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
6.926 -
6.927 - // Don't inline the interpreter entry.
6.928 - mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
6.929 -
6.930 - // create parameter array
6.931 - emitIconstInsn(invokerType.parameterCount());
6.932 - mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
6.933 -
6.934 - // fill parameter array
6.935 - for (int i = 0; i < invokerType.parameterCount(); i++) {
6.936 - Class<?> ptype = invokerType.parameterType(i);
6.937 - mv.visitInsn(Opcodes.DUP);
6.938 - emitIconstInsn(i);
6.939 - emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
6.940 - // box if primitive type
6.941 - if (ptype.isPrimitive()) {
6.942 - emitBoxing(ptype);
6.943 - }
6.944 - mv.visitInsn(Opcodes.AASTORE);
6.945 - }
6.946 - // invoke
6.947 - emitAloadInsn(0);
6.948 - mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
6.949 - mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
6.950 - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;");
6.951 -
6.952 - // maybe unbox
6.953 - Class<?> rtype = invokerType.returnType();
6.954 - if (rtype.isPrimitive() && rtype != void.class) {
6.955 - emitUnboxing(Wrapper.asWrapperType(rtype));
6.956 - }
6.957 -
6.958 - // return statement
6.959 - emitReturnInsn(rtype);
6.960 -
6.961 - classFileEpilogue();
6.962 - bogusMethod(invokerType);
6.963 -
6.964 - final byte[] classFile = cw.toByteArray();
6.965 - maybeDump(className, classFile);
6.966 - return classFile;
6.967 - }
6.968 -
6.969 - /**
6.970 - * Generate bytecode for a NamedFunction invoker.
6.971 - */
6.972 - static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
6.973 - MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
6.974 - String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
6.975 - InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
6.976 - return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
6.977 - }
6.978 -
6.979 - static int nfi = 0;
6.980 -
6.981 - private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
6.982 - MethodType dstType = typeForm.erasedType();
6.983 - classFilePrologue();
6.984 -
6.985 - // Suppress this method in backtraces displayed to the user.
6.986 - mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
6.987 -
6.988 - // Force inlining of this invoker method.
6.989 - mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
6.990 -
6.991 - // Load receiver
6.992 - emitAloadInsn(0);
6.993 -
6.994 - // Load arguments from array
6.995 - for (int i = 0; i < dstType.parameterCount(); i++) {
6.996 - emitAloadInsn(1);
6.997 - emitIconstInsn(i);
6.998 - mv.visitInsn(Opcodes.AALOAD);
6.999 -
6.1000 - // Maybe unbox
6.1001 - Class<?> dptype = dstType.parameterType(i);
6.1002 - if (dptype.isPrimitive()) {
6.1003 - Class<?> sptype = dstType.basicType().wrap().parameterType(i);
6.1004 - Wrapper dstWrapper = Wrapper.forBasicType(dptype);
6.1005 - Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int
6.1006 - emitUnboxing(srcWrapper.wrapperType());
6.1007 - emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
6.1008 - }
6.1009 - }
6.1010 -
6.1011 - // Invoke
6.1012 - String targetDesc = dstType.basicType().toMethodDescriptorString();
6.1013 - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc);
6.1014 -
6.1015 - // Box primitive types
6.1016 - Class<?> rtype = dstType.returnType();
6.1017 - if (rtype != void.class && rtype.isPrimitive()) {
6.1018 - Wrapper srcWrapper = Wrapper.forBasicType(rtype);
6.1019 - Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
6.1020 - // boolean casts not allowed
6.1021 - emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
6.1022 - emitBoxing(dstWrapper.primitiveType());
6.1023 - }
6.1024 -
6.1025 - // If the return type is void we return a null reference.
6.1026 - if (rtype == void.class) {
6.1027 - mv.visitInsn(Opcodes.ACONST_NULL);
6.1028 - }
6.1029 - emitReturnInsn(Object.class); // NOTE: NamedFunction invokers always return a reference value.
6.1030 -
6.1031 - classFileEpilogue();
6.1032 - bogusMethod(dstType);
6.1033 -
6.1034 - final byte[] classFile = cw.toByteArray();
6.1035 - maybeDump(className, classFile);
6.1036 - return classFile;
6.1037 - }
6.1038 -
6.1039 - /**
6.1040 - * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
6.1041 - * for debugging purposes.
6.1042 - */
6.1043 - private void bogusMethod(Object... os) {
6.1044 - if (DUMP_CLASS_FILES) {
6.1045 - mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
6.1046 - for (Object o : os) {
6.1047 - mv.visitLdcInsn(o.toString());
6.1048 - mv.visitInsn(Opcodes.POP);
6.1049 - }
6.1050 - mv.visitInsn(Opcodes.RETURN);
6.1051 - mv.visitMaxs(0, 0);
6.1052 - mv.visitEnd();
6.1053 - }
6.1054 - }
6.1055 -}
7.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/LambdaForm.java Sun Aug 10 06:21:50 2014 +0200
7.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaForm.java Sun Aug 10 07:02:12 2014 +0200
7.3 @@ -450,15 +450,16 @@
7.4 if (vmentry != null && isCompiled) {
7.5 return vmentry; // already compiled somehow
7.6 }
7.7 - try {
7.8 - vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
7.9 - if (TRACE_INTERPRETER)
7.10 - traceInterpreter("compileToBytecode", this);
7.11 - isCompiled = true;
7.12 - return vmentry;
7.13 - } catch (Error | Exception ex) {
7.14 - throw newInternalError("compileToBytecode", ex);
7.15 - }
7.16 + throw newInternalError("compileToBytecode", new Exception());
7.17 +// try {
7.18 +// vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
7.19 +// if (TRACE_INTERPRETER)
7.20 +// traceInterpreter("compileToBytecode", this);
7.21 +// isCompiled = true;
7.22 +// return vmentry;
7.23 +// } catch (Error | Exception ex) {
7.24 +// throw newInternalError("compileToBytecode", ex);
7.25 +// }
7.26 }
7.27
7.28 private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
7.29 @@ -527,7 +528,9 @@
7.30 if (prep != null) return prep;
7.31 assert(isValidSignature(sig));
7.32 prep = new LambdaForm(sig);
7.33 - prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
7.34 +// prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
7.35 + if (true) throw new IllegalStateException();
7.36 +
7.37 //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep);
7.38 return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
7.39 }
7.40 @@ -1129,8 +1132,9 @@
7.41 private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
7.42 MethodHandle mh = typeForm.namedFunctionInvoker;
7.43 if (mh != null) return mh;
7.44 - MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while
7.45 - mh = DirectMethodHandle.make(invoker);
7.46 +// MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while
7.47 + if (true) throw new IllegalStateException();
7.48 +// mh = DirectMethodHandle.make(invoker);
7.49 MethodHandle mh2 = typeForm.namedFunctionInvoker;
7.50 if (mh2 != null) return mh2; // benign race
7.51 if (!mh.type().equals(INVOKER_METHOD_TYPE))
8.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/LambdaMetafactory.java Sun Aug 10 06:21:50 2014 +0200
8.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaMetafactory.java Sun Aug 10 07:02:12 2014 +0200
8.3 @@ -296,12 +296,13 @@
8.4 MethodType instantiatedMethodType)
8.5 throws LambdaConversionException {
8.6 AbstractValidatingLambdaMetafactory mf;
8.7 - mf = new InnerClassLambdaMetafactory(caller, invokedType,
8.8 - invokedName, samMethodType,
8.9 - implMethod, instantiatedMethodType,
8.10 - false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
8.11 - mf.validateMetafactoryArgs();
8.12 - return mf.buildCallSite();
8.13 +// mf = new InnerClassLambdaMetafactory(caller, invokedType,
8.14 +// invokedName, samMethodType,
8.15 +// implMethod, instantiatedMethodType,
8.16 +// false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
8.17 +// mf.validateMetafactoryArgs();
8.18 +// return mf.buildCallSite();
8.19 + throw new IllegalStateException();
8.20 }
8.21
8.22 /**
8.23 @@ -462,14 +463,15 @@
8.24 }
8.25 }
8.26
8.27 - AbstractValidatingLambdaMetafactory mf
8.28 - = new InnerClassLambdaMetafactory(caller, invokedType,
8.29 - invokedName, samMethodType,
8.30 - implMethod,
8.31 - instantiatedMethodType,
8.32 - isSerializable,
8.33 - markerInterfaces, bridges);
8.34 - mf.validateMetafactoryArgs();
8.35 - return mf.buildCallSite();
8.36 +// AbstractValidatingLambdaMetafactory mf
8.37 +// = new InnerClassLambdaMetafactory(caller, invokedType,
8.38 +// invokedName, samMethodType,
8.39 +// implMethod,
8.40 +// instantiatedMethodType,
8.41 +// isSerializable,
8.42 +// markerInterfaces, bridges);
8.43 +// mf.validateMetafactoryArgs();
8.44 +// return mf.buildCallSite();
8.45 + throw new IllegalStateException();
8.46 }
8.47 }
9.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/TypeConvertingMethodAdapter.java Sun Aug 10 06:21:50 2014 +0200
9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
9.3 @@ -1,302 +0,0 @@
9.4 -/*
9.5 - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
9.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9.7 - *
9.8 - * This code is free software; you can redistribute it and/or modify it
9.9 - * under the terms of the GNU General Public License version 2 only, as
9.10 - * published by the Free Software Foundation. Oracle designates this
9.11 - * particular file as subject to the "Classpath" exception as provided
9.12 - * by Oracle in the LICENSE file that accompanied this code.
9.13 - *
9.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
9.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9.17 - * version 2 for more details (a copy is included in the LICENSE file that
9.18 - * accompanied this code).
9.19 - *
9.20 - * You should have received a copy of the GNU General Public License version
9.21 - * 2 along with this work; if not, write to the Free Software Foundation,
9.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
9.23 - *
9.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
9.25 - * or visit www.oracle.com if you need additional information or have any
9.26 - * questions.
9.27 - */
9.28 -
9.29 -package java.lang.invoke;
9.30 -
9.31 -import jdk.internal.org.objectweb.asm.MethodVisitor;
9.32 -import jdk.internal.org.objectweb.asm.Opcodes;
9.33 -import jdk.internal.org.objectweb.asm.Type;
9.34 -import sun.invoke.util.BytecodeDescriptor;
9.35 -import sun.invoke.util.Wrapper;
9.36 -import static sun.invoke.util.Wrapper.*;
9.37 -
9.38 -class TypeConvertingMethodAdapter extends MethodVisitor {
9.39 -
9.40 - TypeConvertingMethodAdapter(MethodVisitor mv) {
9.41 - super(Opcodes.ASM5, mv);
9.42 - }
9.43 -
9.44 - private static final int NUM_WRAPPERS = Wrapper.values().length;
9.45 -
9.46 - private static final String NAME_OBJECT = "java/lang/Object";
9.47 - private static final String WRAPPER_PREFIX = "Ljava/lang/";
9.48 -
9.49 - // Same for all primitives; name of the boxing method
9.50 - private static final String NAME_BOX_METHOD = "valueOf";
9.51 -
9.52 - // Table of opcodes for widening primitive conversions; NOP = no conversion
9.53 - private static final int[][] wideningOpcodes = new int[NUM_WRAPPERS][NUM_WRAPPERS];
9.54 -
9.55 - private static final Wrapper[] FROM_WRAPPER_NAME = new Wrapper[16];
9.56 -
9.57 - // Table of wrappers for primitives, indexed by ASM type sorts
9.58 - private static final Wrapper[] FROM_TYPE_SORT = new Wrapper[16];
9.59 -
9.60 - static {
9.61 - for (Wrapper w : Wrapper.values()) {
9.62 - if (w.basicTypeChar() != 'L') {
9.63 - int wi = hashWrapperName(w.wrapperSimpleName());
9.64 - assert (FROM_WRAPPER_NAME[wi] == null);
9.65 - FROM_WRAPPER_NAME[wi] = w;
9.66 - }
9.67 - }
9.68 -
9.69 - for (int i = 0; i < NUM_WRAPPERS; i++) {
9.70 - for (int j = 0; j < NUM_WRAPPERS; j++) {
9.71 - wideningOpcodes[i][j] = Opcodes.NOP;
9.72 - }
9.73 - }
9.74 -
9.75 - initWidening(LONG, Opcodes.I2L, BYTE, SHORT, INT, CHAR);
9.76 - initWidening(LONG, Opcodes.F2L, FLOAT);
9.77 - initWidening(FLOAT, Opcodes.I2F, BYTE, SHORT, INT, CHAR);
9.78 - initWidening(FLOAT, Opcodes.L2F, LONG);
9.79 - initWidening(DOUBLE, Opcodes.I2D, BYTE, SHORT, INT, CHAR);
9.80 - initWidening(DOUBLE, Opcodes.F2D, FLOAT);
9.81 - initWidening(DOUBLE, Opcodes.L2D, LONG);
9.82 -
9.83 - FROM_TYPE_SORT[Type.BYTE] = Wrapper.BYTE;
9.84 - FROM_TYPE_SORT[Type.SHORT] = Wrapper.SHORT;
9.85 - FROM_TYPE_SORT[Type.INT] = Wrapper.INT;
9.86 - FROM_TYPE_SORT[Type.LONG] = Wrapper.LONG;
9.87 - FROM_TYPE_SORT[Type.CHAR] = Wrapper.CHAR;
9.88 - FROM_TYPE_SORT[Type.FLOAT] = Wrapper.FLOAT;
9.89 - FROM_TYPE_SORT[Type.DOUBLE] = Wrapper.DOUBLE;
9.90 - FROM_TYPE_SORT[Type.BOOLEAN] = Wrapper.BOOLEAN;
9.91 - }
9.92 -
9.93 - private static void initWidening(Wrapper to, int opcode, Wrapper... from) {
9.94 - for (Wrapper f : from) {
9.95 - wideningOpcodes[f.ordinal()][to.ordinal()] = opcode;
9.96 - }
9.97 - }
9.98 -
9.99 - /**
9.100 - * Class name to Wrapper hash, derived from Wrapper.hashWrap()
9.101 - * @param xn
9.102 - * @return The hash code 0-15
9.103 - */
9.104 - private static int hashWrapperName(String xn) {
9.105 - if (xn.length() < 3) {
9.106 - return 0;
9.107 - }
9.108 - return (3 * xn.charAt(1) + xn.charAt(2)) % 16;
9.109 - }
9.110 -
9.111 - private Wrapper wrapperOrNullFromDescriptor(String desc) {
9.112 - if (!desc.startsWith(WRAPPER_PREFIX)) {
9.113 - // Not a class type (array or method), so not a boxed type
9.114 - // or not in the right package
9.115 - return null;
9.116 - }
9.117 - // Pare it down to the simple class name
9.118 - String cname = desc.substring(WRAPPER_PREFIX.length(), desc.length() - 1);
9.119 - // Hash to a Wrapper
9.120 - Wrapper w = FROM_WRAPPER_NAME[hashWrapperName(cname)];
9.121 - if (w == null || w.wrapperSimpleName().equals(cname)) {
9.122 - return w;
9.123 - } else {
9.124 - return null;
9.125 - }
9.126 - }
9.127 -
9.128 - private static String wrapperName(Wrapper w) {
9.129 - return "java/lang/" + w.wrapperSimpleName();
9.130 - }
9.131 -
9.132 - private static String unboxMethod(Wrapper w) {
9.133 - return w.primitiveSimpleName() + "Value";
9.134 - }
9.135 -
9.136 - private static String boxingDescriptor(Wrapper w) {
9.137 - return String.format("(%s)L%s;", w.basicTypeChar(), wrapperName(w));
9.138 - }
9.139 -
9.140 - private static String unboxingDescriptor(Wrapper w) {
9.141 - return "()" + w.basicTypeChar();
9.142 - }
9.143 -
9.144 - void boxIfTypePrimitive(Type t) {
9.145 - Wrapper w = FROM_TYPE_SORT[t.getSort()];
9.146 - if (w != null) {
9.147 - box(w);
9.148 - }
9.149 - }
9.150 -
9.151 - void widen(Wrapper ws, Wrapper wt) {
9.152 - if (ws != wt) {
9.153 - int opcode = wideningOpcodes[ws.ordinal()][wt.ordinal()];
9.154 - if (opcode != Opcodes.NOP) {
9.155 - visitInsn(opcode);
9.156 - }
9.157 - }
9.158 - }
9.159 -
9.160 - void box(Wrapper w) {
9.161 - visitMethodInsn(Opcodes.INVOKESTATIC,
9.162 - wrapperName(w),
9.163 - NAME_BOX_METHOD,
9.164 - boxingDescriptor(w));
9.165 - }
9.166 -
9.167 - /**
9.168 - * Convert types by unboxing. The source type is known to be a primitive wrapper.
9.169 - * @param ws A primitive wrapper corresponding to wrapped reference source type
9.170 - * @param wt A primitive wrapper being converted to
9.171 - */
9.172 - void unbox(String sname, Wrapper wt) {
9.173 - visitMethodInsn(Opcodes.INVOKEVIRTUAL,
9.174 - sname,
9.175 - unboxMethod(wt),
9.176 - unboxingDescriptor(wt));
9.177 - }
9.178 -
9.179 - private String descriptorToName(String desc) {
9.180 - int last = desc.length() - 1;
9.181 - if (desc.charAt(0) == 'L' && desc.charAt(last) == ';') {
9.182 - // In descriptor form
9.183 - return desc.substring(1, last);
9.184 - } else {
9.185 - // Already in internal name form
9.186 - return desc;
9.187 - }
9.188 - }
9.189 -
9.190 - void cast(String ds, String dt) {
9.191 - String ns = descriptorToName(ds);
9.192 - String nt = descriptorToName(dt);
9.193 - if (!nt.equals(ns) && !nt.equals(NAME_OBJECT)) {
9.194 - visitTypeInsn(Opcodes.CHECKCAST, nt);
9.195 - }
9.196 - }
9.197 -
9.198 - private boolean isPrimitive(Wrapper w) {
9.199 - return w != OBJECT;
9.200 - }
9.201 -
9.202 - private Wrapper toWrapper(String desc) {
9.203 - char first = desc.charAt(0);
9.204 - if (first == '[' || first == '(') {
9.205 - first = 'L';
9.206 - }
9.207 - return Wrapper.forBasicType(first);
9.208 - }
9.209 -
9.210 - /**
9.211 - * Convert an argument of type 'arg' to be passed to 'target' assuring that it is 'functional'.
9.212 - * Insert the needed conversion instructions in the method code.
9.213 - * @param arg
9.214 - * @param target
9.215 - * @param functional
9.216 - */
9.217 - void convertType(Class<?> arg, Class<?> target, Class<?> functional) {
9.218 - if (arg.equals(target) && arg.equals(functional)) {
9.219 - return;
9.220 - }
9.221 - if (arg == Void.TYPE || target == Void.TYPE) {
9.222 - return;
9.223 - }
9.224 - if (arg.isPrimitive()) {
9.225 - Wrapper wArg = Wrapper.forPrimitiveType(arg);
9.226 - if (target.isPrimitive()) {
9.227 - // Both primitives: widening
9.228 - widen(wArg, Wrapper.forPrimitiveType(target));
9.229 - } else {
9.230 - // Primitive argument to reference target
9.231 - String dTarget = BytecodeDescriptor.unparse(target);
9.232 - Wrapper wPrimTarget = wrapperOrNullFromDescriptor(dTarget);
9.233 - if (wPrimTarget != null) {
9.234 - // The target is a boxed primitive type, widen to get there before boxing
9.235 - widen(wArg, wPrimTarget);
9.236 - box(wPrimTarget);
9.237 - } else {
9.238 - // Otherwise, box and cast
9.239 - box(wArg);
9.240 - cast(wrapperName(wArg), dTarget);
9.241 - }
9.242 - }
9.243 - } else {
9.244 - String dArg = BytecodeDescriptor.unparse(arg);
9.245 - String dSrc;
9.246 - if (functional.isPrimitive()) {
9.247 - dSrc = dArg;
9.248 - } else {
9.249 - // Cast to convert to possibly more specific type, and generate CCE for invalid arg
9.250 - dSrc = BytecodeDescriptor.unparse(functional);
9.251 - cast(dArg, dSrc);
9.252 - }
9.253 - String dTarget = BytecodeDescriptor.unparse(target);
9.254 - if (target.isPrimitive()) {
9.255 - Wrapper wTarget = toWrapper(dTarget);
9.256 - // Reference argument to primitive target
9.257 - Wrapper wps = wrapperOrNullFromDescriptor(dSrc);
9.258 - if (wps != null) {
9.259 - if (wps.isSigned() || wps.isFloating()) {
9.260 - // Boxed number to primitive
9.261 - unbox(wrapperName(wps), wTarget);
9.262 - } else {
9.263 - // Character or Boolean
9.264 - unbox(wrapperName(wps), wps);
9.265 - widen(wps, wTarget);
9.266 - }
9.267 - } else {
9.268 - // Source type is reference type, but not boxed type,
9.269 - // assume it is super type of target type
9.270 - String intermediate;
9.271 - if (wTarget.isSigned() || wTarget.isFloating()) {
9.272 - // Boxed number to primitive
9.273 - intermediate = "java/lang/Number";
9.274 - } else {
9.275 - // Character or Boolean
9.276 - intermediate = wrapperName(wTarget);
9.277 - }
9.278 - cast(dSrc, intermediate);
9.279 - unbox(intermediate, wTarget);
9.280 - }
9.281 - } else {
9.282 - // Both reference types: just case to target type
9.283 - cast(dSrc, dTarget);
9.284 - }
9.285 - }
9.286 - }
9.287 -
9.288 - /**
9.289 - * The following method is copied from
9.290 - * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very small
9.291 - * and fast Java bytecode manipulation framework.
9.292 - * Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved.
9.293 - */
9.294 - void iconst(final int cst) {
9.295 - if (cst >= -1 && cst <= 5) {
9.296 - mv.visitInsn(Opcodes.ICONST_0 + cst);
9.297 - } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
9.298 - mv.visitIntInsn(Opcodes.BIPUSH, cst);
9.299 - } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
9.300 - mv.visitIntInsn(Opcodes.SIPUSH, cst);
9.301 - } else {
9.302 - mv.visitLdcInsn(cst);
9.303 - }
9.304 - }
9.305 -}
10.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java Sun Aug 10 06:21:50 2014 +0200
10.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Sun Aug 10 07:02:12 2014 +0200
10.3 @@ -94,6 +94,11 @@
10.4 private static final int ENUM = 0x00004000;
10.5 private static final int SYNTHETIC = 0x00001000;
10.6
10.7 + /* Backing store of user-defined values pertaining to this class.
10.8 + * Maintained by the ClassValue class.
10.9 + */
10.10 + transient Object classValueMap;
10.11 +
10.12 /*
10.13 * Constructor. Only the Java Virtual Machine creates Class
10.14 * objects.