1 /* 2 * Copyright (c) 2009, 2019, 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 25 package shared; 26 27 import static jdk.internal.org.objectweb.asm.ClassWriter.*; 28 import jdk.internal.org.objectweb.asm.Label; 29 import jdk.internal.org.objectweb.asm.MethodVisitor; 30 import jdk.internal.org.objectweb.asm.Opcodes; 31 import jdk.internal.org.objectweb.asm.ClassWriter; 32 import static jdk.internal.org.objectweb.asm.Opcodes.*; 33 34 public class ExecutorGenerator { 35 public static final String className = Utils.getInternalName("Test"); 36 private String caseDescription; 37 private String staticTargetName; 38 private String dynamicTargetName; 39 40 private String callerSignature; 41 ExecutorGenerator(String caseDescription, String staticTargetName, String dynamicTargetName)42 public ExecutorGenerator(String caseDescription, 43 String staticTargetName, 44 String dynamicTargetName) { 45 this.caseDescription = caseDescription; 46 this.staticTargetName = Utils.getInternalName(staticTargetName); 47 this.dynamicTargetName = Utils.getInternalName(dynamicTargetName); 48 callerSignature = String.format("(L%s;)Ljava/lang/String;", this.staticTargetName); 49 } 50 generateExecutor(String[] callSites)51 public byte[] generateExecutor(String[] callSites) { 52 ClassWriter cw = new ClassWriter(COMPUTE_MAXS); 53 54 cw.visit(Utils.version, ACC_PUBLIC | (Utils.isACC_SUPER ? ACC_SUPER : 0), className, null, "java/lang/Object", null); 55 56 // Generate constructor 57 { 58 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 59 mv.visitCode(); 60 mv.visitVarInsn(ALOAD, 0); 61 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); 62 mv.visitInsn(RETURN); 63 mv.visitEnd(); 64 mv.visitMaxs(0, 0); 65 } 66 67 // public static void main(String[] args) { 68 // new Test().run(); 69 // } 70 { 71 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); 72 mv.visitCode(); 73 mv.visitTypeInsn(NEW, className); 74 mv.visitInsn(DUP); 75 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V"); 76 mv.visitMethodInsn(INVOKEVIRTUAL, className, "run", "()V"); 77 mv.visitInsn(RETURN); 78 mv.visitEnd(); 79 mv.visitMaxs(0, 0); 80 } 81 82 // private String indent(String result) { 83 // while (result.length() < 8) { 84 // result = " "+result; 85 // } 86 // return result; 87 // } 88 { 89 MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "indent", "(Ljava/lang/String;)Ljava/lang/String;", null, null); 90 mv.visitCode(); 91 Label l0 = new Label(); 92 mv.visitLabel(l0); 93 mv.visitVarInsn(ALOAD, 1); 94 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I"); 95 mv.visitIntInsn(BIPUSH, 8); 96 Label l1 = new Label(); 97 mv.visitJumpInsn(IF_ICMPGE, l1); 98 mv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 99 mv.visitInsn(DUP); 100 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V"); 101 mv.visitLdcInsn(" "); 102 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 103 mv.visitVarInsn(ALOAD, 1); 104 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 105 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;"); 106 mv.visitVarInsn(ASTORE, 1); 107 mv.visitJumpInsn(GOTO, l0); 108 mv.visitLabel(l1); 109 mv.visitVarInsn(ALOAD, 1); 110 mv.visitInsn(ARETURN); 111 mv.visitEnd(); 112 mv.visitMaxs(0, 0); 113 } 114 115 //private String abbr(String result) { 116 // result = result.replaceAll("java.lang.NullPointerException", "NPE"); 117 // result = result.replaceAll("java.lang.IllegalAccessError", "IAE"); 118 // result = result.replaceAll("java.lang.IllegalAccessException", "IAExc"); 119 // result = result.replaceAll("java.lang.NoSuchMethodError", "NSME"); 120 // result = result.replaceAll("java.lang.AbstractMethodError", "AME"); 121 // result = result.replaceAll("java.lang.IncompatibleClassChangeError", "ICCE"); 122 // 123 // return result; 124 //} 125 { 126 MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "abbr", "(Ljava/lang/String;)Ljava/lang/String;", null, null); 127 mv.visitCode(); 128 mv.visitVarInsn(ALOAD, 1); 129 mv.visitLdcInsn("java.lang.NullPointerException"); 130 mv.visitLdcInsn("NPE"); 131 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 132 mv.visitVarInsn(ASTORE, 1); 133 mv.visitVarInsn(ALOAD, 1); 134 mv.visitLdcInsn("java.lang.IllegalAccessError"); 135 mv.visitLdcInsn("IAE"); 136 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 137 mv.visitVarInsn(ASTORE, 1); 138 mv.visitVarInsn(ALOAD, 1); 139 mv.visitLdcInsn("java.lang.IllegalAccessException"); 140 mv.visitLdcInsn("IAExc"); 141 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 142 mv.visitVarInsn(ASTORE, 1); 143 mv.visitVarInsn(ALOAD, 1); 144 mv.visitLdcInsn("java.lang.NoSuchMethodError"); 145 mv.visitLdcInsn("NSME"); 146 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 147 mv.visitVarInsn(ASTORE, 1); 148 mv.visitVarInsn(ALOAD, 1); 149 mv.visitLdcInsn("java.lang.AbstractMethodError"); 150 mv.visitLdcInsn("AME"); 151 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 152 mv.visitVarInsn(ASTORE, 1); 153 mv.visitVarInsn(ALOAD, 1); 154 mv.visitLdcInsn("java.lang.IncompatibleClassChangeError"); 155 mv.visitLdcInsn("ICCE"); 156 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 157 mv.visitVarInsn(ASTORE, 1); 158 mv.visitVarInsn(ALOAD, 1); 159 mv.visitInsn(ARETURN); 160 mv.visitEnd(); 161 mv.visitMaxs(0, 0); 162 } 163 164 // Generate execution method 165 // public void run() { 166 // System.out.print("2048| ! a.A PUB ! b.B PP a.C PROT |"); 167 // 168 // C object = new C(); 169 // 170 // try { 171 // System.out.print(indent(A.call(object))); 172 // } catch (Throwable e) { 173 // System.out.print(indent(abbr(e.getClass().getName()))); 174 // } 175 // 176 // ... 177 // 178 // System.out.println(); 179 // } 180 { 181 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); 182 mv.visitCode(); 183 184 // Generate try/catch blocks 185 Label[][] tryCatchLabels = new Label[callSites.length][3]; 186 for (int I = 0; I < tryCatchLabels.length; I++) { 187 Label[] labels = tryCatchLabels[I]; 188 for (int K = 0; K < labels.length; K++) { 189 labels[K] = new Label(); 190 } 191 192 mv.visitTryCatchBlock(labels[0], labels[1], labels[2], "java/lang/Throwable"); 193 } 194 195 // System.out.print("2048| ! a.A PUB ! b.B PP a.C PROT |"); 196 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 197 mv.visitLdcInsn(caseDescription); 198 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V"); 199 200 // C object = new C(); 201 mv.visitTypeInsn(NEW, dynamicTargetName); 202 mv.visitInsn(DUP); 203 mv.visitMethodInsn(INVOKESPECIAL, dynamicTargetName, "<init>", "()V"); 204 mv.visitVarInsn(ASTORE, 1); 205 206 // for (String site: callSites) { 207 // System.out.print(indent(A.call(object))); 208 // mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 209 // mv.visitVarInsn(ALOAD, 0); 210 // mv.visitVarInsn(ALOAD, 1); 211 // mv.visitMethodInsn(INVOKESTATIC, AbstractGenerator.getInternalName(site), "call", callerSignature); 212 // mv.visitMethodInsn(INVOKESPECIAL, className, "indent", "(Ljava/lang/String;)Ljava/lang/String;"); 213 // mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V"); 214 // } 215 216 Label returnLabel = new Label(); 217 for (int I = 0; I < callSites.length; I++) { 218 String site = callSites[I]; 219 Label[] l = tryCatchLabels[I]; 220 221 Label nextBlock = (I+1 < callSites.length ? tryCatchLabels[I+1][0] : returnLabel); 222 223 mv.visitLabel(l[0]); 224 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 225 mv.visitVarInsn(ALOAD, 0); 226 mv.visitVarInsn(ALOAD, 1); 227 mv.visitMethodInsn(INVOKESTATIC, Utils.getInternalName(site), "call", callerSignature); 228 mv.visitMethodInsn(INVOKESPECIAL, className, "indent", "(Ljava/lang/String;)Ljava/lang/String;"); 229 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V"); 230 mv.visitLabel(l[1]); 231 mv.visitJumpInsn(GOTO, nextBlock); 232 mv.visitLabel(l[2]); 233 mv.visitVarInsn(ASTORE, 2); 234 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 235 mv.visitVarInsn(ALOAD, 0); 236 mv.visitVarInsn(ALOAD, 0); 237 mv.visitVarInsn(ALOAD, 2); 238 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;"); 239 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;"); 240 mv.visitMethodInsn(INVOKESPECIAL, className, "abbr", "(Ljava/lang/String;)Ljava/lang/String;"); 241 mv.visitMethodInsn(INVOKESPECIAL, className, "indent", "(Ljava/lang/String;)Ljava/lang/String;"); 242 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "print", "(Ljava/lang/String;)V"); 243 } 244 mv.visitLabel(returnLabel); 245 246 // System.out.println(); 247 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 248 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "()V"); 249 mv.visitInsn(RETURN); 250 251 mv.visitEnd(); 252 mv.visitMaxs(0, 0); 253 } 254 255 cw.visitEnd(); 256 257 return cw.toByteArray(); 258 } 259 } 260