author | martin |
Tue, 15 Sep 2015 21:56:04 -0700 | |
changeset 32649 | 2ee9017c7597 |
parent 25859 | 3317bb8137f4 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
15526
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
2 |
* Copyright (c) 2001, 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 |
||
26 |
package com.sun.java.util.jar.pack; |
|
27 |
||
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
28 |
import java.io.IOException; |
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
29 |
import java.util.Arrays; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
30 |
import static com.sun.java.util.jar.pack.Constants.*; |
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
31 |
|
2 | 32 |
/** |
33 |
* A parsed bytecode instruction. |
|
34 |
* Provides accessors to various relevant bits. |
|
35 |
* @author John Rose |
|
36 |
*/ |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
37 |
class Instruction { |
2 | 38 |
protected byte[] bytes; // bytecodes |
39 |
protected int pc; // location of this instruction |
|
40 |
protected int bc; // opcode of this instruction |
|
41 |
protected int w; // 0 if normal, 1 if a _wide prefix at pc |
|
42 |
protected int length; // bytes in this instruction |
|
43 |
||
44 |
protected boolean special; |
|
45 |
||
46 |
protected Instruction(byte[] bytes, int pc, int bc, int w, int length) { |
|
47 |
reset(bytes, pc, bc, w, length); |
|
48 |
} |
|
49 |
private void reset(byte[] bytes, int pc, int bc, int w, int length) { |
|
50 |
this.bytes = bytes; |
|
51 |
this.pc = pc; |
|
52 |
this.bc = bc; |
|
53 |
this.w = w; |
|
54 |
this.length = length; |
|
55 |
} |
|
56 |
||
57 |
public int getBC() { |
|
58 |
return bc; |
|
59 |
} |
|
60 |
public boolean isWide() { |
|
61 |
return w != 0; |
|
62 |
} |
|
63 |
public byte[] getBytes() { |
|
64 |
return bytes; |
|
65 |
} |
|
66 |
public int getPC() { |
|
67 |
return pc; |
|
68 |
} |
|
69 |
public int getLength() { |
|
70 |
return length; |
|
71 |
} |
|
72 |
public int getNextPC() { |
|
73 |
return pc + length; |
|
74 |
} |
|
75 |
||
76 |
public Instruction next() { |
|
77 |
int npc = pc + length; |
|
78 |
if (npc == bytes.length) |
|
79 |
return null; |
|
80 |
else |
|
81 |
return Instruction.at(bytes, npc, this); |
|
82 |
} |
|
83 |
||
84 |
public boolean isNonstandard() { |
|
85 |
return isNonstandard(bc); |
|
86 |
} |
|
87 |
||
88 |
public void setNonstandardLength(int length) { |
|
89 |
assert(isNonstandard()); |
|
90 |
this.length = length; |
|
91 |
} |
|
92 |
||
93 |
||
94 |
/** A fake instruction at this pc whose next() will be at nextpc. */ |
|
95 |
public Instruction forceNextPC(int nextpc) { |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
96 |
int llength = nextpc - pc; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
97 |
return new Instruction(bytes, pc, -1, -1, llength); |
2 | 98 |
} |
99 |
||
100 |
public static Instruction at(byte[] bytes, int pc) { |
|
101 |
return Instruction.at(bytes, pc, null); |
|
102 |
} |
|
103 |
||
104 |
public static Instruction at(byte[] bytes, int pc, Instruction reuse) { |
|
105 |
int bc = getByte(bytes, pc); |
|
106 |
int prefix = -1; |
|
107 |
int w = 0; |
|
108 |
int length = BC_LENGTH[w][bc]; |
|
109 |
if (length == 0) { |
|
110 |
// Hard cases: |
|
111 |
switch (bc) { |
|
112 |
case _wide: |
|
113 |
bc = getByte(bytes, pc+1); |
|
114 |
w = 1; |
|
115 |
length = BC_LENGTH[w][bc]; |
|
116 |
if (length == 0) { |
|
117 |
// unknown instruction; treat as one byte |
|
118 |
length = 1; |
|
119 |
} |
|
120 |
break; |
|
121 |
case _tableswitch: |
|
122 |
return new TableSwitch(bytes, pc); |
|
123 |
case _lookupswitch: |
|
124 |
return new LookupSwitch(bytes, pc); |
|
125 |
default: |
|
126 |
// unknown instruction; treat as one byte |
|
127 |
length = 1; |
|
128 |
break; |
|
129 |
} |
|
130 |
} |
|
131 |
assert(length > 0); |
|
132 |
assert(pc+length <= bytes.length); |
|
133 |
// Speed hack: Instruction.next reuses self if possible. |
|
134 |
if (reuse != null && !reuse.special) { |
|
135 |
reuse.reset(bytes, pc, bc, w, length); |
|
136 |
return reuse; |
|
137 |
} |
|
138 |
return new Instruction(bytes, pc, bc, w, length); |
|
139 |
} |
|
140 |
||
141 |
// Return the constant pool reference type, or 0 if none. |
|
142 |
public byte getCPTag() { |
|
143 |
return BC_TAG[w][bc]; |
|
144 |
} |
|
145 |
||
146 |
// Return the constant pool index, or -1 if none. |
|
147 |
public int getCPIndex() { |
|
148 |
int indexLoc = BC_INDEX[w][bc]; |
|
149 |
if (indexLoc == 0) return -1; |
|
150 |
assert(w == 0); |
|
151 |
if (length == 2) |
|
152 |
return getByte(bytes, pc+indexLoc); // _ldc opcode only |
|
153 |
else |
|
154 |
return getShort(bytes, pc+indexLoc); |
|
155 |
} |
|
156 |
||
157 |
public void setCPIndex(int cpi) { |
|
158 |
int indexLoc = BC_INDEX[w][bc]; |
|
159 |
assert(indexLoc != 0); |
|
160 |
if (length == 2) |
|
161 |
setByte(bytes, pc+indexLoc, cpi); // _ldc opcode only |
|
162 |
else |
|
163 |
setShort(bytes, pc+indexLoc, cpi); |
|
164 |
assert(getCPIndex() == cpi); |
|
165 |
} |
|
166 |
||
167 |
public ConstantPool.Entry getCPRef(ConstantPool.Entry[] cpMap) { |
|
168 |
int index = getCPIndex(); |
|
169 |
return (index < 0) ? null : cpMap[index]; |
|
170 |
} |
|
171 |
||
172 |
// Return the slot of the affected local, or -1 if none. |
|
173 |
public int getLocalSlot() { |
|
174 |
int slotLoc = BC_SLOT[w][bc]; |
|
175 |
if (slotLoc == 0) return -1; |
|
176 |
if (w == 0) |
|
177 |
return getByte(bytes, pc+slotLoc); |
|
178 |
else |
|
179 |
return getShort(bytes, pc+slotLoc); |
|
180 |
} |
|
181 |
||
182 |
// Return the target of the branch, or -1 if none. |
|
183 |
public int getBranchLabel() { |
|
184 |
int branchLoc = BC_BRANCH[w][bc]; |
|
185 |
if (branchLoc == 0) return -1; |
|
186 |
assert(w == 0); |
|
187 |
assert(length == 3 || length == 5); |
|
188 |
int offset; |
|
189 |
if (length == 3) |
|
190 |
offset = (short)getShort(bytes, pc+branchLoc); |
|
191 |
else |
|
192 |
offset = getInt(bytes, pc+branchLoc); |
|
193 |
assert(offset+pc >= 0); |
|
194 |
assert(offset+pc <= bytes.length); |
|
195 |
return offset+pc; |
|
196 |
} |
|
197 |
||
198 |
public void setBranchLabel(int targetPC) { |
|
199 |
int branchLoc = BC_BRANCH[w][bc]; |
|
200 |
assert(branchLoc != 0); |
|
201 |
if (length == 3) |
|
202 |
setShort(bytes, pc+branchLoc, targetPC-pc); |
|
203 |
else |
|
204 |
setInt(bytes, pc+branchLoc, targetPC-pc); |
|
205 |
assert(targetPC == getBranchLabel()); |
|
206 |
} |
|
207 |
||
208 |
// Return the trailing constant in the instruction (as a signed value). |
|
209 |
// Return 0 if there is none. |
|
210 |
public int getConstant() { |
|
211 |
int conLoc = BC_CON[w][bc]; |
|
212 |
if (conLoc == 0) return 0; |
|
213 |
switch (length - conLoc) { |
|
214 |
case 1: return (byte) getByte(bytes, pc+conLoc); |
|
215 |
case 2: return (short) getShort(bytes, pc+conLoc); |
|
216 |
} |
|
217 |
assert(false); |
|
218 |
return 0; |
|
219 |
} |
|
220 |
||
221 |
public void setConstant(int con) { |
|
222 |
int conLoc = BC_CON[w][bc]; |
|
223 |
assert(conLoc != 0); |
|
224 |
switch (length - conLoc) { |
|
225 |
case 1: setByte(bytes, pc+conLoc, con); break; |
|
226 |
case 2: setShort(bytes, pc+conLoc, con); break; |
|
227 |
} |
|
228 |
assert(con == getConstant()); |
|
229 |
} |
|
230 |
||
231 |
public abstract static class Switch extends Instruction { |
|
232 |
// Each case is a (value, label) pair, indexed 0 <= n < caseCount |
|
233 |
public abstract int getCaseCount(); |
|
234 |
public abstract int getCaseValue(int n); |
|
235 |
public abstract int getCaseLabel(int n); |
|
236 |
public abstract void setCaseCount(int caseCount); |
|
237 |
public abstract void setCaseValue(int n, int value); |
|
238 |
public abstract void setCaseLabel(int n, int targetPC); |
|
239 |
protected abstract int getLength(int caseCount); |
|
240 |
||
241 |
public int getDefaultLabel() { return intAt(0)+pc; } |
|
242 |
public void setDefaultLabel(int targetPC) { setIntAt(0, targetPC-pc); } |
|
243 |
||
244 |
protected int apc; // aligned pc (table base) |
|
245 |
protected int intAt(int n) { return getInt(bytes, apc + n*4); } |
|
246 |
protected void setIntAt(int n, int x) { setInt(bytes, apc + n*4, x); } |
|
247 |
protected Switch(byte[] bytes, int pc, int bc) { |
|
248 |
super(bytes, pc, bc, /*w*/0, /*length*/0); |
|
249 |
this.apc = alignPC(pc+1); |
|
250 |
this.special = true; |
|
251 |
length = getLength(getCaseCount()); |
|
252 |
} |
|
253 |
public int getAlignedPC() { return apc; } |
|
254 |
public String toString() { |
|
255 |
String s = super.toString(); |
|
256 |
s += " Default:"+labstr(getDefaultLabel()); |
|
257 |
int caseCount = getCaseCount(); |
|
258 |
for (int i = 0; i < caseCount; i++) { |
|
259 |
s += "\n\tCase "+getCaseValue(i)+":"+labstr(getCaseLabel(i)); |
|
260 |
} |
|
261 |
return s; |
|
262 |
} |
|
263 |
public static int alignPC(int apc) { |
|
264 |
while (apc % 4 != 0) ++apc; |
|
265 |
return apc; |
|
266 |
} |
|
267 |
} |
|
268 |
||
269 |
public static class TableSwitch extends Switch { |
|
270 |
// apc: (df, lo, hi, (hi-lo+1)*(label)) |
|
271 |
public int getLowCase() { return intAt(1); } |
|
272 |
public int getHighCase() { return intAt(2); } |
|
273 |
public int getCaseCount() { return intAt(2)-intAt(1)+1; } |
|
274 |
public int getCaseValue(int n) { return getLowCase()+n; } |
|
275 |
public int getCaseLabel(int n) { return intAt(3+n)+pc; } |
|
276 |
||
277 |
public void setLowCase(int val) { setIntAt(1, val); } |
|
278 |
public void setHighCase(int val) { setIntAt(2, val); } |
|
279 |
public void setCaseLabel(int n, int tpc) { setIntAt(3+n, tpc-pc); } |
|
280 |
public void setCaseCount(int caseCount) { |
|
281 |
setHighCase(getLowCase() + caseCount - 1); |
|
282 |
length = getLength(caseCount); |
|
283 |
} |
|
284 |
public void setCaseValue(int n, int val) { |
|
285 |
if (n != 0) throw new UnsupportedOperationException(); |
|
286 |
int caseCount = getCaseCount(); |
|
287 |
setLowCase(val); |
|
288 |
setCaseCount(caseCount); // keep invariant |
|
289 |
} |
|
290 |
||
291 |
TableSwitch(byte[] bytes, int pc) { |
|
292 |
super(bytes, pc, _tableswitch); |
|
293 |
} |
|
294 |
protected int getLength(int caseCount) { |
|
295 |
return (apc-pc) + (3 + caseCount) * 4; |
|
296 |
} |
|
297 |
} |
|
298 |
||
299 |
public static class LookupSwitch extends Switch { |
|
300 |
// apc: (df, nc, nc*(case, label)) |
|
301 |
public int getCaseCount() { return intAt(1); } |
|
302 |
public int getCaseValue(int n) { return intAt(2+n*2+0); } |
|
303 |
public int getCaseLabel(int n) { return intAt(2+n*2+1)+pc; } |
|
304 |
||
305 |
public void setCaseCount(int caseCount) { |
|
306 |
setIntAt(1, caseCount); |
|
307 |
length = getLength(caseCount); |
|
308 |
} |
|
309 |
public void setCaseValue(int n, int val) { setIntAt(2+n*2+0, val); } |
|
310 |
public void setCaseLabel(int n, int tpc) { setIntAt(2+n*2+1, tpc-pc); } |
|
311 |
||
312 |
LookupSwitch(byte[] bytes, int pc) { |
|
313 |
super(bytes, pc, _lookupswitch); |
|
314 |
} |
|
315 |
protected int getLength(int caseCount) { |
|
316 |
return (apc-pc) + (2 + caseCount*2) * 4; |
|
317 |
} |
|
318 |
} |
|
319 |
||
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
320 |
/** Two instructions are equal if they have the same bytes. */ |
2 | 321 |
public boolean equals(Object o) { |
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
322 |
return (o != null) && (o.getClass() == Instruction.class) |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
323 |
&& equals((Instruction) o); |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
324 |
} |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
325 |
|
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
326 |
public int hashCode() { |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
327 |
int hash = 3; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
328 |
hash = 11 * hash + Arrays.hashCode(this.bytes); |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
329 |
hash = 11 * hash + this.pc; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
330 |
hash = 11 * hash + this.bc; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
331 |
hash = 11 * hash + this.w; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
332 |
hash = 11 * hash + this.length; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
333 |
return hash; |
2 | 334 |
} |
335 |
||
336 |
public boolean equals(Instruction that) { |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
6900
diff
changeset
|
337 |
if (this.pc != that.pc) return false; |
2 | 338 |
if (this.bc != that.bc) return false; |
339 |
if (this.w != that.w) return false; |
|
340 |
if (this.length != that.length) return false; |
|
341 |
for (int i = 1; i < length; i++) { |
|
342 |
if (this.bytes[this.pc+i] != that.bytes[that.pc+i]) |
|
343 |
return false; |
|
344 |
} |
|
345 |
return true; |
|
346 |
} |
|
347 |
||
348 |
static String labstr(int pc) { |
|
349 |
if (pc >= 0 && pc < 100000) |
|
350 |
return ((100000+pc)+"").substring(1); |
|
351 |
return pc+""; |
|
352 |
} |
|
353 |
public String toString() { |
|
354 |
return toString(null); |
|
355 |
} |
|
356 |
public String toString(ConstantPool.Entry[] cpMap) { |
|
357 |
String s = labstr(pc) + ": "; |
|
358 |
if (bc >= _bytecode_limit) { |
|
359 |
s += Integer.toHexString(bc); |
|
360 |
return s; |
|
361 |
} |
|
362 |
if (w == 1) s += "wide "; |
|
363 |
String bcname = (bc < BC_NAME.length)? BC_NAME[bc]: null; |
|
364 |
if (bcname == null) { |
|
365 |
return s+"opcode#"+bc; |
|
366 |
} |
|
367 |
s += bcname; |
|
368 |
int tag = getCPTag(); |
|
369 |
if (tag != 0) s += " "+ConstantPool.tagName(tag)+":"; |
|
370 |
int idx = getCPIndex(); |
|
371 |
if (idx >= 0) s += (cpMap == null) ? ""+idx : "="+cpMap[idx].stringValue(); |
|
372 |
int slt = getLocalSlot(); |
|
373 |
if (slt >= 0) s += " Local:"+slt; |
|
374 |
int lab = getBranchLabel(); |
|
375 |
if (lab >= 0) s += " To:"+labstr(lab); |
|
376 |
int con = getConstant(); |
|
377 |
if (con != 0) s += " Con:"+con; |
|
378 |
return s; |
|
379 |
} |
|
380 |
||
381 |
||
382 |
//public static byte constantPoolTagFor(int bc) { return BC_TAG[0][bc]; } |
|
383 |
||
384 |
/// Fetching values from byte arrays: |
|
385 |
||
386 |
public int getIntAt(int off) { |
|
387 |
return getInt(bytes, pc+off); |
|
388 |
} |
|
389 |
public int getShortAt(int off) { |
|
390 |
return getShort(bytes, pc+off); |
|
391 |
} |
|
392 |
public int getByteAt(int off) { |
|
393 |
return getByte(bytes, pc+off); |
|
394 |
} |
|
395 |
||
396 |
||
397 |
public static int getInt(byte[] bytes, int pc) { |
|
398 |
return (getShort(bytes, pc+0) << 16) + (getShort(bytes, pc+2) << 0); |
|
399 |
} |
|
400 |
public static int getShort(byte[] bytes, int pc) { |
|
401 |
return (getByte(bytes, pc+0) << 8) + (getByte(bytes, pc+1) << 0); |
|
402 |
} |
|
403 |
public static int getByte(byte[] bytes, int pc) { |
|
404 |
return bytes[pc] & 0xFF; |
|
405 |
} |
|
406 |
||
407 |
||
408 |
public static void setInt(byte[] bytes, int pc, int x) { |
|
409 |
setShort(bytes, pc+0, x >> 16); |
|
410 |
setShort(bytes, pc+2, x >> 0); |
|
411 |
} |
|
412 |
public static void setShort(byte[] bytes, int pc, int x) { |
|
413 |
setByte(bytes, pc+0, x >> 8); |
|
414 |
setByte(bytes, pc+1, x >> 0); |
|
415 |
} |
|
416 |
public static void setByte(byte[] bytes, int pc, int x) { |
|
417 |
bytes[pc] = (byte)x; |
|
418 |
} |
|
419 |
||
420 |
// some bytecode classifiers |
|
421 |
||
422 |
||
423 |
public static boolean isNonstandard(int bc) { |
|
424 |
return BC_LENGTH[0][bc] < 0; |
|
425 |
} |
|
426 |
||
427 |
public static int opLength(int bc) { |
|
428 |
int l = BC_LENGTH[0][bc]; |
|
429 |
assert(l > 0); |
|
430 |
return l; |
|
431 |
} |
|
432 |
public static int opWideLength(int bc) { |
|
433 |
int l = BC_LENGTH[1][bc]; |
|
434 |
assert(l > 0); |
|
435 |
return l; |
|
436 |
} |
|
437 |
||
438 |
public static boolean isLocalSlotOp(int bc) { |
|
439 |
return (bc < BC_SLOT[0].length && BC_SLOT[0][bc] > 0); |
|
440 |
} |
|
441 |
||
442 |
public static boolean isBranchOp(int bc) { |
|
443 |
return (bc < BC_BRANCH[0].length && BC_BRANCH[0][bc] > 0); |
|
444 |
} |
|
445 |
||
446 |
public static boolean isCPRefOp(int bc) { |
|
447 |
if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return true; |
|
448 |
if (bc >= _xldc_op && bc < _xldc_limit) return true; |
|
16050
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
449 |
if (bc == _invokespecial_int || bc == _invokestatic_int) return true; |
2 | 450 |
return false; |
451 |
} |
|
452 |
||
453 |
public static byte getCPRefOpTag(int bc) { |
|
454 |
if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return BC_TAG[0][bc]; |
|
12544 | 455 |
if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_LoadableValue; |
16050
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
456 |
if (bc == _invokestatic_int || bc == _invokespecial_int) return CONSTANT_InterfaceMethodref; |
2 | 457 |
return CONSTANT_None; |
458 |
} |
|
459 |
||
460 |
public static boolean isFieldOp(int bc) { |
|
461 |
return (bc >= _getstatic && bc <= _putfield); |
|
462 |
} |
|
463 |
||
464 |
public static boolean isInvokeInitOp(int bc) { |
|
465 |
return (bc >= _invokeinit_op && bc < _invokeinit_limit); |
|
466 |
} |
|
467 |
||
468 |
public static boolean isSelfLinkerOp(int bc) { |
|
469 |
return (bc >= _self_linker_op && bc < _self_linker_limit); |
|
470 |
} |
|
471 |
||
472 |
/// Format definitions. |
|
473 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
474 |
private static final byte[][] BC_LENGTH = new byte[2][0x100]; |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
475 |
private static final byte[][] BC_INDEX = new byte[2][0x100]; |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
476 |
private static final byte[][] BC_TAG = new byte[2][0x100]; |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
477 |
private static final byte[][] BC_BRANCH = new byte[2][0x100]; |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
478 |
private static final byte[][] BC_SLOT = new byte[2][0x100]; |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
479 |
private static final byte[][] BC_CON = new byte[2][0x100]; |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
480 |
private static final String[] BC_NAME = new String[0x100]; // debug only |
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
25859
diff
changeset
|
481 |
private static final String[][] BC_FORMAT = new String[2][_bytecode_limit]; // debug only |
2 | 482 |
static { |
483 |
for (int i = 0; i < _bytecode_limit; i++) { |
|
484 |
BC_LENGTH[0][i] = -1; |
|
485 |
BC_LENGTH[1][i] = -1; |
|
486 |
} |
|
487 |
def("b", _nop, _dconst_1); |
|
488 |
def("bx", _bipush); |
|
489 |
def("bxx", _sipush); |
|
490 |
def("bk", _ldc); // do not pack |
|
491 |
def("bkk", _ldc_w, _ldc2_w); // do not pack |
|
492 |
def("blwbll", _iload, _aload); |
|
493 |
def("b", _iload_0, _saload); |
|
494 |
def("blwbll", _istore, _astore); |
|
495 |
def("b", _istore_0, _lxor); |
|
496 |
def("blxwbllxx", _iinc); |
|
497 |
def("b", _i2l, _dcmpg); |
|
498 |
def("boo", _ifeq, _jsr); // pack oo |
|
499 |
def("blwbll", _ret); |
|
500 |
def("", _tableswitch, _lookupswitch); // pack all ints, omit padding |
|
501 |
def("b", _ireturn, _return); |
|
502 |
def("bkf", _getstatic, _putfield); // pack kf (base=Field) |
|
503 |
def("bkm", _invokevirtual, _invokestatic); // pack kn (base=Method) |
|
504 |
def("bkixx", _invokeinterface); // pack ki (base=IMethod), omit xx |
|
12544 | 505 |
def("bkyxx", _invokedynamic); // pack ky (base=Any), omit xx |
2 | 506 |
def("bkc", _new); // pack kc |
507 |
def("bx", _newarray); |
|
508 |
def("bkc", _anewarray); // pack kc |
|
509 |
def("b", _arraylength, _athrow); |
|
510 |
def("bkc", _checkcast, _instanceof); // pack kc |
|
511 |
def("b", _monitorenter, _monitorexit); |
|
512 |
def("", _wide); |
|
513 |
def("bkcx", _multianewarray); // pack kc |
|
514 |
def("boo", _ifnull, _ifnonnull); // pack oo |
|
515 |
def("boooo", _goto_w, _jsr_w); // pack oooo |
|
516 |
for (int i = 0; i < _bytecode_limit; i++) { |
|
517 |
//System.out.println(i+": l="+BC_LENGTH[0][i]+" i="+BC_INDEX[0][i]); |
|
518 |
//assert(BC_LENGTH[0][i] != -1); |
|
519 |
if (BC_LENGTH[0][i] == -1) { |
|
520 |
continue; // unknown opcode |
|
521 |
} |
|
522 |
||
523 |
// Have a complete mapping, to support spurious _wide prefixes. |
|
524 |
if (BC_LENGTH[1][i] == -1) |
|
525 |
BC_LENGTH[1][i] = (byte)(1+BC_LENGTH[0][i]); |
|
526 |
} |
|
527 |
||
528 |
String names = |
|
529 |
"nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 "+ |
|
530 |
"iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 "+ |
|
531 |
"bipush sipush ldc ldc_w ldc2_w iload lload fload dload aload iload_0 "+ |
|
532 |
"iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 "+ |
|
533 |
"fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 "+ |
|
534 |
"aload_3 iaload laload faload daload aaload baload caload saload istore "+ |
|
535 |
"lstore fstore dstore astore istore_0 istore_1 istore_2 istore_3 lstore_0 "+ |
|
536 |
"lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 "+ |
|
537 |
"dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore "+ |
|
538 |
"lastore fastore dastore aastore bastore castore sastore pop pop2 dup "+ |
|
539 |
"dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd isub lsub "+ |
|
540 |
"fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem "+ |
|
541 |
"ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior lor "+ |
|
542 |
"ixor lxor iinc i2l i2f i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f i2b i2c "+ |
|
543 |
"i2s lcmp fcmpl fcmpg dcmpl dcmpg ifeq ifne iflt ifge ifgt ifle if_icmpeq "+ |
|
544 |
"if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "+ |
|
545 |
"goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "+ |
|
546 |
"areturn return getstatic putstatic getfield putfield invokevirtual "+ |
|
12544 | 547 |
"invokespecial invokestatic invokeinterface invokedynamic new newarray "+ |
2 | 548 |
"anewarray arraylength athrow checkcast instanceof monitorenter "+ |
549 |
"monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w "; |
|
550 |
for (int bc = 0; names.length() > 0; bc++) { |
|
551 |
int sp = names.indexOf(' '); |
|
552 |
BC_NAME[bc] = names.substring(0, sp); |
|
553 |
names = names.substring(sp+1); |
|
554 |
} |
|
555 |
} |
|
556 |
public static String byteName(int bc) { |
|
557 |
String iname; |
|
558 |
if (bc < BC_NAME.length && BC_NAME[bc] != null) { |
|
559 |
iname = BC_NAME[bc]; |
|
560 |
} else if (isSelfLinkerOp(bc)) { |
|
561 |
int idx = (bc - _self_linker_op); |
|
562 |
boolean isSuper = (idx >= _self_linker_super_flag); |
|
563 |
if (isSuper) idx -= _self_linker_super_flag; |
|
564 |
boolean isAload = (idx >= _self_linker_aload_flag); |
|
565 |
if (isAload) idx -= _self_linker_aload_flag; |
|
566 |
int origBC = _first_linker_op + idx; |
|
567 |
assert(origBC >= _first_linker_op && origBC <= _last_linker_op); |
|
568 |
iname = BC_NAME[origBC]; |
|
569 |
iname += (isSuper ? "_super" : "_this"); |
|
570 |
if (isAload) iname = "aload_0&" + iname; |
|
571 |
iname = "*"+iname; |
|
572 |
} else if (isInvokeInitOp(bc)) { |
|
573 |
int idx = (bc - _invokeinit_op); |
|
574 |
switch (idx) { |
|
575 |
case _invokeinit_self_option: |
|
576 |
iname = "*invokespecial_init_this"; break; |
|
577 |
case _invokeinit_super_option: |
|
578 |
iname = "*invokespecial_init_super"; break; |
|
579 |
default: |
|
580 |
assert(idx == _invokeinit_new_option); |
|
581 |
iname = "*invokespecial_init_new"; break; |
|
582 |
} |
|
583 |
} else { |
|
584 |
switch (bc) { |
|
585 |
case _ildc: iname = "*ildc"; break; |
|
586 |
case _fldc: iname = "*fldc"; break; |
|
587 |
case _ildc_w: iname = "*ildc_w"; break; |
|
588 |
case _fldc_w: iname = "*fldc_w"; break; |
|
589 |
case _dldc2_w: iname = "*dldc2_w"; break; |
|
590 |
case _cldc: iname = "*cldc"; break; |
|
591 |
case _cldc_w: iname = "*cldc_w"; break; |
|
12544 | 592 |
case _qldc: iname = "*qldc"; break; |
593 |
case _qldc_w: iname = "*qldc_w"; break; |
|
2 | 594 |
case _byte_escape: iname = "*byte_escape"; break; |
595 |
case _ref_escape: iname = "*ref_escape"; break; |
|
596 |
case _end_marker: iname = "*end"; break; |
|
597 |
default: iname = "*bc#"+bc; break; |
|
598 |
} |
|
599 |
} |
|
600 |
return iname; |
|
601 |
} |
|
602 |
private static int BW = 4; // width of classification field |
|
603 |
private static void def(String fmt, int bc) { |
|
604 |
def(fmt, bc, bc); |
|
605 |
} |
|
606 |
private static void def(String fmt, int from_bc, int to_bc) { |
|
607 |
String[] fmts = { fmt, null }; |
|
608 |
if (fmt.indexOf('w') > 0) { |
|
609 |
fmts[1] = fmt.substring(fmt.indexOf('w')); |
|
610 |
fmts[0] = fmt.substring(0, fmt.indexOf('w')); |
|
611 |
} |
|
612 |
for (int w = 0; w <= 1; w++) { |
|
613 |
fmt = fmts[w]; |
|
614 |
if (fmt == null) continue; |
|
615 |
int length = fmt.length(); |
|
616 |
int index = Math.max(0, fmt.indexOf('k')); |
|
617 |
int tag = CONSTANT_None; |
|
618 |
int branch = Math.max(0, fmt.indexOf('o')); |
|
619 |
int slot = Math.max(0, fmt.indexOf('l')); |
|
620 |
int con = Math.max(0, fmt.indexOf('x')); |
|
621 |
if (index > 0 && index+1 < length) { |
|
622 |
switch (fmt.charAt(index+1)) { |
|
623 |
case 'c': tag = CONSTANT_Class; break; |
|
12544 | 624 |
case 'k': tag = CONSTANT_LoadableValue; break; |
2 | 625 |
case 'f': tag = CONSTANT_Fieldref; break; |
626 |
case 'm': tag = CONSTANT_Methodref; break; |
|
627 |
case 'i': tag = CONSTANT_InterfaceMethodref; break; |
|
12544 | 628 |
case 'y': tag = CONSTANT_InvokeDynamic; break; |
2 | 629 |
} |
630 |
assert(tag != CONSTANT_None); |
|
631 |
} else if (index > 0 && length == 2) { |
|
632 |
assert(from_bc == _ldc); |
|
12544 | 633 |
tag = CONSTANT_LoadableValue; // _ldc opcode only |
2 | 634 |
} |
635 |
for (int bc = from_bc; bc <= to_bc; bc++) { |
|
636 |
BC_FORMAT[w][bc] = fmt; |
|
637 |
assert(BC_LENGTH[w][bc] == -1); |
|
638 |
BC_LENGTH[w][bc] = (byte) length; |
|
639 |
BC_INDEX[w][bc] = (byte) index; |
|
640 |
BC_TAG[w][bc] = (byte) tag; |
|
641 |
assert(!(index == 0 && tag != CONSTANT_None)); |
|
642 |
BC_BRANCH[w][bc] = (byte) branch; |
|
643 |
BC_SLOT[w][bc] = (byte) slot; |
|
644 |
assert(branch == 0 || slot == 0); // not both branch & local |
|
645 |
assert(branch == 0 || index == 0); // not both branch & cp |
|
646 |
assert(slot == 0 || index == 0); // not both local & cp |
|
647 |
BC_CON[w][bc] = (byte) con; |
|
648 |
} |
|
649 |
} |
|
650 |
} |
|
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
651 |
|
16050
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
652 |
public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap, |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
653 |
Package.Version clsVersion) throws FormatException { |
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
654 |
Instruction i = at(code, 0); |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
655 |
while (i != null) { |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
656 |
int opcode = i.getBC(); |
12544 | 657 |
if (opcode < _nop || opcode > _jsr_w) { |
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
658 |
String message = "illegal opcode: " + opcode + " " + i; |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
659 |
throw new FormatException(message); |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
660 |
} |
15526
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
661 |
ConstantPool.Entry e = i.getCPRef(cpMap); |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
662 |
if (e != null) { |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
663 |
byte tag = i.getCPTag(); |
16050
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
664 |
boolean match = e.tagMatches(tag); |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
665 |
if (!match && |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
666 |
(i.bc == _invokespecial || i.bc == _invokestatic) && |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
667 |
e.tagMatches(CONSTANT_InterfaceMethodref) && |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
668 |
clsVersion.greaterThan(Constants.JAVA7_MAX_CLASS_VERSION)) { |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
669 |
match = true; |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
670 |
} |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
671 |
if (!match) { |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
672 |
String message = "illegal reference, expected type=" |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
673 |
+ ConstantPool.tagName(tag) + ": " |
1eee624cddb3
8007297: [pack200] allow opcodes with InterfaceMethodRefs
ksrini
parents:
15526
diff
changeset
|
674 |
+ i.toString(cpMap); |
15526
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
675 |
throw new FormatException(message); |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
676 |
} |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
12544
diff
changeset
|
677 |
} |
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
678 |
i = i.next(); |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
679 |
} |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
680 |
} |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
681 |
static class FormatException extends IOException { |
10115 | 682 |
private static final long serialVersionUID = 3175572275651367015L; |
683 |
||
6900
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
684 |
FormatException(String message) { |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
685 |
super(message); |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
686 |
} |
a3ca67586333
6982312: (pack200) pack200 fails with the jdk7 class files
ksrini
parents:
5506
diff
changeset
|
687 |
} |
2 | 688 |
} |