|
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 |
|
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 |
|
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 } |