8294969: Convert jdk.jdeps javap to use the Classfile API

Reviewed-by: vromero
This commit is contained in:
Adam Sotona 2023-09-18 08:35:31 +00:00
parent fbc766ee21
commit 1203e11a8d
29 changed files with 2012 additions and 2870 deletions

View File

@ -102,6 +102,16 @@ public sealed interface ClassReader extends ConstantPool
*/
PoolEntry readEntry(int offset);
/**
* {@return the constant pool entry of a given type whose index is given
* at the specified offset within the classfile}
* @param offset the offset of the index within the classfile
* @param cls the entry type
* @throws ConstantPoolException if the index is out of range of the
* constant pool size, or zero, or the entry is not of the given type
*/
<T extends PoolEntry> T readEntry(int offset, Class<T> cls);
/**
* {@return the constant pool entry whose index is given at the specified
* offset within the classfile, or null if the index at the specified

View File

@ -38,6 +38,11 @@ public sealed interface DynamicConstantPoolEntry extends PoolEntry
*/
BootstrapMethodEntry bootstrap();
/**
* {@return index of the entry in the bootstrap method table for this constant}
*/
int bootstrapMethodIndex();
/**
* {@return the invocation name and type}
*/

View File

@ -383,7 +383,7 @@ public abstract sealed class AbstractInstruction
@Override
public FieldRefEntry field() {
if (fieldEntry == null)
fieldEntry = (FieldRefEntry) code.classReader.readEntry(pos + 1);
fieldEntry = code.classReader.readEntry(pos + 1, FieldRefEntry.class);
return fieldEntry;
}
@ -413,7 +413,7 @@ public abstract sealed class AbstractInstruction
@Override
public MemberRefEntry method() {
if (methodEntry == null)
methodEntry = (MemberRefEntry) code.classReader.readEntry(pos + 1);
methodEntry = code.classReader.readEntry(pos + 1, MemberRefEntry.class);
return methodEntry;
}
@ -453,7 +453,7 @@ public abstract sealed class AbstractInstruction
@Override
public MemberRefEntry method() {
if (methodEntry == null)
methodEntry = (InterfaceMethodRefEntry) code.classReader.readEntry(pos + 1);
methodEntry = code.classReader.readEntry(pos + 1, InterfaceMethodRefEntry.class);
return methodEntry;
}
@ -493,7 +493,7 @@ public abstract sealed class AbstractInstruction
@Override
public InvokeDynamicEntry invokedynamic() {
if (indyEntry == null)
indyEntry = (InvokeDynamicEntry) code.classReader.readEntry(pos + 1);
indyEntry = code.classReader.readEntry(pos + 1, InvokeDynamicEntry.class);
return indyEntry;
}

View File

@ -815,6 +815,13 @@ public abstract sealed class AbstractPoolEntry {
return bootstrapMethod;
}
/**
* @return the bsmIndex
*/
public int bootstrapMethodIndex() {
return bsmIndex;
}
/**
* @return the nameAndType
*/

View File

@ -58,14 +58,14 @@ class AnnotationReader {
char tag = (char) classReader.readU1(p);
++p;
return switch (tag) {
case AEV_BYTE -> new AnnotationImpl.OfByteImpl((IntegerEntry)classReader.readEntry(p));
case AEV_CHAR -> new AnnotationImpl.OfCharacterImpl((IntegerEntry)classReader.readEntry(p));
case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl((DoubleEntry)classReader.readEntry(p));
case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl((FloatEntry)classReader.readEntry(p));
case AEV_INT -> new AnnotationImpl.OfIntegerImpl((IntegerEntry)classReader.readEntry(p));
case AEV_LONG -> new AnnotationImpl.OfLongImpl((LongEntry)classReader.readEntry(p));
case AEV_SHORT -> new AnnotationImpl.OfShortImpl((IntegerEntry)classReader.readEntry(p));
case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl((IntegerEntry)classReader.readEntry(p));
case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class));
case AEV_CHAR -> new AnnotationImpl.OfCharacterImpl(classReader.readEntry(p, IntegerEntry.class));
case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class));
case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class));
case AEV_INT -> new AnnotationImpl.OfIntegerImpl(classReader.readEntry(p, IntegerEntry.class));
case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class));
case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class));
case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class));
case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readUtf8Entry(p));
case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readUtf8Entry(p), classReader.readUtf8Entry(p + 2));
case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readUtf8Entry(p));

View File

@ -483,7 +483,7 @@ public abstract sealed class BoundAttribute<T extends Attribute<T>>
@Override
public ConstantValueEntry constant() {
return (ConstantValueEntry) classReader.readEntry(payloadStart);
return classReader.readEntry(payloadStart, ConstantValueEntry.class);
}
}

View File

@ -27,7 +27,6 @@ package jdk.internal.classfile.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@ -37,10 +36,6 @@ import jdk.internal.classfile.attribute.BootstrapMethodsAttribute;
import jdk.internal.classfile.constantpool.ClassEntry;
import jdk.internal.classfile.constantpool.ConstantPoolException;
import jdk.internal.classfile.constantpool.LoadableConstantEntry;
import jdk.internal.classfile.constantpool.MethodHandleEntry;
import jdk.internal.classfile.constantpool.ModuleEntry;
import jdk.internal.classfile.constantpool.NameAndTypeEntry;
import jdk.internal.classfile.constantpool.PackageEntry;
import jdk.internal.classfile.constantpool.PoolEntry;
import jdk.internal.classfile.constantpool.Utf8Entry;
@ -61,6 +56,10 @@ import static jdk.internal.classfile.Classfile.TAG_NAMEANDTYPE;
import static jdk.internal.classfile.Classfile.TAG_PACKAGE;
import static jdk.internal.classfile.Classfile.TAG_STRING;
import static jdk.internal.classfile.Classfile.TAG_UTF8;
import jdk.internal.classfile.constantpool.MethodHandleEntry;
import jdk.internal.classfile.constantpool.ModuleEntry;
import jdk.internal.classfile.constantpool.NameAndTypeEntry;
import jdk.internal.classfile.constantpool.PackageEntry;
public final class ClassReaderImpl
implements ClassReader {
@ -156,7 +155,7 @@ public final class ClassReaderImpl
@Override
public ClassEntry thisClassEntry() {
if (thisClass == null) {
thisClass = readClassEntry(thisClassPos);
thisClass = readEntry(thisClassPos, ClassEntry.class);
}
return thisClass;
}
@ -391,6 +390,13 @@ public final class ClassReaderImpl
return entryByIndex(readU2(pos));
}
@Override
public <T extends PoolEntry> T readEntry(int pos, Class<T> cls) {
var e = readEntry(pos);
if (cls.isInstance(e)) return cls.cast(e);
throw new ConstantPoolException("Not a " + cls.getSimpleName() + " at index: " + readU2(pos));
}
@Override
public PoolEntry readEntryOrNull(int pos) {
int index = readU2(pos);
@ -417,32 +423,27 @@ public final class ClassReaderImpl
@Override
public ModuleEntry readModuleEntry(int pos) {
if (readEntry(pos) instanceof ModuleEntry me) return me;
throw new ConstantPoolException("Not a module entry at pos: " + pos);
return readEntry(pos, ModuleEntry.class);
}
@Override
public PackageEntry readPackageEntry(int pos) {
if (readEntry(pos) instanceof PackageEntry pe) return pe;
throw new ConstantPoolException("Not a package entry at pos: " + pos);
return readEntry(pos, PackageEntry.class);
}
@Override
public ClassEntry readClassEntry(int pos) {
if (readEntry(pos) instanceof ClassEntry ce) return ce;
throw new ConstantPoolException("Not a class entry at pos: " + pos);
return readEntry(pos, ClassEntry.class);
}
@Override
public NameAndTypeEntry readNameAndTypeEntry(int pos) {
if (readEntry(pos) instanceof NameAndTypeEntry nate) return nate;
throw new ConstantPoolException("Not a name and type entry at pos: " + pos);
return readEntry(pos, NameAndTypeEntry.class);
}
@Override
public MethodHandleEntry readMethodHandleEntry(int pos) {
if (readEntry(pos) instanceof MethodHandleEntry mhe) return mhe;
throw new ConstantPoolException("Not a method handle entry at pos: " + pos);
return readEntry(pos, MethodHandleEntry.class);
}
@Override

View File

@ -186,15 +186,19 @@ module java.base {
java.logging;
exports jdk.internal.classfile to
jdk.jartool,
jdk.jdeps,
jdk.jlink,
jdk.jshell;
exports jdk.internal.classfile.attribute to
jdk.jartool,
jdk.jdeps,
jdk.jlink;
exports jdk.internal.classfile.constantpool to
jdk.jartool,
jdk.jdeps,
jdk.jlink;
exports jdk.internal.classfile.instruction to
jdk.jdeps,
jdk.jlink,
jdk.jshell;
exports jdk.internal.org.objectweb.asm to

View File

@ -25,17 +25,14 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.Annotation;
import com.sun.tools.classfile.TypeAnnotation;
import com.sun.tools.classfile.Annotation.Annotation_element_value;
import com.sun.tools.classfile.Annotation.Array_element_value;
import com.sun.tools.classfile.Annotation.Class_element_value;
import com.sun.tools.classfile.Annotation.Enum_element_value;
import com.sun.tools.classfile.Annotation.Primitive_element_value;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Descriptor;
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
import java.util.List;
import jdk.internal.classfile.Annotation;
import jdk.internal.classfile.AnnotationElement;
import jdk.internal.classfile.AnnotationValue;
import jdk.internal.classfile.constantpool.*;
import jdk.internal.classfile.Signature;
import jdk.internal.classfile.TypeAnnotation;
import jdk.internal.classfile.attribute.CodeAttribute;
/**
* A writer for writing annotations as text.
@ -68,15 +65,15 @@ public class AnnotationWriter extends BasicWriter {
}
public void write(Annotation annot, boolean resolveIndices) {
writeDescriptor(annot.type_index, resolveIndices);
writeDescriptor(annot.className(), resolveIndices);
if (resolveIndices) {
boolean showParens = annot.num_element_value_pairs > 0;
boolean showParens = annot.elements().size() > 0;
if (showParens) {
println("(");
indent(+1);
}
for (int i = 0; i < annot.num_element_value_pairs; i++) {
write(annot.element_value_pairs[i], true);
for (var element : annot.elements()) {
write(element, true);
println();
}
if (showParens) {
@ -85,143 +82,126 @@ public class AnnotationWriter extends BasicWriter {
}
} else {
print("(");
for (int i = 0; i < annot.num_element_value_pairs; i++) {
for (int i = 0; i < annot.elements().size(); i++) {
if (i > 0)
print(",");
write(annot.element_value_pairs[i], false);
write(annot.elements().get(i), false);
}
print(")");
}
}
public void write(TypeAnnotation annot) {
write(annot, true, false);
public void write(TypeAnnotation annot, CodeAttribute lr) {
write(annot, true, false, lr);
println();
indent(+1);
write(annot.annotation, true);
write(annot, true);
indent(-1);
}
public void write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices) {
write(annot.annotation, resolveIndices);
public void write(TypeAnnotation annot, boolean showOffsets,
boolean resolveIndices, CodeAttribute lr) {
write(annot, resolveIndices);
print(": ");
write(annot.position, showOffsets);
write(annot.targetInfo(), annot.targetPath(), showOffsets, lr);
}
public void write(TypeAnnotation.Position pos, boolean showOffsets) {
print(pos.type);
public void write(TypeAnnotation.TargetInfo targetInfo,
List<TypeAnnotation.TypePathComponent> targetPath,
boolean showOffsets, CodeAttribute lr) {
print(targetInfo.targetType());
switch (pos.type) {
// instanceof
case INSTANCEOF:
// new expression
case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
if (showOffsets) {
print(", offset=");
print(pos.offset);
}
break;
// local variable
case LOCAL_VARIABLE:
// resource variable
case RESOURCE_VARIABLE:
if (pos.lvarOffset == null) {
print(", lvarOffset is Null!");
break;
}
print(", {");
for (int i = 0; i < pos.lvarOffset.length; ++i) {
if (i != 0) print("; ");
switch (targetInfo) {
// instanceof
// new expression
// constructor/method reference receiver
case TypeAnnotation.OffsetTarget pos -> {
if (showOffsets) {
print("start_pc=");
print(pos.lvarOffset[i]);
print(", offset=");
print(lr.labelToBci(pos.target()));
}
print(", length=");
print(pos.lvarLength[i]);
print(", index=");
print(pos.lvarIndex[i]);
}
print("}");
break;
// exception parameter
case EXCEPTION_PARAMETER:
print(", exception_index=");
print(pos.exception_index);
break;
// method receiver
case METHOD_RECEIVER:
// Do nothing
break;
// type parameter
case CLASS_TYPE_PARAMETER:
case METHOD_TYPE_PARAMETER:
print(", param_index=");
print(pos.parameter_index);
break;
// type parameter bound
case CLASS_TYPE_PARAMETER_BOUND:
case METHOD_TYPE_PARAMETER_BOUND:
print(", param_index=");
print(pos.parameter_index);
print(", bound_index=");
print(pos.bound_index);
break;
// class extends or implements clause
case CLASS_EXTENDS:
print(", type_index=");
print(pos.type_index);
break;
// throws
case THROWS:
print(", type_index=");
print(pos.type_index);
break;
// method parameter
case METHOD_FORMAL_PARAMETER:
print(", param_index=");
print(pos.parameter_index);
break;
// type cast
case CAST:
// method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT:
if (showOffsets) {
print(", offset=");
print(pos.offset);
case TypeAnnotation.LocalVarTarget pos -> {
if (pos.table().isEmpty()) {
print(", lvarOffset is Null!");
break;
}
print(", {");
var table = pos.table();
for (int i = 0; i < table.size(); ++i) {
var e = table.get(i);
if (i != 0) print("; ");
int startPc = lr.labelToBci(e.startLabel());
if (showOffsets) {
print("start_pc=");
print(startPc);
}
print(", length=");
print(lr.labelToBci(e.endLabel()) - startPc);
print(", index=");
print(e.index());
}
print("}");
}
print(", type_index=");
print(pos.type_index);
break;
// We don't need to worry about these
case METHOD_RETURN:
case FIELD:
break;
case UNKNOWN:
throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!");
default:
throw new AssertionError("AnnotationWriter: Unknown target type for position: " + pos);
case TypeAnnotation.CatchTarget pos -> {
print(", exception_index=");
print(pos.exceptionTableIndex());
}
case TypeAnnotation.TypeParameterTarget pos -> {
print(", param_index=");
print(pos.typeParameterIndex());
}
case TypeAnnotation.TypeParameterBoundTarget pos -> {
print(", param_index=");
print(pos.typeParameterIndex());
print(", bound_index=");
print(pos.boundIndex());
}
case TypeAnnotation.SupertypeTarget pos -> {
print(", type_index=");
print(pos.supertypeIndex());
}
case TypeAnnotation.ThrowsTarget pos -> {
print(", type_index=");
print(pos.throwsTargetIndex());
}
case TypeAnnotation.FormalParameterTarget pos -> {
print(", param_index=");
print(pos.formalParameterIndex());
}
case TypeAnnotation.TypeArgumentTarget pos -> {
if (showOffsets) {
print(", offset=");
print(lr.labelToBci(pos.target()));
}
print(", type_index=");
print(pos.typeArgumentIndex());
}
case TypeAnnotation.EmptyTarget pos -> {
// Do nothing
}
default ->
throw new AssertionError("AnnotationWriter: Unhandled target type: "
+ targetInfo.getClass());
}
// Append location data for generics/arrays.
if (!pos.location.isEmpty()) {
if (!targetPath.isEmpty()) {
print(", location=");
print(pos.location);
print(targetPath.stream().map(tp -> tp.typePathKind().toString() +
(tp.typePathKind() == TypeAnnotation.TypePathComponent.Kind.TYPE_ARGUMENT
? ("(" + tp.typeArgumentIndex() + ")")
: "")).toList());
}
}
public void write(Annotation.element_value_pair pair, boolean resolveIndices) {
writeIndex(pair.element_name_index, resolveIndices);
public void write(AnnotationElement pair, boolean resolveIndices) {
writeIndex(pair.name(), resolveIndices);
print("=");
write(pair.value, resolveIndices);
write(pair.value(), resolveIndices);
}
public void write(Annotation.element_value value) {
public void write(AnnotationValue value) {
write(value, false);
println();
indent(+1);
@ -229,122 +209,94 @@ public class AnnotationWriter extends BasicWriter {
indent(-1);
}
public void write(Annotation.element_value value, boolean resolveIndices) {
ev_writer.write(value, resolveIndices);
}
private void writeDescriptor(int index, boolean resolveIndices) {
private void writeDescriptor(Utf8Entry entry, boolean resolveIndices) {
if (resolveIndices) {
try {
ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
Descriptor d = new Descriptor(index);
print(d.getFieldType(constant_pool));
return;
} catch (ConstantPoolException | InvalidDescriptor ignore) {
}
print(classWriter.sigPrinter.print(Signature.parseFrom(entry.stringValue())));
return;
}
print("#" + index);
print("#" + entry.index());
}
private void writeIndex(int index, boolean resolveIndices) {
private void writeIndex(PoolEntry entry, boolean resolveIndices) {
if (resolveIndices) {
print(constantWriter.stringValue(index));
print(constantWriter.stringValue(entry));
} else
print("#" + index);
print("#" + entry.index());
}
element_value_Writer ev_writer = new element_value_Writer();
class element_value_Writer implements Annotation.element_value.Visitor<Void,Boolean> {
public void write(Annotation.element_value value, boolean resolveIndices) {
value.accept(this, resolveIndices);
}
@Override
public Void visitPrimitive(Primitive_element_value ev, Boolean resolveIndices) {
if (resolveIndices) {
int index = ev.const_value_index;
switch (ev.tag) {
case 'B':
print("(byte) ");
print(constantWriter.stringValue(index));
break;
case 'C':
print("'");
print(constantWriter.charValue(index));
print("'");
break;
case 'D':
case 'F':
case 'I':
case 'J':
print(constantWriter.stringValue(index));
break;
case 'S':
print("(short) ");
print(constantWriter.stringValue(index));
break;
case 'Z':
print(constantWriter.booleanValue(index));
break;
case 's':
print("\"");
print(constantWriter.stringValue(index));
print("\"");
break;
default:
print(((char) ev.tag) + "#" + ev.const_value_index);
break;
public void write(AnnotationValue value, boolean resolveIndices) {
switch (value) {
case AnnotationValue.OfConstant ev -> {
if (resolveIndices) {
var entry = ev.constant();
switch (ev.tag()) {
case 'B':
print("(byte) ");
print(constantWriter.stringValue(entry));
break;
case 'C':
print("'");
print(constantWriter.charValue(entry));
print("'");
break;
case 'D':
case 'F':
case 'I':
case 'J':
print(constantWriter.stringValue(entry));
break;
case 'S':
print("(short) ");
print(constantWriter.stringValue(entry));
break;
case 'Z':
print(constantWriter.booleanValue(entry));
break;
case 's':
print("\"");
print(constantWriter.stringValue(entry));
print("\"");
break;
default:
print(ev.tag() + "#" + entry.index());
break;
}
} else {
print(ev.tag() + "#" + ev.constant().index());
}
} else {
print(((char) ev.tag) + "#" + ev.const_value_index);
}
return null;
}
@Override
public Void visitEnum(Enum_element_value ev, Boolean resolveIndices) {
if (resolveIndices) {
writeIndex(ev.type_name_index, resolveIndices);
print(".");
writeIndex(ev.const_name_index, resolveIndices);
} else {
print(((char) ev.tag) + "#" + ev.type_name_index + ".#" + ev.const_name_index);
case AnnotationValue.OfEnum ev -> {
if (resolveIndices) {
writeIndex(ev.className(), resolveIndices);
print(".");
writeIndex(ev.constantName(), resolveIndices);
} else {
print(ev.tag() + "#" + ev.className().index() + ".#"
+ ev.constantName().index());
}
}
return null;
}
@Override
public Void visitClass(Class_element_value ev, Boolean resolveIndices) {
if (resolveIndices) {
print("class ");
writeIndex(ev.class_info_index, resolveIndices);
} else {
print(((char) ev.tag) + "#" + ev.class_info_index);
case AnnotationValue.OfClass ev -> {
if (resolveIndices) {
print("class ");
writeIndex(ev.className(), resolveIndices);
} else {
print(ev.tag() + "#" + ev.className().index());
}
}
return null;
}
@Override
public Void visitAnnotation(Annotation_element_value ev, Boolean resolveIndices) {
print((char) ev.tag);
AnnotationWriter.this.write(ev.annotation_value, resolveIndices);
return null;
}
@Override
public Void visitArray(Array_element_value ev, Boolean resolveIndices) {
print("[");
for (int i = 0; i < ev.num_values; i++) {
if (i > 0)
print(",");
write(ev.values[i], resolveIndices);
case AnnotationValue.OfAnnotation ev -> {
print(ev.tag());
AnnotationWriter.this.write(ev.annotation(), resolveIndices);
}
case AnnotationValue.OfArray ev -> {
print("[");
for (int i = 0; i < ev.values().size(); i++) {
if (i > 0)
print(",");
write(ev.values().get(i), resolveIndices);
}
print("]");
}
print("]");
return null;
}
}
private final ClassWriter classWriter;

View File

@ -26,10 +26,7 @@
package com.sun.tools.javap;
import java.io.PrintWriter;
import com.sun.tools.classfile.AttributeException;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.DescriptorException;
import java.util.function.Supplier;
/*
* A writer similar to a PrintWriter but which does not hide exceptions.
@ -57,6 +54,14 @@ public class BasicWriter {
lineWriter.print(o == null ? null : o.toString());
}
protected void print(Supplier<Object> safeguardedCode) {
try {
print(safeguardedCode.get());
} catch (IllegalArgumentException e) {
print(report(e));
}
}
protected void println() {
lineWriter.println();
}
@ -71,6 +76,11 @@ public class BasicWriter {
lineWriter.println();
}
protected void println(Supplier<Object> safeguardedCode) {
print(safeguardedCode);
lineWriter.println();
}
protected void indent(int delta) {
lineWriter.indent(delta);
}
@ -83,23 +93,15 @@ public class BasicWriter {
lineWriter.pendingNewline = b;
}
protected String report(AttributeException e) {
out.println("Error: " + e.getMessage()); // i18n?
return "???";
}
protected String report(ConstantPoolException e) {
out.println("Error: " + e.getMessage()); // i18n?
return "???";
}
protected String report(DescriptorException e) {
protected String report(Exception e) {
out.println("Error: " + e.getMessage()); // i18n?
errorReported = true;
return "???";
}
protected String report(String msg) {
out.println("Error: " + msg); // i18n?
errorReported = true;
return "???";
}
@ -123,6 +125,7 @@ public class BasicWriter {
private LineWriter lineWriter;
private PrintWriter out;
protected Messages messages;
protected boolean errorReported;
private static class LineWriter {
static LineWriter instance(Context context) {

View File

@ -28,14 +28,15 @@ package com.sun.tools.javap;
import java.util.ArrayList;
import java.util.List;
import com.sun.tools.classfile.AccessFlags;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.DescriptorException;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.Instruction.TypeKind;
import com.sun.tools.classfile.Method;
import java.util.Locale;
import java.util.stream.Collectors;
import jdk.internal.classfile.Classfile;
import jdk.internal.classfile.Opcode;
import jdk.internal.classfile.constantpool.*;
import jdk.internal.classfile.Instruction;
import jdk.internal.classfile.MethodModel;
import jdk.internal.classfile.attribute.CodeAttribute;
import jdk.internal.classfile.instruction.*;
/*
* Write the contents of a Code attribute.
@ -68,161 +69,148 @@ public class CodeWriter extends BasicWriter {
options = Options.instance(context);
}
void write(Code_attribute attr, ConstantPool constant_pool) {
void write(CodeAttribute attr) {
println("Code:");
indent(+1);
writeVerboseHeader(attr, constant_pool);
writeVerboseHeader(attr);
writeInstrs(attr);
writeExceptionTable(attr);
attrWriter.write(attr, attr.attributes, constant_pool);
attrWriter.write(attr.attributes(), attr);
indent(-1);
}
public void writeVerboseHeader(Code_attribute attr, ConstantPool constant_pool) {
Method method = classWriter.getMethod();
String argCount;
try {
int n = method.descriptor.getParameterCount(constant_pool);
if (!method.access_flags.is(AccessFlags.ACC_STATIC))
++n; // for 'this'
argCount = Integer.toString(n);
} catch (ConstantPoolException e) {
argCount = report(e);
} catch (DescriptorException e) {
argCount = report(e);
}
println("stack=" + attr.max_stack +
", locals=" + attr.max_locals +
", args_size=" + argCount);
public void writeVerboseHeader(CodeAttribute attr) {
MethodModel method = attr.parent().get();
int n = method.methodTypeSymbol().parameterCount();
if ((method.flags().flagsMask() & Classfile.ACC_STATIC) == 0)
++n; // for 'this'
println("stack=" + attr.maxStack() +
", locals=" + attr.maxLocals() +
", args_size=" + Integer.toString(n));
}
public void writeInstrs(Code_attribute attr) {
public void writeInstrs(CodeAttribute attr) {
List<InstructionDetailWriter> detailWriters = getDetailWriters(attr);
for (Instruction instr: attr.getInstructions()) {
try {
for (InstructionDetailWriter w: detailWriters)
w.writeDetails(instr);
writeInstr(instr);
} catch (ArrayIndexOutOfBoundsException | IllegalStateException e) {
println(report("error at or after byte " + instr.getPC()));
break;
int pc = 0;
try {
for (var coe: attr) {
if (coe instanceof Instruction instr) {
for (InstructionDetailWriter w: detailWriters)
w.writeDetails(pc, instr);
writeInstr(pc, instr, attr);
pc += instr.sizeInBytes();
}
}
} catch (IllegalArgumentException e) {
report("error at or after byte " + pc);
}
for (InstructionDetailWriter w: detailWriters)
w.flush();
w.flush(pc);
}
public void writeInstr(Instruction instr) {
print(String.format("%4d: %-13s ", instr.getPC(), instr.getMnemonic()));
// compute the number of indentations for the body of multi-line instructions
// This is 6 (the width of "%4d: "), divided by the width of each indentation level,
// and rounded up to the next integer.
int indentWidth = options.indentWidth;
int indent = (6 + indentWidth - 1) / indentWidth;
instr.accept(instructionPrinter, indent);
println();
public void writeInstr(int pc, Instruction ins, CodeAttribute lr) {
print(String.format("%4d: %-13s ", pc, ins.opcode().name().toLowerCase(Locale.US)));
try {
// compute the number of indentations for the body of multi-line instructions
// This is 6 (the width of "%4d: "), divided by the width of each indentation level,
// and rounded up to the next integer.
int indentWidth = options.indentWidth;
int indent = (6 + indentWidth - 1) / indentWidth;
switch (ins) {
case BranchInstruction instr ->
print(lr.labelToBci(instr.target()));
case ConstantInstruction.ArgumentConstantInstruction instr ->
print(instr.constantValue());
case ConstantInstruction.LoadConstantInstruction instr ->
printConstantPoolRef(instr.constantEntry());
case FieldInstruction instr ->
printConstantPoolRef(instr.field());
case InvokeDynamicInstruction instr ->
printConstantPoolRefAndValue(instr.invokedynamic(), 0);
case InvokeInstruction instr -> {
if (instr.isInterface() && instr.opcode() != Opcode.INVOKESTATIC)
printConstantPoolRefAndValue(instr.method(), instr.count());
else printConstantPoolRef(instr.method());
}
case LoadInstruction instr ->
print(instr.sizeInBytes() > 1 ? instr.slot() : "");
case StoreInstruction instr ->
print(instr.sizeInBytes() > 1 ? instr.slot() : "");
case IncrementInstruction instr ->
print(instr.slot() + ", " + instr.constant());
case LookupSwitchInstruction instr -> {
var cases = instr.cases();
print("{ // " + cases.size());
indent(indent);
for (var c : cases)
print(String.format("%n%12d: %d", c.caseValue(),
lr.labelToBci(c.target())));
print("\n default: " + lr.labelToBci(instr.defaultTarget()) + "\n}");
indent(-indent);
}
case NewMultiArrayInstruction instr ->
printConstantPoolRefAndValue(instr.arrayType(), instr.dimensions());
case NewObjectInstruction instr ->
printConstantPoolRef(instr.className());
case NewPrimitiveArrayInstruction instr ->
print(" " + instr.typeKind().typeName());
case NewReferenceArrayInstruction instr ->
printConstantPoolRef(instr.componentType());
case TableSwitchInstruction instr -> {
print("{ // " + instr.lowValue() + " to " + instr.highValue());
indent(indent);
var caseMap = instr.cases().stream().collect(
Collectors.toMap(SwitchCase::caseValue, SwitchCase::target));
for (int i = instr.lowValue(); i <= instr.highValue(); i++)
print(String.format("%n%12d: %d", i,
lr.labelToBci(caseMap.getOrDefault(i, instr.defaultTarget()))));
print("\n default: " + lr.labelToBci(instr.defaultTarget()) + "\n}");
indent(-indent);
}
case TypeCheckInstruction instr ->
printConstantPoolRef(instr.type());
default -> {}
}
println();
} catch (IllegalArgumentException e) {
println(report(e));
}
}
// where
Instruction.KindVisitor<Void,Integer> instructionPrinter =
new Instruction.KindVisitor<>() {
public Void visitNoOperands(Instruction instr, Integer indent) {
return null;
}
private void printConstantPoolRef(PoolEntry entry) {
print("#" + entry.index());
tab();
print("// ");
constantWriter.write(entry.index());
}
public Void visitArrayType(Instruction instr, TypeKind kind, Integer indent) {
print(" " + kind.name);
return null;
}
private void printConstantPoolRefAndValue(PoolEntry entry, int value) {
print("#" + entry.index() + ", " + value);
tab();
print("// ");
constantWriter.write(entry.index());
}
public Void visitBranch(Instruction instr, int offset, Integer indent) {
print((instr.getPC() + offset));
return null;
}
public Void visitConstantPoolRef(Instruction instr, int index, Integer indent) {
print("#" + index);
tab();
print("// ");
printConstant(index);
return null;
}
public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Integer indent) {
print("#" + index + ", " + value);
tab();
print("// ");
printConstant(index);
return null;
}
public Void visitLocal(Instruction instr, int index, Integer indent) {
print(index);
return null;
}
public Void visitLocalAndValue(Instruction instr, int index, int value, Integer indent) {
print(index + ", " + value);
return null;
}
public Void visitLookupSwitch(Instruction instr,
int default_, int npairs, int[] matches, int[] offsets, Integer indent) {
int pc = instr.getPC();
print("{ // " + npairs);
indent(indent);
for (int i = 0; i < npairs; i++) {
print(String.format("%n%12d: %d", matches[i], (pc + offsets[i])));
}
print("\n default: " + (pc + default_) + "\n}");
indent(-indent);
return null;
}
public Void visitTableSwitch(Instruction instr,
int default_, int low, int high, int[] offsets, Integer indent) {
int pc = instr.getPC();
print("{ // " + low + " to " + high);
indent(indent);
for (int i = 0; i < offsets.length; i++) {
print(String.format("%n%12d: %d", (low + i), (pc + offsets[i])));
}
print("\n default: " + (pc + default_) + "\n}");
indent(-indent);
return null;
}
public Void visitValue(Instruction instr, int value, Integer indent) {
print(value);
return null;
}
public Void visitUnknown(Instruction instr, Integer indent) {
return null;
}
};
public void writeExceptionTable(Code_attribute attr) {
if (attr.exception_table_length > 0) {
public void writeExceptionTable(CodeAttribute attr) {
var excTable = attr.exceptionHandlers();
if (excTable.size() > 0) {
println("Exception table:");
indent(+1);
println(" from to target type");
for (int i = 0; i < attr.exception_table.length; i++) {
Code_attribute.Exception_data handler = attr.exception_table[i];
for (var handler : excTable) {
print(String.format(" %5d %5d %5d",
handler.start_pc, handler.end_pc, handler.handler_pc));
attr.labelToBci(handler.tryStart()),
attr.labelToBci(handler.tryEnd()),
attr.labelToBci(handler.handler())));
print(" ");
int catch_type = handler.catch_type;
if (catch_type == 0) {
var catch_type = handler.catchType();
if (catch_type.isEmpty()) {
println("any");
} else {
print("Class ");
println(constantWriter.stringValue(catch_type));
println(constantWriter.stringValue(catch_type.get()));
}
}
indent(-1);
@ -230,14 +218,10 @@ public class CodeWriter extends BasicWriter {
}
private void printConstant(int index) {
constantWriter.write(index);
}
private List<InstructionDetailWriter> getDetailWriters(Code_attribute attr) {
private List<InstructionDetailWriter> getDetailWriters(CodeAttribute attr) {
List<InstructionDetailWriter> detailWriters = new ArrayList<>();
if (options.details.contains(InstructionDetailWriter.Kind.SOURCE)) {
sourceWriter.reset(classWriter.getClassFile(), attr);
sourceWriter.reset(attr);
if (sourceWriter.hasSource())
detailWriters.add(sourceWriter);
else

View File

@ -25,11 +25,8 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import static com.sun.tools.classfile.ConstantPool.*;
import jdk.internal.classfile.constantpool.*;
import static jdk.internal.classfile.Classfile.*;
/*
* Write a constant pool entry.
@ -55,122 +52,11 @@ public class ConstantWriter extends BasicWriter {
}
protected void writeConstantPool() {
ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
var constant_pool = classWriter.getClassModel().constantPool();
writeConstantPool(constant_pool);
}
protected void writeConstantPool(ConstantPool constant_pool) {
ConstantPool.Visitor<Integer, Void> v = new ConstantPool.Visitor<>() {
public Integer visitClass(CONSTANT_Class_info info, Void p) {
print("#" + info.name_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitDouble(CONSTANT_Double_info info, Void p) {
println(stringValue(info));
return 2;
}
public Integer visitFieldref(CONSTANT_Fieldref_info info, Void p) {
print("#" + info.class_index + ".#" + info.name_and_type_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitFloat(CONSTANT_Float_info info, Void p) {
println(stringValue(info));
return 1;
}
public Integer visitInteger(CONSTANT_Integer_info info, Void p) {
println(stringValue(info));
return 1;
}
public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
print("#" + info.class_index + ".#" + info.name_and_type_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
print("#" + info.bootstrap_method_attr_index + ":#" + info.name_and_type_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitDynamicConstant(CONSTANT_Dynamic_info info, Void p) {
print("#" + info.bootstrap_method_attr_index + ":#" + info.name_and_type_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitLong(CONSTANT_Long_info info, Void p) {
println(stringValue(info));
return 2;
}
public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) {
print("#" + info.class_index + ".#" + info.name_and_type_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
print(info.reference_kind.tag + ":#" + info.reference_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitMethodType(CONSTANT_MethodType_info info, Void p) {
print("#" + info.descriptor_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitModule(CONSTANT_Module_info info, Void p) {
print("#" + info.name_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
print("#" + info.name_index + ":#" + info.type_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitPackage(CONSTANT_Package_info info, Void p) {
print("#" + info.name_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitString(CONSTANT_String_info info, Void p) {
print("#" + info.string_index);
tab();
println("// " + stringValue(info));
return 1;
}
public Integer visitUtf8(CONSTANT_Utf8_info info, Void p) {
println(stringValue(info));
return 1;
}
};
println("Constant pool:");
indent(+1);
int width = String.valueOf(constant_pool.size()).length() + 1;
@ -178,321 +64,228 @@ public class ConstantWriter extends BasicWriter {
while (cpx < constant_pool.size()) {
print(String.format("%" + width + "s", ("#" + cpx)));
try {
CPInfo cpInfo = constant_pool.get(cpx);
print(String.format(" = %-18s ", cpTagName(cpInfo)));
cpx += cpInfo.accept(v, null);
} catch (ConstantPool.InvalidIndex ex) {
// should not happen
var cpInfo = constant_pool.entryByIndex(cpx);
print(String.format(" = %-18s ", cpTagName(cpInfo.tag())));
switch (cpInfo) {
case ClassEntry info -> {
print(() -> "#" + info.name().index());
tab();
println(() -> "// " + stringValue(info));
}
case AnnotationConstantValueEntry info -> {
println(() -> stringValue(info));
}
case MemberRefEntry info -> {
print(() -> "#" + info.owner().index() + ".#"
+ info.nameAndType().index());
tab();
println(() -> "// " + stringValue(info));
}
case DynamicConstantPoolEntry info -> {
print(() -> "#" + info.bootstrapMethodIndex() + ":#"
+ info.nameAndType().index());
tab();
println(() -> "// " + stringValue(info));
}
case MethodHandleEntry info -> {
print(() -> info.kind() + ":#" + info.reference().index());
tab();
println(() -> "// " + stringValue(info));
}
case MethodTypeEntry info -> {
print(() -> "#" + info.descriptor().index());
tab();
println(() -> "// " + stringValue(info));
}
case ModuleEntry info -> {
print(() -> "#" + info.name().index());
tab();
println(() -> "// " + stringValue(info));
}
case NameAndTypeEntry info -> {
print(() -> "#" + info.name().index() + ":#" + info.type().index());
tab();
println(() -> "// " + stringValue(info));
}
case PackageEntry info -> {
print(() -> "#" + info.name().index());
tab();
println("// " + stringValue(info));
}
case StringEntry info -> {
print(() -> "#" + info.utf8().index());
tab();
println(() -> "// " + stringValue(info));
}
default ->
throw new IllegalArgumentException("unknown entry: "+ cpInfo);
}
cpx += cpInfo.width();
} catch (IllegalArgumentException e) {
println(report(e));
cpx++;
}
}
indent(-1);
}
protected void write(int cpx) {
ClassFile classFile = classWriter.getClassFile();
if (cpx == 0) {
print("#0");
return;
}
var classModel = classWriter.getClassModel();
CPInfo cpInfo;
try {
cpInfo = classFile.constant_pool.get(cpx);
} catch (ConstantPoolException e) {
print("#" + cpx);
return;
}
int tag = cpInfo.getTag();
switch (tag) {
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_Fieldref:
// simplify references within this class
CPRefInfo ref = (CPRefInfo) cpInfo;
try {
if (ref.class_index == classFile.this_class)
cpInfo = classFile.constant_pool.get(ref.name_and_type_index);
} catch (ConstantPool.InvalidIndex e) {
// ignore, for now
}
var cpInfo = classModel.constantPool().entryByIndex(cpx);
var tag = cpInfo.tag();
if (cpInfo instanceof MemberRefEntry ref) {
// simplify references within this class
if (ref.owner().index() == classModel.thisClass().index())
cpInfo = ref.nameAndType();
}
print(tagName(tag) + " " + stringValue(cpInfo));
}
String cpTagName(CPInfo cpInfo) {
String n = cpInfo.getClass().getSimpleName();
return n.replace("CONSTANT_", "").replace("_info", "");
String cpTagName(int tag) {
return switch (tag) {
case TAG_UTF8 -> "Utf8";
case TAG_INTEGER -> "Integer";
case TAG_FLOAT -> "Float";
case TAG_LONG -> "Long";
case TAG_DOUBLE -> "Double";
case TAG_CLASS -> "Class";
case TAG_STRING -> "String";
case TAG_FIELDREF -> "Fieldref";
case TAG_METHODHANDLE -> "MethodHandle";
case TAG_METHODTYPE -> "MethodType";
case TAG_METHODREF -> "Methodref";
case TAG_INTERFACEMETHODREF -> "InterfaceMethodref";
case TAG_INVOKEDYNAMIC -> "InvokeDynamic";
case TAG_CONSTANTDYNAMIC -> "Dynamic";
case TAG_NAMEANDTYPE -> "NameAndType";
default -> "Unknown";
};
}
String tagName(int tag) {
switch (tag) {
case CONSTANT_Utf8:
return "Utf8";
case CONSTANT_Integer:
return "int";
case CONSTANT_Float:
return "float";
case CONSTANT_Long:
return "long";
case CONSTANT_Double:
return "double";
case CONSTANT_Class:
return "class";
case CONSTANT_String:
return "String";
case CONSTANT_Fieldref:
return "Field";
case CONSTANT_MethodHandle:
return "MethodHandle";
case CONSTANT_MethodType:
return "MethodType";
case CONSTANT_Methodref:
return "Method";
case CONSTANT_InterfaceMethodref:
return "InterfaceMethod";
case CONSTANT_InvokeDynamic:
return "InvokeDynamic";
case CONSTANT_Dynamic:
return "Dynamic";
case CONSTANT_NameAndType:
return "NameAndType";
default:
return "(unknown tag " + tag + ")";
return switch (tag) {
case TAG_UTF8 -> "Utf8";
case TAG_INTEGER -> "int";
case TAG_FLOAT -> "float";
case TAG_LONG -> "long";
case TAG_DOUBLE -> "double";
case TAG_CLASS -> "class";
case TAG_STRING -> "String";
case TAG_FIELDREF -> "Field";
case TAG_METHODHANDLE -> "MethodHandle";
case TAG_METHODTYPE -> "MethodType";
case TAG_METHODREF -> "Method";
case TAG_INTERFACEMETHODREF -> "InterfaceMethod";
case TAG_INVOKEDYNAMIC -> "InvokeDynamic";
case TAG_CONSTANTDYNAMIC -> "Dynamic";
case TAG_NAMEANDTYPE -> "NameAndType";
default -> "(unknown tag " + tag + ")";
};
}
String booleanValue(PoolEntry info) {
if (info instanceof IntegerEntry ie) {
switch (ie.intValue()) {
case 0: return "false";
case 1: return "true";
}
}
return "#" + info.index();
}
String booleanValue(int constant_pool_index) {
ClassFile classFile = classWriter.getClassFile();
try {
CPInfo info = classFile.constant_pool.get(constant_pool_index);
if (info instanceof CONSTANT_Integer_info) {
int value = ((CONSTANT_Integer_info) info).value;
switch (value) {
case 0: return "false";
case 1: return "true";
}
}
return "#" + constant_pool_index;
} catch (ConstantPool.InvalidIndex e) {
return report(e);
var info = classWriter.getClassModel().constantPool()
.entryByIndex(constant_pool_index);
if (info instanceof IntegerEntry ie) {
switch (ie.intValue()) {
case 0: return "false";
case 1: return "true";
}
}
return "#" + constant_pool_index;
}
String charValue(PoolEntry info) {
if (info instanceof IntegerEntry ie) {
int value = ie.intValue();
return String.valueOf((char) value);
} else {
return "#" + info.index();
}
}
String charValue(int constant_pool_index) {
ClassFile classFile = classWriter.getClassFile();
try {
CPInfo info = classFile.constant_pool.get(constant_pool_index);
if (info instanceof CONSTANT_Integer_info) {
int value = ((CONSTANT_Integer_info) info).value;
return String.valueOf((char) value);
} else {
return "#" + constant_pool_index;
}
} catch (ConstantPool.InvalidIndex e) {
return report(e);
var info = classWriter.getClassModel().constantPool()
.entryByIndex(constant_pool_index);
if (info instanceof IntegerEntry ie) {
int value = ie.intValue();
return String.valueOf((char) value);
} else {
return "#" + constant_pool_index;
}
}
String stringValue(int constant_pool_index) {
ClassFile classFile = classWriter.getClassFile();
try {
return stringValue(classFile.constant_pool.get(constant_pool_index));
} catch (ConstantPool.InvalidIndex e) {
return report(e);
}
return stringValue(classWriter.getClassModel().constantPool()
.entryByIndex(constant_pool_index));
}
String stringValue(CPInfo cpInfo) {
return stringValueVisitor.visit(cpInfo);
}
StringValueVisitor stringValueVisitor = new StringValueVisitor();
private class StringValueVisitor implements ConstantPool.Visitor<String, Void> {
public String visit(CPInfo info) {
return info.accept(this, null);
}
public String visitClass(CONSTANT_Class_info info, Void p) {
return getCheckedName(info);
}
String getCheckedName(CONSTANT_Class_info info) {
try {
return checkName(info.getName());
} catch (ConstantPoolException e) {
return report(e);
String stringValue(PoolEntry cpInfo) {
return switch (cpInfo) {
case ClassEntry info -> checkName(info.asInternalName());
case DoubleEntry info -> info.doubleValue() + "d";
case MemberRefEntry info -> checkName(info.owner().asInternalName())
+ '.' + stringValue(info.nameAndType());
case FloatEntry info -> info.floatValue()+ "f";
case IntegerEntry info -> String.valueOf(info.intValue());
case DynamicConstantPoolEntry info -> "#" + info.bootstrapMethodIndex()
+ ":" + stringValue(info.nameAndType());
case LongEntry info -> info.longValue()+ "l";
case ModuleEntry info -> checkName(info.name().stringValue());
case NameAndTypeEntry info -> checkName(info.name().stringValue())
+ ':' + info.type().stringValue();
case PackageEntry info -> checkName(info.name().stringValue());
case MethodHandleEntry info -> {
String kind = switch (info.asSymbol().kind()) {
case STATIC, INTERFACE_STATIC -> "REF_invokeStatic";
case VIRTUAL -> "REF_invokeVirtual";
case INTERFACE_VIRTUAL -> "REF_invokeInterface";
case SPECIAL, INTERFACE_SPECIAL -> "REF_invokeSpecial";
case CONSTRUCTOR -> "REF_newInvokeSpecial";
case GETTER -> "REF_getField";
case SETTER -> "REF_putField";
case STATIC_GETTER -> "REF_getStatic";
case STATIC_SETTER -> "REF_putStatic";
};
yield kind + " " + stringValue(info.reference());
}
}
public String visitDouble(CONSTANT_Double_info info, Void p) {
return info.value + "d";
}
public String visitFieldref(CONSTANT_Fieldref_info info, Void p) {
return visitRef(info, p);
}
public String visitFloat(CONSTANT_Float_info info, Void p) {
return info.value + "f";
}
public String visitInteger(CONSTANT_Integer_info info, Void p) {
return String.valueOf(info.value);
}
public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
return visitRef(info, p);
}
public String visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
try {
String callee = stringValue(info.getNameAndTypeInfo());
return "#" + info.bootstrap_method_attr_index + ":" + callee;
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitDynamicConstant(CONSTANT_Dynamic_info info, Void p) {
try {
String callee = stringValue(info.getNameAndTypeInfo());
return "#" + info.bootstrap_method_attr_index + ":" + callee;
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitLong(CONSTANT_Long_info info, Void p) {
return info.value + "l";
}
public String visitModule(CONSTANT_Module_info info, Void p) {
try {
return checkName(info.getName());
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
return getCheckedName(info) + ":" + getType(info);
}
String getCheckedName(CONSTANT_NameAndType_info info) {
try {
return checkName(info.getName());
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitPackage(CONSTANT_Package_info info, Void p) {
try {
return checkName(info.getName());
} catch (ConstantPoolException e) {
return report(e);
}
}
String getType(CONSTANT_NameAndType_info info) {
try {
return info.getType();
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
try {
return info.reference_kind + " " + stringValue(info.getCPRefInfo());
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitMethodType(CONSTANT_MethodType_info info, Void p) {
try {
return info.getType();
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitMethodref(CONSTANT_Methodref_info info, Void p) {
return visitRef(info, p);
}
public String visitString(CONSTANT_String_info info, Void p) {
try {
ClassFile classFile = classWriter.getClassFile();
int string_index = info.string_index;
return stringValue(classFile.constant_pool.getUTF8Info(string_index));
} catch (ConstantPoolException e) {
return report(e);
}
}
public String visitUtf8(CONSTANT_Utf8_info info, Void p) {
String s = info.value;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '\t':
sb.append('\\').append('t');
break;
case '\n':
sb.append('\\').append('n');
break;
case '\r':
sb.append('\\').append('r');
break;
case '\b':
sb.append('\\').append('b');
break;
case '\f':
sb.append('\\').append('f');
break;
case '\"':
sb.append('\\').append('\"');
break;
case '\'':
sb.append('\\').append('\'');
break;
case '\\':
sb.append('\\').append('\\');
break;
default:
if (Character.isISOControl(c)) {
sb.append(String.format("\\u%04x", (int) c));
break;
}
sb.append(c);
case MethodTypeEntry info -> info.descriptor().stringValue();
case StringEntry info -> stringValue(info.utf8());
case Utf8Entry info -> {
StringBuilder sb = new StringBuilder();
for (char c : info.stringValue().toCharArray()) {
sb.append(switch (c) {
case '\t' -> "\\t";
case '\n' -> "\\n";
case '\r' -> "\\r";
case '\b' -> "\\b";
case '\f' -> "\\f";
case '\"' -> "\\\"";
case '\'' -> "\\\'";
case '\\' -> "\\\\";
default -> Character.isISOControl(c)
? String.format("\\u%04x", (int) c) : c;
});
}
yield sb.toString();
}
return sb.toString();
}
String visitRef(CPRefInfo info, Void p) {
String cn = getCheckedClassName(info);
String nat;
try {
nat = stringValue(info.getNameAndTypeInfo());
} catch (ConstantPoolException e) {
nat = report(e);
}
return cn + "." + nat;
}
String getCheckedClassName(CPRefInfo info) {
try {
return checkName(info.getClassName());
} catch (ConstantPoolException e) {
return report(e);
}
}
default -> throw new IllegalArgumentException("unknown " + cpInfo);
};
}
/* If name is a valid binary name, return it; otherwise quote it. */

View File

@ -25,7 +25,7 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.Instruction;
import jdk.internal.classfile.Instruction;
/*
@ -56,6 +56,6 @@ public abstract class InstructionDetailWriter extends BasicWriter {
super(context);
}
abstract void writeDetails(Instruction instr);
void flush() { }
abstract void writeDetails(int pc, Instruction instr);
void flush(int pc) { }
}

View File

@ -67,7 +67,10 @@ import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import com.sun.tools.classfile.*;
import jdk.internal.classfile.ClassModel;
import jdk.internal.classfile.Classfile;
import jdk.internal.classfile.constantpool.*;
import static jdk.internal.classfile.Classfile.*;
/**
* "Main" class for javap, normally accessed from the command line
@ -166,7 +169,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
@Override
void process(JavapTask task, String opt, String arg) {
task.options.accessOptions.add(opt);
task.options.showAccess = AccessFlags.ACC_PUBLIC;
task.options.showAccess = ACC_PUBLIC;
}
},
@ -174,7 +177,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
@Override
void process(JavapTask task, String opt, String arg) {
task.options.accessOptions.add(opt);
task.options.showAccess = AccessFlags.ACC_PROTECTED;
task.options.showAccess = ACC_PROTECTED;
}
},
@ -193,7 +196,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
!task.options.accessOptions.contains("-private")) {
task.options.accessOptions.add(opt);
}
task.options.showAccess = AccessFlags.ACC_PRIVATE;
task.options.showAccess = ACC_PRIVATE;
}
},
@ -349,7 +352,6 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
context = new Context();
context.put(Messages.class, this);
options = Options.instance(context);
attributeFactory = new Attribute.Factory();
}
public JavapTask(Writer out,
@ -633,7 +635,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
} catch (OutOfMemoryError e) {
reportError("err.nomem");
result = EXIT_ERROR;
} catch (FatalError e) {
} catch (IllegalArgumentException e) {
Object msg = e.getLocalizedMessage();
if (msg == null) {
msg = e;
@ -654,7 +656,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
}
protected int writeClass(ClassWriter classWriter, String className)
throws IOException, ConstantPoolException {
throws IOException {
JavaFileObject fo = open(className);
if (fo == null) {
reportError("err.class.not.found", className);
@ -663,34 +665,26 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
ClassFileInfo cfInfo = read(fo);
if (!className.endsWith(".class")) {
if (cfInfo.cf.this_class == 0) {
if (!className.equals("module-info")) {
reportWarning("warn.unexpected.class", fo.getName(), className);
}
} else {
String cfName = cfInfo.cf.getName();
if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", "."))) {
reportWarning("warn.unexpected.class", fo.getName(), className);
}
String cfName = cfInfo.cm.thisClass().asInternalName();
if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", "."))) {
reportWarning("warn.unexpected.class", fo.getName(), className);
}
}
write(cfInfo);
if (!write(cfInfo)) return EXIT_ERROR;
if (options.showInnerClasses) {
ClassFile cf = cfInfo.cf;
Attribute a = cf.getAttribute(Attribute.InnerClasses);
if (a instanceof InnerClasses_attribute) {
InnerClasses_attribute inners = (InnerClasses_attribute) a;
ClassModel cm = cfInfo.cm;
var a = cm.findAttribute(jdk.internal.classfile.Attributes.INNER_CLASSES);
if (a.isPresent()) {
var inners = a.get();
try {
int result = EXIT_OK;
for (int i = 0; i < inners.classes.length; i++) {
int outerIndex = inners.classes[i].outer_class_info_index;
ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
String outerClassName = outerClassInfo.getName();
if (outerClassName.equals(cf.getName())) {
int innerIndex = inners.classes[i].inner_class_info_index;
ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
String innerClassName = innerClassInfo.getName();
for (var inner : inners.classes()) {
var outerClassInfo = inner.outerClass();
String outerClassName = outerClassInfo.map(ClassEntry::asInternalName).orElse(null);
if (cm.thisClass().asInternalName().equals(outerClassName)) {
var innerClassInfo = inner.innerClass();
String innerClassName = innerClassInfo.asInternalName();
classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
classWriter.println();
result = writeClass(classWriter, innerClassName);
@ -698,13 +692,10 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
}
}
return result;
} catch (ConstantPoolException e) {
} catch (IllegalArgumentException e) {
reportError("err.bad.innerclasses.attribute", className);
return EXIT_ERROR;
}
} else if (a != null) {
reportError("err.bad.innerclasses.attribute", className);
return EXIT_ERROR;
}
}
@ -811,19 +802,19 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
}
public static class ClassFileInfo {
ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
ClassFileInfo(JavaFileObject fo, ClassModel cm, byte[] digest, int size) {
this.fo = fo;
this.cf = cf;
this.cm = cm;
this.digest = digest;
this.size = size;
}
public final JavaFileObject fo;
public final ClassFile cf;
public final ClassModel cm;
public final byte[] digest;
public final int size;
}
public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
public ClassFileInfo read(JavaFileObject fo) throws IOException {
InputStream in = fo.openInputStream();
try {
SizeInputStream sizeIn = null;
@ -836,17 +827,16 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
in = new DigestInputStream(in, md);
in = sizeIn = new SizeInputStream(in);
}
ClassFile cf = ClassFile.read(in, attributeFactory);
ClassModel cm = Classfile.of().parse(in.readAllBytes());
byte[] digest = (md == null) ? null : md.digest();
int size = (sizeIn == null) ? -1 : sizeIn.size();
return new ClassFileInfo(fo, cf, digest, size);
return new ClassFileInfo(fo, cm, digest, size);
} finally {
in.close();
}
}
public void write(ClassFileInfo info) {
public boolean write(ClassFileInfo info) {
ClassWriter classWriter = ClassWriter.instance(context);
if (options.sysInfo || options.verbose) {
classWriter.setFile(info.fo.toUri());
@ -855,56 +845,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
classWriter.setFileSize(info.size);
}
classWriter.write(info.cf);
}
protected void setClassFile(ClassFile classFile) {
ClassWriter classWriter = ClassWriter.instance(context);
classWriter.setClassFile(classFile);
}
protected void setMethod(Method enclosingMethod) {
ClassWriter classWriter = ClassWriter.instance(context);
classWriter.setMethod(enclosingMethod);
}
protected void write(Attribute value) {
AttributeWriter attrWriter = AttributeWriter.instance(context);
ClassWriter classWriter = ClassWriter.instance(context);
ClassFile cf = classWriter.getClassFile();
attrWriter.write(cf, value, cf.constant_pool);
}
protected void write(Attributes attrs) {
AttributeWriter attrWriter = AttributeWriter.instance(context);
ClassWriter classWriter = ClassWriter.instance(context);
ClassFile cf = classWriter.getClassFile();
attrWriter.write(cf, attrs, cf.constant_pool);
}
protected void write(ConstantPool constant_pool) {
ConstantWriter constantWriter = ConstantWriter.instance(context);
constantWriter.writeConstantPool(constant_pool);
}
protected void write(ConstantPool constant_pool, int value) {
ConstantWriter constantWriter = ConstantWriter.instance(context);
constantWriter.write(value);
}
protected void write(ConstantPool.CPInfo value) {
ConstantWriter constantWriter = ConstantWriter.instance(context);
constantWriter.println(value);
}
protected void write(Field value) {
ClassWriter classWriter = ClassWriter.instance(context);
classWriter.writeField(value);
}
protected void write(Method value) {
ClassWriter classWriter = ClassWriter.instance(context);
classWriter.writeMethod(value);
return classWriter.write(info.cm);
}
private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
@ -944,7 +885,8 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
if (result == null)
result = l;
else
throw new IOException("multiple definitions found for " + moduleName);
throw new IOException("multiple definitions found for "
+ moduleName);
}
}
if (result != null)
@ -957,7 +899,8 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
private void showHelp() {
printLines(getMessage("main.usage", progname));
for (Option o: recognizedOptions) {
String name = o.aliases[0].replaceAll("^-+", "").replaceAll("-+", "_"); // there must always be at least one name
// there must always be at least one name
String name = o.aliases[0].replaceAll("^-+", "").replaceAll("-+", "_");
if (name.startsWith("X") || name.equals("fullversion"))
continue;
printLines(getMessage("main.opt." + name));
@ -1000,7 +943,8 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
try {
versionRB = ResourceBundle.getBundle(versionRBName);
} catch (MissingResourceException e) {
return getMessage("version.resource.missing", System.getProperty("java.version"));
return getMessage("version.resource.missing",
System.getProperty("java.version"));
}
}
try {
@ -1064,7 +1008,8 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
@Override
public String toString() {
return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
return getClass().getName() + "[key=" + key + ",args="
+ Arrays.asList(args) + "]";
}
};
@ -1089,10 +1034,12 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
ResourceBundle b = bundles.get(locale);
if (b == null) {
try {
b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap",
locale);
bundles.put(locale, b);
} catch (MissingResourceException e) {
throw new InternalError("Cannot find javap resource bundle for locale " + locale);
throw new InternalError("Cannot find javap resource bundle for locale "
+ locale);
}
}
@ -1114,7 +1061,6 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
//ResourceBundle bundle;
Locale task_locale;
Map<Locale, ResourceBundle> bundles;
protected Attribute.Factory attributeFactory;
private static final String progname = "javap";

View File

@ -25,19 +25,15 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Descriptor;
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.LocalVariableTable_attribute;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import jdk.internal.classfile.Attributes;
import jdk.internal.classfile.CodeModel;
import jdk.internal.classfile.Instruction;
import jdk.internal.classfile.Signature;
import jdk.internal.classfile.attribute.LocalVariableInfo;
/**
* Annotate instructions with details about local variables.
@ -47,22 +43,24 @@ import java.util.Map;
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class LocalVariableTableWriter extends InstructionDetailWriter {
public class LocalVariableTableWriter extends InstructionDetailWriter {
public enum NoteKind {
START("start") {
public boolean match(LocalVariableTable_attribute.Entry entry, int pc) {
return (pc == entry.start_pc);
@Override
public boolean match(LocalVariableInfo entry, int pc) {
return (pc == entry.startPc());
}
},
END("end") {
public boolean match(LocalVariableTable_attribute.Entry entry, int pc) {
return (pc == entry.start_pc + entry.length);
@Override
public boolean match(LocalVariableInfo entry, int pc) {
return (pc == entry.startPc() + entry.length());
}
};
NoteKind(String text) {
this.text = text;
}
public abstract boolean match(LocalVariableTable_attribute.Entry entry, int pc);
public abstract boolean match(LocalVariableInfo entry, int pc);
public final String text;
}
@ -79,71 +77,56 @@ public class LocalVariableTableWriter extends InstructionDetailWriter {
classWriter = ClassWriter.instance(context);
}
public void reset(Code_attribute attr) {
public void reset(CodeModel attr) {
codeAttr = attr;
pcMap = new HashMap<>();
LocalVariableTable_attribute lvt =
(LocalVariableTable_attribute) (attr.attributes.get(Attribute.LocalVariableTable));
if (lvt == null)
var lvt = attr.findAttribute(Attributes.LOCAL_VARIABLE_TABLE);
if (lvt.isEmpty())
return;
for (int i = 0; i < lvt.local_variable_table.length; i++) {
LocalVariableTable_attribute.Entry entry = lvt.local_variable_table[i];
put(entry.start_pc, entry);
put(entry.start_pc + entry.length, entry);
for (var entry : lvt.get().localVariables()) {
put(entry.startPc(), entry);
put(entry.startPc() + entry.length(), entry);
}
}
public void writeDetails(Instruction instr) {
int pc = instr.getPC();
@Override
public void writeDetails(int pc, Instruction instr) {
writeLocalVariables(pc, NoteKind.END);
writeLocalVariables(pc, NoteKind.START);
}
@Override
public void flush() {
int pc = codeAttr.code_length;
public void flush(int pc) {
writeLocalVariables(pc, NoteKind.END);
}
public void writeLocalVariables(int pc, NoteKind kind) {
ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
String indent = space(2); // get from Options?
List<LocalVariableTable_attribute.Entry> entries = pcMap.get(pc);
var entries = pcMap.get(pc);
if (entries != null) {
for (ListIterator<LocalVariableTable_attribute.Entry> iter =
entries.listIterator(kind == NoteKind.END ? entries.size() : 0);
for (var iter = entries.listIterator(kind == NoteKind.END ? entries.size() : 0);
kind == NoteKind.END ? iter.hasPrevious() : iter.hasNext() ; ) {
LocalVariableTable_attribute.Entry entry =
kind == NoteKind.END ? iter.previous() : iter.next();
var entry = kind == NoteKind.END ? iter.previous() : iter.next();
if (kind.match(entry, pc)) {
print(indent);
print(kind.text);
print(" local ");
print(entry.index);
print(entry.slot());
print(" // ");
Descriptor d = new Descriptor(entry.descriptor_index);
try {
print(d.getFieldType(constant_pool));
} catch (InvalidDescriptor e) {
print(report(e));
} catch (ConstantPoolException e) {
print(report(e));
}
print(classWriter.sigPrinter.print(
Signature.parseFrom(entry.type().stringValue())));
print(" ");
try {
print(constant_pool.getUTF8Value(entry.name_index));
} catch (ConstantPoolException e) {
print(report(e));
}
print(entry.name().stringValue());
println();
}
}
}
}
private void put(int pc, LocalVariableTable_attribute.Entry entry) {
List<LocalVariableTable_attribute.Entry> list = pcMap.get(pc);
private void put(int pc, LocalVariableInfo entry) {
var list = pcMap.get(pc);
if (list == null) {
list = new ArrayList<>();
pcMap.put(pc, list);
@ -153,6 +136,6 @@ public class LocalVariableTableWriter extends InstructionDetailWriter {
}
private ClassWriter classWriter;
private Code_attribute codeAttr;
private Map<Integer, List<LocalVariableTable_attribute.Entry>> pcMap;
private CodeModel codeAttr;
private Map<Integer, List<LocalVariableInfo>> pcMap;
}

View File

@ -25,20 +25,15 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Descriptor;
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
import com.sun.tools.classfile.Signature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import jdk.internal.classfile.Attributes;
import jdk.internal.classfile.CodeModel;
import jdk.internal.classfile.Instruction;
import jdk.internal.classfile.Signature;
import jdk.internal.classfile.attribute.LocalVariableTypeInfo;
/**
* Annotate instructions with details about local variables.
@ -51,19 +46,21 @@ import java.util.Map;
public class LocalVariableTypeTableWriter extends InstructionDetailWriter {
public enum NoteKind {
START("start") {
public boolean match(LocalVariableTypeTable_attribute.Entry entry, int pc) {
return (pc == entry.start_pc);
@Override
public boolean match(LocalVariableTypeInfo entry, int pc) {
return (pc == entry.startPc());
}
},
END("end") {
public boolean match(LocalVariableTypeTable_attribute.Entry entry, int pc) {
return (pc == entry.start_pc + entry.length);
@Override
public boolean match(LocalVariableTypeInfo entry, int pc) {
return (pc == entry.startPc() + entry.length());
}
};
NoteKind(String text) {
this.text = text;
}
public abstract boolean match(LocalVariableTypeTable_attribute.Entry entry, int pc);
public abstract boolean match(LocalVariableTypeInfo entry, int pc);
public final String text;
}
@ -80,71 +77,60 @@ public class LocalVariableTypeTableWriter extends InstructionDetailWriter {
classWriter = ClassWriter.instance(context);
}
public void reset(Code_attribute attr) {
public void reset(CodeModel attr) {
codeAttr = attr;
pcMap = new HashMap<>();
LocalVariableTypeTable_attribute lvt =
(LocalVariableTypeTable_attribute) (attr.attributes.get(Attribute.LocalVariableTypeTable));
if (lvt == null)
var lvt = attr.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE);
if (lvt.isEmpty())
return;
for (int i = 0; i < lvt.local_variable_table.length; i++) {
LocalVariableTypeTable_attribute.Entry entry = lvt.local_variable_table[i];
put(entry.start_pc, entry);
put(entry.start_pc + entry.length, entry);
for (var entry : lvt.get().localVariableTypes()) {
put(entry.startPc(), entry);
put(entry.startPc() + entry.length(), entry);
}
}
public void writeDetails(Instruction instr) {
int pc = instr.getPC();
@Override
public void writeDetails(int pc, Instruction instr) {
writeLocalVariables(pc, NoteKind.END);
writeLocalVariables(pc, NoteKind.START);
}
@Override
public void flush() {
int pc = codeAttr.code_length;
public void flush(int pc) {
writeLocalVariables(pc, NoteKind.END);
}
public void writeLocalVariables(int pc, NoteKind kind) {
ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
String indent = space(2); // get from Options?
List<LocalVariableTypeTable_attribute.Entry> entries = pcMap.get(pc);
var entries = pcMap.get(pc);
if (entries != null) {
for (ListIterator<LocalVariableTypeTable_attribute.Entry> iter =
entries.listIterator(kind == NoteKind.END ? entries.size() : 0);
for (var iter = entries.listIterator(kind == NoteKind.END ? entries.size() : 0);
kind == NoteKind.END ? iter.hasPrevious() : iter.hasNext() ; ) {
LocalVariableTypeTable_attribute.Entry entry =
kind == NoteKind.END ? iter.previous() : iter.next();
var entry = kind == NoteKind.END ? iter.previous() : iter.next();
if (kind.match(entry, pc)) {
print(indent);
print(kind.text);
print(" generic local ");
print(entry.index);
print(entry.slot());
print(" // ");
Descriptor d = new Signature(entry.signature_index);
try {
print(d.getFieldType(constant_pool).replace("/", "."));
} catch (InvalidDescriptor e) {
print(report(e));
} catch (ConstantPoolException e) {
print(classWriter.sigPrinter.print(Signature.parseFrom(
entry.signature().stringValue())).replace("/", "."));
} catch (Exception e) {
print(report(e));
}
print(" ");
try {
print(constant_pool.getUTF8Value(entry.name_index));
} catch (ConstantPoolException e) {
print(report(e));
}
print(entry.name().stringValue());
println();
}
}
}
}
private void put(int pc, LocalVariableTypeTable_attribute.Entry entry) {
List<LocalVariableTypeTable_attribute.Entry> list = pcMap.get(pc);
private void put(int pc, LocalVariableTypeInfo entry) {
var list = pcMap.get(pc);
if (list == null) {
list = new ArrayList<>();
pcMap.put(pc, list);
@ -154,6 +140,6 @@ public class LocalVariableTypeTableWriter extends InstructionDetailWriter {
}
private ClassWriter classWriter;
private Code_attribute codeAttr;
private Map<Integer, List<LocalVariableTypeTable_attribute.Entry>> pcMap;
private CodeModel codeAttr;
private Map<Integer, List<LocalVariableTypeInfo>> pcMap;
}

View File

@ -29,7 +29,7 @@ import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import com.sun.tools.classfile.AccessFlags;
import static jdk.internal.classfile.Classfile.*;
/*
* Provides access to javap's options, set via the command line
@ -54,16 +54,16 @@ public class Options {
/**
* Checks access of class, field or method.
*/
public boolean checkAccess(AccessFlags flags){
public boolean checkAccess(int flags){
boolean isPublic = flags.is(AccessFlags.ACC_PUBLIC);
boolean isProtected = flags.is(AccessFlags.ACC_PROTECTED);
boolean isPrivate = flags.is(AccessFlags.ACC_PRIVATE);
boolean isPublic = (flags & ACC_PUBLIC) != 0;
boolean isProtected = (flags & ACC_PROTECTED) != 0;
boolean isPrivate = (flags & ACC_PRIVATE) != 0;
boolean isPackage = !(isPublic || isProtected || isPrivate);
if ((showAccess == AccessFlags.ACC_PUBLIC) && (isProtected || isPrivate || isPackage))
if ((showAccess == ACC_PUBLIC) && (isProtected || isPrivate || isPackage))
return false;
else if ((showAccess == AccessFlags.ACC_PROTECTED) && (isPrivate || isPackage))
else if ((showAccess == ACC_PROTECTED) && (isPrivate || isPackage))
return false;
else if ((showAccess == 0) && (isPrivate))
return false;

View File

@ -30,7 +30,6 @@ import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
@ -40,13 +39,10 @@ import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.LineNumberTable_attribute;
import com.sun.tools.classfile.SourceFile_attribute;
import jdk.internal.classfile.Attributes;
import jdk.internal.classfile.ClassModel;
import jdk.internal.classfile.CodeModel;
import jdk.internal.classfile.Instruction;
/**
@ -74,14 +70,15 @@ public class SourceWriter extends InstructionDetailWriter {
this.fileManager = fileManager;
}
public void reset(ClassFile cf, Code_attribute attr) {
setSource(cf);
public void reset(CodeModel attr) {
setSource(attr.parent().get().parent().get());
setLineMap(attr);
}
public void writeDetails(Instruction instr) {
@Override
public void writeDetails(int pc, Instruction instr) {
String indent = space(40); // could get from Options?
Set<Integer> lines = lineMap.get(instr.getPC());
var lines = lineMap.get(pc);
if (lines != null) {
for (int line: lines) {
print(indent);
@ -105,37 +102,34 @@ public class SourceWriter extends InstructionDetailWriter {
return (sourceLines.length > 0);
}
private void setLineMap(Code_attribute attr) {
private void setLineMap(CodeModel attr) {
SortedMap<Integer, SortedSet<Integer>> map = new TreeMap<>();
SortedSet<Integer> allLines = new TreeSet<>();
for (Attribute a: attr.attributes) {
if (a instanceof LineNumberTable_attribute) {
LineNumberTable_attribute t = (LineNumberTable_attribute) a;
for (LineNumberTable_attribute.Entry e: t.line_number_table) {
int start_pc = e.start_pc;
int line = e.line_number;
SortedSet<Integer> pcLines = map.get(start_pc);
if (pcLines == null) {
pcLines = new TreeSet<>();
map.put(start_pc, pcLines);
}
pcLines.add(line);
allLines.add(line);
for (var t : attr.findAttributes(Attributes.LINE_NUMBER_TABLE)) {
for (var e: t.lineNumbers()) {
int start_pc = e.startPc();
int line = e.lineNumber();
SortedSet<Integer> pcLines = map.get(start_pc);
if (pcLines == null) {
pcLines = new TreeSet<>();
map.put(start_pc, pcLines);
}
pcLines.add(line);
allLines.add(line);
}
}
lineMap = map;
lineList = new ArrayList<>(allLines);
}
private void setSource(ClassFile cf) {
private void setSource(ClassModel cf) {
if (cf != classFile) {
classFile = cf;
sourceLines = splitLines(readSource(cf));
}
}
private String readSource(ClassFile cf) {
private String readSource(ClassModel cf) {
if (fileManager == null)
return null;
@ -150,14 +144,13 @@ public class SourceWriter extends InstructionDetailWriter {
// additional classes to determine the outmost class from any
// InnerClasses and EnclosingMethod attributes.
try {
String className = cf.getName();
SourceFile_attribute sf =
(SourceFile_attribute) cf.attributes.get(Attribute.SourceFile);
if (sf == null) {
String className = cf.thisClass().asInternalName();
var sf = cf.findAttribute(Attributes.SOURCE_FILE);
if (sf.isEmpty()) {
report(messages.getMessage("err.no.SourceFile.attribute"));
return null;
}
String sourceFile = sf.getSourceFile(cf.constant_pool);
String sourceFile = sf.get().sourceFile().stringValue();
String fileBase = sourceFile.endsWith(".java")
? sourceFile.substring(0, sourceFile.length() - 5) : sourceFile;
int sep = className.lastIndexOf("/");
@ -172,9 +165,6 @@ public class SourceWriter extends InstructionDetailWriter {
return null;
}
return fo.getCharContent(true).toString();
} catch (ConstantPoolException e) {
report(e);
return null;
} catch (IOException e) {
report(e.getLocalizedMessage());
return null;
@ -205,7 +195,7 @@ public class SourceWriter extends InstructionDetailWriter {
}
private JavaFileManager fileManager;
private ClassFile classFile;
private ClassModel classFile;
private SortedMap<Integer, SortedSet<Integer>> lineMap;
private List<Integer> lineList;
private String[] sourceLines;

View File

@ -25,23 +25,16 @@
package com.sun.tools.javap;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.internal.classfile.Attributes;
import jdk.internal.classfile.Classfile;
import com.sun.tools.classfile.AccessFlags;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Descriptor;
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.Method;
import com.sun.tools.classfile.StackMapTable_attribute;
import com.sun.tools.classfile.StackMapTable_attribute.*;
import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*;
import jdk.internal.classfile.Instruction;
import jdk.internal.classfile.attribute.CodeAttribute;
import jdk.internal.classfile.attribute.StackMapFrameInfo;
import jdk.internal.classfile.attribute.StackMapTableAttribute;
/**
* Annotate instructions with stack map.
@ -62,228 +55,108 @@ public class StackMapWriter extends InstructionDetailWriter {
protected StackMapWriter(Context context) {
super(context);
context.put(StackMapWriter.class, this);
classWriter = ClassWriter.instance(context);
}
public void reset(Code_attribute attr) {
setStackMap((StackMapTable_attribute) attr.attributes.get(Attribute.StackMapTable));
public void reset(CodeAttribute code) {
setStackMap(code);
}
void setStackMap(StackMapTable_attribute attr) {
void setStackMap(CodeAttribute code) {
StackMapTableAttribute attr = code.findAttribute(Attributes.STACK_MAP_TABLE)
.orElse(null);
if (attr == null) {
map = null;
return;
}
Method m = classWriter.getMethod();
Descriptor d = m.descriptor;
String[] args;
try {
ConstantPool cp = classWriter.getClassFile().constant_pool;
String argString = d.getParameterTypes(cp);
args = argString.substring(1, argString.length() - 1).split("[, ]+");
} catch (ConstantPoolException | InvalidDescriptor e) {
return;
}
boolean isStatic = m.access_flags.is(AccessFlags.ACC_STATIC);
verification_type_info[] initialLocals = new verification_type_info[(isStatic ? 0 : 1) + args.length];
if (!isStatic)
initialLocals[0] = new CustomVerificationTypeInfo("this");
for (int i = 0; i < args.length; i++) {
initialLocals[(isStatic ? 0 : 1) + i] =
new CustomVerificationTypeInfo(args[i].replace(".", "/"));
var m = code.parent().get();
if ((m.flags().flagsMask() & Classfile.ACC_STATIC) == 0) {
thisClassName = m.parent().get().thisClass().asInternalName();
} else {
thisClassName = null;
}
map = new HashMap<>();
StackMapBuilder builder = new StackMapBuilder();
// using -1 as the pc for the initial frame effectively compensates for
// the difference in behavior for the first stack map frame (where the
// pc offset is just offset_delta) compared to subsequent frames (where
// the pc offset is always offset_delta+1).
int pc = -1;
map.put(pc, new StackMap(initialLocals, empty));
for (int i = 0; i < attr.entries.length; i++)
pc = attr.entries[i].accept(builder, pc);
this.code = code;
for (var fr : attr.entries())
map.put(code.labelToBci(fr.target()), fr);
}
public void writeInitialDetails() {
writeDetails(-1);
}
public void writeDetails(Instruction instr) {
writeDetails(instr.getPC());
@Override
public void writeDetails(int pc, Instruction instr) {
writeDetails(pc);
}
private void writeDetails(int pc) {
if (map == null)
return;
StackMap m = map.get(pc);
var m = map.get(pc);
if (m != null) {
print("StackMap locals: ", m.locals);
print("StackMap stack: ", m.stack);
print("StackMap locals: ", m.locals(), true);
print("StackMap stack: ", m.stack(), false);
}
}
void print(String label, verification_type_info[] entries) {
void print(String label, List<StackMapFrameInfo.VerificationTypeInfo> entries,
boolean firstThis) {
print(label);
for (int i = 0; i < entries.length; i++) {
for (var e : entries) {
print(" ");
print(entries[i]);
print(e, firstThis);
firstThis = false;
}
println();
}
void print(verification_type_info entry) {
void print(StackMapFrameInfo.VerificationTypeInfo entry, boolean firstThis) {
if (entry == null) {
print("ERROR");
return;
}
switch (entry.tag) {
case -1:
print(((CustomVerificationTypeInfo) entry).text);
break;
switch (entry) {
case StackMapFrameInfo.SimpleVerificationTypeInfo s -> {
switch (s) {
case ITEM_TOP ->
print("top");
case ITEM_Top:
print("top");
break;
case ITEM_INTEGER ->
print("int");
case ITEM_Integer:
print("int");
break;
case ITEM_FLOAT ->
print("float");
case ITEM_Float:
print("float");
break;
case ITEM_LONG ->
print("long");
case ITEM_Long:
print("long");
break;
case ITEM_DOUBLE ->
print("double");
case ITEM_Double:
print("double");
break;
case ITEM_NULL ->
print("null");
case ITEM_Null:
print("null");
break;
case ITEM_UninitializedThis:
print("uninit_this");
break;
case ITEM_Object:
try {
ConstantPool cp = classWriter.getClassFile().constant_pool;
ConstantPool.CONSTANT_Class_info class_info = cp.getClassInfo(((Object_variable_info) entry).cpool_index);
print(cp.getUTF8Value(class_info.name_index));
} catch (ConstantPoolException e) {
print("??");
case ITEM_UNINITIALIZED_THIS ->
print("uninit_this");
}
break;
}
case ITEM_Uninitialized:
print(((Uninitialized_variable_info) entry).offset);
break;
case StackMapFrameInfo.ObjectVerificationTypeInfo o -> {
String cln = o.className().asInternalName();
print(firstThis && cln.equals(thisClassName) ? "this" : cln);
}
case StackMapFrameInfo.UninitializedVerificationTypeInfo u ->
print(code.labelToBci(u.newTarget()));
}
}
private Map<Integer, StackMap> map;
private ClassWriter classWriter;
class StackMapBuilder
implements StackMapTable_attribute.stack_map_frame.Visitor<Integer, Integer> {
public Integer visit_same_frame(same_frame frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta() + 1;
StackMap m = map.get(pc);
assert (m != null);
map.put(new_pc, m);
return new_pc;
}
public Integer visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta() + 1;
StackMap prev = map.get(pc);
assert (prev != null);
StackMap m = new StackMap(prev.locals, frame.stack);
map.put(new_pc, m);
return new_pc;
}
public Integer visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta() + 1;
StackMap prev = map.get(pc);
assert (prev != null);
StackMap m = new StackMap(prev.locals, frame.stack);
map.put(new_pc, m);
return new_pc;
}
public Integer visit_chop_frame(chop_frame frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta() + 1;
StackMap prev = map.get(pc);
assert (prev != null);
int k = 251 - frame.frame_type;
verification_type_info[] new_locals = Arrays.copyOf(prev.locals, prev.locals.length - k);
StackMap m = new StackMap(new_locals, empty);
map.put(new_pc, m);
return new_pc;
}
public Integer visit_same_frame_extended(same_frame_extended frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta();
StackMap m = map.get(pc);
assert (m != null);
map.put(new_pc, m);
return new_pc;
}
public Integer visit_append_frame(append_frame frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta() + 1;
StackMap prev = map.get(pc);
assert (prev != null);
verification_type_info[] new_locals = new verification_type_info[prev.locals.length + frame.locals.length];
System.arraycopy(prev.locals, 0, new_locals, 0, prev.locals.length);
System.arraycopy(frame.locals, 0, new_locals, prev.locals.length, frame.locals.length);
StackMap m = new StackMap(new_locals, empty);
map.put(new_pc, m);
return new_pc;
}
public Integer visit_full_frame(full_frame frame, Integer pc) {
int new_pc = pc + frame.getOffsetDelta() + 1;
StackMap m = new StackMap(frame.locals, frame.stack);
map.put(new_pc, m);
return new_pc;
}
}
static class StackMap {
StackMap(verification_type_info[] locals, verification_type_info[] stack) {
this.locals = locals;
this.stack = stack;
}
private final verification_type_info[] locals;
private final verification_type_info[] stack;
}
static class CustomVerificationTypeInfo extends verification_type_info {
public CustomVerificationTypeInfo(String text) {
super(-1);
this.text = text;
}
private String text;
}
private final verification_type_info[] empty = { };
private Map<Integer, StackMapFrameInfo> map;
private String thisClassName;
private CodeAttribute code;
}

View File

@ -25,14 +25,13 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.Code_attribute.Exception_data;
import com.sun.tools.classfile.Instruction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import jdk.internal.classfile.Instruction;
import jdk.internal.classfile.instruction.ExceptionCatch;
import jdk.internal.classfile.attribute.CodeAttribute;
/**
* Annotate instructions with details about try blocks.
@ -45,24 +44,24 @@ import java.util.Map;
public class TryBlockWriter extends InstructionDetailWriter {
public enum NoteKind {
START("try") {
public boolean match(Exception_data entry, int pc) {
return (pc == entry.start_pc);
public boolean match(ExceptionCatch entry, int pc, CodeAttribute lr) {
return (pc == lr.labelToBci(entry.tryStart()));
}
},
END("end try") {
public boolean match(Exception_data entry, int pc) {
return (pc == entry.end_pc);
public boolean match(ExceptionCatch entry, int pc, CodeAttribute lr) {
return (pc == lr.labelToBci(entry.tryEnd()));
}
},
HANDLER("catch") {
public boolean match(Exception_data entry, int pc) {
return (pc == entry.handler_pc);
public boolean match(ExceptionCatch entry, int pc, CodeAttribute lr) {
return (pc == lr.labelToBci(entry.handler()));
}
};
NoteKind(String text) {
this.text = text;
}
public abstract boolean match(Exception_data entry, int pc);
public abstract boolean match(ExceptionCatch entry, int pc, CodeAttribute lr);
public final String text;
}
@ -79,46 +78,49 @@ public class TryBlockWriter extends InstructionDetailWriter {
constantWriter = ConstantWriter.instance(context);
}
public void reset(Code_attribute attr) {
public void reset(CodeAttribute attr) {
indexMap = new HashMap<>();
pcMap = new HashMap<>();
for (int i = 0; i < attr.exception_table.length; i++) {
Exception_data entry = attr.exception_table[i];
lr = attr;
var excs = attr.exceptionHandlers();
for (int i = 0; i < excs.size(); i++) {
var entry = excs.get(i);
indexMap.put(entry, i);
put(entry.start_pc, entry);
put(entry.end_pc, entry);
put(entry.handler_pc, entry);
put(lr.labelToBci(entry.tryStart()), entry);
put(lr.labelToBci(entry.tryEnd()), entry);
put(lr.labelToBci(entry.handler()), entry);
}
}
public void writeDetails(Instruction instr) {
writeTrys(instr, NoteKind.END);
writeTrys(instr, NoteKind.START);
writeTrys(instr, NoteKind.HANDLER);
@Override
public void writeDetails(int pc, Instruction instr) {
writeTrys(pc, instr, NoteKind.END);
writeTrys(pc, instr, NoteKind.START);
writeTrys(pc, instr, NoteKind.HANDLER);
}
public void writeTrys(Instruction instr, NoteKind kind) {
public void writeTrys(int pc, Instruction instr, NoteKind kind) {
String indent = space(2); // get from Options?
int pc = instr.getPC();
List<Exception_data> entries = pcMap.get(pc);
var entries = pcMap.get(pc);
if (entries != null) {
for (ListIterator<Exception_data> iter =
for (var iter =
entries.listIterator(kind == NoteKind.END ? entries.size() : 0);
kind == NoteKind.END ? iter.hasPrevious() : iter.hasNext() ; ) {
Exception_data entry =
var entry =
kind == NoteKind.END ? iter.previous() : iter.next();
if (kind.match(entry, pc)) {
if (kind.match(entry, pc, lr)) {
print(indent);
print(kind.text);
print("[");
print(indexMap.get(entry));
print("] ");
if (entry.catch_type == 0)
var ct = entry.catchType();
if (ct.isEmpty())
print("finally");
else {
print("#" + entry.catch_type);
print("#" + ct.get().index());
print(" // ");
constantWriter.write(entry.catch_type);
constantWriter.write(ct.get().index());
}
println();
}
@ -126,8 +128,8 @@ public class TryBlockWriter extends InstructionDetailWriter {
}
}
private void put(int pc, Exception_data entry) {
List<Exception_data> list = pcMap.get(pc);
private void put(int pc, ExceptionCatch entry) {
var list = pcMap.get(pc);
if (list == null) {
list = new ArrayList<>();
pcMap.put(pc, list);
@ -136,7 +138,8 @@ public class TryBlockWriter extends InstructionDetailWriter {
list.add(entry);
}
private Map<Integer, List<Exception_data>> pcMap;
private Map<Exception_data, Integer> indexMap;
private Map<Integer, List<ExceptionCatch>> pcMap;
private Map<ExceptionCatch, Integer> indexMap;
private ConstantWriter constantWriter;
private CodeAttribute lr;
}

View File

@ -25,20 +25,17 @@
package com.sun.tools.javap;
import com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.Code_attribute;
import com.sun.tools.classfile.TypeAnnotation;
import com.sun.tools.classfile.TypeAnnotation.Position;
import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.Method;
import com.sun.tools.classfile.RuntimeInvisibleTypeAnnotations_attribute;
import com.sun.tools.classfile.RuntimeTypeAnnotations_attribute;
import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import com.sun.tools.javac.util.StringUtils;
import java.util.Optional;
import jdk.internal.classfile.Attributes;
import jdk.internal.classfile.Instruction;
import jdk.internal.classfile.MethodModel;
import jdk.internal.classfile.TypeAnnotation;
import jdk.internal.classfile.attribute.CodeAttribute;
/**
* Annotate instructions with details about type annotations.
@ -74,28 +71,37 @@ public class TypeAnnotationWriter extends InstructionDetailWriter {
classWriter = ClassWriter.instance(context);
}
public void reset(Code_attribute attr) {
Method m = classWriter.getMethod();
public void reset(CodeAttribute attr) {
MethodModel m = attr.parent().get();
pcMap = new HashMap<>();
check(NoteKind.VISIBLE, (RuntimeVisibleTypeAnnotations_attribute) m.attributes.get(Attribute.RuntimeVisibleTypeAnnotations));
check(NoteKind.INVISIBLE, (RuntimeInvisibleTypeAnnotations_attribute) m.attributes.get(Attribute.RuntimeInvisibleTypeAnnotations));
codeAttribute = attr;
check(NoteKind.VISIBLE,
m.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)
.map(a -> a.annotations()));
check(NoteKind.INVISIBLE,
m.findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS)
.map(a -> a.annotations()));
}
private void check(NoteKind kind, RuntimeTypeAnnotations_attribute attr) {
if (attr == null)
private void check(NoteKind kind, Optional<List<TypeAnnotation>> annos) {
if (annos.isEmpty())
return;
for (TypeAnnotation anno: attr.annotations) {
Position p = anno.position;
Note note = null;
if (p.offset != -1)
addNote(p.offset, note = new Note(kind, anno));
if (p.lvarOffset != null) {
for (int i = 0; i < p.lvarOffset.length; i++) {
if (note == null)
note = new Note(kind, anno);
addNote(p.lvarOffset[i], note);
for (TypeAnnotation anno: annos.get()) {
switch (anno.targetInfo()) {
case TypeAnnotation.LocalVarTarget p -> {
Note note = null;
for (var lvar : p.table()) {
if (note == null)
note = new Note(kind, anno);
addNote(codeAttribute.labelToBci(lvar.startLabel()), note);
}
}
case TypeAnnotation.OffsetTarget p ->
addNote(codeAttribute.labelToBci(p.target()), new Note(kind, anno));
case TypeAnnotation.TypeArgumentTarget p ->
addNote(codeAttribute.labelToBci(p.target()), new Note(kind, anno));
default -> {}
}
}
}
@ -108,17 +114,16 @@ public class TypeAnnotationWriter extends InstructionDetailWriter {
}
@Override
void writeDetails(Instruction instr) {
void writeDetails(int pc, Instruction instr) {
String indent = space(2); // get from Options?
int pc = instr.getPC();
List<Note> notes = pcMap.get(pc);
if (notes != null) {
for (Note n: notes) {
print(indent);
print("@");
annotationWriter.write(n.anno, false, true);
annotationWriter.write(n.anno, false, true, codeAttribute);
print(", ");
println(StringUtils.toLowerCase(n.kind.toString()));
println(n.kind.toString().toLowerCase(Locale.US));
}
}
}
@ -126,4 +131,5 @@ public class TypeAnnotationWriter extends InstructionDetailWriter {
private AnnotationWriter annotationWriter;
private ClassWriter classWriter;
private Map<Integer, List<Note>> pcMap;
private CodeAttribute codeAttribute;
}

View File

@ -130,6 +130,7 @@ serviceability/sa/ClhsdbPmap.java#core 8267433 macosx-x64
serviceability/sa/ClhsdbPstack.java#core 8267433 macosx-x64
serviceability/sa/TestJmapCore.java 8267433 macosx-x64
serviceability/sa/TestJmapCoreMetaspace.java 8267433 macosx-x64
serviceability/sa/ClhsdbDumpclass.java 8316342 generic-all
serviceability/attach/ConcAttachTest.java 8290043 linux-all

View File

@ -30,13 +30,21 @@
* @modules jdk.jdeps/com.sun.tools.javap
*/
import java.io.PrintWriter;
import java.io.StringWriter;
public class T8260403 {
public static void main(String args[]) throws Exception {
if (com.sun.tools.javap.Main.run(new String[]{"-c", System.getProperty("test.classes") + "/InvalidSignature.class"},
new PrintWriter(System.out)) != 0) {
throw new AssertionError();
}
var sw = new StringWriter();
int res = com.sun.tools.javap.Main.run(
new String[]{"-c", System.getProperty("test.classes") + "/InvalidSignature.class"},
new PrintWriter(sw));
System.out.println(sw);
if (res == 0)
throw new AssertionError("Failure exit code expected");
if (sw.toString().contains("Fatal error"))
throw new AssertionError("Unguarded fatal error");
if (sw.toString().contains("error while reading constant pool"))
throw new AssertionError("Unguarded constant pool error");
}
}

View File

@ -60,7 +60,9 @@ public class T6866657
JavapTask t = new JavapTask(log, fileManager, null);
t.handleOptions(new String[] { "-sysinfo", className });
JavapTask.ClassFileInfo cfInfo = t.read(fo);
expectEqual(cfInfo.cf.byteLength(), cfInfo.size);
try (var in = fo.openInputStream()) {
expectEqual(in.readAllBytes().length, cfInfo.size);
}
}
} catch (Exception e) {
e.printStackTrace();

View File

@ -56,7 +56,9 @@ public class T7186925
JavapTask t = new JavapTask(null, fileManager, null);
t.handleOptions(new String[] { "-sysinfo", className });
JavapTask.ClassFileInfo cfInfo = t.read(fo);
expectEqual(cfInfo.cf.byteLength(), cfInfo.size);
try (var in = fo.openInputStream()) {
expectEqual(in.readAllBytes().length, cfInfo.size);
}
}
} catch (NullPointerException ee) {
ee.printStackTrace();

View File

@ -0,0 +1,54 @@
class Malformed {
0xCAFEBABE;
0; // minor version
0; // version
[] { // Constant Pool
; // first element is empty
Utf8 "Code"; // #1
Method #0 #0; // #2
class #0; // #3
} // Constant Pool
0x0000; // access
#0;// this_cpx
#3;// super_cpx
[] { // Interfaces
#0;
#3;
} // Interfaces
[] { // fields
{ // Member
0x0000; // access
#0; // name_cpx
#0; // sig_cpx
[] { // Attributes
} // Attributes
} // Member
} // fields
[] { // methods
{ // Member
0x0000; // access
#0; // name_cpx
#0; // sig_cpx
[] { // Attributes
Attr(#1) { // Code
0; // max_stack
0; // max_locals
Bytes[]{
}
[] { // Traps
} // end Traps
[] { // Attributes
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[] { // Attributes
} // Attributes
} // end class Malformed

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8294969
* @summary javap test safeguarding malformed class file
* @build Malformed
* @run main MalformedTest
* @modules jdk.jdeps/com.sun.tools.javap
*/
import java.io.PrintWriter;
import java.io.StringWriter;
public class MalformedTest {
public static void main(String args[]) throws Exception {
var sw = new StringWriter();
int res = com.sun.tools.javap.Main.run(
new String[]{"-c", "-v", System.getProperty("test.classes") + "/Malformed.class"},
new PrintWriter(sw));
System.out.println(sw);
if (res == 0)
throw new AssertionError("Failure exit code expected");
if (sw.toString().contains("Fatal error"))
throw new AssertionError("Unguarded fatal error");
if (sw.toString().contains("error while reading constant pool"))
throw new AssertionError("Unguarded constant pool error");
}
}