author | redestad |
Thu, 13 Dec 2018 15:31:05 +0100 | |
changeset 53018 | 8bf9268df0e2 |
parent 47216 | 71c04702a3d5 |
child 57956 | e0b8b019d2f5 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
15261 | 2 |
* Copyright (c) 2003, 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 |
||
7192
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
28 |
import com.sun.java.util.jar.pack.ConstantPool.Entry; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
29 |
import com.sun.java.util.jar.pack.ConstantPool.Index; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
30 |
import java.io.ByteArrayOutputStream; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
31 |
import java.io.IOException; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
32 |
import java.util.ArrayList; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
33 |
import java.util.Arrays; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
34 |
import java.util.Collection; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
35 |
import java.util.Collections; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
36 |
import java.util.HashMap; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
37 |
import java.util.List; |
445c518364c4
7003227: (pack200) intermittent failures compiling pack200
ksrini
parents:
6901
diff
changeset
|
38 |
import java.util.Map; |
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
39 |
import static com.sun.java.util.jar.pack.Constants.*; |
2 | 40 |
|
41 |
/** |
|
42 |
* Represents an attribute in a class-file. |
|
43 |
* Takes care to remember where constant pool indexes occur. |
|
44 |
* Implements the "little language" of Pack200 for describing |
|
45 |
* attribute layouts. |
|
46 |
* @author John Rose |
|
47 |
*/ |
|
10115 | 48 |
class Attribute implements Comparable<Attribute> { |
2 | 49 |
// Attribute instance fields. |
50 |
||
51 |
Layout def; // the name and format of this attr |
|
52 |
byte[] bytes; // the actual bytes |
|
53 |
Object fixups; // reference relocations, if any are required |
|
54 |
||
55 |
public String name() { return def.name(); } |
|
56 |
public Layout layout() { return def; } |
|
57 |
public byte[] bytes() { return bytes; } |
|
58 |
public int size() { return bytes.length; } |
|
59 |
public Entry getNameRef() { return def.getNameRef(); } |
|
60 |
||
61 |
private Attribute(Attribute old) { |
|
62 |
this.def = old.def; |
|
63 |
this.bytes = old.bytes; |
|
64 |
this.fixups = old.fixups; |
|
65 |
} |
|
66 |
||
67 |
public Attribute(Layout def, byte[] bytes, Object fixups) { |
|
68 |
this.def = def; |
|
69 |
this.bytes = bytes; |
|
70 |
this.fixups = fixups; |
|
71 |
Fixups.setBytes(fixups, bytes); |
|
72 |
} |
|
73 |
public Attribute(Layout def, byte[] bytes) { |
|
74 |
this(def, bytes, null); |
|
75 |
} |
|
76 |
||
77 |
public Attribute addContent(byte[] bytes, Object fixups) { |
|
78 |
assert(isCanonical()); |
|
79 |
if (bytes.length == 0 && fixups == null) |
|
80 |
return this; |
|
81 |
Attribute res = new Attribute(this); |
|
82 |
res.bytes = bytes; |
|
83 |
res.fixups = fixups; |
|
84 |
Fixups.setBytes(fixups, bytes); |
|
85 |
return res; |
|
86 |
} |
|
87 |
public Attribute addContent(byte[] bytes) { |
|
88 |
return addContent(bytes, null); |
|
89 |
} |
|
90 |
||
91 |
public void finishRefs(Index ix) { |
|
92 |
if (fixups != null) { |
|
93 |
Fixups.finishRefs(fixups, bytes, ix); |
|
94 |
fixups = null; |
|
95 |
} |
|
96 |
} |
|
97 |
||
98 |
public boolean isCanonical() { |
|
99 |
return this == def.canon; |
|
100 |
} |
|
101 |
||
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
102 |
@Override |
10115 | 103 |
public int compareTo(Attribute that) { |
2 | 104 |
return this.def.compareTo(that.def); |
105 |
} |
|
106 |
||
6313 | 107 |
private static final Map<List<Attribute>, List<Attribute>> canonLists = new HashMap<>(); |
108 |
private static final Map<Layout, Attribute> attributes = new HashMap<>(); |
|
109 |
private static final Map<Layout, Attribute> standardDefs = new HashMap<>(); |
|
2 | 110 |
|
111 |
// Canonicalized lists of trivial attrs (Deprecated, etc.) |
|
112 |
// are used by trimToSize, in order to reduce footprint |
|
113 |
// of some common cases. (Note that Code attributes are |
|
114 |
// always zero size.) |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
115 |
public static List<Attribute> getCanonList(List<Attribute> al) { |
2 | 116 |
synchronized (canonLists) { |
6313 | 117 |
List<Attribute> cl = canonLists.get(al); |
2 | 118 |
if (cl == null) { |
6313 | 119 |
cl = new ArrayList<>(al.size()); |
2 | 120 |
cl.addAll(al); |
121 |
cl = Collections.unmodifiableList(cl); |
|
122 |
canonLists.put(al, cl); |
|
123 |
} |
|
124 |
return cl; |
|
125 |
} |
|
126 |
} |
|
127 |
||
128 |
// Find the canonical empty attribute with the given ctype, name, layout. |
|
129 |
public static Attribute find(int ctype, String name, String layout) { |
|
130 |
Layout key = Layout.makeKey(ctype, name, layout); |
|
131 |
synchronized (attributes) { |
|
6313 | 132 |
Attribute a = attributes.get(key); |
2 | 133 |
if (a == null) { |
134 |
a = new Layout(ctype, name, layout).canonicalInstance(); |
|
135 |
attributes.put(key, a); |
|
136 |
} |
|
137 |
return a; |
|
138 |
} |
|
139 |
} |
|
140 |
||
6313 | 141 |
public static Layout keyForLookup(int ctype, String name) { |
2 | 142 |
return Layout.makeKey(ctype, name); |
143 |
} |
|
144 |
||
145 |
// Find canonical empty attribute with given ctype and name, |
|
146 |
// and with the standard layout. |
|
6313 | 147 |
public static Attribute lookup(Map<Layout, Attribute> defs, int ctype, |
148 |
String name) { |
|
149 |
if (defs == null) { |
|
150 |
defs = standardDefs; |
|
151 |
} |
|
152 |
return defs.get(Layout.makeKey(ctype, name)); |
|
2 | 153 |
} |
6313 | 154 |
|
155 |
public static Attribute define(Map<Layout, Attribute> defs, int ctype, |
|
156 |
String name, String layout) { |
|
2 | 157 |
Attribute a = find(ctype, name, layout); |
158 |
defs.put(Layout.makeKey(ctype, name), a); |
|
159 |
return a; |
|
160 |
} |
|
161 |
||
162 |
static { |
|
6313 | 163 |
Map<Layout, Attribute> sd = standardDefs; |
2 | 164 |
define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH"); |
165 |
define(sd, ATTR_CONTEXT_CLASS, "Synthetic", ""); |
|
166 |
define(sd, ATTR_CONTEXT_CLASS, "Deprecated", ""); |
|
167 |
define(sd, ATTR_CONTEXT_CLASS, "SourceFile", "RUH"); |
|
168 |
define(sd, ATTR_CONTEXT_CLASS, "EnclosingMethod", "RCHRDNH"); |
|
169 |
define(sd, ATTR_CONTEXT_CLASS, "InnerClasses", "NH[RCHRCNHRUNHFH]"); |
|
12544 | 170 |
define(sd, ATTR_CONTEXT_CLASS, "BootstrapMethods", "NH[RMHNH[KLH]]"); |
2 | 171 |
|
172 |
define(sd, ATTR_CONTEXT_FIELD, "Signature", "RSH"); |
|
173 |
define(sd, ATTR_CONTEXT_FIELD, "Synthetic", ""); |
|
174 |
define(sd, ATTR_CONTEXT_FIELD, "Deprecated", ""); |
|
175 |
define(sd, ATTR_CONTEXT_FIELD, "ConstantValue", "KQH"); |
|
176 |
||
177 |
define(sd, ATTR_CONTEXT_METHOD, "Signature", "RSH"); |
|
178 |
define(sd, ATTR_CONTEXT_METHOD, "Synthetic", ""); |
|
179 |
define(sd, ATTR_CONTEXT_METHOD, "Deprecated", ""); |
|
180 |
define(sd, ATTR_CONTEXT_METHOD, "Exceptions", "NH[RCH]"); |
|
16013
3569e84e7429
8008262: pack200 should support MethodParameters - part 2
ksrini
parents:
15526
diff
changeset
|
181 |
define(sd, ATTR_CONTEXT_METHOD, "MethodParameters", "NB[RUNHFH]"); |
2 | 182 |
//define(sd, ATTR_CONTEXT_METHOD, "Code", "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]"); |
183 |
||
184 |
define(sd, ATTR_CONTEXT_CODE, "StackMapTable", |
|
185 |
("[NH[(1)]]" + |
|
186 |
"[TB" + |
|
187 |
"(64-127)[(2)]" + |
|
188 |
"(247)[(1)(2)]" + |
|
189 |
"(248-251)[(1)]" + |
|
190 |
"(252)[(1)(2)]" + |
|
191 |
"(253)[(1)(2)(2)]" + |
|
192 |
"(254)[(1)(2)(2)(2)]" + |
|
193 |
"(255)[(1)NH[(2)]NH[(2)]]" + |
|
194 |
"()[]" + |
|
195 |
"]" + |
|
196 |
"[H]" + |
|
197 |
"[TB(7)[RCH](8)[PH]()[]]")); |
|
198 |
||
199 |
define(sd, ATTR_CONTEXT_CODE, "LineNumberTable", "NH[PHH]"); |
|
200 |
define(sd, ATTR_CONTEXT_CODE, "LocalVariableTable", "NH[PHOHRUHRSHH]"); |
|
201 |
define(sd, ATTR_CONTEXT_CODE, "LocalVariableTypeTable", "NH[PHOHRUHRSHH]"); |
|
202 |
//define(sd, ATTR_CONTEXT_CODE, "CharacterRangeTable", "NH[PHPOHIIH]"); |
|
203 |
//define(sd, ATTR_CONTEXT_CODE, "CoverageTable", "NH[PHHII]"); |
|
204 |
||
205 |
// Note: Code and InnerClasses are special-cased elsewhere. |
|
206 |
// Their layout specs. are given here for completeness. |
|
207 |
// The Code spec is incomplete, in that it does not distinguish |
|
208 |
// bytecode bytes or locate CP references. |
|
12544 | 209 |
// The BootstrapMethods attribute is also special-cased |
210 |
// elsewhere as an appendix to the local constant pool. |
|
2 | 211 |
} |
212 |
||
213 |
// Metadata. |
|
214 |
// |
|
215 |
// We define metadata using similar layouts |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
216 |
// for all five kinds of metadata attributes and 2 type metadata attributes |
2 | 217 |
// |
218 |
// Regular annotations are a counted list of [RSHNH[RUH(1)]][...] |
|
219 |
// pack.method.attribute.RuntimeVisibleAnnotations=[NH[(1)]][RSHNH[RUH(1)]][TB...] |
|
220 |
// |
|
221 |
// Parameter annotations are a counted list of regular annotations. |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
222 |
// pack.method.attribute.RuntimeVisibleParameterAnnotations=[NB[(1)]][NH[(1)]][RSHNH[RUH(1)]][TB...] |
2 | 223 |
// |
224 |
// RuntimeInvisible annotations are defined similarly... |
|
225 |
// Non-method annotations are defined similarly... |
|
226 |
// |
|
227 |
// Annotation are a simple tagged value [TB...] |
|
228 |
// pack.attribute.method.AnnotationDefault=[TB...] |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
229 |
|
2 | 230 |
static { |
231 |
String mdLayouts[] = { |
|
232 |
Attribute.normalizeLayoutString |
|
233 |
("" |
|
234 |
+"\n # parameter_annotations :=" |
|
235 |
+"\n [ NB[(1)] ] # forward call to annotations" |
|
236 |
), |
|
237 |
Attribute.normalizeLayoutString |
|
238 |
("" |
|
239 |
+"\n # annotations :=" |
|
240 |
+"\n [ NH[(1)] ] # forward call to annotation" |
|
241 |
+"\n " |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
242 |
), |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
243 |
Attribute.normalizeLayoutString |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
244 |
("" |
2 | 245 |
+"\n # annotation :=" |
246 |
+"\n [RSH" |
|
247 |
+"\n NH[RUH (1)] # forward call to value" |
|
248 |
+"\n ]" |
|
249 |
), |
|
250 |
Attribute.normalizeLayoutString |
|
251 |
("" |
|
252 |
+"\n # value :=" |
|
253 |
+"\n [TB # Callable 2 encodes one tagged value." |
|
254 |
+"\n (\\B,\\C,\\I,\\S,\\Z)[KIH]" |
|
255 |
+"\n (\\D)[KDH]" |
|
256 |
+"\n (\\F)[KFH]" |
|
257 |
+"\n (\\J)[KJH]" |
|
258 |
+"\n (\\c)[RSH]" |
|
259 |
+"\n (\\e)[RSH RUH]" |
|
260 |
+"\n (\\s)[RUH]" |
|
261 |
+"\n (\\[)[NH[(0)]] # backward self-call to value" |
|
262 |
+"\n (\\@)[RSH NH[RUH (0)]] # backward self-call to value" |
|
263 |
+"\n ()[] ]" |
|
264 |
) |
|
265 |
}; |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
266 |
/* |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
267 |
* RuntimeVisibleTypeAnnotation and RuntimeInvisibleTypeAnnotatation are |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
268 |
* similar to RuntimeVisibleAnnotation and RuntimeInvisibleAnnotation, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
269 |
* a type-annotation union and a type-path structure precedes the |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
270 |
* annotation structure |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
271 |
*/ |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
272 |
String typeLayouts[] = { |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
273 |
Attribute.normalizeLayoutString |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
274 |
("" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
275 |
+"\n # type-annotations :=" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
276 |
+"\n [ NH[(1)(2)(3)] ] # forward call to type-annotations" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
277 |
), |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
278 |
Attribute.normalizeLayoutString |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
279 |
( "" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
280 |
+"\n # type-annotation :=" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
281 |
+"\n [TB" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
282 |
+"\n (0-1) [B] # {CLASS, METHOD}_TYPE_PARAMETER" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
283 |
+"\n (16) [FH] # CLASS_EXTENDS" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
284 |
+"\n (17-18) [BB] # {CLASS, METHOD}_TYPE_PARAMETER_BOUND" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
285 |
+"\n (19-21) [] # FIELD, METHOD_RETURN, METHOD_RECEIVER" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
286 |
+"\n (22) [B] # METHOD_FORMAL_PARAMETER" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
287 |
+"\n (23) [H] # THROWS" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
288 |
+"\n (64-65) [NH[PHOHH]] # LOCAL_VARIABLE, RESOURCE_VARIABLE" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
289 |
+"\n (66) [H] # EXCEPTION_PARAMETER" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
290 |
+"\n (67-70) [PH] # INSTANCEOF, NEW, {CONSTRUCTOR, METHOD}_REFERENCE_RECEIVER" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
291 |
+"\n (71-75) [PHB] # CAST, {CONSTRUCTOR,METHOD}_INVOCATION_TYPE_ARGUMENT, {CONSTRUCTOR, METHOD}_REFERENCE_TYPE_ARGUMENT" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
292 |
+"\n ()[] ]" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
293 |
), |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
294 |
Attribute.normalizeLayoutString |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
295 |
("" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
296 |
+"\n # type-path" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
297 |
+"\n [ NB[BB] ]" |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
298 |
) |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
299 |
}; |
6313 | 300 |
Map<Layout, Attribute> sd = standardDefs; |
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
301 |
String defaultLayout = mdLayouts[3]; |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
302 |
String annotationsLayout = mdLayouts[1] + mdLayouts[2] + mdLayouts[3]; |
2 | 303 |
String paramsLayout = mdLayouts[0] + annotationsLayout; |
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
304 |
String typesLayout = typeLayouts[0] + typeLayouts[1] + |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
305 |
typeLayouts[2] + mdLayouts[2] + mdLayouts[3]; |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
306 |
|
2 | 307 |
for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) { |
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
308 |
if (ctype != ATTR_CONTEXT_CODE) { |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
309 |
define(sd, ctype, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
310 |
"RuntimeVisibleAnnotations", annotationsLayout); |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
311 |
define(sd, ctype, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
312 |
"RuntimeInvisibleAnnotations", annotationsLayout); |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
313 |
|
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
314 |
if (ctype == ATTR_CONTEXT_METHOD) { |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
315 |
define(sd, ctype, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
316 |
"RuntimeVisibleParameterAnnotations", paramsLayout); |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
317 |
define(sd, ctype, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
318 |
"RuntimeInvisibleParameterAnnotations", paramsLayout); |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
319 |
define(sd, ctype, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
320 |
"AnnotationDefault", defaultLayout); |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
321 |
} |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
322 |
} |
2 | 323 |
define(sd, ctype, |
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
324 |
"RuntimeVisibleTypeAnnotations", typesLayout); |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
325 |
define(sd, ctype, |
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
326 |
"RuntimeInvisibleTypeAnnotations", typesLayout); |
2 | 327 |
} |
328 |
} |
|
329 |
||
330 |
public static String contextName(int ctype) { |
|
331 |
switch (ctype) { |
|
332 |
case ATTR_CONTEXT_CLASS: return "class"; |
|
333 |
case ATTR_CONTEXT_FIELD: return "field"; |
|
334 |
case ATTR_CONTEXT_METHOD: return "method"; |
|
335 |
case ATTR_CONTEXT_CODE: return "code"; |
|
336 |
} |
|
337 |
return null; |
|
338 |
} |
|
339 |
||
340 |
/** Base class for any attributed object (Class, Field, Method, Code). |
|
341 |
* Flags are included because they are used to help transmit the |
|
342 |
* presence of attributes. That is, flags are a mix of modifier |
|
343 |
* bits and attribute indicators. |
|
344 |
*/ |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
345 |
public abstract static |
2 | 346 |
class Holder { |
347 |
||
348 |
// We need this abstract method to interpret embedded CP refs. |
|
349 |
protected abstract Entry[] getCPMap(); |
|
350 |
||
351 |
protected int flags; // defined here for convenience |
|
6313 | 352 |
protected List<Attribute> attributes; |
2 | 353 |
|
354 |
public int attributeSize() { |
|
355 |
return (attributes == null) ? 0 : attributes.size(); |
|
356 |
} |
|
357 |
||
358 |
public void trimToSize() { |
|
359 |
if (attributes == null) { |
|
360 |
return; |
|
361 |
} |
|
6313 | 362 |
if (attributes.isEmpty()) { |
2 | 363 |
attributes = null; |
364 |
return; |
|
365 |
} |
|
366 |
if (attributes instanceof ArrayList) { |
|
6313 | 367 |
ArrayList<Attribute> al = (ArrayList<Attribute>)attributes; |
2 | 368 |
al.trimToSize(); |
369 |
boolean allCanon = true; |
|
6313 | 370 |
for (Attribute a : al) { |
2 | 371 |
if (!a.isCanonical()) { |
372 |
allCanon = false; |
|
373 |
} |
|
374 |
if (a.fixups != null) { |
|
375 |
assert(!a.isCanonical()); |
|
376 |
a.fixups = Fixups.trimToSize(a.fixups); |
|
377 |
} |
|
378 |
} |
|
379 |
if (allCanon) { |
|
380 |
// Replace private writable attribute list |
|
381 |
// with only trivial entries by public unique |
|
382 |
// immutable attribute list with the same entries. |
|
383 |
attributes = getCanonList(al); |
|
384 |
} |
|
385 |
} |
|
386 |
} |
|
387 |
||
388 |
public void addAttribute(Attribute a) { |
|
389 |
if (attributes == null) |
|
6313 | 390 |
attributes = new ArrayList<>(3); |
2 | 391 |
else if (!(attributes instanceof ArrayList)) |
6313 | 392 |
attributes = new ArrayList<>(attributes); // unfreeze it |
2 | 393 |
attributes.add(a); |
394 |
} |
|
395 |
||
396 |
public Attribute removeAttribute(Attribute a) { |
|
397 |
if (attributes == null) return null; |
|
398 |
if (!attributes.contains(a)) return null; |
|
399 |
if (!(attributes instanceof ArrayList)) |
|
6313 | 400 |
attributes = new ArrayList<>(attributes); // unfreeze it |
2 | 401 |
attributes.remove(a); |
402 |
return a; |
|
403 |
} |
|
404 |
||
405 |
public Attribute getAttribute(int n) { |
|
6313 | 406 |
return attributes.get(n); |
2 | 407 |
} |
408 |
||
6313 | 409 |
protected void visitRefs(int mode, Collection<Entry> refs) { |
2 | 410 |
if (attributes == null) return; |
6313 | 411 |
for (Attribute a : attributes) { |
2 | 412 |
a.visitRefs(this, mode, refs); |
413 |
} |
|
414 |
} |
|
415 |
||
6313 | 416 |
static final List<Attribute> noAttributes = Arrays.asList(new Attribute[0]); |
2 | 417 |
|
6313 | 418 |
public List<Attribute> getAttributes() { |
2 | 419 |
if (attributes == null) |
420 |
return noAttributes; |
|
421 |
return attributes; |
|
422 |
} |
|
423 |
||
6313 | 424 |
public void setAttributes(List<Attribute> attrList) { |
2 | 425 |
if (attrList.isEmpty()) |
426 |
attributes = null; |
|
427 |
else |
|
428 |
attributes = attrList; |
|
429 |
} |
|
430 |
||
431 |
public Attribute getAttribute(String attrName) { |
|
432 |
if (attributes == null) return null; |
|
6313 | 433 |
for (Attribute a : attributes) { |
2 | 434 |
if (a.name().equals(attrName)) |
435 |
return a; |
|
436 |
} |
|
437 |
return null; |
|
438 |
} |
|
439 |
||
440 |
public Attribute getAttribute(Layout attrDef) { |
|
441 |
if (attributes == null) return null; |
|
6313 | 442 |
for (Attribute a : attributes) { |
2 | 443 |
if (a.layout() == attrDef) |
444 |
return a; |
|
445 |
} |
|
446 |
return null; |
|
447 |
} |
|
448 |
||
449 |
public Attribute removeAttribute(String attrName) { |
|
450 |
return removeAttribute(getAttribute(attrName)); |
|
451 |
} |
|
452 |
||
453 |
public Attribute removeAttribute(Layout attrDef) { |
|
454 |
return removeAttribute(getAttribute(attrDef)); |
|
455 |
} |
|
456 |
||
457 |
public void strip(String attrName) { |
|
458 |
removeAttribute(getAttribute(attrName)); |
|
459 |
} |
|
460 |
} |
|
461 |
||
462 |
// Lightweight interface to hide details of band structure. |
|
463 |
// Also used for testing. |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
464 |
public abstract static |
2 | 465 |
class ValueStream { |
466 |
public int getInt(int bandIndex) { throw undef(); } |
|
467 |
public void putInt(int bandIndex, int value) { throw undef(); } |
|
468 |
public Entry getRef(int bandIndex) { throw undef(); } |
|
469 |
public void putRef(int bandIndex, Entry ref) { throw undef(); } |
|
470 |
// Note: decodeBCI goes w/ getInt/Ref; encodeBCI goes w/ putInt/Ref |
|
471 |
public int decodeBCI(int bciCode) { throw undef(); } |
|
472 |
public int encodeBCI(int bci) { throw undef(); } |
|
473 |
public void noteBackCall(int whichCallable) { /* ignore by default */ } |
|
474 |
private RuntimeException undef() { |
|
475 |
return new UnsupportedOperationException("ValueStream method"); |
|
476 |
} |
|
477 |
} |
|
478 |
||
479 |
// Element kinds: |
|
480 |
static final byte EK_INT = 1; // B H I SH etc. |
|
481 |
static final byte EK_BCI = 2; // PH POH etc. |
|
482 |
static final byte EK_BCO = 3; // OH etc. |
|
483 |
static final byte EK_FLAG = 4; // FH etc. |
|
484 |
static final byte EK_REPL = 5; // NH[...] etc. |
|
485 |
static final byte EK_REF = 6; // RUH, RUNH, KQH, etc. |
|
486 |
static final byte EK_UN = 7; // TB(...)[...] etc. |
|
487 |
static final byte EK_CASE = 8; // (...)[...] etc. |
|
488 |
static final byte EK_CALL = 9; // (0), (1), etc. |
|
489 |
static final byte EK_CBLE = 10; // [...][...] etc. |
|
490 |
static final byte EF_SIGN = 1<<0; // INT is signed |
|
491 |
static final byte EF_DELTA = 1<<1; // BCI/BCI value is diff'ed w/ previous |
|
492 |
static final byte EF_NULL = 1<<2; // null REF is expected/allowed |
|
493 |
static final byte EF_BACK = 1<<3; // call, callable, case is backward |
|
494 |
static final int NO_BAND_INDEX = -1; |
|
495 |
||
496 |
/** A "class" of attributes, characterized by a context-type, name |
|
497 |
* and format. The formats are specified in a "little language". |
|
498 |
*/ |
|
499 |
public static |
|
10115 | 500 |
class Layout implements Comparable<Layout> { |
2 | 501 |
int ctype; // attribute context type, e.g., ATTR_CONTEXT_CODE |
502 |
String name; // name of attribute |
|
503 |
boolean hasRefs; // this kind of attr contains CP refs? |
|
504 |
String layout; // layout specification |
|
505 |
int bandCount; // total number of elems |
|
506 |
Element[] elems; // tokenization of layout |
|
507 |
Attribute canon; // canonical instance of this layout |
|
508 |
||
509 |
public int ctype() { return ctype; } |
|
510 |
public String name() { return name; } |
|
511 |
public String layout() { return layout; } |
|
512 |
public Attribute canonicalInstance() { return canon; } |
|
513 |
||
514 |
public Entry getNameRef() { |
|
6313 | 515 |
return ConstantPool.getUtf8Entry(name()); |
2 | 516 |
} |
517 |
||
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
518 |
public boolean isEmpty() { |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
519 |
return layout.isEmpty(); |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
520 |
} |
2 | 521 |
|
522 |
public Layout(int ctype, String name, String layout) { |
|
523 |
this.ctype = ctype; |
|
524 |
this.name = name.intern(); |
|
525 |
this.layout = layout.intern(); |
|
526 |
assert(ctype < ATTR_CONTEXT_LIMIT); |
|
527 |
boolean hasCallables = layout.startsWith("["); |
|
528 |
try { |
|
529 |
if (!hasCallables) { |
|
530 |
this.elems = tokenizeLayout(this, -1, layout); |
|
531 |
} else { |
|
532 |
String[] bodies = splitBodies(layout); |
|
533 |
// Make the callables now, so they can be linked immediately. |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
534 |
Element[] lelems = new Element[bodies.length]; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
535 |
this.elems = lelems; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
536 |
for (int i = 0; i < lelems.length; i++) { |
2 | 537 |
Element ce = this.new Element(); |
538 |
ce.kind = EK_CBLE; |
|
539 |
ce.removeBand(); |
|
540 |
ce.bandIndex = NO_BAND_INDEX; |
|
541 |
ce.layout = bodies[i]; |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
542 |
lelems[i] = ce; |
2 | 543 |
} |
544 |
// Next fill them in. |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
545 |
for (int i = 0; i < lelems.length; i++) { |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
546 |
Element ce = lelems[i]; |
2 | 547 |
ce.body = tokenizeLayout(this, i, bodies[i]); |
548 |
} |
|
549 |
//System.out.println(Arrays.asList(elems)); |
|
550 |
} |
|
551 |
} catch (StringIndexOutOfBoundsException ee) { |
|
552 |
// simplest way to catch syntax errors... |
|
553 |
throw new RuntimeException("Bad attribute layout: "+layout, ee); |
|
554 |
} |
|
555 |
// Some uses do not make a fresh one for each occurrence. |
|
556 |
// For example, if layout == "", we only need one attr to share. |
|
557 |
canon = new Attribute(this, noBytes); |
|
558 |
} |
|
559 |
private Layout() {} |
|
560 |
static Layout makeKey(int ctype, String name, String layout) { |
|
561 |
Layout def = new Layout(); |
|
562 |
def.ctype = ctype; |
|
563 |
def.name = name.intern(); |
|
564 |
def.layout = layout.intern(); |
|
565 |
assert(ctype < ATTR_CONTEXT_LIMIT); |
|
566 |
return def; |
|
567 |
} |
|
568 |
static Layout makeKey(int ctype, String name) { |
|
569 |
return makeKey(ctype, name, ""); |
|
570 |
} |
|
571 |
||
572 |
public Attribute addContent(byte[] bytes, Object fixups) { |
|
573 |
return canon.addContent(bytes, fixups); |
|
574 |
} |
|
575 |
public Attribute addContent(byte[] bytes) { |
|
576 |
return canon.addContent(bytes, null); |
|
577 |
} |
|
578 |
||
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
579 |
@Override |
2 | 580 |
public boolean equals(Object x) { |
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
581 |
return ( x != null) && ( x.getClass() == Layout.class ) && |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
582 |
equals((Layout)x); |
2 | 583 |
} |
584 |
public boolean equals(Layout that) { |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
585 |
return this.name.equals(that.name) |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
586 |
&& this.layout.equals(that.layout) |
2 | 587 |
&& this.ctype == that.ctype; |
588 |
} |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
589 |
@Override |
2 | 590 |
public int hashCode() { |
591 |
return (((17 + name.hashCode()) |
|
592 |
* 37 + layout.hashCode()) |
|
593 |
* 37 + ctype); |
|
594 |
} |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
595 |
@Override |
10115 | 596 |
public int compareTo(Layout that) { |
2 | 597 |
int r; |
598 |
r = this.name.compareTo(that.name); |
|
599 |
if (r != 0) return r; |
|
600 |
r = this.layout.compareTo(that.layout); |
|
601 |
if (r != 0) return r; |
|
602 |
return this.ctype - that.ctype; |
|
603 |
} |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
604 |
@Override |
2 | 605 |
public String toString() { |
606 |
String str = contextName(ctype)+"."+name+"["+layout+"]"; |
|
607 |
// If -ea, print out more informative strings! |
|
608 |
assert((str = stringForDebug()) != null); |
|
609 |
return str; |
|
610 |
} |
|
611 |
private String stringForDebug() { |
|
612 |
return contextName(ctype)+"."+name+Arrays.asList(elems); |
|
613 |
} |
|
614 |
||
615 |
public |
|
616 |
class Element { |
|
617 |
String layout; // spelling in the little language |
|
618 |
byte flags; // EF_SIGN, etc. |
|
619 |
byte kind; // EK_UINT, etc. |
|
620 |
byte len; // scalar length of element |
|
621 |
byte refKind; // CONSTANT_String, etc. |
|
622 |
int bandIndex; // which band does this element govern? |
|
623 |
int value; // extra parameter |
|
624 |
Element[] body; // extra data (for replications, unions, calls) |
|
625 |
||
626 |
boolean flagTest(byte mask) { return (flags & mask) != 0; } |
|
627 |
||
628 |
Element() { |
|
629 |
bandIndex = bandCount++; |
|
630 |
} |
|
631 |
||
632 |
void removeBand() { |
|
633 |
--bandCount; |
|
634 |
assert(bandIndex == bandCount); |
|
635 |
bandIndex = NO_BAND_INDEX; |
|
636 |
} |
|
637 |
||
638 |
public boolean hasBand() { |
|
639 |
return bandIndex >= 0; |
|
640 |
} |
|
641 |
public String toString() { |
|
642 |
String str = layout; |
|
643 |
// If -ea, print out more informative strings! |
|
644 |
assert((str = stringForDebug()) != null); |
|
645 |
return str; |
|
646 |
} |
|
647 |
private String stringForDebug() { |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
648 |
Element[] lbody = this.body; |
2 | 649 |
switch (kind) { |
650 |
case EK_CALL: |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
651 |
lbody = null; |
2 | 652 |
break; |
653 |
case EK_CASE: |
|
654 |
if (flagTest(EF_BACK)) |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
655 |
lbody = null; |
2 | 656 |
break; |
657 |
} |
|
658 |
return layout |
|
659 |
+ (!hasBand()?"":"#"+bandIndex) |
|
660 |
+ "<"+ (flags==0?"":""+flags)+kind+len |
|
661 |
+ (refKind==0?"":""+refKind) + ">" |
|
662 |
+ (value==0?"":"("+value+")") |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
663 |
+ (lbody==null?"": ""+Arrays.asList(lbody)); |
2 | 664 |
} |
665 |
} |
|
666 |
||
667 |
public boolean hasCallables() { |
|
668 |
return (elems.length > 0 && elems[0].kind == EK_CBLE); |
|
669 |
} |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
670 |
private static final Element[] noElems = {}; |
2 | 671 |
public Element[] getCallables() { |
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
672 |
if (hasCallables()) { |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
673 |
Element[] nelems = Arrays.copyOf(elems, elems.length); |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
674 |
return nelems; |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
675 |
} else |
2 | 676 |
return noElems; // no callables at all |
677 |
} |
|
678 |
public Element[] getEntryPoint() { |
|
679 |
if (hasCallables()) |
|
680 |
return elems[0].body; // body of first callable |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
681 |
else { |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
682 |
Element[] nelems = Arrays.copyOf(elems, elems.length); |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
683 |
return nelems; // no callables; whole body |
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
684 |
} |
2 | 685 |
} |
686 |
||
687 |
/** Return a sequence of tokens from the given attribute bytes. |
|
688 |
* Sequence elements will be 1-1 correspondent with my layout tokens. |
|
689 |
*/ |
|
690 |
public void parse(Holder holder, |
|
691 |
byte[] bytes, int pos, int len, ValueStream out) { |
|
692 |
int end = parseUsing(getEntryPoint(), |
|
693 |
holder, bytes, pos, len, out); |
|
694 |
if (end != pos + len) |
|
695 |
throw new InternalError("layout parsed "+(end-pos)+" out of "+len+" bytes"); |
|
696 |
} |
|
697 |
/** Given a sequence of tokens, return the attribute bytes. |
|
698 |
* Sequence elements must be 1-1 correspondent with my layout tokens. |
|
699 |
* The returned object is a cookie for Fixups.finishRefs, which |
|
700 |
* must be used to harden any references into integer indexes. |
|
701 |
*/ |
|
702 |
public Object unparse(ValueStream in, ByteArrayOutputStream out) { |
|
703 |
Object[] fixups = { null }; |
|
704 |
unparseUsing(getEntryPoint(), fixups, in, out); |
|
705 |
return fixups[0]; // return ref-bearing cookie, if any |
|
706 |
} |
|
707 |
||
12857
0a5f341c2a28
7168401: pack200 does not produce a compatible pack file for JDK7 classes if indy is not present
ksrini
parents:
12544
diff
changeset
|
708 |
public String layoutForClassVersion(Package.Version vers) { |
0a5f341c2a28
7168401: pack200 does not produce a compatible pack file for JDK7 classes if indy is not present
ksrini
parents:
12544
diff
changeset
|
709 |
if (vers.lessThan(JAVA6_MAX_CLASS_VERSION)) { |
2 | 710 |
// Disallow layout syntax in the oldest protocol version. |
711 |
return expandCaseDashNotation(layout); |
|
712 |
} |
|
713 |
return layout; |
|
714 |
} |
|
715 |
} |
|
716 |
||
717 |
public static |
|
718 |
class FormatException extends IOException { |
|
10115 | 719 |
private static final long serialVersionUID = -2542243830788066513L; |
720 |
||
2 | 721 |
private int ctype; |
722 |
private String name; |
|
723 |
String layout; |
|
724 |
public FormatException(String message, |
|
725 |
int ctype, String name, String layout) { |
|
6901 | 726 |
super(ATTR_CONTEXT_NAME[ctype]+ " attribute \"" + name + "\"" + |
727 |
(message == null? "" : (": " + message))); |
|
2 | 728 |
this.ctype = ctype; |
729 |
this.name = name; |
|
730 |
this.layout = layout; |
|
731 |
} |
|
732 |
public FormatException(String message, |
|
733 |
int ctype, String name) { |
|
734 |
this(message, ctype, name, null); |
|
735 |
} |
|
736 |
} |
|
737 |
||
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
738 |
void visitRefs(Holder holder, int mode, final Collection<Entry> refs) { |
2 | 739 |
if (mode == VRM_CLASSIC) { |
740 |
refs.add(getNameRef()); |
|
741 |
} |
|
742 |
// else the name is owned by the layout, and is processed elsewhere |
|
743 |
if (bytes.length == 0) return; // quick exit |
|
744 |
if (!def.hasRefs) return; // quick exit |
|
745 |
if (fixups != null) { |
|
746 |
Fixups.visitRefs(fixups, refs); |
|
747 |
return; |
|
748 |
} |
|
749 |
// References (to a local cpMap) are embedded in the bytes. |
|
750 |
def.parse(holder, bytes, 0, bytes.length, |
|
751 |
new ValueStream() { |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
752 |
@Override |
2 | 753 |
public void putInt(int bandIndex, int value) { |
754 |
} |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
755 |
@Override |
2 | 756 |
public void putRef(int bandIndex, Entry ref) { |
757 |
refs.add(ref); |
|
758 |
} |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
759 |
@Override |
2 | 760 |
public int encodeBCI(int bci) { |
761 |
return bci; |
|
762 |
} |
|
763 |
}); |
|
764 |
} |
|
765 |
||
766 |
public void parse(Holder holder, byte[] bytes, int pos, int len, ValueStream out) { |
|
767 |
def.parse(holder, bytes, pos, len, out); |
|
768 |
} |
|
769 |
public Object unparse(ValueStream in, ByteArrayOutputStream out) { |
|
770 |
return def.unparse(in, out); |
|
771 |
} |
|
772 |
||
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
773 |
@Override |
2 | 774 |
public String toString() { |
775 |
return def |
|
776 |
+"{"+(bytes == null ? -1 : size())+"}" |
|
777 |
+(fixups == null? "": fixups.toString()); |
|
778 |
} |
|
779 |
||
780 |
/** Remove any informal "pretty printing" from the layout string. |
|
781 |
* Removes blanks and control chars. |
|
782 |
* Removes '#' comments (to end of line). |
|
783 |
* Replaces '\c' by the decimal code of the character c. |
|
784 |
* Replaces '0xNNN' by the decimal code of the hex number NNN. |
|
785 |
*/ |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
786 |
public static |
2 | 787 |
String normalizeLayoutString(String layout) { |
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
788 |
StringBuilder buf = new StringBuilder(); |
2 | 789 |
for (int i = 0, len = layout.length(); i < len; ) { |
790 |
char ch = layout.charAt(i++); |
|
791 |
if (ch <= ' ') { |
|
792 |
// Skip whitespace and control chars |
|
793 |
continue; |
|
794 |
} else if (ch == '#') { |
|
795 |
// Skip to end of line. |
|
796 |
int end1 = layout.indexOf('\n', i); |
|
797 |
int end2 = layout.indexOf('\r', i); |
|
798 |
if (end1 < 0) end1 = len; |
|
799 |
if (end2 < 0) end2 = len; |
|
800 |
i = Math.min(end1, end2); |
|
801 |
} else if (ch == '\\') { |
|
802 |
// Map a character reference to its decimal code. |
|
803 |
buf.append((int) layout.charAt(i++)); |
|
804 |
} else if (ch == '0' && layout.startsWith("0x", i-1)) { |
|
805 |
// Map a hex numeral to its decimal code. |
|
806 |
int start = i-1; |
|
807 |
int end = start+2; |
|
808 |
while (end < len) { |
|
809 |
int dig = layout.charAt(end); |
|
810 |
if ((dig >= '0' && dig <= '9') || |
|
811 |
(dig >= 'a' && dig <= 'f')) |
|
812 |
++end; |
|
813 |
else |
|
814 |
break; |
|
815 |
} |
|
816 |
if (end > start) { |
|
817 |
String num = layout.substring(start, end); |
|
818 |
buf.append(Integer.decode(num)); |
|
819 |
i = end; |
|
820 |
} else { |
|
821 |
buf.append(ch); |
|
822 |
} |
|
823 |
} else { |
|
824 |
buf.append(ch); |
|
825 |
} |
|
826 |
} |
|
827 |
String result = buf.toString(); |
|
828 |
if (false && !result.equals(layout)) { |
|
829 |
Utils.log.info("Normalizing layout string"); |
|
830 |
Utils.log.info(" From: "+layout); |
|
831 |
Utils.log.info(" To: "+result); |
|
832 |
} |
|
833 |
return result; |
|
834 |
} |
|
835 |
||
836 |
/// Subroutines for parsing and unparsing: |
|
837 |
||
838 |
/** Parse the attribute layout language. |
|
839 |
<pre> |
|
840 |
attribute_layout: |
|
841 |
( layout_element )* | ( callable )+ |
|
842 |
layout_element: |
|
843 |
( integral | replication | union | call | reference ) |
|
844 |
||
845 |
callable: |
|
846 |
'[' body ']' |
|
847 |
body: |
|
848 |
( layout_element )+ |
|
849 |
||
850 |
integral: |
|
851 |
( unsigned_int | signed_int | bc_index | bc_offset | flag ) |
|
852 |
unsigned_int: |
|
853 |
uint_type |
|
854 |
signed_int: |
|
855 |
'S' uint_type |
|
856 |
any_int: |
|
857 |
( unsigned_int | signed_int ) |
|
858 |
bc_index: |
|
859 |
( 'P' uint_type | 'PO' uint_type ) |
|
860 |
bc_offset: |
|
861 |
'O' any_int |
|
862 |
flag: |
|
863 |
'F' uint_type |
|
864 |
uint_type: |
|
865 |
( 'B' | 'H' | 'I' | 'V' ) |
|
866 |
||
867 |
replication: |
|
868 |
'N' uint_type '[' body ']' |
|
869 |
||
870 |
union: |
|
871 |
'T' any_int (union_case)* '(' ')' '[' (body)? ']' |
|
872 |
union_case: |
|
873 |
'(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']' |
|
874 |
union_case_tag: |
|
875 |
( numeral | numeral '-' numeral ) |
|
876 |
call: |
|
877 |
'(' numeral ')' |
|
878 |
||
879 |
reference: |
|
880 |
reference_type ( 'N' )? uint_type |
|
881 |
reference_type: |
|
882 |
( constant_ref | schema_ref | utf8_ref | untyped_ref ) |
|
883 |
constant_ref: |
|
12544 | 884 |
( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' | 'KM' | 'KT' | 'KL' ) |
2 | 885 |
schema_ref: |
12544 | 886 |
( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' | 'RY' | 'RB' | 'RN' ) |
2 | 887 |
utf8_ref: |
888 |
'RU' |
|
889 |
untyped_ref: |
|
890 |
'RQ' |
|
891 |
||
892 |
numeral: |
|
893 |
'(' ('-')? (digit)+ ')' |
|
894 |
digit: |
|
895 |
( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ) |
|
896 |
</pre> |
|
897 |
*/ |
|
898 |
static //private |
|
899 |
Layout.Element[] tokenizeLayout(Layout self, int curCble, String layout) { |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
900 |
List<Layout.Element> col = new ArrayList<>(layout.length()); |
2 | 901 |
tokenizeLayout(self, curCble, layout, col); |
902 |
Layout.Element[] res = new Layout.Element[col.size()]; |
|
903 |
col.toArray(res); |
|
904 |
return res; |
|
905 |
} |
|
906 |
static //private |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
907 |
void tokenizeLayout(Layout self, int curCble, String layout, List<Layout.Element> col) { |
2 | 908 |
boolean prevBCI = false; |
909 |
for (int len = layout.length(), i = 0; i < len; ) { |
|
910 |
int start = i; |
|
911 |
int body; |
|
912 |
Layout.Element e = self.new Element(); |
|
913 |
byte kind; |
|
914 |
//System.out.println("at "+i+": ..."+layout.substring(i)); |
|
915 |
// strip a prefix |
|
916 |
switch (layout.charAt(i++)) { |
|
917 |
/// layout_element: integral |
|
918 |
case 'B': case 'H': case 'I': case 'V': // unsigned_int |
|
919 |
kind = EK_INT; |
|
920 |
--i; // reparse |
|
921 |
i = tokenizeUInt(e, layout, i); |
|
922 |
break; |
|
923 |
case 'S': // signed_int |
|
924 |
kind = EK_INT; |
|
925 |
--i; // reparse |
|
926 |
i = tokenizeSInt(e, layout, i); |
|
927 |
break; |
|
928 |
case 'P': // bc_index |
|
929 |
kind = EK_BCI; |
|
930 |
if (layout.charAt(i++) == 'O') { |
|
931 |
// bc_index: 'PO' tokenizeUInt |
|
932 |
e.flags |= EF_DELTA; |
|
933 |
// must follow P or PO: |
|
934 |
if (!prevBCI) |
|
935 |
{ i = -i; continue; } // fail |
|
936 |
i++; // move forward |
|
937 |
} |
|
938 |
--i; // reparse |
|
939 |
i = tokenizeUInt(e, layout, i); |
|
940 |
break; |
|
941 |
case 'O': // bc_offset |
|
942 |
kind = EK_BCO; |
|
943 |
e.flags |= EF_DELTA; |
|
944 |
// must follow P or PO: |
|
945 |
if (!prevBCI) |
|
946 |
{ i = -i; continue; } // fail |
|
947 |
i = tokenizeSInt(e, layout, i); |
|
948 |
break; |
|
949 |
case 'F': // flag |
|
950 |
kind = EK_FLAG; |
|
951 |
i = tokenizeUInt(e, layout, i); |
|
952 |
break; |
|
953 |
case 'N': // replication: 'N' uint '[' elem ... ']' |
|
954 |
kind = EK_REPL; |
|
955 |
i = tokenizeUInt(e, layout, i); |
|
956 |
if (layout.charAt(i++) != '[') |
|
957 |
{ i = -i; continue; } // fail |
|
958 |
i = skipBody(layout, body = i); |
|
959 |
e.body = tokenizeLayout(self, curCble, |
|
960 |
layout.substring(body, i++)); |
|
961 |
break; |
|
962 |
case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']' |
|
963 |
kind = EK_UN; |
|
964 |
i = tokenizeSInt(e, layout, i); |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
965 |
List<Layout.Element> cases = new ArrayList<>(); |
2 | 966 |
for (;;) { |
967 |
// Keep parsing cases until we hit the default case. |
|
968 |
if (layout.charAt(i++) != '(') |
|
969 |
{ i = -i; break; } // fail |
|
970 |
int beg = i; |
|
971 |
i = layout.indexOf(')', i); |
|
972 |
String cstr = layout.substring(beg, i++); |
|
973 |
int cstrlen = cstr.length(); |
|
974 |
if (layout.charAt(i++) != '[') |
|
975 |
{ i = -i; break; } // fail |
|
976 |
// Check for duplication. |
|
977 |
if (layout.charAt(i) == ']') |
|
978 |
body = i; // missing body, which is legal here |
|
979 |
else |
|
980 |
i = skipBody(layout, body = i); |
|
981 |
Layout.Element[] cbody |
|
982 |
= tokenizeLayout(self, curCble, |
|
983 |
layout.substring(body, i++)); |
|
984 |
if (cstrlen == 0) { |
|
985 |
Layout.Element ce = self.new Element(); |
|
986 |
ce.body = cbody; |
|
987 |
ce.kind = EK_CASE; |
|
988 |
ce.removeBand(); |
|
989 |
cases.add(ce); |
|
990 |
break; // done with the whole union |
|
991 |
} else { |
|
992 |
// Parse a case string. |
|
993 |
boolean firstCaseNum = true; |
|
994 |
for (int cp = 0, endp;; cp = endp+1) { |
|
995 |
// Look for multiple case tags: |
|
996 |
endp = cstr.indexOf(',', cp); |
|
997 |
if (endp < 0) endp = cstrlen; |
|
998 |
String cstr1 = cstr.substring(cp, endp); |
|
53018
8bf9268df0e2
8215281: Use String.isEmpty() when applicable in java.base
redestad
parents:
47216
diff
changeset
|
999 |
if (cstr1.isEmpty()) |
2 | 1000 |
cstr1 = "empty"; // will fail parse |
1001 |
int value0, value1; |
|
1002 |
// Check for a case range (new in 1.6). |
|
1003 |
int dash = findCaseDash(cstr1, 0); |
|
1004 |
if (dash >= 0) { |
|
1005 |
value0 = parseIntBefore(cstr1, dash); |
|
1006 |
value1 = parseIntAfter(cstr1, dash); |
|
1007 |
if (value0 >= value1) |
|
1008 |
{ i = -i; break; } // fail |
|
1009 |
} else { |
|
1010 |
value0 = value1 = Integer.parseInt(cstr1); |
|
1011 |
} |
|
1012 |
// Add a case for each value in value0..value1 |
|
1013 |
for (;; value0++) { |
|
1014 |
Layout.Element ce = self.new Element(); |
|
1015 |
ce.body = cbody; // all cases share one body |
|
1016 |
ce.kind = EK_CASE; |
|
1017 |
ce.removeBand(); |
|
1018 |
if (!firstCaseNum) |
|
1019 |
// "backward case" repeats a body |
|
1020 |
ce.flags |= EF_BACK; |
|
1021 |
firstCaseNum = false; |
|
1022 |
ce.value = value0; |
|
1023 |
cases.add(ce); |
|
1024 |
if (value0 == value1) break; |
|
1025 |
} |
|
1026 |
if (endp == cstrlen) { |
|
1027 |
break; // done with this case |
|
1028 |
} |
|
1029 |
} |
|
1030 |
} |
|
1031 |
} |
|
1032 |
e.body = new Layout.Element[cases.size()]; |
|
1033 |
cases.toArray(e.body); |
|
1034 |
e.kind = kind; |
|
1035 |
for (int j = 0; j < e.body.length-1; j++) { |
|
1036 |
Layout.Element ce = e.body[j]; |
|
1037 |
if (matchCase(e, ce.value) != ce) { |
|
1038 |
// Duplicate tag. |
|
1039 |
{ i = -i; break; } // fail |
|
1040 |
} |
|
1041 |
} |
|
1042 |
break; |
|
1043 |
case '(': // call: '(' '-'? digit+ ')' |
|
1044 |
kind = EK_CALL; |
|
1045 |
e.removeBand(); |
|
1046 |
i = layout.indexOf(')', i); |
|
1047 |
String cstr = layout.substring(start+1, i++); |
|
1048 |
int offset = Integer.parseInt(cstr); |
|
1049 |
int target = curCble + offset; |
|
1050 |
if (!(offset+"").equals(cstr) || |
|
1051 |
self.elems == null || |
|
1052 |
target < 0 || |
|
1053 |
target >= self.elems.length) |
|
1054 |
{ i = -i; continue; } // fail |
|
1055 |
Layout.Element ce = self.elems[target]; |
|
1056 |
assert(ce.kind == EK_CBLE); |
|
1057 |
e.value = target; |
|
1058 |
e.body = new Layout.Element[]{ ce }; |
|
1059 |
// Is it a (recursive) backward call? |
|
1060 |
if (offset <= 0) { |
|
1061 |
// Yes. Mark both caller and callee backward. |
|
1062 |
e.flags |= EF_BACK; |
|
1063 |
ce.flags |= EF_BACK; |
|
1064 |
} |
|
1065 |
break; |
|
1066 |
case 'K': // reference_type: constant_ref |
|
1067 |
kind = EK_REF; |
|
1068 |
switch (layout.charAt(i++)) { |
|
1069 |
case 'I': e.refKind = CONSTANT_Integer; break; |
|
1070 |
case 'J': e.refKind = CONSTANT_Long; break; |
|
1071 |
case 'F': e.refKind = CONSTANT_Float; break; |
|
1072 |
case 'D': e.refKind = CONSTANT_Double; break; |
|
1073 |
case 'S': e.refKind = CONSTANT_String; break; |
|
12544 | 1074 |
case 'Q': e.refKind = CONSTANT_FieldSpecific; break; |
1075 |
||
1076 |
// new in 1.7: |
|
1077 |
case 'M': e.refKind = CONSTANT_MethodHandle; break; |
|
1078 |
case 'T': e.refKind = CONSTANT_MethodType; break; |
|
1079 |
case 'L': e.refKind = CONSTANT_LoadableValue; break; |
|
2 | 1080 |
default: { i = -i; continue; } // fail |
1081 |
} |
|
1082 |
break; |
|
1083 |
case 'R': // schema_ref |
|
1084 |
kind = EK_REF; |
|
1085 |
switch (layout.charAt(i++)) { |
|
1086 |
case 'C': e.refKind = CONSTANT_Class; break; |
|
1087 |
case 'S': e.refKind = CONSTANT_Signature; break; |
|
1088 |
case 'D': e.refKind = CONSTANT_NameandType; break; |
|
1089 |
case 'F': e.refKind = CONSTANT_Fieldref; break; |
|
1090 |
case 'M': e.refKind = CONSTANT_Methodref; break; |
|
1091 |
case 'I': e.refKind = CONSTANT_InterfaceMethodref; break; |
|
1092 |
||
1093 |
case 'U': e.refKind = CONSTANT_Utf8; break; //utf8_ref |
|
1094 |
case 'Q': e.refKind = CONSTANT_All; break; //untyped_ref |
|
1095 |
||
12544 | 1096 |
// new in 1.7: |
1097 |
case 'Y': e.refKind = CONSTANT_InvokeDynamic; break; |
|
1098 |
case 'B': e.refKind = CONSTANT_BootstrapMethod; break; |
|
1099 |
case 'N': e.refKind = CONSTANT_AnyMember; break; |
|
1100 |
||
2 | 1101 |
default: { i = -i; continue; } // fail |
1102 |
} |
|
1103 |
break; |
|
1104 |
default: { i = -i; continue; } // fail |
|
1105 |
} |
|
1106 |
||
1107 |
// further parsing of refs |
|
1108 |
if (kind == EK_REF) { |
|
1109 |
// reference: reference_type -><- ( 'N' )? tokenizeUInt |
|
1110 |
if (layout.charAt(i++) == 'N') { |
|
1111 |
e.flags |= EF_NULL; |
|
1112 |
i++; // move forward |
|
1113 |
} |
|
1114 |
--i; // reparse |
|
1115 |
i = tokenizeUInt(e, layout, i); |
|
1116 |
self.hasRefs = true; |
|
1117 |
} |
|
1118 |
||
1119 |
prevBCI = (kind == EK_BCI); |
|
1120 |
||
1121 |
// store the new element |
|
1122 |
e.kind = kind; |
|
1123 |
e.layout = layout.substring(start, i); |
|
1124 |
col.add(e); |
|
1125 |
} |
|
1126 |
} |
|
1127 |
static //private |
|
1128 |
String[] splitBodies(String layout) { |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
1129 |
List<String> bodies = new ArrayList<>(); |
2 | 1130 |
// Parse several independent layout bodies: "[foo][bar]...[baz]" |
1131 |
for (int i = 0; i < layout.length(); i++) { |
|
1132 |
if (layout.charAt(i++) != '[') |
|
1133 |
layout.charAt(-i); // throw error |
|
1134 |
int body; |
|
1135 |
i = skipBody(layout, body = i); |
|
1136 |
bodies.add(layout.substring(body, i)); |
|
1137 |
} |
|
1138 |
String[] res = new String[bodies.size()]; |
|
1139 |
bodies.toArray(res); |
|
1140 |
return res; |
|
1141 |
} |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
1142 |
private static |
2 | 1143 |
int skipBody(String layout, int i) { |
1144 |
assert(layout.charAt(i-1) == '['); |
|
1145 |
if (layout.charAt(i) == ']') |
|
1146 |
// No empty bodies, please. |
|
1147 |
return -i; |
|
1148 |
// skip balanced [...[...]...] |
|
1149 |
for (int depth = 1; depth > 0; ) { |
|
1150 |
switch (layout.charAt(i++)) { |
|
1151 |
case '[': depth++; break; |
|
1152 |
case ']': depth--; break; |
|
1153 |
} |
|
1154 |
} |
|
1155 |
--i; // get before bracket |
|
1156 |
assert(layout.charAt(i) == ']'); |
|
1157 |
return i; // return closing bracket |
|
1158 |
} |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
1159 |
private static |
2 | 1160 |
int tokenizeUInt(Layout.Element e, String layout, int i) { |
1161 |
switch (layout.charAt(i++)) { |
|
1162 |
case 'V': e.len = 0; break; |
|
1163 |
case 'B': e.len = 1; break; |
|
1164 |
case 'H': e.len = 2; break; |
|
1165 |
case 'I': e.len = 4; break; |
|
1166 |
default: return -i; |
|
1167 |
} |
|
1168 |
return i; |
|
1169 |
} |
|
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
1170 |
private static |
2 | 1171 |
int tokenizeSInt(Layout.Element e, String layout, int i) { |
1172 |
if (layout.charAt(i) == 'S') { |
|
1173 |
e.flags |= EF_SIGN; |
|
1174 |
++i; |
|
1175 |
} |
|
1176 |
return tokenizeUInt(e, layout, i); |
|
1177 |
} |
|
1178 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
1179 |
private static |
2 | 1180 |
boolean isDigit(char c) { |
1181 |
return c >= '0' && c <= '9'; |
|
1182 |
} |
|
1183 |
||
1184 |
/** Find an occurrence of hyphen '-' between two numerals. */ |
|
1185 |
static //private |
|
1186 |
int findCaseDash(String layout, int fromIndex) { |
|
1187 |
if (fromIndex <= 0) fromIndex = 1; // minimum dash pos |
|
1188 |
int lastDash = layout.length() - 2; // maximum dash pos |
|
1189 |
for (;;) { |
|
1190 |
int dash = layout.indexOf('-', fromIndex); |
|
1191 |
if (dash < 0 || dash > lastDash) return -1; |
|
1192 |
if (isDigit(layout.charAt(dash-1))) { |
|
1193 |
char afterDash = layout.charAt(dash+1); |
|
1194 |
if (afterDash == '-' && dash+2 < layout.length()) |
|
1195 |
afterDash = layout.charAt(dash+2); |
|
1196 |
if (isDigit(afterDash)) { |
|
1197 |
// matched /[0-9]--?[0-9]/; return position of dash |
|
1198 |
return dash; |
|
1199 |
} |
|
1200 |
} |
|
1201 |
fromIndex = dash+1; |
|
1202 |
} |
|
1203 |
} |
|
1204 |
static |
|
1205 |
int parseIntBefore(String layout, int dash) { |
|
1206 |
int end = dash; |
|
1207 |
int beg = end; |
|
6313 | 1208 |
while (beg > 0 && isDigit(layout.charAt(beg-1))) { |
1209 |
--beg; |
|
1210 |
} |
|
2 | 1211 |
if (beg == end) return Integer.parseInt("empty"); |
1212 |
// skip backward over a sign |
|
1213 |
if (beg >= 1 && layout.charAt(beg-1) == '-') --beg; |
|
1214 |
assert(beg == 0 || !isDigit(layout.charAt(beg-1))); |
|
1215 |
return Integer.parseInt(layout.substring(beg, end)); |
|
1216 |
} |
|
1217 |
static |
|
1218 |
int parseIntAfter(String layout, int dash) { |
|
1219 |
int beg = dash+1; |
|
1220 |
int end = beg; |
|
1221 |
int limit = layout.length(); |
|
1222 |
if (end < limit && layout.charAt(end) == '-') ++end; |
|
6313 | 1223 |
while (end < limit && isDigit(layout.charAt(end))) { |
1224 |
++end; |
|
1225 |
} |
|
2 | 1226 |
if (beg == end) return Integer.parseInt("empty"); |
1227 |
return Integer.parseInt(layout.substring(beg, end)); |
|
1228 |
} |
|
1229 |
/** For compatibility with 1.5 pack, expand 1-5 into 1,2,3,4,5. */ |
|
1230 |
static |
|
1231 |
String expandCaseDashNotation(String layout) { |
|
1232 |
int dash = findCaseDash(layout, 0); |
|
1233 |
if (dash < 0) return layout; // no dashes (the common case) |
|
7795
98021fc612af
6990106: FindBugs scan - Malicious code vulnerability Warnings in com.sun.java.util.jar.pack.*
ksrini
parents:
7192
diff
changeset
|
1234 |
StringBuilder result = new StringBuilder(layout.length() * 3); |
2 | 1235 |
int sofar = 0; // how far have we processed the layout? |
1236 |
for (;;) { |
|
1237 |
// for each dash, collect everything up to the dash |
|
31471
ae27c6f1d8bf
8077242: (str) Optimize AbstractStringBuilder.append(CharSequence, int, int) for String argument
igerasim
parents:
25859
diff
changeset
|
1238 |
result.append(layout, sofar, dash); |
2 | 1239 |
sofar = dash+1; // skip the dash |
1240 |
// then collect intermediate values |
|
1241 |
int value0 = parseIntBefore(layout, dash); |
|
1242 |
int value1 = parseIntAfter(layout, dash); |
|
1243 |
assert(value0 < value1); |
|
1244 |
result.append(","); // close off value0 numeral |
|
1245 |
for (int i = value0+1; i < value1; i++) { |
|
1246 |
result.append(i); |
|
1247 |
result.append(","); // close off i numeral |
|
1248 |
} |
|
1249 |
dash = findCaseDash(layout, sofar); |
|
1250 |
if (dash < 0) break; |
|
1251 |
} |
|
31471
ae27c6f1d8bf
8077242: (str) Optimize AbstractStringBuilder.append(CharSequence, int, int) for String argument
igerasim
parents:
25859
diff
changeset
|
1252 |
result.append(layout, sofar, layout.length()); // collect the rest |
2 | 1253 |
return result.toString(); |
1254 |
} |
|
1255 |
static { |
|
1256 |
assert(expandCaseDashNotation("1-5").equals("1,2,3,4,5")); |
|
1257 |
assert(expandCaseDashNotation("-2--1").equals("-2,-1")); |
|
1258 |
assert(expandCaseDashNotation("-2-1").equals("-2,-1,0,1")); |
|
1259 |
assert(expandCaseDashNotation("-1-0").equals("-1,0")); |
|
1260 |
} |
|
1261 |
||
1262 |
// Parse attribute bytes, putting values into bands. Returns new pos. |
|
1263 |
// Used when reading a class file (local refs resolved with local cpMap). |
|
1264 |
// Also used for ad hoc scanning. |
|
1265 |
static |
|
1266 |
int parseUsing(Layout.Element[] elems, Holder holder, |
|
1267 |
byte[] bytes, int pos, int len, ValueStream out) { |
|
1268 |
int prevBCI = 0; |
|
1269 |
int prevRBCI = 0; |
|
1270 |
int end = pos + len; |
|
1271 |
int[] buf = { 0 }; // for calls to parseInt, holds 2nd result |
|
1272 |
for (int i = 0; i < elems.length; i++) { |
|
1273 |
Layout.Element e = elems[i]; |
|
1274 |
int bandIndex = e.bandIndex; |
|
1275 |
int value; |
|
1276 |
int BCI, RBCI; |
|
1277 |
switch (e.kind) { |
|
1278 |
case EK_INT: |
|
1279 |
pos = parseInt(e, bytes, pos, buf); |
|
1280 |
value = buf[0]; |
|
1281 |
out.putInt(bandIndex, value); |
|
1282 |
break; |
|
1283 |
case EK_BCI: // PH, POH |
|
1284 |
pos = parseInt(e, bytes, pos, buf); |
|
1285 |
BCI = buf[0]; |
|
1286 |
RBCI = out.encodeBCI(BCI); |
|
1287 |
if (!e.flagTest(EF_DELTA)) { |
|
1288 |
// PH: transmit R(bci), store bci |
|
1289 |
value = RBCI; |
|
1290 |
} else { |
|
1291 |
// POH: transmit D(R(bci)), store bci |
|
1292 |
value = RBCI - prevRBCI; |
|
1293 |
} |
|
1294 |
prevBCI = BCI; |
|
1295 |
prevRBCI = RBCI; |
|
1296 |
out.putInt(bandIndex, value); |
|
1297 |
break; |
|
1298 |
case EK_BCO: // OH |
|
1299 |
assert(e.flagTest(EF_DELTA)); |
|
1300 |
// OH: transmit D(R(bci)), store D(bci) |
|
1301 |
pos = parseInt(e, bytes, pos, buf); |
|
1302 |
BCI = prevBCI + buf[0]; |
|
1303 |
RBCI = out.encodeBCI(BCI); |
|
1304 |
value = RBCI - prevRBCI; |
|
1305 |
prevBCI = BCI; |
|
1306 |
prevRBCI = RBCI; |
|
1307 |
out.putInt(bandIndex, value); |
|
1308 |
break; |
|
1309 |
case EK_FLAG: |
|
1310 |
pos = parseInt(e, bytes, pos, buf); |
|
1311 |
value = buf[0]; |
|
1312 |
out.putInt(bandIndex, value); |
|
1313 |
break; |
|
1314 |
case EK_REPL: |
|
1315 |
pos = parseInt(e, bytes, pos, buf); |
|
1316 |
value = buf[0]; |
|
1317 |
out.putInt(bandIndex, value); |
|
1318 |
for (int j = 0; j < value; j++) { |
|
1319 |
pos = parseUsing(e.body, holder, bytes, pos, end-pos, out); |
|
1320 |
} |
|
1321 |
break; // already transmitted the scalar value |
|
1322 |
case EK_UN: |
|
1323 |
pos = parseInt(e, bytes, pos, buf); |
|
1324 |
value = buf[0]; |
|
1325 |
out.putInt(bandIndex, value); |
|
1326 |
Layout.Element ce = matchCase(e, value); |
|
1327 |
pos = parseUsing(ce.body, holder, bytes, pos, end-pos, out); |
|
1328 |
||
1329 |
break; // already transmitted the scalar value |
|
1330 |
case EK_CALL: |
|
1331 |
// Adjust band offset if it is a backward call. |
|
1332 |
assert(e.body.length == 1); |
|
1333 |
assert(e.body[0].kind == EK_CBLE); |
|
1334 |
if (e.flagTest(EF_BACK)) |
|
1335 |
out.noteBackCall(e.value); |
|
1336 |
pos = parseUsing(e.body[0].body, holder, bytes, pos, end-pos, out); |
|
1337 |
break; // no additional scalar value to transmit |
|
1338 |
case EK_REF: |
|
1339 |
pos = parseInt(e, bytes, pos, buf); |
|
1340 |
int localRef = buf[0]; |
|
1341 |
Entry globalRef; |
|
1342 |
if (localRef == 0) { |
|
1343 |
globalRef = null; // N.B. global null reference is -1 |
|
1344 |
} else { |
|
15526
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1345 |
Entry[] cpMap = holder.getCPMap(); |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1346 |
globalRef = (localRef >= 0 && localRef < cpMap.length |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1347 |
? cpMap[localRef] |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1348 |
: null); |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1349 |
byte tag = e.refKind; |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1350 |
if (globalRef != null && tag == CONSTANT_Signature |
2 | 1351 |
&& globalRef.getTag() == CONSTANT_Utf8) { |
1352 |
// Cf. ClassReader.readSignatureRef. |
|
1353 |
String typeName = globalRef.stringValue(); |
|
1354 |
globalRef = ConstantPool.getSignatureEntry(typeName); |
|
15526
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1355 |
} |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1356 |
String got = (globalRef == null |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1357 |
? "invalid CP index" |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1358 |
: "type=" + ConstantPool.tagName(globalRef.tag)); |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1359 |
if (globalRef == null || !globalRef.tagMatches(tag)) { |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1360 |
throw new IllegalArgumentException( |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1361 |
"Bad constant, expected type=" + |
84de8685a2d0
8003549: (pack200) assertion errors when processing lambda class files with IMethods
ksrini
parents:
15261
diff
changeset
|
1362 |
ConstantPool.tagName(tag) + " got " + got); |
2 | 1363 |
} |
1364 |
} |
|
1365 |
out.putRef(bandIndex, globalRef); |
|
1366 |
break; |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
1367 |
default: assert(false); |
2 | 1368 |
} |
1369 |
} |
|
1370 |
return pos; |
|
1371 |
} |
|
1372 |
||
1373 |
static |
|
1374 |
Layout.Element matchCase(Layout.Element e, int value) { |
|
1375 |
assert(e.kind == EK_UN); |
|
1376 |
int lastj = e.body.length-1; |
|
1377 |
for (int j = 0; j < lastj; j++) { |
|
1378 |
Layout.Element ce = e.body[j]; |
|
1379 |
assert(ce.kind == EK_CASE); |
|
1380 |
if (value == ce.value) |
|
1381 |
return ce; |
|
1382 |
} |
|
1383 |
return e.body[lastj]; |
|
1384 |
} |
|
1385 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
1386 |
private static |
2 | 1387 |
int parseInt(Layout.Element e, byte[] bytes, int pos, int[] buf) { |
1388 |
int value = 0; |
|
1389 |
int loBits = e.len * 8; |
|
1390 |
// Read in big-endian order: |
|
1391 |
for (int bitPos = loBits; (bitPos -= 8) >= 0; ) { |
|
1392 |
value += (bytes[pos++] & 0xFF) << bitPos; |
|
1393 |
} |
|
1394 |
if (loBits < 32 && e.flagTest(EF_SIGN)) { |
|
1395 |
// sign-extend subword value |
|
1396 |
int hiBits = 32 - loBits; |
|
1397 |
value = (value << hiBits) >> hiBits; |
|
1398 |
} |
|
1399 |
buf[0] = value; |
|
1400 |
return pos; |
|
1401 |
} |
|
1402 |
||
1403 |
// Format attribute bytes, drawing values from bands. |
|
1404 |
// Used when emptying attribute bands into a package model. |
|
1405 |
// (At that point CP refs. are not yet assigned indexes.) |
|
1406 |
static |
|
1407 |
void unparseUsing(Layout.Element[] elems, Object[] fixups, |
|
1408 |
ValueStream in, ByteArrayOutputStream out) { |
|
1409 |
int prevBCI = 0; |
|
1410 |
int prevRBCI = 0; |
|
1411 |
for (int i = 0; i < elems.length; i++) { |
|
1412 |
Layout.Element e = elems[i]; |
|
1413 |
int bandIndex = e.bandIndex; |
|
1414 |
int value; |
|
1415 |
int BCI, RBCI; // "RBCI" is R(BCI), BCI's coded representation |
|
1416 |
switch (e.kind) { |
|
1417 |
case EK_INT: |
|
1418 |
value = in.getInt(bandIndex); |
|
1419 |
unparseInt(e, value, out); |
|
1420 |
break; |
|
1421 |
case EK_BCI: // PH, POH |
|
1422 |
value = in.getInt(bandIndex); |
|
1423 |
if (!e.flagTest(EF_DELTA)) { |
|
1424 |
// PH: transmit R(bci), store bci |
|
1425 |
RBCI = value; |
|
1426 |
} else { |
|
1427 |
// POH: transmit D(R(bci)), store bci |
|
1428 |
RBCI = prevRBCI + value; |
|
1429 |
} |
|
1430 |
assert(prevBCI == in.decodeBCI(prevRBCI)); |
|
1431 |
BCI = in.decodeBCI(RBCI); |
|
1432 |
unparseInt(e, BCI, out); |
|
1433 |
prevBCI = BCI; |
|
1434 |
prevRBCI = RBCI; |
|
1435 |
break; |
|
1436 |
case EK_BCO: // OH |
|
1437 |
value = in.getInt(bandIndex); |
|
1438 |
assert(e.flagTest(EF_DELTA)); |
|
1439 |
// OH: transmit D(R(bci)), store D(bci) |
|
1440 |
assert(prevBCI == in.decodeBCI(prevRBCI)); |
|
1441 |
RBCI = prevRBCI + value; |
|
1442 |
BCI = in.decodeBCI(RBCI); |
|
1443 |
unparseInt(e, BCI - prevBCI, out); |
|
1444 |
prevBCI = BCI; |
|
1445 |
prevRBCI = RBCI; |
|
1446 |
break; |
|
1447 |
case EK_FLAG: |
|
1448 |
value = in.getInt(bandIndex); |
|
1449 |
unparseInt(e, value, out); |
|
1450 |
break; |
|
1451 |
case EK_REPL: |
|
1452 |
value = in.getInt(bandIndex); |
|
1453 |
unparseInt(e, value, out); |
|
1454 |
for (int j = 0; j < value; j++) { |
|
1455 |
unparseUsing(e.body, fixups, in, out); |
|
1456 |
} |
|
1457 |
break; |
|
1458 |
case EK_UN: |
|
1459 |
value = in.getInt(bandIndex); |
|
1460 |
unparseInt(e, value, out); |
|
1461 |
Layout.Element ce = matchCase(e, value); |
|
1462 |
unparseUsing(ce.body, fixups, in, out); |
|
1463 |
break; |
|
1464 |
case EK_CALL: |
|
1465 |
assert(e.body.length == 1); |
|
1466 |
assert(e.body[0].kind == EK_CBLE); |
|
1467 |
unparseUsing(e.body[0].body, fixups, in, out); |
|
1468 |
break; |
|
1469 |
case EK_REF: |
|
1470 |
Entry globalRef = in.getRef(bandIndex); |
|
1471 |
int localRef; |
|
1472 |
if (globalRef != null) { |
|
1473 |
// It's a one-element array, really an lvalue. |
|
17490
46864558d068
8001163: [pack200] should support attributes introduced by JSR-308
ksrini
parents:
16013
diff
changeset
|
1474 |
fixups[0] = Fixups.addRefWithLoc(fixups[0], out.size(), globalRef); |
2 | 1475 |
localRef = 0; // placeholder for fixups |
1476 |
} else { |
|
1477 |
localRef = 0; // fixed null value |
|
1478 |
} |
|
1479 |
unparseInt(e, localRef, out); |
|
1480 |
break; |
|
1481 |
default: assert(false); continue; |
|
1482 |
} |
|
1483 |
} |
|
1484 |
} |
|
1485 |
||
32649
2ee9017c7597
8136583: Core libraries should use blessed modifier order
martin
parents:
31471
diff
changeset
|
1486 |
private static |
2 | 1487 |
void unparseInt(Layout.Element e, int value, ByteArrayOutputStream out) { |
1488 |
int loBits = e.len * 8; |
|
1489 |
if (loBits == 0) { |
|
1490 |
// It is not stored at all ('V' layout). |
|
1491 |
return; |
|
1492 |
} |
|
1493 |
if (loBits < 32) { |
|
1494 |
int hiBits = 32 - loBits; |
|
1495 |
int codedValue; |
|
1496 |
if (e.flagTest(EF_SIGN)) |
|
1497 |
codedValue = (value << hiBits) >> hiBits; |
|
1498 |
else |
|
1499 |
codedValue = (value << hiBits) >>> hiBits; |
|
1500 |
if (codedValue != value) |
|
1501 |
throw new InternalError("cannot code in "+e.len+" bytes: "+value); |
|
1502 |
} |
|
1503 |
// Write in big-endian order: |
|
1504 |
for (int bitPos = loBits; (bitPos -= 8) >= 0; ) { |
|
1505 |
out.write((byte)(value >>> bitPos)); |
|
1506 |
} |
|
1507 |
} |
|
1508 |
||
1509 |
/* |
|
1510 |
/// Testing. |
|
1511 |
public static void main(String av[]) { |
|
1512 |
int maxVal = 12; |
|
1513 |
int iters = 0; |
|
1514 |
boolean verbose; |
|
1515 |
int ap = 0; |
|
1516 |
while (ap < av.length) { |
|
1517 |
if (!av[ap].startsWith("-")) break; |
|
1518 |
if (av[ap].startsWith("-m")) |
|
1519 |
maxVal = Integer.parseInt(av[ap].substring(2)); |
|
1520 |
else if (av[ap].startsWith("-i")) |
|
1521 |
iters = Integer.parseInt(av[ap].substring(2)); |
|
1522 |
else |
|
1523 |
throw new RuntimeException("Bad option: "+av[ap]); |
|
1524 |
ap++; |
|
1525 |
} |
|
1526 |
verbose = (iters == 0); |
|
1527 |
if (iters <= 0) iters = 1; |
|
1528 |
if (ap == av.length) { |
|
1529 |
av = new String[] { |
|
1530 |
"HH", // ClassFile.version |
|
1531 |
"RUH", // SourceFile |
|
1532 |
"RCHRDNH", // EnclosingMethod |
|
1533 |
"KQH", // ConstantValue |
|
1534 |
"NH[RCH]", // Exceptions |
|
1535 |
"NH[PHH]", // LineNumberTable |
|
1536 |
"NH[PHOHRUHRSHH]", // LocalVariableTable |
|
1537 |
"NH[PHPOHIIH]", // CharacterRangeTable |
|
1538 |
"NH[PHHII]", // CoverageTable |
|
1539 |
"NH[RCHRCNHRUNHFH]", // InnerClasses |
|
12544 | 1540 |
"NH[RMHNH[KLH]]", // BootstrapMethods |
2 | 1541 |
"HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]", // Code |
1542 |
"=AnnotationDefault", |
|
1543 |
// Like metadata, but with a compact tag set: |
|
1544 |
"[NH[(1)]]" |
|
12544 | 1545 |
+"[NH[(1)]]" |
1546 |
+"[RSHNH[RUH(1)]]" |
|
1547 |
+"[TB(0,1,3)[KIH](2)[KDH](5)[KFH](4)[KJH](7)[RSH](8)[RSHRUH](9)[RUH](10)[(-1)](6)[NH[(0)]]()[]]", |
|
2 | 1548 |
"" |
1549 |
}; |
|
1550 |
ap = 0; |
|
1551 |
} |
|
12544 | 1552 |
Utils.currentInstance.set(new PackerImpl()); |
2 | 1553 |
final int[][] counts = new int[2][3]; // int bci ref |
1554 |
final Entry[] cpMap = new Entry[maxVal+1]; |
|
1555 |
for (int i = 0; i < cpMap.length; i++) { |
|
1556 |
if (i == 0) continue; // 0 => null |
|
1557 |
cpMap[i] = ConstantPool.getLiteralEntry(new Integer(i)); |
|
1558 |
} |
|
12544 | 1559 |
Package.Class cls = new Package().new Class(""); |
2 | 1560 |
cls.cpMap = cpMap; |
1561 |
class TestValueStream extends ValueStream { |
|
12544 | 1562 |
java.util.Random rand = new java.util.Random(0); |
2 | 1563 |
ArrayList history = new ArrayList(); |
1564 |
int ckidx = 0; |
|
1565 |
int maxVal; |
|
1566 |
boolean verbose; |
|
1567 |
void reset() { history.clear(); ckidx = 0; } |
|
1568 |
public int getInt(int bandIndex) { |
|
1569 |
counts[0][0]++; |
|
1570 |
int value = rand.nextInt(maxVal+1); |
|
1571 |
history.add(new Integer(bandIndex)); |
|
1572 |
history.add(new Integer(value)); |
|
1573 |
return value; |
|
1574 |
} |
|
1575 |
public void putInt(int bandIndex, int token) { |
|
1576 |
counts[1][0]++; |
|
1577 |
if (verbose) |
|
1578 |
System.out.print(" "+bandIndex+":"+token); |
|
1579 |
// Make sure this put parallels a previous get: |
|
1580 |
int check0 = ((Integer)history.get(ckidx+0)).intValue(); |
|
1581 |
int check1 = ((Integer)history.get(ckidx+1)).intValue(); |
|
1582 |
if (check0 != bandIndex || check1 != token) { |
|
1583 |
if (!verbose) |
|
1584 |
System.out.println(history.subList(0, ckidx)); |
|
1585 |
System.out.println(" *** Should be "+check0+":"+check1); |
|
1586 |
throw new RuntimeException("Failed test!"); |
|
1587 |
} |
|
1588 |
ckidx += 2; |
|
1589 |
} |
|
1590 |
public Entry getRef(int bandIndex) { |
|
1591 |
counts[0][2]++; |
|
1592 |
int value = getInt(bandIndex); |
|
1593 |
if (value < 0 || value > maxVal) { |
|
1594 |
System.out.println(" *** Unexpected ref code "+value); |
|
1595 |
return ConstantPool.getLiteralEntry(new Integer(value)); |
|
1596 |
} |
|
1597 |
return cpMap[value]; |
|
1598 |
} |
|
1599 |
public void putRef(int bandIndex, Entry ref) { |
|
1600 |
counts[1][2]++; |
|
1601 |
if (ref == null) { |
|
1602 |
putInt(bandIndex, 0); |
|
1603 |
return; |
|
1604 |
} |
|
1605 |
Number refValue = null; |
|
1606 |
if (ref instanceof ConstantPool.NumberEntry) |
|
1607 |
refValue = ((ConstantPool.NumberEntry)ref).numberValue(); |
|
1608 |
int value; |
|
1609 |
if (!(refValue instanceof Integer)) { |
|
1610 |
System.out.println(" *** Unexpected ref "+ref); |
|
1611 |
value = -1; |
|
1612 |
} else { |
|
1613 |
value = ((Integer)refValue).intValue(); |
|
1614 |
} |
|
1615 |
putInt(bandIndex, value); |
|
1616 |
} |
|
1617 |
public int encodeBCI(int bci) { |
|
1618 |
counts[1][1]++; |
|
1619 |
// move LSB to MSB of low byte |
|
1620 |
int code = (bci >> 8) << 8; // keep high bits |
|
1621 |
code += (bci & 0xFE) >> 1; |
|
1622 |
code += (bci & 0x01) << 7; |
|
1623 |
return code ^ (8<<8); // mark it clearly as coded |
|
1624 |
} |
|
1625 |
public int decodeBCI(int bciCode) { |
|
1626 |
counts[0][1]++; |
|
1627 |
bciCode ^= (8<<8); // remove extra mark |
|
1628 |
int bci = (bciCode >> 8) << 8; // keep high bits |
|
1629 |
bci += (bciCode & 0x7F) << 1; |
|
1630 |
bci += (bciCode & 0x80) >> 7; |
|
1631 |
return bci; |
|
1632 |
} |
|
1633 |
} |
|
1634 |
TestValueStream tts = new TestValueStream(); |
|
1635 |
tts.maxVal = maxVal; |
|
1636 |
tts.verbose = verbose; |
|
1637 |
ByteArrayOutputStream buf = new ByteArrayOutputStream(); |
|
1638 |
for (int i = 0; i < (1 << 30); i = (i + 1) * 5) { |
|
1639 |
int ei = tts.encodeBCI(i); |
|
1640 |
int di = tts.decodeBCI(ei); |
|
1641 |
if (di != i) System.out.println("i="+Integer.toHexString(i)+ |
|
1642 |
" ei="+Integer.toHexString(ei)+ |
|
1643 |
" di="+Integer.toHexString(di)); |
|
1644 |
} |
|
1645 |
while (iters-- > 0) { |
|
1646 |
for (int i = ap; i < av.length; i++) { |
|
1647 |
String layout = av[i]; |
|
1648 |
if (layout.startsWith("=")) { |
|
1649 |
String name = layout.substring(1); |
|
12544 | 1650 |
for (Attribute a : standardDefs.values()) { |
2 | 1651 |
if (a.name().equals(name)) { |
1652 |
layout = a.layout().layout(); |
|
1653 |
break; |
|
1654 |
} |
|
1655 |
} |
|
1656 |
if (layout.startsWith("=")) { |
|
1657 |
System.out.println("Could not find "+name+" in "+standardDefs.values()); |
|
1658 |
} |
|
1659 |
} |
|
1660 |
Layout self = new Layout(0, "Foo", layout); |
|
1661 |
if (verbose) { |
|
1662 |
System.out.print("/"+layout+"/ => "); |
|
1663 |
System.out.println(Arrays.asList(self.elems)); |
|
1664 |
} |
|
1665 |
buf.reset(); |
|
1666 |
tts.reset(); |
|
1667 |
Object fixups = self.unparse(tts, buf); |
|
1668 |
byte[] bytes = buf.toByteArray(); |
|
1669 |
// Attach the references to the byte array. |
|
1670 |
Fixups.setBytes(fixups, bytes); |
|
1671 |
// Patch the references to their frozen values. |
|
1672 |
Fixups.finishRefs(fixups, bytes, new Index("test", cpMap)); |
|
1673 |
if (verbose) { |
|
1674 |
System.out.print(" bytes: {"); |
|
1675 |
for (int j = 0; j < bytes.length; j++) { |
|
1676 |
System.out.print(" "+bytes[j]); |
|
1677 |
} |
|
1678 |
System.out.println("}"); |
|
1679 |
} |
|
1680 |
if (verbose) { |
|
1681 |
System.out.print(" parse: {"); |
|
1682 |
} |
|
12544 | 1683 |
self.parse(cls, bytes, 0, bytes.length, tts); |
2 | 1684 |
if (verbose) { |
1685 |
System.out.println("}"); |
|
1686 |
} |
|
1687 |
} |
|
1688 |
} |
|
1689 |
for (int j = 0; j <= 1; j++) { |
|
1690 |
System.out.print("values "+(j==0?"read":"written")+": {"); |
|
1691 |
for (int k = 0; k < counts[j].length; k++) { |
|
1692 |
System.out.print(" "+counts[j][k]); |
|
1693 |
} |
|
1694 |
System.out.println(" }"); |
|
1695 |
} |
|
1696 |
} |
|
1697 |
//*/ |
|
1698 |
} |