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 *
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.
24 */
25 package jdk.internal.classfile.impl;
26
27 import java.lang.classfile.*;
28 import java.lang.classfile.attribute.CodeAttribute;
29 import jdk.internal.classfile.components.ClassPrinter;
30 import java.lang.classfile.constantpool.ClassEntry;
31 import java.lang.classfile.constantpool.ModuleEntry;
32 import java.lang.classfile.constantpool.PoolEntry;
33 import java.lang.classfile.constantpool.Utf8Entry;
34 import java.lang.constant.ClassDesc;
35 import java.lang.constant.MethodTypeDesc;
36 import java.lang.constant.ModuleDesc;
37 import java.lang.reflect.AccessFlag;
38 import java.util.AbstractList;
39 import java.util.Collection;
40 import java.util.List;
41 import java.util.function.Consumer;
42 import java.util.function.Function;
43
44 import jdk.internal.access.SharedSecrets;
45 import jdk.internal.constant.ClassOrInterfaceDescImpl;
46 import jdk.internal.vm.annotation.ForceInline;
47 import jdk.internal.vm.annotation.Stable;
48
49 import static java.lang.classfile.ClassFile.ACC_STATIC;
50 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double;
51 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long;
52 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
53
54 /**
55 * Helper to create and manipulate type descriptors, where type descriptors are
56 * represented as JVM type descriptor strings and symbols are represented as
57 * name strings
58 */
59 public final class Util {
60
61 private Util() {
62 }
63
64 public static <T> Consumer<Consumer<T>> writingAll(Iterable<T> container) {
65 record ForEachConsumer<T>(Iterable<T> container) implements Consumer<Consumer<T>> {
66 @Override
67 public void accept(Consumer<T> consumer) {
68 container.forEach(consumer);
69 }
70 }
71 return new ForEachConsumer<>(container);
72 }
73
74 public static Consumer<MethodBuilder> buildingCode(Consumer<? super CodeBuilder> codeHandler) {
75 record WithCodeMethodHandler(Consumer<? super CodeBuilder> codeHandler) implements Consumer<MethodBuilder> {
76 @Override
77 public void accept(MethodBuilder builder) {
78 builder.withCode(codeHandler);
79 }
80 }
179 public U get(int index) {
180 return mapper.apply(list.get(index));
181 }
182
183 @Override
184 public int size() {
185 return list.size();
186 }
187 };
188 }
189
190 public static List<ClassEntry> entryList(List<? extends ClassDesc> list) {
191 var result = new Object[list.size()]; // null check
192 int i = 0;
193 for (var entry : list) {
194 result[i++] = TemporaryConstantPool.INSTANCE.classEntry(entry);
195 }
196 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
197 }
198
199 public static List<ModuleEntry> moduleEntryList(List<? extends ModuleDesc> list) {
200 var result = new Object[list.size()]; // null check
201 int i = 0;
202 for (var entry : list) {
203 result[i++] = TemporaryConstantPool.INSTANCE.moduleEntry(entry);
204 }
205 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
206 }
207
208 public static void checkKind(Opcode op, Opcode.Kind k) {
209 if (op.kind() != k)
210 throw badOpcodeKindException(op, k);
211 }
212
213 public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode.Kind k) {
214 return new IllegalArgumentException(
215 String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k));
216 }
217
218 /// Ensures the given value won't be truncated when written as a u1
237
238 /// Ensures the given mask won't be truncated when written as an access flag
239 public static char checkFlags(int mask) {
240 return checkU2(mask, "access flags");
241 }
242
243 public static int flagsToBits(AccessFlag.Location location, Collection<AccessFlag> flags) {
244 int i = 0;
245 for (AccessFlag f : flags) {
246 if (!f.locations().contains(location)) {
247 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
248 }
249 i |= f.mask();
250 }
251 return i;
252 }
253
254 public static int flagsToBits(AccessFlag.Location location, AccessFlag... flags) {
255 int i = 0;
256 for (AccessFlag f : flags) {
257 if (!f.locations().contains(location)) {
258 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
259 }
260 i |= f.mask();
261 }
262 return i;
263 }
264
265 public static boolean has(AccessFlag.Location location, int flagsMask, AccessFlag flag) {
266 return (flag.mask() & flagsMask) == flag.mask() && flag.locations().contains(location);
267 }
268
269 public static ClassDesc fieldTypeSymbol(Utf8Entry utf8) {
270 return ((AbstractPoolEntry.Utf8EntryImpl) utf8).fieldTypeSymbol();
271 }
272
273 public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) {
274 return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol();
275 }
276
277 @SuppressWarnings("unchecked")
278 public static <T extends Attribute<T>> void writeAttribute(BufWriterImpl writer, Attribute<?> attr) {
279 if (attr instanceof CustomAttribute<?> ca) {
280 var mapper = (AttributeMapper<T>) ca.attributeMapper();
281 mapper.writeAttribute(writer, (T) ca);
282 } else {
283 assert attr instanceof BoundAttribute || attr instanceof UnboundAttribute;
284 ((Writable) attr).writeTo(writer);
285 }
286 }
299 static void writeList(BufWriterImpl buf, Writable[] array, int size) {
300 Util.checkU2(size, "member count");
301 buf.writeU2(size);
302 for (int i = 0; i < size; i++) {
303 array[i].writeTo(buf);
304 }
305 }
306
307 public static int slotSize(ClassDesc desc) {
308 return desc == CD_void ? 0 : isDoubleSlot(desc) ? 2 : 1;
309 }
310
311 public static int paramSlotSize(ClassDesc desc) {
312 return isDoubleSlot(desc) ? 2 : 1;
313 }
314
315 public static boolean isDoubleSlot(ClassDesc desc) {
316 return desc == CD_double || desc == CD_long;
317 }
318
319 public static void dumpMethod(SplitConstantPool cp,
320 ClassDesc cls,
321 String methodName,
322 MethodTypeDesc methodDesc,
323 int acc,
324 RawBytecodeHelper.CodeRange bytecode,
325 Consumer<String> dump) {
326
327 // try to dump debug info about corrupted bytecode
328 try {
329 var cc = ClassFile.of();
330 var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb ->
331 clb.withMethod(methodName, methodDesc, acc, mb ->
332 ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute<CodeAttribute>(Attributes.code()) {
333 @Override
334 public void writeBody(BufWriterImpl b) {
335 b.writeU2U2(-1, -1);//max stack & locals
336 b.writeInt(bytecode.length());
337 b.writeBytes(bytecode.array(), 0, bytecode.length());
338 b.writeU2U2(0, 0);//exception handlers & attributes
342 public Utf8Entry attributeName() {
343 return cp.utf8Entry(Attributes.NAME_CODE);
344 }
345 }))));
346 ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump);
347 } catch (Error | Exception _) {
348 // fallback to bytecode hex dump
349 dumpBytesHex(dump, bytecode.array(), bytecode.length());
350 }
351 }
352
353 public static void dumpBytesHex(Consumer<String> dump, byte[] bytes, int length) {
354 for (int i = 0; i < length; i++) {
355 if (i % 16 == 0) {
356 dump.accept("%n%04x:".formatted(i));
357 }
358 dump.accept(" %02x".formatted(bytes[i]));
359 }
360 }
361
362 public static void writeListIndices(BufWriter writer, List<? extends PoolEntry> list) {
363 writer.writeU2(list.size());
364 for (PoolEntry info : list) {
365 writer.writeIndex(info);
366 }
367 }
368
369 public static boolean writeLocalVariable(BufWriterImpl buf, PseudoInstruction lvOrLvt) {
370 return ((WritableLocalVariable) lvOrLvt).writeLocalTo(buf);
371 }
372
373 /**
374 * A generic interface for objects to write to a
375 * buf writer. Do not implement unless necessary,
376 * as this writeTo is public, which can be troublesome.
377 */
378 interface Writable {
379 void writeTo(BufWriterImpl writer);
380 }
381
|
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 *
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.
24 */
25 package jdk.internal.classfile.impl;
26
27 import java.lang.classfile.*;
28 import java.lang.classfile.attribute.CodeAttribute;
29 import jdk.internal.classfile.components.ClassPrinter;
30 import java.lang.classfile.constantpool.ClassEntry;
31 import java.lang.classfile.constantpool.ConstantPool;
32 import java.lang.classfile.constantpool.ConstantPoolBuilder;
33 import java.lang.classfile.constantpool.ModuleEntry;
34 import java.lang.classfile.constantpool.PoolEntry;
35 import java.lang.classfile.constantpool.Utf8Entry;
36 import java.lang.constant.ClassDesc;
37 import java.lang.constant.MethodTypeDesc;
38 import java.lang.constant.ModuleDesc;
39 import java.lang.reflect.AccessFlag;
40 import java.util.AbstractList;
41 import java.util.Collection;
42 import java.util.List;
43 import java.util.function.Consumer;
44 import java.util.function.Function;
45
46 import jdk.internal.access.SharedSecrets;
47 import jdk.internal.constant.ClassOrInterfaceDescImpl;
48 import jdk.internal.reflect.PreviewAccessFlags;
49 import jdk.internal.vm.annotation.ForceInline;
50 import jdk.internal.vm.annotation.Stable;
51
52 import static java.lang.classfile.ClassFile.ACC_STATIC;
53 import static java.lang.constant.ConstantDescs.INIT_NAME;
54 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double;
55 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long;
56 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
57
58 /**
59 * Helper to create and manipulate type descriptors, where type descriptors are
60 * represented as JVM type descriptor strings and symbols are represented as
61 * name strings
62 */
63 public final class Util {
64
65 public static final int VALUE_OBJECTS_MAJOR = ClassFile.latestMajorVersion();
66
67 private Util() {
68 }
69
70 public static <T> Consumer<Consumer<T>> writingAll(Iterable<T> container) {
71 record ForEachConsumer<T>(Iterable<T> container) implements Consumer<Consumer<T>> {
72 @Override
73 public void accept(Consumer<T> consumer) {
74 container.forEach(consumer);
75 }
76 }
77 return new ForEachConsumer<>(container);
78 }
79
80 public static Consumer<MethodBuilder> buildingCode(Consumer<? super CodeBuilder> codeHandler) {
81 record WithCodeMethodHandler(Consumer<? super CodeBuilder> codeHandler) implements Consumer<MethodBuilder> {
82 @Override
83 public void accept(MethodBuilder builder) {
84 builder.withCode(codeHandler);
85 }
86 }
185 public U get(int index) {
186 return mapper.apply(list.get(index));
187 }
188
189 @Override
190 public int size() {
191 return list.size();
192 }
193 };
194 }
195
196 public static List<ClassEntry> entryList(List<? extends ClassDesc> list) {
197 var result = new Object[list.size()]; // null check
198 int i = 0;
199 for (var entry : list) {
200 result[i++] = TemporaryConstantPool.INSTANCE.classEntry(entry);
201 }
202 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
203 }
204
205 public static List<Utf8Entry> fieldDescriptorList(List<? extends ClassDesc> list) {
206 var result = new Object[list.size()]; // null check
207 int i = 0;
208 for (var entry : list) {
209 result[i++] = TemporaryConstantPool.INSTANCE.utf8Entry(entry);
210 }
211 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
212 }
213
214 public static List<ModuleEntry> moduleEntryList(List<? extends ModuleDesc> list) {
215 var result = new Object[list.size()]; // null check
216 int i = 0;
217 for (var entry : list) {
218 result[i++] = TemporaryConstantPool.INSTANCE.moduleEntry(entry);
219 }
220 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
221 }
222
223 public static void checkKind(Opcode op, Opcode.Kind k) {
224 if (op.kind() != k)
225 throw badOpcodeKindException(op, k);
226 }
227
228 public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode.Kind k) {
229 return new IllegalArgumentException(
230 String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k));
231 }
232
233 /// Ensures the given value won't be truncated when written as a u1
252
253 /// Ensures the given mask won't be truncated when written as an access flag
254 public static char checkFlags(int mask) {
255 return checkU2(mask, "access flags");
256 }
257
258 public static int flagsToBits(AccessFlag.Location location, Collection<AccessFlag> flags) {
259 int i = 0;
260 for (AccessFlag f : flags) {
261 if (!f.locations().contains(location)) {
262 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
263 }
264 i |= f.mask();
265 }
266 return i;
267 }
268
269 public static int flagsToBits(AccessFlag.Location location, AccessFlag... flags) {
270 int i = 0;
271 for (AccessFlag f : flags) {
272 if (!f.locations().contains(location) && !PreviewAccessFlags.locations(f).contains(location)) {
273 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
274 }
275 i |= f.mask();
276 }
277 return i;
278 }
279
280 public static boolean has(AccessFlag.Location location, int flagsMask, AccessFlag flag) {
281 return (flag.mask() & flagsMask) == flag.mask() && (flag.locations().contains(location)
282 || PreviewAccessFlags.locations(flag).contains(location));
283 }
284
285 public static ClassDesc fieldTypeSymbol(Utf8Entry utf8) {
286 return ((AbstractPoolEntry.Utf8EntryImpl) utf8).fieldTypeSymbol();
287 }
288
289 public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) {
290 return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol();
291 }
292
293 @SuppressWarnings("unchecked")
294 public static <T extends Attribute<T>> void writeAttribute(BufWriterImpl writer, Attribute<?> attr) {
295 if (attr instanceof CustomAttribute<?> ca) {
296 var mapper = (AttributeMapper<T>) ca.attributeMapper();
297 mapper.writeAttribute(writer, (T) ca);
298 } else {
299 assert attr instanceof BoundAttribute || attr instanceof UnboundAttribute;
300 ((Writable) attr).writeTo(writer);
301 }
302 }
315 static void writeList(BufWriterImpl buf, Writable[] array, int size) {
316 Util.checkU2(size, "member count");
317 buf.writeU2(size);
318 for (int i = 0; i < size; i++) {
319 array[i].writeTo(buf);
320 }
321 }
322
323 public static int slotSize(ClassDesc desc) {
324 return desc == CD_void ? 0 : isDoubleSlot(desc) ? 2 : 1;
325 }
326
327 public static int paramSlotSize(ClassDesc desc) {
328 return isDoubleSlot(desc) ? 2 : 1;
329 }
330
331 public static boolean isDoubleSlot(ClassDesc desc) {
332 return desc == CD_double || desc == CD_long;
333 }
334
335 public static boolean checkConstantPoolsCompatible(ConstantPool one, ConstantPool two) {
336 if (one.equals(two))
337 return true;
338 if (one instanceof ConstantPoolBuilder cpb && cpb.canWriteDirect(two))
339 return true;
340 return two instanceof ConstantPoolBuilder cpb && cpb.canWriteDirect(one);
341 }
342
343 public static void dumpMethod(SplitConstantPool cp,
344 ClassDesc cls,
345 String methodName,
346 MethodTypeDesc methodDesc,
347 int acc,
348 RawBytecodeHelper.CodeRange bytecode,
349 Consumer<String> dump) {
350
351 // try to dump debug info about corrupted bytecode
352 try {
353 var cc = ClassFile.of();
354 var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb ->
355 clb.withMethod(methodName, methodDesc, acc, mb ->
356 ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute<CodeAttribute>(Attributes.code()) {
357 @Override
358 public void writeBody(BufWriterImpl b) {
359 b.writeU2U2(-1, -1);//max stack & locals
360 b.writeInt(bytecode.length());
361 b.writeBytes(bytecode.array(), 0, bytecode.length());
362 b.writeU2U2(0, 0);//exception handlers & attributes
366 public Utf8Entry attributeName() {
367 return cp.utf8Entry(Attributes.NAME_CODE);
368 }
369 }))));
370 ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump);
371 } catch (Error | Exception _) {
372 // fallback to bytecode hex dump
373 dumpBytesHex(dump, bytecode.array(), bytecode.length());
374 }
375 }
376
377 public static void dumpBytesHex(Consumer<String> dump, byte[] bytes, int length) {
378 for (int i = 0; i < length; i++) {
379 if (i % 16 == 0) {
380 dump.accept("%n%04x:".formatted(i));
381 }
382 dump.accept(" %02x".formatted(bytes[i]));
383 }
384 }
385
386 public static boolean canSkipMethodInflation(ClassReader cr, MethodInfo method, BufWriterImpl buf) {
387 if (!buf.canWriteDirect(cr)) {
388 return false;
389 }
390 if (method.methodName().equalsString(INIT_NAME) &&
391 !buf.strictFieldsMatch(((ClassReaderImpl) cr).getContainedClass())) {
392 return false;
393 }
394 return true;
395 }
396
397 public static void writeListIndices(BufWriter writer, List<? extends PoolEntry> list) {
398 writer.writeU2(list.size());
399 for (PoolEntry info : list) {
400 writer.writeIndex(info);
401 }
402 }
403
404 public static boolean writeLocalVariable(BufWriterImpl buf, PseudoInstruction lvOrLvt) {
405 return ((WritableLocalVariable) lvOrLvt).writeLocalTo(buf);
406 }
407
408 /**
409 * A generic interface for objects to write to a
410 * buf writer. Do not implement unless necessary,
411 * as this writeTo is public, which can be troublesome.
412 */
413 interface Writable {
414 void writeTo(BufWriterImpl writer);
415 }
416
|