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