1 /* 2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package vm.mlvm.cp.share; 25 26 import jdk.internal.org.objectweb.asm.ClassWriter; 27 import jdk.internal.org.objectweb.asm.ClassWriterExt; 28 import jdk.internal.org.objectweb.asm.Handle; 29 import jdk.internal.org.objectweb.asm.MethodVisitor; 30 import jdk.internal.org.objectweb.asm.Opcodes; 31 import jdk.internal.org.objectweb.asm.Type; 32 import jdk.internal.org.objectweb.asm.Label; 33 34 import vm.mlvm.share.ClassfileGenerator; 35 import vm.mlvm.share.Env; 36 37 public class GenManyIndyIncorrectBootstrap extends GenFullCP { 38 39 /** 40 * Generates a class file and writes it to a file 41 * @see vm.mlvm.share.ClassfileGenerator 42 * @param args Parameters for ClassfileGenerator.main() method 43 */ 44 public static void main(String[] args) { 45 ClassfileGenerator.main(args); 46 } 47 48 /** 49 * Create class constructor, which 50 * create a call site for target method 51 * and puts it into static and instance fields 52 * @param cw Class writer object 53 */ 54 @Override 55 protected void createInitMethod(ClassWriter cw) { 56 MethodVisitor mw = cw.visitMethod( 57 Opcodes.ACC_PUBLIC, 58 INIT_METHOD_NAME, INIT_METHOD_SIGNATURE, 59 null, 60 new String[0]); 61 62 mw.visitVarInsn(Opcodes.ALOAD, 0); 63 mw.visitMethodInsn(Opcodes.INVOKESPECIAL, PARENT_CLASS_NAME, 64 INIT_METHOD_NAME, INIT_METHOD_SIGNATURE); 65 66 // Create a call site for the target method and store it into bootstrap fields 67 mw.visitVarInsn(Opcodes.ALOAD, 0); 68 mw.visitTypeInsn(Opcodes.NEW, JLI_CONSTANTCALLSITE); 69 mw.visitInsn(Opcodes.DUP); 70 mw.visitMethodInsn(Opcodes.INVOKESTATIC, JLI_METHODHANDLES, 71 "lookup", "()" + fd(JLI_METHODHANDLES_LOOKUP)); 72 mw.visitLdcInsn(Type.getObjectType(fullClassName)); 73 mw.visitLdcInsn(TARGET_METHOD_NAME); 74 mw.visitLdcInsn(TARGET_METHOD_SIGNATURE); 75 mw.visitLdcInsn(Type.getObjectType(fullClassName)); 76 mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, JL_CLASS, 77 "getClassLoader", "()" + fd(JL_CLASSLOADER)); 78 mw.visitMethodInsn(Opcodes.INVOKESTATIC, JLI_METHODTYPE, 79 "fromMethodDescriptorString", "(" + fd(JL_STRING) + fd(JL_CLASSLOADER) + ")" + fd(JLI_METHODTYPE)); 80 mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, JLI_METHODHANDLES_LOOKUP, 81 "findStatic", "(" + fd(JL_CLASS) + fd(JL_STRING) + fd(JLI_METHODTYPE) + ")" + fd(JLI_METHODHANDLE)); 82 mw.visitMethodInsn(Opcodes.INVOKESPECIAL, JLI_CONSTANTCALLSITE, 83 INIT_METHOD_NAME, "(" + fd(JLI_METHODHANDLE) + ")V"); 84 mw.visitInsn(Opcodes.DUP); 85 mw.visitFieldInsn(Opcodes.PUTSTATIC, fullClassName, STATIC_BOOTSTRAP_FIELD_NAME, STATIC_BOOTSTRAP_FIELD_SIGNATURE); 86 mw.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, INSTANCE_BOOTSTRAP_FIELD_NAME, INSTANCE_BOOTSTRAP_FIELD_SIGNATURE); 87 88 finishMethodCode(mw); 89 } 90 91 /** 92 * Creates a target method which always throw. It should not be called, 93 * since all invokedynamic instructions have invalid bootstrap method types 94 * @param cw Class writer object 95 */ 96 @Override 97 protected void createTargetMethod(ClassWriter cw) { 98 createThrowRuntimeExceptionMethod(cw, true, TARGET_METHOD_NAME, TARGET_METHOD_SIGNATURE); 99 } 100 101 /** 102 * Creates a bootstrap method which always throw. It should not be called, 103 * since all invokedynamic instructions have invalid bootstrap method types 104 * @param cw Class writer object 105 */ 106 @Override 107 protected void createBootstrapMethod(ClassWriter cw) { 108 createThrowRuntimeExceptionMethod(cw, true, BOOTSTRAP_METHOD_NAME, BOOTSTRAP_METHOD_SIGNATURE); 109 } 110 111 /** 112 * Generates common data for class plus two fields that hold CallSite 113 * and used as bootstrap targets 114 * @param cw Class writer object 115 */ 116 @Override 117 protected void generateCommonData(ClassWriterExt cw) { 118 cw.setCacheInvokeDynamic(false); 119 120 cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, 121 STATIC_BOOTSTRAP_FIELD_NAME, 122 STATIC_BOOTSTRAP_FIELD_SIGNATURE, null, null); 123 124 cw.visitField(Opcodes.ACC_PUBLIC, 125 INSTANCE_BOOTSTRAP_FIELD_NAME, 126 INSTANCE_BOOTSTRAP_FIELD_SIGNATURE, null, null); 127 128 super.generateCommonData(cw); 129 130 createThrowRuntimeExceptionMethod(cw, false, INSTANCE_BOOTSTRAP_METHOD_NAME, INSTANCE_BOOTSTRAP_METHOD_SIGNATURE); 131 } 132 133 Label throwMethodLabel; 134 135 // The exception to expect that is wrapped in a BootstrapMethodError 136 static final String WRAPPED_EXCEPTION = "java/lang/invoke/WrongMethodTypeException"; 137 138 // The error to expect that is not wrapped in a BootstrapMethodError and 139 // is thrown directly 140 static final String DIRECT_ERROR = "java/lang/IncompatibleClassChangeError"; 141 142 /** 143 * Generates an invokedynamic instruction (plus CP entry) 144 * which has invalid reference kind in the CP method handle entry for the bootstrap method 145 * @param cw Class writer object 146 * @param mw Method writer object 147 */ 148 @Override 149 protected void generateCPEntryData(ClassWriter cw, MethodVisitor mw) { 150 HandleType[] types = HandleType.values(); 151 HandleType type = types[Env.getRNG().nextInt(types.length)]; 152 153 switch (type) { 154 case GETFIELD: 155 case PUTFIELD: 156 case GETSTATIC: 157 case PUTSTATIC: 158 case INVOKESPECIAL: 159 case INVOKEVIRTUAL: 160 case INVOKEINTERFACE: 161 // Handle these cases 162 break; 163 default: 164 // And don't generate code for all other cases 165 return; 166 } 167 168 Label indyThrowableBegin = new Label(); 169 Label indyThrowableEnd = new Label(); 170 Label catchThrowableLabel = new Label(); 171 172 Label indyBootstrapBegin = new Label(); 173 Label indyBootstrapEnd = new Label(); 174 Label catchBootstrapLabel = new Label(); 175 176 mw.visitTryCatchBlock(indyBootstrapBegin, indyBootstrapEnd, catchBootstrapLabel, JL_BOOTSTRAPMETHODERROR); 177 mw.visitLabel(indyBootstrapBegin); 178 179 mw.visitTryCatchBlock(indyThrowableBegin, indyThrowableEnd, catchThrowableLabel, JL_THROWABLE); 180 mw.visitLabel(indyThrowableBegin); 181 182 Handle bsm; 183 switch (type) { 184 case GETFIELD: 185 case PUTFIELD: 186 bsm = new Handle(type.asmTag, 187 fullClassName, 188 INSTANCE_BOOTSTRAP_FIELD_NAME, 189 INSTANCE_BOOTSTRAP_FIELD_SIGNATURE); 190 break; 191 case GETSTATIC: 192 case PUTSTATIC: 193 bsm = new Handle(type.asmTag, 194 fullClassName, 195 STATIC_BOOTSTRAP_FIELD_NAME, 196 STATIC_BOOTSTRAP_FIELD_SIGNATURE); 197 break; 198 case INVOKESPECIAL: 199 case INVOKEVIRTUAL: 200 case INVOKEINTERFACE: 201 bsm = new Handle(type.asmTag, 202 fullClassName, 203 INSTANCE_BOOTSTRAP_METHOD_NAME, 204 INSTANCE_BOOTSTRAP_METHOD_SIGNATURE); 205 break; 206 default: 207 throw new Error("Unexpected handle type " + type); 208 } 209 210 mw.visitInvokeDynamicInsn(TARGET_METHOD_NAME, 211 TARGET_METHOD_SIGNATURE, 212 bsm); 213 214 mw.visitLabel(indyBootstrapEnd); 215 mw.visitLabel(indyThrowableEnd); 216 217 // No exception at all, throw error 218 Label throwLabel = new Label(); 219 mw.visitJumpInsn(Opcodes.GOTO, throwLabel); 220 221 // JDK-8079697 workaround: we have to generate stackmaps manually 222 mw.visitFrame(Opcodes.F_SAME1, 0, new Object[0], 1, new Object[] { JL_BOOTSTRAPMETHODERROR }); 223 224 // Got a bootstrapmethoderror as expected, check that it is wrapping what we expect 225 mw.visitLabel(catchBootstrapLabel); 226 227 // Save error in case we need to rethrow it 228 mw.visitInsn(Opcodes.DUP); 229 mw.visitVarInsn(Opcodes.ASTORE, 1); 230 mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, JL_THROWABLE, "getCause", "()" + fd(JL_THROWABLE)); 231 232 // If it is the expected exception, goto next block 233 mw.visitTypeInsn(Opcodes.INSTANCEOF, WRAPPED_EXCEPTION); 234 Label nextBlockLabel = new Label(); 235 mw.visitJumpInsn(Opcodes.IFNE, nextBlockLabel); 236 237 // Not the exception we were expectiong, throw error 238 mw.visitVarInsn(Opcodes.ALOAD, 1); // Use full chain as cause 239 createThrowRuntimeExceptionCodeWithCause(mw, 240 "invokedynamic got an unexpected wrapped exception (expected " + WRAPPED_EXCEPTION 241 + ", bootstrap type=" + type 242 + ", opcode=" + type.asmTag + ")!"); 243 244 // JDK-8079697 workaround: we have to generate stackmaps manually 245 mw.visitFrame(Opcodes.F_SAME1, 0, new Object[0], 1, new Object[] { JL_THROWABLE }); 246 mw.visitLabel(catchThrowableLabel); 247 248 // Save error in case we need to rethrow it 249 mw.visitInsn(Opcodes.DUP); 250 mw.visitVarInsn(Opcodes.ASTORE, 1); 251 252 // If it is the expected exception, goto next block 253 mw.visitTypeInsn(Opcodes.INSTANCEOF, DIRECT_ERROR); 254 mw.visitJumpInsn(Opcodes.IFNE, nextBlockLabel); 255 256 // Not the exception we were expectiong, throw error 257 mw.visitVarInsn(Opcodes.ALOAD, 1); // Use full chain as cause 258 createThrowRuntimeExceptionCodeWithCause(mw, 259 "invokedynamic got an unexpected exception (expected " + DIRECT_ERROR 260 + ", bootstrap type" + type 261 + ", opcode=" + type.asmTag + ")!"); 262 263 // JDK-8079697 workaround: we have to generate stackmaps manually 264 mw.visitFrame(Opcodes.F_CHOP, 0, new Object[0], 0, new Object[0]); 265 266 // Unable to place this code once in the method epilog due to bug in ASM 267 mw.visitLabel(throwLabel); 268 createThrowRuntimeExceptionCode(mw, 269 "invokedynamic should always throw (bootstrap type" + type +", opcode=" + type.asmTag + ")!"); 270 271 mw.visitFrame(Opcodes.F_SAME, 0, new Object[0], 0, new Object[0]); 272 mw.visitLabel(nextBlockLabel); 273 } 274 }