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