author | sherman |
Tue, 30 Aug 2011 11:53:11 -0700 | |
changeset 10419 | 12c063b39232 |
parent 5506 | 202f599c92aa |
child 11119 | 6ff03c1202ce |
permissions | -rw-r--r-- |
2 | 1 |
/* |
5506 | 2 |
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.misc; |
|
27 |
||
28 |
import java.io.ByteArrayOutputStream; |
|
29 |
import java.io.DataOutputStream; |
|
30 |
import java.io.FileOutputStream; |
|
31 |
import java.io.IOException; |
|
32 |
import java.io.OutputStream; |
|
33 |
import java.lang.reflect.Array; |
|
34 |
import java.lang.reflect.Method; |
|
35 |
import java.util.ArrayList; |
|
36 |
import java.util.HashMap; |
|
37 |
import java.util.LinkedList; |
|
38 |
import java.util.List; |
|
39 |
import java.util.ListIterator; |
|
40 |
import java.util.Map; |
|
41 |
import sun.security.action.GetBooleanAction; |
|
42 |
||
43 |
/** |
|
44 |
* ProxyGenerator contains the code to generate a dynamic proxy class |
|
45 |
* for the java.lang.reflect.Proxy API. |
|
46 |
* |
|
47 |
* The external interfaces to ProxyGenerator is the static |
|
48 |
* "generateProxyClass" method. |
|
49 |
* |
|
50 |
* @author Peter Jones |
|
51 |
* @since 1.3 |
|
52 |
*/ |
|
53 |
public class ProxyGenerator { |
|
54 |
/* |
|
55 |
* In the comments below, "JVMS" refers to The Java Virtual Machine |
|
56 |
* Specification Second Edition and "JLS" refers to the original |
|
57 |
* version of The Java Language Specification, unless otherwise |
|
58 |
* specified. |
|
59 |
*/ |
|
60 |
||
61 |
/* generate 1.5-era class file version */ |
|
62 |
private static final int CLASSFILE_MAJOR_VERSION = 49; |
|
63 |
private static final int CLASSFILE_MINOR_VERSION = 0; |
|
64 |
||
65 |
/* |
|
66 |
* beginning of constants copied from |
|
67 |
* sun.tools.java.RuntimeConstants (which no longer exists): |
|
68 |
*/ |
|
69 |
||
70 |
/* constant pool tags */ |
|
71 |
private static final int CONSTANT_UTF8 = 1; |
|
72 |
private static final int CONSTANT_UNICODE = 2; |
|
73 |
private static final int CONSTANT_INTEGER = 3; |
|
74 |
private static final int CONSTANT_FLOAT = 4; |
|
75 |
private static final int CONSTANT_LONG = 5; |
|
76 |
private static final int CONSTANT_DOUBLE = 6; |
|
77 |
private static final int CONSTANT_CLASS = 7; |
|
78 |
private static final int CONSTANT_STRING = 8; |
|
79 |
private static final int CONSTANT_FIELD = 9; |
|
80 |
private static final int CONSTANT_METHOD = 10; |
|
81 |
private static final int CONSTANT_INTERFACEMETHOD = 11; |
|
82 |
private static final int CONSTANT_NAMEANDTYPE = 12; |
|
83 |
||
84 |
/* access and modifier flags */ |
|
85 |
private static final int ACC_PUBLIC = 0x00000001; |
|
86 |
private static final int ACC_PRIVATE = 0x00000002; |
|
87 |
// private static final int ACC_PROTECTED = 0x00000004; |
|
88 |
private static final int ACC_STATIC = 0x00000008; |
|
89 |
private static final int ACC_FINAL = 0x00000010; |
|
90 |
// private static final int ACC_SYNCHRONIZED = 0x00000020; |
|
91 |
// private static final int ACC_VOLATILE = 0x00000040; |
|
92 |
// private static final int ACC_TRANSIENT = 0x00000080; |
|
93 |
// private static final int ACC_NATIVE = 0x00000100; |
|
94 |
// private static final int ACC_INTERFACE = 0x00000200; |
|
95 |
// private static final int ACC_ABSTRACT = 0x00000400; |
|
96 |
private static final int ACC_SUPER = 0x00000020; |
|
97 |
// private static final int ACC_STRICT = 0x00000800; |
|
98 |
||
99 |
/* opcodes */ |
|
100 |
// private static final int opc_nop = 0; |
|
101 |
private static final int opc_aconst_null = 1; |
|
102 |
// private static final int opc_iconst_m1 = 2; |
|
103 |
private static final int opc_iconst_0 = 3; |
|
104 |
// private static final int opc_iconst_1 = 4; |
|
105 |
// private static final int opc_iconst_2 = 5; |
|
106 |
// private static final int opc_iconst_3 = 6; |
|
107 |
// private static final int opc_iconst_4 = 7; |
|
108 |
// private static final int opc_iconst_5 = 8; |
|
109 |
// private static final int opc_lconst_0 = 9; |
|
110 |
// private static final int opc_lconst_1 = 10; |
|
111 |
// private static final int opc_fconst_0 = 11; |
|
112 |
// private static final int opc_fconst_1 = 12; |
|
113 |
// private static final int opc_fconst_2 = 13; |
|
114 |
// private static final int opc_dconst_0 = 14; |
|
115 |
// private static final int opc_dconst_1 = 15; |
|
116 |
private static final int opc_bipush = 16; |
|
117 |
private static final int opc_sipush = 17; |
|
118 |
private static final int opc_ldc = 18; |
|
119 |
private static final int opc_ldc_w = 19; |
|
120 |
// private static final int opc_ldc2_w = 20; |
|
121 |
private static final int opc_iload = 21; |
|
122 |
private static final int opc_lload = 22; |
|
123 |
private static final int opc_fload = 23; |
|
124 |
private static final int opc_dload = 24; |
|
125 |
private static final int opc_aload = 25; |
|
126 |
private static final int opc_iload_0 = 26; |
|
127 |
// private static final int opc_iload_1 = 27; |
|
128 |
// private static final int opc_iload_2 = 28; |
|
129 |
// private static final int opc_iload_3 = 29; |
|
130 |
private static final int opc_lload_0 = 30; |
|
131 |
// private static final int opc_lload_1 = 31; |
|
132 |
// private static final int opc_lload_2 = 32; |
|
133 |
// private static final int opc_lload_3 = 33; |
|
134 |
private static final int opc_fload_0 = 34; |
|
135 |
// private static final int opc_fload_1 = 35; |
|
136 |
// private static final int opc_fload_2 = 36; |
|
137 |
// private static final int opc_fload_3 = 37; |
|
138 |
private static final int opc_dload_0 = 38; |
|
139 |
// private static final int opc_dload_1 = 39; |
|
140 |
// private static final int opc_dload_2 = 40; |
|
141 |
// private static final int opc_dload_3 = 41; |
|
142 |
private static final int opc_aload_0 = 42; |
|
143 |
// private static final int opc_aload_1 = 43; |
|
144 |
// private static final int opc_aload_2 = 44; |
|
145 |
// private static final int opc_aload_3 = 45; |
|
146 |
// private static final int opc_iaload = 46; |
|
147 |
// private static final int opc_laload = 47; |
|
148 |
// private static final int opc_faload = 48; |
|
149 |
// private static final int opc_daload = 49; |
|
150 |
// private static final int opc_aaload = 50; |
|
151 |
// private static final int opc_baload = 51; |
|
152 |
// private static final int opc_caload = 52; |
|
153 |
// private static final int opc_saload = 53; |
|
154 |
// private static final int opc_istore = 54; |
|
155 |
// private static final int opc_lstore = 55; |
|
156 |
// private static final int opc_fstore = 56; |
|
157 |
// private static final int opc_dstore = 57; |
|
158 |
private static final int opc_astore = 58; |
|
159 |
// private static final int opc_istore_0 = 59; |
|
160 |
// private static final int opc_istore_1 = 60; |
|
161 |
// private static final int opc_istore_2 = 61; |
|
162 |
// private static final int opc_istore_3 = 62; |
|
163 |
// private static final int opc_lstore_0 = 63; |
|
164 |
// private static final int opc_lstore_1 = 64; |
|
165 |
// private static final int opc_lstore_2 = 65; |
|
166 |
// private static final int opc_lstore_3 = 66; |
|
167 |
// private static final int opc_fstore_0 = 67; |
|
168 |
// private static final int opc_fstore_1 = 68; |
|
169 |
// private static final int opc_fstore_2 = 69; |
|
170 |
// private static final int opc_fstore_3 = 70; |
|
171 |
// private static final int opc_dstore_0 = 71; |
|
172 |
// private static final int opc_dstore_1 = 72; |
|
173 |
// private static final int opc_dstore_2 = 73; |
|
174 |
// private static final int opc_dstore_3 = 74; |
|
175 |
private static final int opc_astore_0 = 75; |
|
176 |
// private static final int opc_astore_1 = 76; |
|
177 |
// private static final int opc_astore_2 = 77; |
|
178 |
// private static final int opc_astore_3 = 78; |
|
179 |
// private static final int opc_iastore = 79; |
|
180 |
// private static final int opc_lastore = 80; |
|
181 |
// private static final int opc_fastore = 81; |
|
182 |
// private static final int opc_dastore = 82; |
|
183 |
private static final int opc_aastore = 83; |
|
184 |
// private static final int opc_bastore = 84; |
|
185 |
// private static final int opc_castore = 85; |
|
186 |
// private static final int opc_sastore = 86; |
|
187 |
private static final int opc_pop = 87; |
|
188 |
// private static final int opc_pop2 = 88; |
|
189 |
private static final int opc_dup = 89; |
|
190 |
// private static final int opc_dup_x1 = 90; |
|
191 |
// private static final int opc_dup_x2 = 91; |
|
192 |
// private static final int opc_dup2 = 92; |
|
193 |
// private static final int opc_dup2_x1 = 93; |
|
194 |
// private static final int opc_dup2_x2 = 94; |
|
195 |
// private static final int opc_swap = 95; |
|
196 |
// private static final int opc_iadd = 96; |
|
197 |
// private static final int opc_ladd = 97; |
|
198 |
// private static final int opc_fadd = 98; |
|
199 |
// private static final int opc_dadd = 99; |
|
200 |
// private static final int opc_isub = 100; |
|
201 |
// private static final int opc_lsub = 101; |
|
202 |
// private static final int opc_fsub = 102; |
|
203 |
// private static final int opc_dsub = 103; |
|
204 |
// private static final int opc_imul = 104; |
|
205 |
// private static final int opc_lmul = 105; |
|
206 |
// private static final int opc_fmul = 106; |
|
207 |
// private static final int opc_dmul = 107; |
|
208 |
// private static final int opc_idiv = 108; |
|
209 |
// private static final int opc_ldiv = 109; |
|
210 |
// private static final int opc_fdiv = 110; |
|
211 |
// private static final int opc_ddiv = 111; |
|
212 |
// private static final int opc_irem = 112; |
|
213 |
// private static final int opc_lrem = 113; |
|
214 |
// private static final int opc_frem = 114; |
|
215 |
// private static final int opc_drem = 115; |
|
216 |
// private static final int opc_ineg = 116; |
|
217 |
// private static final int opc_lneg = 117; |
|
218 |
// private static final int opc_fneg = 118; |
|
219 |
// private static final int opc_dneg = 119; |
|
220 |
// private static final int opc_ishl = 120; |
|
221 |
// private static final int opc_lshl = 121; |
|
222 |
// private static final int opc_ishr = 122; |
|
223 |
// private static final int opc_lshr = 123; |
|
224 |
// private static final int opc_iushr = 124; |
|
225 |
// private static final int opc_lushr = 125; |
|
226 |
// private static final int opc_iand = 126; |
|
227 |
// private static final int opc_land = 127; |
|
228 |
// private static final int opc_ior = 128; |
|
229 |
// private static final int opc_lor = 129; |
|
230 |
// private static final int opc_ixor = 130; |
|
231 |
// private static final int opc_lxor = 131; |
|
232 |
// private static final int opc_iinc = 132; |
|
233 |
// private static final int opc_i2l = 133; |
|
234 |
// private static final int opc_i2f = 134; |
|
235 |
// private static final int opc_i2d = 135; |
|
236 |
// private static final int opc_l2i = 136; |
|
237 |
// private static final int opc_l2f = 137; |
|
238 |
// private static final int opc_l2d = 138; |
|
239 |
// private static final int opc_f2i = 139; |
|
240 |
// private static final int opc_f2l = 140; |
|
241 |
// private static final int opc_f2d = 141; |
|
242 |
// private static final int opc_d2i = 142; |
|
243 |
// private static final int opc_d2l = 143; |
|
244 |
// private static final int opc_d2f = 144; |
|
245 |
// private static final int opc_i2b = 145; |
|
246 |
// private static final int opc_i2c = 146; |
|
247 |
// private static final int opc_i2s = 147; |
|
248 |
// private static final int opc_lcmp = 148; |
|
249 |
// private static final int opc_fcmpl = 149; |
|
250 |
// private static final int opc_fcmpg = 150; |
|
251 |
// private static final int opc_dcmpl = 151; |
|
252 |
// private static final int opc_dcmpg = 152; |
|
253 |
// private static final int opc_ifeq = 153; |
|
254 |
// private static final int opc_ifne = 154; |
|
255 |
// private static final int opc_iflt = 155; |
|
256 |
// private static final int opc_ifge = 156; |
|
257 |
// private static final int opc_ifgt = 157; |
|
258 |
// private static final int opc_ifle = 158; |
|
259 |
// private static final int opc_if_icmpeq = 159; |
|
260 |
// private static final int opc_if_icmpne = 160; |
|
261 |
// private static final int opc_if_icmplt = 161; |
|
262 |
// private static final int opc_if_icmpge = 162; |
|
263 |
// private static final int opc_if_icmpgt = 163; |
|
264 |
// private static final int opc_if_icmple = 164; |
|
265 |
// private static final int opc_if_acmpeq = 165; |
|
266 |
// private static final int opc_if_acmpne = 166; |
|
267 |
// private static final int opc_goto = 167; |
|
268 |
// private static final int opc_jsr = 168; |
|
269 |
// private static final int opc_ret = 169; |
|
270 |
// private static final int opc_tableswitch = 170; |
|
271 |
// private static final int opc_lookupswitch = 171; |
|
272 |
private static final int opc_ireturn = 172; |
|
273 |
private static final int opc_lreturn = 173; |
|
274 |
private static final int opc_freturn = 174; |
|
275 |
private static final int opc_dreturn = 175; |
|
276 |
private static final int opc_areturn = 176; |
|
277 |
private static final int opc_return = 177; |
|
278 |
private static final int opc_getstatic = 178; |
|
279 |
private static final int opc_putstatic = 179; |
|
280 |
private static final int opc_getfield = 180; |
|
281 |
// private static final int opc_putfield = 181; |
|
282 |
private static final int opc_invokevirtual = 182; |
|
283 |
private static final int opc_invokespecial = 183; |
|
284 |
private static final int opc_invokestatic = 184; |
|
285 |
private static final int opc_invokeinterface = 185; |
|
286 |
private static final int opc_new = 187; |
|
287 |
// private static final int opc_newarray = 188; |
|
288 |
private static final int opc_anewarray = 189; |
|
289 |
// private static final int opc_arraylength = 190; |
|
290 |
private static final int opc_athrow = 191; |
|
291 |
private static final int opc_checkcast = 192; |
|
292 |
// private static final int opc_instanceof = 193; |
|
293 |
// private static final int opc_monitorenter = 194; |
|
294 |
// private static final int opc_monitorexit = 195; |
|
295 |
private static final int opc_wide = 196; |
|
296 |
// private static final int opc_multianewarray = 197; |
|
297 |
// private static final int opc_ifnull = 198; |
|
298 |
// private static final int opc_ifnonnull = 199; |
|
299 |
// private static final int opc_goto_w = 200; |
|
300 |
// private static final int opc_jsr_w = 201; |
|
301 |
||
302 |
// end of constants copied from sun.tools.java.RuntimeConstants |
|
303 |
||
304 |
/** name of the superclass of proxy classes */ |
|
305 |
private final static String superclassName = "java/lang/reflect/Proxy"; |
|
306 |
||
307 |
/** name of field for storing a proxy instance's invocation handler */ |
|
308 |
private final static String handlerFieldName = "h"; |
|
309 |
||
310 |
/** debugging flag for saving generated class files */ |
|
311 |
private final static boolean saveGeneratedFiles = |
|
312 |
java.security.AccessController.doPrivileged( |
|
313 |
new GetBooleanAction( |
|
314 |
"sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue(); |
|
315 |
||
316 |
/** |
|
317 |
* Generate a proxy class given a name and a list of proxy interfaces. |
|
318 |
*/ |
|
319 |
public static byte[] generateProxyClass(final String name, |
|
320 |
Class[] interfaces) |
|
321 |
{ |
|
322 |
ProxyGenerator gen = new ProxyGenerator(name, interfaces); |
|
323 |
final byte[] classFile = gen.generateClassFile(); |
|
324 |
||
325 |
if (saveGeneratedFiles) { |
|
326 |
java.security.AccessController.doPrivileged( |
|
51 | 327 |
new java.security.PrivilegedAction<Void>() { |
328 |
public Void run() { |
|
2 | 329 |
try { |
330 |
FileOutputStream file = |
|
331 |
new FileOutputStream(dotToSlash(name) + ".class"); |
|
332 |
file.write(classFile); |
|
333 |
file.close(); |
|
334 |
return null; |
|
335 |
} catch (IOException e) { |
|
336 |
throw new InternalError( |
|
337 |
"I/O exception saving generated file: " + e); |
|
338 |
} |
|
339 |
} |
|
340 |
}); |
|
341 |
} |
|
342 |
||
343 |
return classFile; |
|
344 |
} |
|
345 |
||
346 |
/* preloaded Method objects for methods in java.lang.Object */ |
|
347 |
private static Method hashCodeMethod; |
|
348 |
private static Method equalsMethod; |
|
349 |
private static Method toStringMethod; |
|
350 |
static { |
|
351 |
try { |
|
352 |
hashCodeMethod = Object.class.getMethod("hashCode"); |
|
353 |
equalsMethod = |
|
354 |
Object.class.getMethod("equals", new Class[] { Object.class }); |
|
355 |
toStringMethod = Object.class.getMethod("toString"); |
|
356 |
} catch (NoSuchMethodException e) { |
|
357 |
throw new NoSuchMethodError(e.getMessage()); |
|
358 |
} |
|
359 |
} |
|
360 |
||
361 |
/** name of proxy class */ |
|
362 |
private String className; |
|
363 |
||
364 |
/** proxy interfaces */ |
|
365 |
private Class[] interfaces; |
|
366 |
||
367 |
/** constant pool of class being generated */ |
|
368 |
private ConstantPool cp = new ConstantPool(); |
|
369 |
||
370 |
/** FieldInfo struct for each field of generated class */ |
|
371 |
private List<FieldInfo> fields = new ArrayList<FieldInfo>(); |
|
372 |
||
373 |
/** MethodInfo struct for each method of generated class */ |
|
374 |
private List<MethodInfo> methods = new ArrayList<MethodInfo>(); |
|
375 |
||
376 |
/** |
|
377 |
* maps method signature string to list of ProxyMethod objects for |
|
378 |
* proxy methods with that signature |
|
379 |
*/ |
|
380 |
private Map<String, List<ProxyMethod>> proxyMethods = |
|
381 |
new HashMap<String,List<ProxyMethod>>(); |
|
382 |
||
383 |
/** count of ProxyMethod objects added to proxyMethods */ |
|
384 |
private int proxyMethodCount = 0; |
|
385 |
||
386 |
/** |
|
387 |
* Construct a ProxyGenerator to generate a proxy class with the |
|
388 |
* specified name and for the given interfaces. |
|
389 |
* |
|
390 |
* A ProxyGenerator object contains the state for the ongoing |
|
391 |
* generation of a particular proxy class. |
|
392 |
*/ |
|
393 |
private ProxyGenerator(String className, Class[] interfaces) { |
|
394 |
this.className = className; |
|
395 |
this.interfaces = interfaces; |
|
396 |
} |
|
397 |
||
398 |
/** |
|
399 |
* Generate a class file for the proxy class. This method drives the |
|
400 |
* class file generation process. |
|
401 |
*/ |
|
402 |
private byte[] generateClassFile() { |
|
403 |
||
404 |
/* ============================================================ |
|
405 |
* Step 1: Assemble ProxyMethod objects for all methods to |
|
406 |
* generate proxy dispatching code for. |
|
407 |
*/ |
|
408 |
||
409 |
/* |
|
410 |
* Record that proxy methods are needed for the hashCode, equals, |
|
411 |
* and toString methods of java.lang.Object. This is done before |
|
412 |
* the methods from the proxy interfaces so that the methods from |
|
413 |
* java.lang.Object take precedence over duplicate methods in the |
|
414 |
* proxy interfaces. |
|
415 |
*/ |
|
416 |
addProxyMethod(hashCodeMethod, Object.class); |
|
417 |
addProxyMethod(equalsMethod, Object.class); |
|
418 |
addProxyMethod(toStringMethod, Object.class); |
|
419 |
||
420 |
/* |
|
421 |
* Now record all of the methods from the proxy interfaces, giving |
|
422 |
* earlier interfaces precedence over later ones with duplicate |
|
423 |
* methods. |
|
424 |
*/ |
|
425 |
for (int i = 0; i < interfaces.length; i++) { |
|
426 |
Method[] methods = interfaces[i].getMethods(); |
|
427 |
for (int j = 0; j < methods.length; j++) { |
|
428 |
addProxyMethod(methods[j], interfaces[i]); |
|
429 |
} |
|
430 |
} |
|
431 |
||
432 |
/* |
|
433 |
* For each set of proxy methods with the same signature, |
|
434 |
* verify that the methods' return types are compatible. |
|
435 |
*/ |
|
436 |
for (List<ProxyMethod> sigmethods : proxyMethods.values()) { |
|
437 |
checkReturnTypes(sigmethods); |
|
438 |
} |
|
439 |
||
440 |
/* ============================================================ |
|
441 |
* Step 2: Assemble FieldInfo and MethodInfo structs for all of |
|
442 |
* fields and methods in the class we are generating. |
|
443 |
*/ |
|
444 |
try { |
|
445 |
methods.add(generateConstructor()); |
|
446 |
||
447 |
for (List<ProxyMethod> sigmethods : proxyMethods.values()) { |
|
448 |
for (ProxyMethod pm : sigmethods) { |
|
449 |
||
450 |
// add static field for method's Method object |
|
451 |
fields.add(new FieldInfo(pm.methodFieldName, |
|
452 |
"Ljava/lang/reflect/Method;", |
|
453 |
ACC_PRIVATE | ACC_STATIC)); |
|
454 |
||
455 |
// generate code for proxy method and add it |
|
456 |
methods.add(pm.generateMethod()); |
|
457 |
} |
|
458 |
} |
|
459 |
||
460 |
methods.add(generateStaticInitializer()); |
|
461 |
||
462 |
} catch (IOException e) { |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
5506
diff
changeset
|
463 |
throw new InternalError("unexpected I/O Exception", e); |
2 | 464 |
} |
465 |
||
466 |
if (methods.size() > 65535) { |
|
467 |
throw new IllegalArgumentException("method limit exceeded"); |
|
468 |
} |
|
469 |
if (fields.size() > 65535) { |
|
470 |
throw new IllegalArgumentException("field limit exceeded"); |
|
471 |
} |
|
472 |
||
473 |
/* ============================================================ |
|
474 |
* Step 3: Write the final class file. |
|
475 |
*/ |
|
476 |
||
477 |
/* |
|
478 |
* Make sure that constant pool indexes are reserved for the |
|
479 |
* following items before starting to write the final class file. |
|
480 |
*/ |
|
481 |
cp.getClass(dotToSlash(className)); |
|
482 |
cp.getClass(superclassName); |
|
483 |
for (int i = 0; i < interfaces.length; i++) { |
|
484 |
cp.getClass(dotToSlash(interfaces[i].getName())); |
|
485 |
} |
|
486 |
||
487 |
/* |
|
488 |
* Disallow new constant pool additions beyond this point, since |
|
489 |
* we are about to write the final constant pool table. |
|
490 |
*/ |
|
491 |
cp.setReadOnly(); |
|
492 |
||
493 |
ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
|
494 |
DataOutputStream dout = new DataOutputStream(bout); |
|
495 |
||
496 |
try { |
|
497 |
/* |
|
498 |
* Write all the items of the "ClassFile" structure. |
|
499 |
* See JVMS section 4.1. |
|
500 |
*/ |
|
501 |
// u4 magic; |
|
502 |
dout.writeInt(0xCAFEBABE); |
|
503 |
// u2 minor_version; |
|
504 |
dout.writeShort(CLASSFILE_MINOR_VERSION); |
|
505 |
// u2 major_version; |
|
506 |
dout.writeShort(CLASSFILE_MAJOR_VERSION); |
|
507 |
||
508 |
cp.write(dout); // (write constant pool) |
|
509 |
||
510 |
// u2 access_flags; |
|
511 |
dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER); |
|
512 |
// u2 this_class; |
|
513 |
dout.writeShort(cp.getClass(dotToSlash(className))); |
|
514 |
// u2 super_class; |
|
515 |
dout.writeShort(cp.getClass(superclassName)); |
|
516 |
||
517 |
// u2 interfaces_count; |
|
518 |
dout.writeShort(interfaces.length); |
|
519 |
// u2 interfaces[interfaces_count]; |
|
520 |
for (int i = 0; i < interfaces.length; i++) { |
|
521 |
dout.writeShort(cp.getClass( |
|
522 |
dotToSlash(interfaces[i].getName()))); |
|
523 |
} |
|
524 |
||
525 |
// u2 fields_count; |
|
526 |
dout.writeShort(fields.size()); |
|
527 |
// field_info fields[fields_count]; |
|
528 |
for (FieldInfo f : fields) { |
|
529 |
f.write(dout); |
|
530 |
} |
|
531 |
||
532 |
// u2 methods_count; |
|
533 |
dout.writeShort(methods.size()); |
|
534 |
// method_info methods[methods_count]; |
|
535 |
for (MethodInfo m : methods) { |
|
536 |
m.write(dout); |
|
537 |
} |
|
538 |
||
539 |
// u2 attributes_count; |
|
540 |
dout.writeShort(0); // (no ClassFile attributes for proxy classes) |
|
541 |
||
542 |
} catch (IOException e) { |
|
10419
12c063b39232
7084245: Update usages of InternalError to use exception chaining
sherman
parents:
5506
diff
changeset
|
543 |
throw new InternalError("unexpected I/O Exception", e); |
2 | 544 |
} |
545 |
||
546 |
return bout.toByteArray(); |
|
547 |
} |
|
548 |
||
549 |
/** |
|
550 |
* Add another method to be proxied, either by creating a new |
|
551 |
* ProxyMethod object or augmenting an old one for a duplicate |
|
552 |
* method. |
|
553 |
* |
|
554 |
* "fromClass" indicates the proxy interface that the method was |
|
555 |
* found through, which may be different from (a subinterface of) |
|
556 |
* the method's "declaring class". Note that the first Method |
|
557 |
* object passed for a given name and descriptor identifies the |
|
558 |
* Method object (and thus the declaring class) that will be |
|
559 |
* passed to the invocation handler's "invoke" method for a given |
|
560 |
* set of duplicate methods. |
|
561 |
*/ |
|
562 |
private void addProxyMethod(Method m, Class fromClass) { |
|
563 |
String name = m.getName(); |
|
564 |
Class[] parameterTypes = m.getParameterTypes(); |
|
565 |
Class returnType = m.getReturnType(); |
|
566 |
Class[] exceptionTypes = m.getExceptionTypes(); |
|
567 |
||
568 |
String sig = name + getParameterDescriptors(parameterTypes); |
|
569 |
List<ProxyMethod> sigmethods = proxyMethods.get(sig); |
|
570 |
if (sigmethods != null) { |
|
571 |
for (ProxyMethod pm : sigmethods) { |
|
572 |
if (returnType == pm.returnType) { |
|
573 |
/* |
|
574 |
* Found a match: reduce exception types to the |
|
575 |
* greatest set of exceptions that can thrown |
|
576 |
* compatibly with the throws clauses of both |
|
577 |
* overridden methods. |
|
578 |
*/ |
|
51 | 579 |
List<Class<?>> legalExceptions = new ArrayList<Class<?>>(); |
2 | 580 |
collectCompatibleTypes( |
581 |
exceptionTypes, pm.exceptionTypes, legalExceptions); |
|
582 |
collectCompatibleTypes( |
|
583 |
pm.exceptionTypes, exceptionTypes, legalExceptions); |
|
584 |
pm.exceptionTypes = new Class[legalExceptions.size()]; |
|
585 |
pm.exceptionTypes = |
|
586 |
legalExceptions.toArray(pm.exceptionTypes); |
|
587 |
return; |
|
588 |
} |
|
589 |
} |
|
590 |
} else { |
|
591 |
sigmethods = new ArrayList<ProxyMethod>(3); |
|
592 |
proxyMethods.put(sig, sigmethods); |
|
593 |
} |
|
594 |
sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, |
|
595 |
exceptionTypes, fromClass)); |
|
596 |
} |
|
597 |
||
598 |
/** |
|
599 |
* For a given set of proxy methods with the same signature, check |
|
600 |
* that their return types are compatible according to the Proxy |
|
601 |
* specification. |
|
602 |
* |
|
603 |
* Specifically, if there is more than one such method, then all |
|
604 |
* of the return types must be reference types, and there must be |
|
605 |
* one return type that is assignable to each of the rest of them. |
|
606 |
*/ |
|
607 |
private static void checkReturnTypes(List<ProxyMethod> methods) { |
|
608 |
/* |
|
609 |
* If there is only one method with a given signature, there |
|
610 |
* cannot be a conflict. This is the only case in which a |
|
611 |
* primitive (or void) return type is allowed. |
|
612 |
*/ |
|
613 |
if (methods.size() < 2) { |
|
614 |
return; |
|
615 |
} |
|
616 |
||
617 |
/* |
|
618 |
* List of return types that are not yet known to be |
|
619 |
* assignable from ("covered" by) any of the others. |
|
620 |
*/ |
|
51 | 621 |
LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>(); |
2 | 622 |
|
623 |
nextNewReturnType: |
|
624 |
for (ProxyMethod pm : methods) { |
|
51 | 625 |
Class<?> newReturnType = pm.returnType; |
2 | 626 |
if (newReturnType.isPrimitive()) { |
627 |
throw new IllegalArgumentException( |
|
628 |
"methods with same signature " + |
|
629 |
getFriendlyMethodSignature(pm.methodName, |
|
630 |
pm.parameterTypes) + |
|
631 |
" but incompatible return types: " + |
|
632 |
newReturnType.getName() + " and others"); |
|
633 |
} |
|
634 |
boolean added = false; |
|
635 |
||
636 |
/* |
|
637 |
* Compare the new return type to the existing uncovered |
|
638 |
* return types. |
|
639 |
*/ |
|
51 | 640 |
ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator(); |
2 | 641 |
while (liter.hasNext()) { |
51 | 642 |
Class<?> uncoveredReturnType = liter.next(); |
2 | 643 |
|
644 |
/* |
|
645 |
* If an existing uncovered return type is assignable |
|
646 |
* to this new one, then we can forget the new one. |
|
647 |
*/ |
|
648 |
if (newReturnType.isAssignableFrom(uncoveredReturnType)) { |
|
649 |
assert !added; |
|
650 |
continue nextNewReturnType; |
|
651 |
} |
|
652 |
||
653 |
/* |
|
654 |
* If the new return type is assignable to an existing |
|
655 |
* uncovered one, then should replace the existing one |
|
656 |
* with the new one (or just forget the existing one, |
|
657 |
* if the new one has already be put in the list). |
|
658 |
*/ |
|
659 |
if (uncoveredReturnType.isAssignableFrom(newReturnType)) { |
|
660 |
// (we can assume that each return type is unique) |
|
661 |
if (!added) { |
|
662 |
liter.set(newReturnType); |
|
663 |
added = true; |
|
664 |
} else { |
|
665 |
liter.remove(); |
|
666 |
} |
|
667 |
} |
|
668 |
} |
|
669 |
||
670 |
/* |
|
671 |
* If we got through the list of existing uncovered return |
|
672 |
* types without an assignability relationship, then add |
|
673 |
* the new return type to the list of uncovered ones. |
|
674 |
*/ |
|
675 |
if (!added) { |
|
676 |
uncoveredReturnTypes.add(newReturnType); |
|
677 |
} |
|
678 |
} |
|
679 |
||
680 |
/* |
|
681 |
* We shouldn't end up with more than one return type that is |
|
682 |
* not assignable from any of the others. |
|
683 |
*/ |
|
684 |
if (uncoveredReturnTypes.size() > 1) { |
|
685 |
ProxyMethod pm = methods.get(0); |
|
686 |
throw new IllegalArgumentException( |
|
687 |
"methods with same signature " + |
|
688 |
getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) + |
|
689 |
" but incompatible return types: " + uncoveredReturnTypes); |
|
690 |
} |
|
691 |
} |
|
692 |
||
693 |
/** |
|
694 |
* A FieldInfo object contains information about a particular field |
|
695 |
* in the class being generated. The class mirrors the data items of |
|
696 |
* the "field_info" structure of the class file format (see JVMS 4.5). |
|
697 |
*/ |
|
698 |
private class FieldInfo { |
|
699 |
public int accessFlags; |
|
700 |
public String name; |
|
701 |
public String descriptor; |
|
702 |
||
703 |
public FieldInfo(String name, String descriptor, int accessFlags) { |
|
704 |
this.name = name; |
|
705 |
this.descriptor = descriptor; |
|
706 |
this.accessFlags = accessFlags; |
|
707 |
||
708 |
/* |
|
709 |
* Make sure that constant pool indexes are reserved for the |
|
710 |
* following items before starting to write the final class file. |
|
711 |
*/ |
|
712 |
cp.getUtf8(name); |
|
713 |
cp.getUtf8(descriptor); |
|
714 |
} |
|
715 |
||
716 |
public void write(DataOutputStream out) throws IOException { |
|
717 |
/* |
|
718 |
* Write all the items of the "field_info" structure. |
|
719 |
* See JVMS section 4.5. |
|
720 |
*/ |
|
721 |
// u2 access_flags; |
|
722 |
out.writeShort(accessFlags); |
|
723 |
// u2 name_index; |
|
724 |
out.writeShort(cp.getUtf8(name)); |
|
725 |
// u2 descriptor_index; |
|
726 |
out.writeShort(cp.getUtf8(descriptor)); |
|
727 |
// u2 attributes_count; |
|
728 |
out.writeShort(0); // (no field_info attributes for proxy classes) |
|
729 |
} |
|
730 |
} |
|
731 |
||
732 |
/** |
|
733 |
* An ExceptionTableEntry object holds values for the data items of |
|
734 |
* an entry in the "exception_table" item of the "Code" attribute of |
|
735 |
* "method_info" structures (see JVMS 4.7.3). |
|
736 |
*/ |
|
737 |
private static class ExceptionTableEntry { |
|
738 |
public short startPc; |
|
739 |
public short endPc; |
|
740 |
public short handlerPc; |
|
741 |
public short catchType; |
|
742 |
||
743 |
public ExceptionTableEntry(short startPc, short endPc, |
|
744 |
short handlerPc, short catchType) |
|
745 |
{ |
|
746 |
this.startPc = startPc; |
|
747 |
this.endPc = endPc; |
|
748 |
this.handlerPc = handlerPc; |
|
749 |
this.catchType = catchType; |
|
750 |
} |
|
751 |
}; |
|
752 |
||
753 |
/** |
|
754 |
* A MethodInfo object contains information about a particular method |
|
755 |
* in the class being generated. This class mirrors the data items of |
|
756 |
* the "method_info" structure of the class file format (see JVMS 4.6). |
|
757 |
*/ |
|
758 |
private class MethodInfo { |
|
759 |
public int accessFlags; |
|
760 |
public String name; |
|
761 |
public String descriptor; |
|
762 |
public short maxStack; |
|
763 |
public short maxLocals; |
|
764 |
public ByteArrayOutputStream code = new ByteArrayOutputStream(); |
|
765 |
public List<ExceptionTableEntry> exceptionTable = |
|
766 |
new ArrayList<ExceptionTableEntry>(); |
|
767 |
public short[] declaredExceptions; |
|
768 |
||
769 |
public MethodInfo(String name, String descriptor, int accessFlags) { |
|
770 |
this.name = name; |
|
771 |
this.descriptor = descriptor; |
|
772 |
this.accessFlags = accessFlags; |
|
773 |
||
774 |
/* |
|
775 |
* Make sure that constant pool indexes are reserved for the |
|
776 |
* following items before starting to write the final class file. |
|
777 |
*/ |
|
778 |
cp.getUtf8(name); |
|
779 |
cp.getUtf8(descriptor); |
|
780 |
cp.getUtf8("Code"); |
|
781 |
cp.getUtf8("Exceptions"); |
|
782 |
} |
|
783 |
||
784 |
public void write(DataOutputStream out) throws IOException { |
|
785 |
/* |
|
786 |
* Write all the items of the "method_info" structure. |
|
787 |
* See JVMS section 4.6. |
|
788 |
*/ |
|
789 |
// u2 access_flags; |
|
790 |
out.writeShort(accessFlags); |
|
791 |
// u2 name_index; |
|
792 |
out.writeShort(cp.getUtf8(name)); |
|
793 |
// u2 descriptor_index; |
|
794 |
out.writeShort(cp.getUtf8(descriptor)); |
|
795 |
// u2 attributes_count; |
|
796 |
out.writeShort(2); // (two method_info attributes:) |
|
797 |
||
798 |
// Write "Code" attribute. See JVMS section 4.7.3. |
|
799 |
||
800 |
// u2 attribute_name_index; |
|
801 |
out.writeShort(cp.getUtf8("Code")); |
|
802 |
// u4 attribute_length; |
|
803 |
out.writeInt(12 + code.size() + 8 * exceptionTable.size()); |
|
804 |
// u2 max_stack; |
|
805 |
out.writeShort(maxStack); |
|
806 |
// u2 max_locals; |
|
807 |
out.writeShort(maxLocals); |
|
808 |
// u2 code_length; |
|
809 |
out.writeInt(code.size()); |
|
810 |
// u1 code[code_length]; |
|
811 |
code.writeTo(out); |
|
812 |
// u2 exception_table_length; |
|
813 |
out.writeShort(exceptionTable.size()); |
|
814 |
for (ExceptionTableEntry e : exceptionTable) { |
|
815 |
// u2 start_pc; |
|
816 |
out.writeShort(e.startPc); |
|
817 |
// u2 end_pc; |
|
818 |
out.writeShort(e.endPc); |
|
819 |
// u2 handler_pc; |
|
820 |
out.writeShort(e.handlerPc); |
|
821 |
// u2 catch_type; |
|
822 |
out.writeShort(e.catchType); |
|
823 |
} |
|
824 |
// u2 attributes_count; |
|
825 |
out.writeShort(0); |
|
826 |
||
827 |
// write "Exceptions" attribute. See JVMS section 4.7.4. |
|
828 |
||
829 |
// u2 attribute_name_index; |
|
830 |
out.writeShort(cp.getUtf8("Exceptions")); |
|
831 |
// u4 attributes_length; |
|
832 |
out.writeInt(2 + 2 * declaredExceptions.length); |
|
833 |
// u2 number_of_exceptions; |
|
834 |
out.writeShort(declaredExceptions.length); |
|
835 |
// u2 exception_index_table[number_of_exceptions]; |
|
836 |
for (int i = 0; i < declaredExceptions.length; i++) { |
|
837 |
out.writeShort(declaredExceptions[i]); |
|
838 |
} |
|
839 |
} |
|
840 |
||
841 |
} |
|
842 |
||
843 |
/** |
|
844 |
* A ProxyMethod object represents a proxy method in the proxy class |
|
845 |
* being generated: a method whose implementation will encode and |
|
846 |
* dispatch invocations to the proxy instance's invocation handler. |
|
847 |
*/ |
|
848 |
private class ProxyMethod { |
|
849 |
||
850 |
public String methodName; |
|
851 |
public Class[] parameterTypes; |
|
852 |
public Class returnType; |
|
853 |
public Class[] exceptionTypes; |
|
854 |
public Class fromClass; |
|
855 |
public String methodFieldName; |
|
856 |
||
857 |
private ProxyMethod(String methodName, Class[] parameterTypes, |
|
858 |
Class returnType, Class[] exceptionTypes, |
|
859 |
Class fromClass) |
|
860 |
{ |
|
861 |
this.methodName = methodName; |
|
862 |
this.parameterTypes = parameterTypes; |
|
863 |
this.returnType = returnType; |
|
864 |
this.exceptionTypes = exceptionTypes; |
|
865 |
this.fromClass = fromClass; |
|
866 |
this.methodFieldName = "m" + proxyMethodCount++; |
|
867 |
} |
|
868 |
||
869 |
/** |
|
870 |
* Return a MethodInfo object for this method, including generating |
|
871 |
* the code and exception table entry. |
|
872 |
*/ |
|
873 |
private MethodInfo generateMethod() throws IOException { |
|
874 |
String desc = getMethodDescriptor(parameterTypes, returnType); |
|
875 |
MethodInfo minfo = new MethodInfo(methodName, desc, |
|
876 |
ACC_PUBLIC | ACC_FINAL); |
|
877 |
||
878 |
int[] parameterSlot = new int[parameterTypes.length]; |
|
879 |
int nextSlot = 1; |
|
880 |
for (int i = 0; i < parameterSlot.length; i++) { |
|
881 |
parameterSlot[i] = nextSlot; |
|
882 |
nextSlot += getWordsPerType(parameterTypes[i]); |
|
883 |
} |
|
884 |
int localSlot0 = nextSlot; |
|
885 |
short pc, tryBegin = 0, tryEnd; |
|
886 |
||
887 |
DataOutputStream out = new DataOutputStream(minfo.code); |
|
888 |
||
889 |
code_aload(0, out); |
|
890 |
||
891 |
out.writeByte(opc_getfield); |
|
892 |
out.writeShort(cp.getFieldRef( |
|
893 |
superclassName, |
|
894 |
handlerFieldName, "Ljava/lang/reflect/InvocationHandler;")); |
|
895 |
||
896 |
code_aload(0, out); |
|
897 |
||
898 |
out.writeByte(opc_getstatic); |
|
899 |
out.writeShort(cp.getFieldRef( |
|
900 |
dotToSlash(className), |
|
901 |
methodFieldName, "Ljava/lang/reflect/Method;")); |
|
902 |
||
903 |
if (parameterTypes.length > 0) { |
|
904 |
||
905 |
code_ipush(parameterTypes.length, out); |
|
906 |
||
907 |
out.writeByte(opc_anewarray); |
|
908 |
out.writeShort(cp.getClass("java/lang/Object")); |
|
909 |
||
910 |
for (int i = 0; i < parameterTypes.length; i++) { |
|
911 |
||
912 |
out.writeByte(opc_dup); |
|
913 |
||
914 |
code_ipush(i, out); |
|
915 |
||
916 |
codeWrapArgument(parameterTypes[i], parameterSlot[i], out); |
|
917 |
||
918 |
out.writeByte(opc_aastore); |
|
919 |
} |
|
920 |
} else { |
|
921 |
||
922 |
out.writeByte(opc_aconst_null); |
|
923 |
} |
|
924 |
||
925 |
out.writeByte(opc_invokeinterface); |
|
926 |
out.writeShort(cp.getInterfaceMethodRef( |
|
927 |
"java/lang/reflect/InvocationHandler", |
|
928 |
"invoke", |
|
929 |
"(Ljava/lang/Object;Ljava/lang/reflect/Method;" + |
|
930 |
"[Ljava/lang/Object;)Ljava/lang/Object;")); |
|
931 |
out.writeByte(4); |
|
932 |
out.writeByte(0); |
|
933 |
||
934 |
if (returnType == void.class) { |
|
935 |
||
936 |
out.writeByte(opc_pop); |
|
937 |
||
938 |
out.writeByte(opc_return); |
|
939 |
||
940 |
} else { |
|
941 |
||
942 |
codeUnwrapReturnValue(returnType, out); |
|
943 |
} |
|
944 |
||
945 |
tryEnd = pc = (short) minfo.code.size(); |
|
946 |
||
51 | 947 |
List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes); |
2 | 948 |
if (catchList.size() > 0) { |
949 |
||
51 | 950 |
for (Class<?> ex : catchList) { |
2 | 951 |
minfo.exceptionTable.add(new ExceptionTableEntry( |
952 |
tryBegin, tryEnd, pc, |
|
953 |
cp.getClass(dotToSlash(ex.getName())))); |
|
954 |
} |
|
955 |
||
956 |
out.writeByte(opc_athrow); |
|
957 |
||
958 |
pc = (short) minfo.code.size(); |
|
959 |
||
960 |
minfo.exceptionTable.add(new ExceptionTableEntry( |
|
961 |
tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable"))); |
|
962 |
||
963 |
code_astore(localSlot0, out); |
|
964 |
||
965 |
out.writeByte(opc_new); |
|
966 |
out.writeShort(cp.getClass( |
|
967 |
"java/lang/reflect/UndeclaredThrowableException")); |
|
968 |
||
969 |
out.writeByte(opc_dup); |
|
970 |
||
971 |
code_aload(localSlot0, out); |
|
972 |
||
973 |
out.writeByte(opc_invokespecial); |
|
974 |
||
975 |
out.writeShort(cp.getMethodRef( |
|
976 |
"java/lang/reflect/UndeclaredThrowableException", |
|
977 |
"<init>", "(Ljava/lang/Throwable;)V")); |
|
978 |
||
979 |
out.writeByte(opc_athrow); |
|
980 |
} |
|
981 |
||
982 |
if (minfo.code.size() > 65535) { |
|
983 |
throw new IllegalArgumentException("code size limit exceeded"); |
|
984 |
} |
|
985 |
||
986 |
minfo.maxStack = 10; |
|
987 |
minfo.maxLocals = (short) (localSlot0 + 1); |
|
988 |
minfo.declaredExceptions = new short[exceptionTypes.length]; |
|
989 |
for (int i = 0; i < exceptionTypes.length; i++) { |
|
990 |
minfo.declaredExceptions[i] = cp.getClass( |
|
991 |
dotToSlash(exceptionTypes[i].getName())); |
|
992 |
} |
|
993 |
||
994 |
return minfo; |
|
995 |
} |
|
996 |
||
997 |
/** |
|
998 |
* Generate code for wrapping an argument of the given type |
|
999 |
* whose value can be found at the specified local variable |
|
1000 |
* index, in order for it to be passed (as an Object) to the |
|
1001 |
* invocation handler's "invoke" method. The code is written |
|
1002 |
* to the supplied stream. |
|
1003 |
*/ |
|
1004 |
private void codeWrapArgument(Class type, int slot, |
|
1005 |
DataOutputStream out) |
|
1006 |
throws IOException |
|
1007 |
{ |
|
1008 |
if (type.isPrimitive()) { |
|
1009 |
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type); |
|
1010 |
||
1011 |
if (type == int.class || |
|
1012 |
type == boolean.class || |
|
1013 |
type == byte.class || |
|
1014 |
type == char.class || |
|
1015 |
type == short.class) |
|
1016 |
{ |
|
1017 |
code_iload(slot, out); |
|
1018 |
} else if (type == long.class) { |
|
1019 |
code_lload(slot, out); |
|
1020 |
} else if (type == float.class) { |
|
1021 |
code_fload(slot, out); |
|
1022 |
} else if (type == double.class) { |
|
1023 |
code_dload(slot, out); |
|
1024 |
} else { |
|
1025 |
throw new AssertionError(); |
|
1026 |
} |
|
1027 |
||
1028 |
out.writeByte(opc_invokestatic); |
|
1029 |
out.writeShort(cp.getMethodRef( |
|
1030 |
prim.wrapperClassName, |
|
1031 |
"valueOf", prim.wrapperValueOfDesc)); |
|
1032 |
||
1033 |
} else { |
|
1034 |
||
1035 |
code_aload(slot, out); |
|
1036 |
} |
|
1037 |
} |
|
1038 |
||
1039 |
/** |
|
1040 |
* Generate code for unwrapping a return value of the given |
|
1041 |
* type from the invocation handler's "invoke" method (as type |
|
1042 |
* Object) to its correct type. The code is written to the |
|
1043 |
* supplied stream. |
|
1044 |
*/ |
|
1045 |
private void codeUnwrapReturnValue(Class type, DataOutputStream out) |
|
1046 |
throws IOException |
|
1047 |
{ |
|
1048 |
if (type.isPrimitive()) { |
|
1049 |
PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type); |
|
1050 |
||
1051 |
out.writeByte(opc_checkcast); |
|
1052 |
out.writeShort(cp.getClass(prim.wrapperClassName)); |
|
1053 |
||
1054 |
out.writeByte(opc_invokevirtual); |
|
1055 |
out.writeShort(cp.getMethodRef( |
|
1056 |
prim.wrapperClassName, |
|
1057 |
prim.unwrapMethodName, prim.unwrapMethodDesc)); |
|
1058 |
||
1059 |
if (type == int.class || |
|
1060 |
type == boolean.class || |
|
1061 |
type == byte.class || |
|
1062 |
type == char.class || |
|
1063 |
type == short.class) |
|
1064 |
{ |
|
1065 |
out.writeByte(opc_ireturn); |
|
1066 |
} else if (type == long.class) { |
|
1067 |
out.writeByte(opc_lreturn); |
|
1068 |
} else if (type == float.class) { |
|
1069 |
out.writeByte(opc_freturn); |
|
1070 |
} else if (type == double.class) { |
|
1071 |
out.writeByte(opc_dreturn); |
|
1072 |
} else { |
|
1073 |
throw new AssertionError(); |
|
1074 |
} |
|
1075 |
||
1076 |
} else { |
|
1077 |
||
1078 |
out.writeByte(opc_checkcast); |
|
1079 |
out.writeShort(cp.getClass(dotToSlash(type.getName()))); |
|
1080 |
||
1081 |
out.writeByte(opc_areturn); |
|
1082 |
} |
|
1083 |
} |
|
1084 |
||
1085 |
/** |
|
1086 |
* Generate code for initializing the static field that stores |
|
1087 |
* the Method object for this proxy method. The code is written |
|
1088 |
* to the supplied stream. |
|
1089 |
*/ |
|
1090 |
private void codeFieldInitialization(DataOutputStream out) |
|
1091 |
throws IOException |
|
1092 |
{ |
|
1093 |
codeClassForName(fromClass, out); |
|
1094 |
||
1095 |
code_ldc(cp.getString(methodName), out); |
|
1096 |
||
1097 |
code_ipush(parameterTypes.length, out); |
|
1098 |
||
1099 |
out.writeByte(opc_anewarray); |
|
1100 |
out.writeShort(cp.getClass("java/lang/Class")); |
|
1101 |
||
1102 |
for (int i = 0; i < parameterTypes.length; i++) { |
|
1103 |
||
1104 |
out.writeByte(opc_dup); |
|
1105 |
||
1106 |
code_ipush(i, out); |
|
1107 |
||
1108 |
if (parameterTypes[i].isPrimitive()) { |
|
1109 |
PrimitiveTypeInfo prim = |
|
1110 |
PrimitiveTypeInfo.get(parameterTypes[i]); |
|
1111 |
||
1112 |
out.writeByte(opc_getstatic); |
|
1113 |
out.writeShort(cp.getFieldRef( |
|
1114 |
prim.wrapperClassName, "TYPE", "Ljava/lang/Class;")); |
|
1115 |
||
1116 |
} else { |
|
1117 |
codeClassForName(parameterTypes[i], out); |
|
1118 |
} |
|
1119 |
||
1120 |
out.writeByte(opc_aastore); |
|
1121 |
} |
|
1122 |
||
1123 |
out.writeByte(opc_invokevirtual); |
|
1124 |
out.writeShort(cp.getMethodRef( |
|
1125 |
"java/lang/Class", |
|
1126 |
"getMethod", |
|
1127 |
"(Ljava/lang/String;[Ljava/lang/Class;)" + |
|
1128 |
"Ljava/lang/reflect/Method;")); |
|
1129 |
||
1130 |
out.writeByte(opc_putstatic); |
|
1131 |
out.writeShort(cp.getFieldRef( |
|
1132 |
dotToSlash(className), |
|
1133 |
methodFieldName, "Ljava/lang/reflect/Method;")); |
|
1134 |
} |
|
1135 |
} |
|
1136 |
||
1137 |
/** |
|
1138 |
* Generate the constructor method for the proxy class. |
|
1139 |
*/ |
|
1140 |
private MethodInfo generateConstructor() throws IOException { |
|
1141 |
MethodInfo minfo = new MethodInfo( |
|
1142 |
"<init>", "(Ljava/lang/reflect/InvocationHandler;)V", |
|
1143 |
ACC_PUBLIC); |
|
1144 |
||
1145 |
DataOutputStream out = new DataOutputStream(minfo.code); |
|
1146 |
||
1147 |
code_aload(0, out); |
|
1148 |
||
1149 |
code_aload(1, out); |
|
1150 |
||
1151 |
out.writeByte(opc_invokespecial); |
|
1152 |
out.writeShort(cp.getMethodRef( |
|
1153 |
superclassName, |
|
1154 |
"<init>", "(Ljava/lang/reflect/InvocationHandler;)V")); |
|
1155 |
||
1156 |
out.writeByte(opc_return); |
|
1157 |
||
1158 |
minfo.maxStack = 10; |
|
1159 |
minfo.maxLocals = 2; |
|
1160 |
minfo.declaredExceptions = new short[0]; |
|
1161 |
||
1162 |
return minfo; |
|
1163 |
} |
|
1164 |
||
1165 |
/** |
|
1166 |
* Generate the static initializer method for the proxy class. |
|
1167 |
*/ |
|
1168 |
private MethodInfo generateStaticInitializer() throws IOException { |
|
1169 |
MethodInfo minfo = new MethodInfo( |
|
1170 |
"<clinit>", "()V", ACC_STATIC); |
|
1171 |
||
1172 |
int localSlot0 = 1; |
|
1173 |
short pc, tryBegin = 0, tryEnd; |
|
1174 |
||
1175 |
DataOutputStream out = new DataOutputStream(minfo.code); |
|
1176 |
||
1177 |
for (List<ProxyMethod> sigmethods : proxyMethods.values()) { |
|
1178 |
for (ProxyMethod pm : sigmethods) { |
|
1179 |
pm.codeFieldInitialization(out); |
|
1180 |
} |
|
1181 |
} |
|
1182 |
||
1183 |
out.writeByte(opc_return); |
|
1184 |
||
1185 |
tryEnd = pc = (short) minfo.code.size(); |
|
1186 |
||
1187 |
minfo.exceptionTable.add(new ExceptionTableEntry( |
|
1188 |
tryBegin, tryEnd, pc, |
|
1189 |
cp.getClass("java/lang/NoSuchMethodException"))); |
|
1190 |
||
1191 |
code_astore(localSlot0, out); |
|
1192 |
||
1193 |
out.writeByte(opc_new); |
|
1194 |
out.writeShort(cp.getClass("java/lang/NoSuchMethodError")); |
|
1195 |
||
1196 |
out.writeByte(opc_dup); |
|
1197 |
||
1198 |
code_aload(localSlot0, out); |
|
1199 |
||
1200 |
out.writeByte(opc_invokevirtual); |
|
1201 |
out.writeShort(cp.getMethodRef( |
|
1202 |
"java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); |
|
1203 |
||
1204 |
out.writeByte(opc_invokespecial); |
|
1205 |
out.writeShort(cp.getMethodRef( |
|
1206 |
"java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V")); |
|
1207 |
||
1208 |
out.writeByte(opc_athrow); |
|
1209 |
||
1210 |
pc = (short) minfo.code.size(); |
|
1211 |
||
1212 |
minfo.exceptionTable.add(new ExceptionTableEntry( |
|
1213 |
tryBegin, tryEnd, pc, |
|
1214 |
cp.getClass("java/lang/ClassNotFoundException"))); |
|
1215 |
||
1216 |
code_astore(localSlot0, out); |
|
1217 |
||
1218 |
out.writeByte(opc_new); |
|
1219 |
out.writeShort(cp.getClass("java/lang/NoClassDefFoundError")); |
|
1220 |
||
1221 |
out.writeByte(opc_dup); |
|
1222 |
||
1223 |
code_aload(localSlot0, out); |
|
1224 |
||
1225 |
out.writeByte(opc_invokevirtual); |
|
1226 |
out.writeShort(cp.getMethodRef( |
|
1227 |
"java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); |
|
1228 |
||
1229 |
out.writeByte(opc_invokespecial); |
|
1230 |
out.writeShort(cp.getMethodRef( |
|
1231 |
"java/lang/NoClassDefFoundError", |
|
1232 |
"<init>", "(Ljava/lang/String;)V")); |
|
1233 |
||
1234 |
out.writeByte(opc_athrow); |
|
1235 |
||
1236 |
if (minfo.code.size() > 65535) { |
|
1237 |
throw new IllegalArgumentException("code size limit exceeded"); |
|
1238 |
} |
|
1239 |
||
1240 |
minfo.maxStack = 10; |
|
1241 |
minfo.maxLocals = (short) (localSlot0 + 1); |
|
1242 |
minfo.declaredExceptions = new short[0]; |
|
1243 |
||
1244 |
return minfo; |
|
1245 |
} |
|
1246 |
||
1247 |
||
1248 |
/* |
|
1249 |
* =============== Code Generation Utility Methods =============== |
|
1250 |
*/ |
|
1251 |
||
1252 |
/* |
|
1253 |
* The following methods generate code for the load or store operation |
|
1254 |
* indicated by their name for the given local variable. The code is |
|
1255 |
* written to the supplied stream. |
|
1256 |
*/ |
|
1257 |
||
1258 |
private void code_iload(int lvar, DataOutputStream out) |
|
1259 |
throws IOException |
|
1260 |
{ |
|
1261 |
codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out); |
|
1262 |
} |
|
1263 |
||
1264 |
private void code_lload(int lvar, DataOutputStream out) |
|
1265 |
throws IOException |
|
1266 |
{ |
|
1267 |
codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out); |
|
1268 |
} |
|
1269 |
||
1270 |
private void code_fload(int lvar, DataOutputStream out) |
|
1271 |
throws IOException |
|
1272 |
{ |
|
1273 |
codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out); |
|
1274 |
} |
|
1275 |
||
1276 |
private void code_dload(int lvar, DataOutputStream out) |
|
1277 |
throws IOException |
|
1278 |
{ |
|
1279 |
codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out); |
|
1280 |
} |
|
1281 |
||
1282 |
private void code_aload(int lvar, DataOutputStream out) |
|
1283 |
throws IOException |
|
1284 |
{ |
|
1285 |
codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out); |
|
1286 |
} |
|
1287 |
||
1288 |
// private void code_istore(int lvar, DataOutputStream out) |
|
1289 |
// throws IOException |
|
1290 |
// { |
|
1291 |
// codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out); |
|
1292 |
// } |
|
1293 |
||
1294 |
// private void code_lstore(int lvar, DataOutputStream out) |
|
1295 |
// throws IOException |
|
1296 |
// { |
|
1297 |
// codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out); |
|
1298 |
// } |
|
1299 |
||
1300 |
// private void code_fstore(int lvar, DataOutputStream out) |
|
1301 |
// throws IOException |
|
1302 |
// { |
|
1303 |
// codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out); |
|
1304 |
// } |
|
1305 |
||
1306 |
// private void code_dstore(int lvar, DataOutputStream out) |
|
1307 |
// throws IOException |
|
1308 |
// { |
|
1309 |
// codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out); |
|
1310 |
// } |
|
1311 |
||
1312 |
private void code_astore(int lvar, DataOutputStream out) |
|
1313 |
throws IOException |
|
1314 |
{ |
|
1315 |
codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out); |
|
1316 |
} |
|
1317 |
||
1318 |
/** |
|
1319 |
* Generate code for a load or store instruction for the given local |
|
1320 |
* variable. The code is written to the supplied stream. |
|
1321 |
* |
|
1322 |
* "opcode" indicates the opcode form of the desired load or store |
|
1323 |
* instruction that takes an explicit local variable index, and |
|
1324 |
* "opcode_0" indicates the corresponding form of the instruction |
|
1325 |
* with the implicit index 0. |
|
1326 |
*/ |
|
1327 |
private void codeLocalLoadStore(int lvar, int opcode, int opcode_0, |
|
1328 |
DataOutputStream out) |
|
1329 |
throws IOException |
|
1330 |
{ |
|
1331 |
assert lvar >= 0 && lvar <= 0xFFFF; |
|
1332 |
if (lvar <= 3) { |
|
1333 |
out.writeByte(opcode_0 + lvar); |
|
1334 |
} else if (lvar <= 0xFF) { |
|
1335 |
out.writeByte(opcode); |
|
1336 |
out.writeByte(lvar & 0xFF); |
|
1337 |
} else { |
|
1338 |
/* |
|
1339 |
* Use the "wide" instruction modifier for local variable |
|
1340 |
* indexes that do not fit into an unsigned byte. |
|
1341 |
*/ |
|
1342 |
out.writeByte(opc_wide); |
|
1343 |
out.writeByte(opcode); |
|
1344 |
out.writeShort(lvar & 0xFFFF); |
|
1345 |
} |
|
1346 |
} |
|
1347 |
||
1348 |
/** |
|
1349 |
* Generate code for an "ldc" instruction for the given constant pool |
|
1350 |
* index (the "ldc_w" instruction is used if the index does not fit |
|
1351 |
* into an unsigned byte). The code is written to the supplied stream. |
|
1352 |
*/ |
|
1353 |
private void code_ldc(int index, DataOutputStream out) |
|
1354 |
throws IOException |
|
1355 |
{ |
|
1356 |
assert index >= 0 && index <= 0xFFFF; |
|
1357 |
if (index <= 0xFF) { |
|
1358 |
out.writeByte(opc_ldc); |
|
1359 |
out.writeByte(index & 0xFF); |
|
1360 |
} else { |
|
1361 |
out.writeByte(opc_ldc_w); |
|
1362 |
out.writeShort(index & 0xFFFF); |
|
1363 |
} |
|
1364 |
} |
|
1365 |
||
1366 |
/** |
|
1367 |
* Generate code to push a constant integer value on to the operand |
|
1368 |
* stack, using the "iconst_<i>", "bipush", or "sipush" instructions |
|
1369 |
* depending on the size of the value. The code is written to the |
|
1370 |
* supplied stream. |
|
1371 |
*/ |
|
1372 |
private void code_ipush(int value, DataOutputStream out) |
|
1373 |
throws IOException |
|
1374 |
{ |
|
1375 |
if (value >= -1 && value <= 5) { |
|
1376 |
out.writeByte(opc_iconst_0 + value); |
|
1377 |
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { |
|
1378 |
out.writeByte(opc_bipush); |
|
1379 |
out.writeByte(value & 0xFF); |
|
1380 |
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { |
|
1381 |
out.writeByte(opc_sipush); |
|
1382 |
out.writeShort(value & 0xFFFF); |
|
1383 |
} else { |
|
1384 |
throw new AssertionError(); |
|
1385 |
} |
|
1386 |
} |
|
1387 |
||
1388 |
/** |
|
1389 |
* Generate code to invoke the Class.forName with the name of the given |
|
1390 |
* class to get its Class object at runtime. The code is written to |
|
1391 |
* the supplied stream. Note that the code generated by this method |
|
1392 |
* may caused the checked ClassNotFoundException to be thrown. |
|
1393 |
*/ |
|
1394 |
private void codeClassForName(Class cl, DataOutputStream out) |
|
1395 |
throws IOException |
|
1396 |
{ |
|
1397 |
code_ldc(cp.getString(cl.getName()), out); |
|
1398 |
||
1399 |
out.writeByte(opc_invokestatic); |
|
1400 |
out.writeShort(cp.getMethodRef( |
|
1401 |
"java/lang/Class", |
|
1402 |
"forName", "(Ljava/lang/String;)Ljava/lang/Class;")); |
|
1403 |
} |
|
1404 |
||
1405 |
||
1406 |
/* |
|
1407 |
* ==================== General Utility Methods ==================== |
|
1408 |
*/ |
|
1409 |
||
1410 |
/** |
|
1411 |
* Convert a fully qualified class name that uses '.' as the package |
|
1412 |
* separator, the external representation used by the Java language |
|
1413 |
* and APIs, to a fully qualified class name that uses '/' as the |
|
1414 |
* package separator, the representation used in the class file |
|
1415 |
* format (see JVMS section 4.2). |
|
1416 |
*/ |
|
1417 |
private static String dotToSlash(String name) { |
|
1418 |
return name.replace('.', '/'); |
|
1419 |
} |
|
1420 |
||
1421 |
/** |
|
1422 |
* Return the "method descriptor" string for a method with the given |
|
1423 |
* parameter types and return type. See JVMS section 4.3.3. |
|
1424 |
*/ |
|
1425 |
private static String getMethodDescriptor(Class[] parameterTypes, |
|
1426 |
Class returnType) |
|
1427 |
{ |
|
1428 |
return getParameterDescriptors(parameterTypes) + |
|
1429 |
((returnType == void.class) ? "V" : getFieldType(returnType)); |
|
1430 |
} |
|
1431 |
||
1432 |
/** |
|
1433 |
* Return the list of "parameter descriptor" strings enclosed in |
|
1434 |
* parentheses corresponding to the given parameter types (in other |
|
1435 |
* words, a method descriptor without a return descriptor). This |
|
1436 |
* string is useful for constructing string keys for methods without |
|
1437 |
* regard to their return type. |
|
1438 |
*/ |
|
1439 |
private static String getParameterDescriptors(Class[] parameterTypes) { |
|
1440 |
StringBuilder desc = new StringBuilder("("); |
|
1441 |
for (int i = 0; i < parameterTypes.length; i++) { |
|
1442 |
desc.append(getFieldType(parameterTypes[i])); |
|
1443 |
} |
|
1444 |
desc.append(')'); |
|
1445 |
return desc.toString(); |
|
1446 |
} |
|
1447 |
||
1448 |
/** |
|
1449 |
* Return the "field type" string for the given type, appropriate for |
|
1450 |
* a field descriptor, a parameter descriptor, or a return descriptor |
|
1451 |
* other than "void". See JVMS section 4.3.2. |
|
1452 |
*/ |
|
1453 |
private static String getFieldType(Class type) { |
|
1454 |
if (type.isPrimitive()) { |
|
1455 |
return PrimitiveTypeInfo.get(type).baseTypeString; |
|
1456 |
} else if (type.isArray()) { |
|
1457 |
/* |
|
1458 |
* According to JLS 20.3.2, the getName() method on Class does |
|
1459 |
* return the VM type descriptor format for array classes (only); |
|
1460 |
* using that should be quicker than the otherwise obvious code: |
|
1461 |
* |
|
1462 |
* return "[" + getTypeDescriptor(type.getComponentType()); |
|
1463 |
*/ |
|
1464 |
return type.getName().replace('.', '/'); |
|
1465 |
} else { |
|
1466 |
return "L" + dotToSlash(type.getName()) + ";"; |
|
1467 |
} |
|
1468 |
} |
|
1469 |
||
1470 |
/** |
|
1471 |
* Returns a human-readable string representing the signature of a |
|
1472 |
* method with the given name and parameter types. |
|
1473 |
*/ |
|
1474 |
private static String getFriendlyMethodSignature(String name, |
|
1475 |
Class[] parameterTypes) |
|
1476 |
{ |
|
1477 |
StringBuilder sig = new StringBuilder(name); |
|
1478 |
sig.append('('); |
|
1479 |
for (int i = 0; i < parameterTypes.length; i++) { |
|
1480 |
if (i > 0) { |
|
1481 |
sig.append(','); |
|
1482 |
} |
|
1483 |
Class parameterType = parameterTypes[i]; |
|
1484 |
int dimensions = 0; |
|
1485 |
while (parameterType.isArray()) { |
|
1486 |
parameterType = parameterType.getComponentType(); |
|
1487 |
dimensions++; |
|
1488 |
} |
|
1489 |
sig.append(parameterType.getName()); |
|
1490 |
while (dimensions-- > 0) { |
|
1491 |
sig.append("[]"); |
|
1492 |
} |
|
1493 |
} |
|
1494 |
sig.append(')'); |
|
1495 |
return sig.toString(); |
|
1496 |
} |
|
1497 |
||
1498 |
/** |
|
1499 |
* Return the number of abstract "words", or consecutive local variable |
|
1500 |
* indexes, required to contain a value of the given type. See JVMS |
|
1501 |
* section 3.6.1. |
|
1502 |
* |
|
1503 |
* Note that the original version of the JVMS contained a definition of |
|
1504 |
* this abstract notion of a "word" in section 3.4, but that definition |
|
1505 |
* was removed for the second edition. |
|
1506 |
*/ |
|
1507 |
private static int getWordsPerType(Class type) { |
|
1508 |
if (type == long.class || type == double.class) { |
|
1509 |
return 2; |
|
1510 |
} else { |
|
1511 |
return 1; |
|
1512 |
} |
|
1513 |
} |
|
1514 |
||
1515 |
/** |
|
1516 |
* Add to the given list all of the types in the "from" array that |
|
1517 |
* are not already contained in the list and are assignable to at |
|
1518 |
* least one of the types in the "with" array. |
|
1519 |
* |
|
1520 |
* This method is useful for computing the greatest common set of |
|
1521 |
* declared exceptions from duplicate methods inherited from |
|
1522 |
* different interfaces. |
|
1523 |
*/ |
|
51 | 1524 |
private static void collectCompatibleTypes(Class<?>[] from, |
1525 |
Class<?>[] with, |
|
1526 |
List<Class<?>> list) |
|
2 | 1527 |
{ |
1528 |
for (int i = 0; i < from.length; i++) { |
|
1529 |
if (!list.contains(from[i])) { |
|
1530 |
for (int j = 0; j < with.length; j++) { |
|
1531 |
if (with[j].isAssignableFrom(from[i])) { |
|
1532 |
list.add(from[i]); |
|
1533 |
break; |
|
1534 |
} |
|
1535 |
} |
|
1536 |
} |
|
1537 |
} |
|
1538 |
} |
|
1539 |
||
1540 |
/** |
|
1541 |
* Given the exceptions declared in the throws clause of a proxy method, |
|
1542 |
* compute the exceptions that need to be caught from the invocation |
|
1543 |
* handler's invoke method and rethrown intact in the method's |
|
1544 |
* implementation before catching other Throwables and wrapping them |
|
1545 |
* in UndeclaredThrowableExceptions. |
|
1546 |
* |
|
1547 |
* The exceptions to be caught are returned in a List object. Each |
|
1548 |
* exception in the returned list is guaranteed to not be a subclass of |
|
1549 |
* any of the other exceptions in the list, so the catch blocks for |
|
1550 |
* these exceptions may be generated in any order relative to each other. |
|
1551 |
* |
|
1552 |
* Error and RuntimeException are each always contained by the returned |
|
1553 |
* list (if none of their superclasses are contained), since those |
|
1554 |
* unchecked exceptions should always be rethrown intact, and thus their |
|
1555 |
* subclasses will never appear in the returned list. |
|
1556 |
* |
|
1557 |
* The returned List will be empty if java.lang.Throwable is in the |
|
1558 |
* given list of declared exceptions, indicating that no exceptions |
|
1559 |
* need to be caught. |
|
1560 |
*/ |
|
51 | 1561 |
private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) { |
1562 |
List<Class<?>> uniqueList = new ArrayList<Class<?>>(); |
|
2 | 1563 |
// unique exceptions to catch |
1564 |
||
1565 |
uniqueList.add(Error.class); // always catch/rethrow these |
|
1566 |
uniqueList.add(RuntimeException.class); |
|
1567 |
||
1568 |
nextException: |
|
1569 |
for (int i = 0; i < exceptions.length; i++) { |
|
51 | 1570 |
Class<?> ex = exceptions[i]; |
2 | 1571 |
if (ex.isAssignableFrom(Throwable.class)) { |
1572 |
/* |
|
1573 |
* If Throwable is declared to be thrown by the proxy method, |
|
1574 |
* then no catch blocks are necessary, because the invoke |
|
1575 |
* can, at most, throw Throwable anyway. |
|
1576 |
*/ |
|
1577 |
uniqueList.clear(); |
|
1578 |
break; |
|
1579 |
} else if (!Throwable.class.isAssignableFrom(ex)) { |
|
1580 |
/* |
|
1581 |
* Ignore types that cannot be thrown by the invoke method. |
|
1582 |
*/ |
|
1583 |
continue; |
|
1584 |
} |
|
1585 |
/* |
|
1586 |
* Compare this exception against the current list of |
|
1587 |
* exceptions that need to be caught: |
|
1588 |
*/ |
|
1589 |
for (int j = 0; j < uniqueList.size();) { |
|
51 | 1590 |
Class<?> ex2 = uniqueList.get(j); |
2 | 1591 |
if (ex2.isAssignableFrom(ex)) { |
1592 |
/* |
|
1593 |
* if a superclass of this exception is already on |
|
1594 |
* the list to catch, then ignore this one and continue; |
|
1595 |
*/ |
|
1596 |
continue nextException; |
|
1597 |
} else if (ex.isAssignableFrom(ex2)) { |
|
1598 |
/* |
|
1599 |
* if a subclass of this exception is on the list |
|
1600 |
* to catch, then remove it; |
|
1601 |
*/ |
|
1602 |
uniqueList.remove(j); |
|
1603 |
} else { |
|
1604 |
j++; // else continue comparing. |
|
1605 |
} |
|
1606 |
} |
|
1607 |
// This exception is unique (so far): add it to the list to catch. |
|
1608 |
uniqueList.add(ex); |
|
1609 |
} |
|
1610 |
return uniqueList; |
|
1611 |
} |
|
1612 |
||
1613 |
/** |
|
1614 |
* A PrimitiveTypeInfo object contains assorted information about |
|
1615 |
* a primitive type in its public fields. The struct for a particular |
|
1616 |
* primitive type can be obtained using the static "get" method. |
|
1617 |
*/ |
|
1618 |
private static class PrimitiveTypeInfo { |
|
1619 |
||
1620 |
/** "base type" used in various descriptors (see JVMS section 4.3.2) */ |
|
1621 |
public String baseTypeString; |
|
1622 |
||
1623 |
/** name of corresponding wrapper class */ |
|
1624 |
public String wrapperClassName; |
|
1625 |
||
1626 |
/** method descriptor for wrapper class "valueOf" factory method */ |
|
1627 |
public String wrapperValueOfDesc; |
|
1628 |
||
1629 |
/** name of wrapper class method for retrieving primitive value */ |
|
1630 |
public String unwrapMethodName; |
|
1631 |
||
1632 |
/** descriptor of same method */ |
|
1633 |
public String unwrapMethodDesc; |
|
1634 |
||
1635 |
private static Map<Class,PrimitiveTypeInfo> table = |
|
1636 |
new HashMap<Class,PrimitiveTypeInfo>(); |
|
1637 |
static { |
|
1638 |
add(byte.class, Byte.class); |
|
1639 |
add(char.class, Character.class); |
|
1640 |
add(double.class, Double.class); |
|
1641 |
add(float.class, Float.class); |
|
1642 |
add(int.class, Integer.class); |
|
1643 |
add(long.class, Long.class); |
|
1644 |
add(short.class, Short.class); |
|
1645 |
add(boolean.class, Boolean.class); |
|
1646 |
} |
|
1647 |
||
1648 |
private static void add(Class primitiveClass, Class wrapperClass) { |
|
1649 |
table.put(primitiveClass, |
|
1650 |
new PrimitiveTypeInfo(primitiveClass, wrapperClass)); |
|
1651 |
} |
|
1652 |
||
1653 |
private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) { |
|
1654 |
assert primitiveClass.isPrimitive(); |
|
1655 |
||
1656 |
baseTypeString = |
|
1657 |
Array.newInstance(primitiveClass, 0) |
|
1658 |
.getClass().getName().substring(1); |
|
1659 |
wrapperClassName = dotToSlash(wrapperClass.getName()); |
|
1660 |
wrapperValueOfDesc = |
|
1661 |
"(" + baseTypeString + ")L" + wrapperClassName + ";"; |
|
1662 |
unwrapMethodName = primitiveClass.getName() + "Value"; |
|
1663 |
unwrapMethodDesc = "()" + baseTypeString; |
|
1664 |
} |
|
1665 |
||
1666 |
public static PrimitiveTypeInfo get(Class cl) { |
|
1667 |
return table.get(cl); |
|
1668 |
} |
|
1669 |
} |
|
1670 |
||
1671 |
||
1672 |
/** |
|
1673 |
* A ConstantPool object represents the constant pool of a class file |
|
1674 |
* being generated. This representation of a constant pool is designed |
|
1675 |
* specifically for use by ProxyGenerator; in particular, it assumes |
|
1676 |
* that constant pool entries will not need to be resorted (for example, |
|
1677 |
* by their type, as the Java compiler does), so that the final index |
|
1678 |
* value can be assigned and used when an entry is first created. |
|
1679 |
* |
|
1680 |
* Note that new entries cannot be created after the constant pool has |
|
1681 |
* been written to a class file. To prevent such logic errors, a |
|
1682 |
* ConstantPool instance can be marked "read only", so that further |
|
1683 |
* attempts to add new entries will fail with a runtime exception. |
|
1684 |
* |
|
1685 |
* See JVMS section 4.4 for more information about the constant pool |
|
1686 |
* of a class file. |
|
1687 |
*/ |
|
1688 |
private static class ConstantPool { |
|
1689 |
||
1690 |
/** |
|
1691 |
* list of constant pool entries, in constant pool index order. |
|
1692 |
* |
|
1693 |
* This list is used when writing the constant pool to a stream |
|
1694 |
* and for assigning the next index value. Note that element 0 |
|
1695 |
* of this list corresponds to constant pool index 1. |
|
1696 |
*/ |
|
1697 |
private List<Entry> pool = new ArrayList<Entry>(32); |
|
1698 |
||
1699 |
/** |
|
1700 |
* maps constant pool data of all types to constant pool indexes. |
|
1701 |
* |
|
1702 |
* This map is used to look up the index of an existing entry for |
|
1703 |
* values of all types. |
|
1704 |
*/ |
|
1705 |
private Map<Object,Short> map = new HashMap<Object,Short>(16); |
|
1706 |
||
1707 |
/** true if no new constant pool entries may be added */ |
|
1708 |
private boolean readOnly = false; |
|
1709 |
||
1710 |
/** |
|
1711 |
* Get or assign the index for a CONSTANT_Utf8 entry. |
|
1712 |
*/ |
|
1713 |
public short getUtf8(String s) { |
|
1714 |
if (s == null) { |
|
1715 |
throw new NullPointerException(); |
|
1716 |
} |
|
1717 |
return getValue(s); |
|
1718 |
} |
|
1719 |
||
1720 |
/** |
|
1721 |
* Get or assign the index for a CONSTANT_Integer entry. |
|
1722 |
*/ |
|
1723 |
public short getInteger(int i) { |
|
1724 |
return getValue(new Integer(i)); |
|
1725 |
} |
|
1726 |
||
1727 |
/** |
|
1728 |
* Get or assign the index for a CONSTANT_Float entry. |
|
1729 |
*/ |
|
1730 |
public short getFloat(float f) { |
|
1731 |
return getValue(new Float(f)); |
|
1732 |
} |
|
1733 |
||
1734 |
/** |
|
1735 |
* Get or assign the index for a CONSTANT_Class entry. |
|
1736 |
*/ |
|
1737 |
public short getClass(String name) { |
|
1738 |
short utf8Index = getUtf8(name); |
|
1739 |
return getIndirect(new IndirectEntry( |
|
1740 |
CONSTANT_CLASS, utf8Index)); |
|
1741 |
} |
|
1742 |
||
1743 |
/** |
|
1744 |
* Get or assign the index for a CONSTANT_String entry. |
|
1745 |
*/ |
|
1746 |
public short getString(String s) { |
|
1747 |
short utf8Index = getUtf8(s); |
|
1748 |
return getIndirect(new IndirectEntry( |
|
1749 |
CONSTANT_STRING, utf8Index)); |
|
1750 |
} |
|
1751 |
||
1752 |
/** |
|
1753 |
* Get or assign the index for a CONSTANT_FieldRef entry. |
|
1754 |
*/ |
|
1755 |
public short getFieldRef(String className, |
|
1756 |
String name, String descriptor) |
|
1757 |
{ |
|
1758 |
short classIndex = getClass(className); |
|
1759 |
short nameAndTypeIndex = getNameAndType(name, descriptor); |
|
1760 |
return getIndirect(new IndirectEntry( |
|
1761 |
CONSTANT_FIELD, classIndex, nameAndTypeIndex)); |
|
1762 |
} |
|
1763 |
||
1764 |
/** |
|
1765 |
* Get or assign the index for a CONSTANT_MethodRef entry. |
|
1766 |
*/ |
|
1767 |
public short getMethodRef(String className, |
|
1768 |
String name, String descriptor) |
|
1769 |
{ |
|
1770 |
short classIndex = getClass(className); |
|
1771 |
short nameAndTypeIndex = getNameAndType(name, descriptor); |
|
1772 |
return getIndirect(new IndirectEntry( |
|
1773 |
CONSTANT_METHOD, classIndex, nameAndTypeIndex)); |
|
1774 |
} |
|
1775 |
||
1776 |
/** |
|
1777 |
* Get or assign the index for a CONSTANT_InterfaceMethodRef entry. |
|
1778 |
*/ |
|
1779 |
public short getInterfaceMethodRef(String className, String name, |
|
1780 |
String descriptor) |
|
1781 |
{ |
|
1782 |
short classIndex = getClass(className); |
|
1783 |
short nameAndTypeIndex = getNameAndType(name, descriptor); |
|
1784 |
return getIndirect(new IndirectEntry( |
|
1785 |
CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex)); |
|
1786 |
} |
|
1787 |
||
1788 |
/** |
|
1789 |
* Get or assign the index for a CONSTANT_NameAndType entry. |
|
1790 |
*/ |
|
1791 |
public short getNameAndType(String name, String descriptor) { |
|
1792 |
short nameIndex = getUtf8(name); |
|
1793 |
short descriptorIndex = getUtf8(descriptor); |
|
1794 |
return getIndirect(new IndirectEntry( |
|
1795 |
CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex)); |
|
1796 |
} |
|
1797 |
||
1798 |
/** |
|
1799 |
* Set this ConstantPool instance to be "read only". |
|
1800 |
* |
|
1801 |
* After this method has been called, further requests to get |
|
1802 |
* an index for a non-existent entry will cause an InternalError |
|
1803 |
* to be thrown instead of creating of the entry. |
|
1804 |
*/ |
|
1805 |
public void setReadOnly() { |
|
1806 |
readOnly = true; |
|
1807 |
} |
|
1808 |
||
1809 |
/** |
|
1810 |
* Write this constant pool to a stream as part of |
|
1811 |
* the class file format. |
|
1812 |
* |
|
1813 |
* This consists of writing the "constant_pool_count" and |
|
1814 |
* "constant_pool[]" items of the "ClassFile" structure, as |
|
1815 |
* described in JVMS section 4.1. |
|
1816 |
*/ |
|
1817 |
public void write(OutputStream out) throws IOException { |
|
1818 |
DataOutputStream dataOut = new DataOutputStream(out); |
|
1819 |
||
1820 |
// constant_pool_count: number of entries plus one |
|
1821 |
dataOut.writeShort(pool.size() + 1); |
|
1822 |
||
1823 |
for (Entry e : pool) { |
|
1824 |
e.write(dataOut); |
|
1825 |
} |
|
1826 |
} |
|
1827 |
||
1828 |
/** |
|
1829 |
* Add a new constant pool entry and return its index. |
|
1830 |
*/ |
|
1831 |
private short addEntry(Entry entry) { |
|
1832 |
pool.add(entry); |
|
1833 |
/* |
|
1834 |
* Note that this way of determining the index of the |
|
1835 |
* added entry is wrong if this pool supports |
|
1836 |
* CONSTANT_Long or CONSTANT_Double entries. |
|
1837 |
*/ |
|
1838 |
if (pool.size() >= 65535) { |
|
1839 |
throw new IllegalArgumentException( |
|
1840 |
"constant pool size limit exceeded"); |
|
1841 |
} |
|
1842 |
return (short) pool.size(); |
|
1843 |
} |
|
1844 |
||
1845 |
/** |
|
1846 |
* Get or assign the index for an entry of a type that contains |
|
1847 |
* a direct value. The type of the given object determines the |
|
1848 |
* type of the desired entry as follows: |
|
1849 |
* |
|
1850 |
* java.lang.String CONSTANT_Utf8 |
|
1851 |
* java.lang.Integer CONSTANT_Integer |
|
1852 |
* java.lang.Float CONSTANT_Float |
|
1853 |
* java.lang.Long CONSTANT_Long |
|
1854 |
* java.lang.Double CONSTANT_DOUBLE |
|
1855 |
*/ |
|
1856 |
private short getValue(Object key) { |
|
1857 |
Short index = map.get(key); |
|
1858 |
if (index != null) { |
|
1859 |
return index.shortValue(); |
|
1860 |
} else { |
|
1861 |
if (readOnly) { |
|
1862 |
throw new InternalError( |
|
1863 |
"late constant pool addition: " + key); |
|
1864 |
} |
|
1865 |
short i = addEntry(new ValueEntry(key)); |
|
1866 |
map.put(key, new Short(i)); |
|
1867 |
return i; |
|
1868 |
} |
|
1869 |
} |
|
1870 |
||
1871 |
/** |
|
1872 |
* Get or assign the index for an entry of a type that contains |
|
1873 |
* references to other constant pool entries. |
|
1874 |
*/ |
|
1875 |
private short getIndirect(IndirectEntry e) { |
|
1876 |
Short index = map.get(e); |
|
1877 |
if (index != null) { |
|
1878 |
return index.shortValue(); |
|
1879 |
} else { |
|
1880 |
if (readOnly) { |
|
1881 |
throw new InternalError("late constant pool addition"); |
|
1882 |
} |
|
1883 |
short i = addEntry(e); |
|
1884 |
map.put(e, new Short(i)); |
|
1885 |
return i; |
|
1886 |
} |
|
1887 |
} |
|
1888 |
||
1889 |
/** |
|
1890 |
* Entry is the abstact superclass of all constant pool entry types |
|
1891 |
* that can be stored in the "pool" list; its purpose is to define a |
|
1892 |
* common method for writing constant pool entries to a class file. |
|
1893 |
*/ |
|
1894 |
private static abstract class Entry { |
|
1895 |
public abstract void write(DataOutputStream out) |
|
1896 |
throws IOException; |
|
1897 |
} |
|
1898 |
||
1899 |
/** |
|
1900 |
* ValueEntry represents a constant pool entry of a type that |
|
1901 |
* contains a direct value (see the comments for the "getValue" |
|
1902 |
* method for a list of such types). |
|
1903 |
* |
|
1904 |
* ValueEntry objects are not used as keys for their entries in the |
|
1905 |
* Map "map", so no useful hashCode or equals methods are defined. |
|
1906 |
*/ |
|
1907 |
private static class ValueEntry extends Entry { |
|
1908 |
private Object value; |
|
1909 |
||
1910 |
public ValueEntry(Object value) { |
|
1911 |
this.value = value; |
|
1912 |
} |
|
1913 |
||
1914 |
public void write(DataOutputStream out) throws IOException { |
|
1915 |
if (value instanceof String) { |
|
1916 |
out.writeByte(CONSTANT_UTF8); |
|
1917 |
out.writeUTF((String) value); |
|
1918 |
} else if (value instanceof Integer) { |
|
1919 |
out.writeByte(CONSTANT_INTEGER); |
|
1920 |
out.writeInt(((Integer) value).intValue()); |
|
1921 |
} else if (value instanceof Float) { |
|
1922 |
out.writeByte(CONSTANT_FLOAT); |
|
1923 |
out.writeFloat(((Float) value).floatValue()); |
|
1924 |
} else if (value instanceof Long) { |
|
1925 |
out.writeByte(CONSTANT_LONG); |
|
1926 |
out.writeLong(((Long) value).longValue()); |
|
1927 |
} else if (value instanceof Double) { |
|
1928 |
out.writeDouble(CONSTANT_DOUBLE); |
|
1929 |
out.writeDouble(((Double) value).doubleValue()); |
|
1930 |
} else { |
|
1931 |
throw new InternalError("bogus value entry: " + value); |
|
1932 |
} |
|
1933 |
} |
|
1934 |
} |
|
1935 |
||
1936 |
/** |
|
1937 |
* IndirectEntry represents a constant pool entry of a type that |
|
1938 |
* references other constant pool entries, i.e., the following types: |
|
1939 |
* |
|
1940 |
* CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref, |
|
1941 |
* CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and |
|
1942 |
* CONSTANT_NameAndType. |
|
1943 |
* |
|
1944 |
* Each of these entry types contains either one or two indexes of |
|
1945 |
* other constant pool entries. |
|
1946 |
* |
|
1947 |
* IndirectEntry objects are used as the keys for their entries in |
|
1948 |
* the Map "map", so the hashCode and equals methods are overridden |
|
1949 |
* to allow matching. |
|
1950 |
*/ |
|
1951 |
private static class IndirectEntry extends Entry { |
|
1952 |
private int tag; |
|
1953 |
private short index0; |
|
1954 |
private short index1; |
|
1955 |
||
1956 |
/** |
|
1957 |
* Construct an IndirectEntry for a constant pool entry type |
|
1958 |
* that contains one index of another entry. |
|
1959 |
*/ |
|
1960 |
public IndirectEntry(int tag, short index) { |
|
1961 |
this.tag = tag; |
|
1962 |
this.index0 = index; |
|
1963 |
this.index1 = 0; |
|
1964 |
} |
|
1965 |
||
1966 |
/** |
|
1967 |
* Construct an IndirectEntry for a constant pool entry type |
|
1968 |
* that contains two indexes for other entries. |
|
1969 |
*/ |
|
1970 |
public IndirectEntry(int tag, short index0, short index1) { |
|
1971 |
this.tag = tag; |
|
1972 |
this.index0 = index0; |
|
1973 |
this.index1 = index1; |
|
1974 |
} |
|
1975 |
||
1976 |
public void write(DataOutputStream out) throws IOException { |
|
1977 |
out.writeByte(tag); |
|
1978 |
out.writeShort(index0); |
|
1979 |
/* |
|
1980 |
* If this entry type contains two indexes, write |
|
1981 |
* out the second, too. |
|
1982 |
*/ |
|
1983 |
if (tag == CONSTANT_FIELD || |
|
1984 |
tag == CONSTANT_METHOD || |
|
1985 |
tag == CONSTANT_INTERFACEMETHOD || |
|
1986 |
tag == CONSTANT_NAMEANDTYPE) |
|
1987 |
{ |
|
1988 |
out.writeShort(index1); |
|
1989 |
} |
|
1990 |
} |
|
1991 |
||
1992 |
public int hashCode() { |
|
1993 |
return tag + index0 + index1; |
|
1994 |
} |
|
1995 |
||
1996 |
public boolean equals(Object obj) { |
|
1997 |
if (obj instanceof IndirectEntry) { |
|
1998 |
IndirectEntry other = (IndirectEntry) obj; |
|
1999 |
if (tag == other.tag && |
|
2000 |
index0 == other.index0 && index1 == other.index1) |
|
2001 |
{ |
|
2002 |
return true; |
|
2003 |
} |
|
2004 |
} |
|
2005 |
return false; |
|
2006 |
} |
|
2007 |
} |
|
2008 |
} |
|
2009 |
} |