Commit 271b59a6 authored by Remi Forax's avatar Remi Forax
Browse files

manually port NEST_MATES branch changes to be compatible with ASM 6.1

parent 3cee35fc
......@@ -154,6 +154,16 @@ public class ClassRemapper extends ClassVisitor {
desc == null ? null : remapper.mapMethodDesc(desc));
}
@Override
public void visitNestHost(String nestHost) {
super.visitNestHost(remapper.mapType(nestHost));
}
@Override
public void visitNestMember(String nestMember) {
super.visitNestMember(remapper.mapType(nestMember));
}
protected FieldVisitor createFieldRemapper(FieldVisitor fv) {
return new FieldRemapper(api, fv, remapper);
}
......
......@@ -140,6 +140,16 @@ public class RemappingClassAdapter extends ClassVisitor {
desc == null ? null : remapper.mapMethodDesc(desc));
}
@Override
public void visitNestHost(String nestHost) {
throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
}
@Override
public void visitNestMember(String nestMember) {
throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
}
protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
return new RemappingFieldAdapter(fv, remapper);
}
......
......@@ -121,6 +121,12 @@ public class ClassNode extends ClassVisitor {
/** The inner classes of this class. */
public List<InnerClassNode> innerClasses;
/** The nest host class of this class */
public String nestHostClass;
/** The nest members of this class */
public List<String> nestMembers;
/** The fields of this class. */
public List<FieldNode> fields;
......@@ -186,6 +192,11 @@ public class ClassNode extends ClassVisitor {
return module;
}
@Override
public void visitNestHost(String nestHost) {
this.nestHostClass = nestHost;
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
outerClass = owner;
......@@ -236,6 +247,14 @@ public class ClassNode extends ClassVisitor {
attrs.add(attribute);
}
@Override
public void visitNestMember(String nestMember) {
if (nestMembers == null) {
nestMembers = new ArrayList<String>();
}
nestMembers.add(nestMember);
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
......@@ -343,6 +362,10 @@ public class ClassNode extends ClassVisitor {
if (module != null) {
module.accept(classVisitor);
}
// Visit nest host class
if (nestHostClass != null) {
classVisitor.visitNestHost(nestHostClass);
}
// Visit the outer class.
if (outerClass != null) {
classVisitor.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
......@@ -382,6 +405,12 @@ public class ClassNode extends ClassVisitor {
classVisitor.visitAttribute(attrs.get(i));
}
}
// visit nest members
if (nestMembers != null) {
for (int i = 0, n = nestMembers.size(); i < n; ++i) {
classVisitor.visitNestMember(nestMembers.get(i));
}
}
// Visit the inner classes.
for (int i = 0, n = innerClasses.size(); i < n; ++i) {
innerClasses.get(i).accept(classVisitor);
......
......@@ -235,6 +235,15 @@ public class ASMifier extends Printer {
return asmifier;
}
@Override
public void visitNestHost(final String nestHost) {
stringBuilder.setLength(0);
stringBuilder.append("cw.visitNestHost(");
appendConstant(nestHost);
stringBuilder.append(");\n\n");
text.add(stringBuilder.toString());
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
stringBuilder.setLength(0);
......@@ -264,6 +273,15 @@ public class ASMifier extends Printer {
visitAttribute(attribute);
}
@Override
public void visitNestMember(final String nestMember) {
stringBuilder.setLength(0);
stringBuilder.append("cw.visitNestMember(");
appendConstant(nestMember);
stringBuilder.append(");\n\n");
text.add(stringBuilder.toString());
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
......
......@@ -128,6 +128,14 @@ public class CheckClassAdapter extends ClassVisitor {
/** Whether the {@link #visitOuterClass} method has been called. */
private boolean visitOuterClassCalled;
/** Whether the {@link #visitNestHost} method has been called. */
private boolean visitNestHostCalled;
/**
* Package of all nest members. Not <tt>null</tt> if the visitNestMember method has been called.
*/
private String nestMemberPackageName;
/** Whether the {@link #visitEnd} method has been called. */
private boolean visitEndCalled;
......@@ -403,12 +411,48 @@ public class CheckClassAdapter extends ClassVisitor {
visitModuleCalled = true;
checkFullyQualifiedName(name, "module name");
checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
CheckModuleAdapter checkModuleAdapter = new CheckModuleAdapter(
api, super.visitModule(name, access, version), (access & Opcodes.ACC_OPEN) != 0);
CheckModuleAdapter checkModuleAdapter =
new CheckModuleAdapter(
api, super.visitModule(name, access, version), (access & Opcodes.ACC_OPEN) != 0);
checkModuleAdapter.classVersion = this.version;
return checkModuleAdapter;
}
@Override
public void visitNestHost(final String nestHost) {
checkState();
CheckMethodAdapter.checkInternalName(nestHost, "nestHost");
if (visitNestHostCalled) {
throw new IllegalStateException("visitNestHost can be called only once.");
}
if (nestMemberPackageName != null) {
throw new IllegalStateException(
"visitNestHost and and visitNestMember are mutually exclusive.");
}
visitNestHostCalled = true;
super.visitNestHost(nestHost);
}
@Override
public void visitNestMember(final String nestMember) {
checkState();
CheckMethodAdapter.checkInternalName(nestMember, "nestMember");
if (visitNestHostCalled) {
throw new IllegalStateException(
"visitMemberOfNest and and visitNestHost are mutually exclusive.");
}
String packageName = packageName(nestMember);
if (nestMemberPackageName == null) {
nestMemberPackageName = packageName;
} else {
if (!nestMemberPackageName.equals(packageName)) {
throw new IllegalStateException(
"nest member " + nestMember + " should be in the package " + nestMemberPackageName);
}
}
super.visitNestMember(nestMember);
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
checkState();
......@@ -1014,4 +1058,18 @@ public class CheckClassAdapter extends ClassVisitor {
"Invalid type reference 0x" + Integer.toHexString(typeRef));
}
}
/**
* Returns the package name of an internal name.
*
* @param name an internal name.
* @return the package name or "" if there is no package
*/
private static String packageName(String name) {
int index = name.lastIndexOf('/');
if (index == -1) {
return "";
}
return name.substring(0, index);
}
}
......@@ -384,6 +384,21 @@ public abstract class Printer {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Nest host class. See {@link org.objectweb.asm.ClassVisitor#visitNestHost}.
*
* <p>Visits the nest host class of the current class. A nest is a set of classes of the same
* package that share access to their private members. The host class should list the current
* class as {@link #visitNestMember(String) nest member}. This method must be called only once and
* only if the current class is a member of a nest. A class is implicitly its own nest, so it's
* invalid to call this method with the current class as argument.
*
* @param nestHost the internal name of the host class of the nest.
*/
public void visitNestHost(final String nestHost) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Class outer class. See {@link org.objectweb.asm.ClassVisitor#visitOuterClass}.
*
......@@ -431,6 +446,19 @@ public abstract class Printer {
*/
public abstract void visitClassAttribute(Attribute attribute);
/**
* Nest member name. See {@link org.objectweb.asm.ClassVisitor#visitNestMember}.
*
* <p>Visits a member of the nest. A nest is a set of classes of the same package that share
* access to their private members. The nest member should declare the current class as its {@link
* #visitNestMember(String) host class}.
*
* @param nestMember the internal name of a nest member.
*/
public void visitNestMember(final String nestMember) {
throw new RuntimeException("Must be overriden");
}
/**
* Class inner name. See {@link org.objectweb.asm.ClassVisitor#visitInnerClass}.
*
......
......@@ -234,6 +234,15 @@ public class Textifier extends Printer {
return addNewTextifier(null);
}
@Override
public void visitNestHost(String nestHost) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("NESTHOST ");
appendDescriptor(INTERNAL_NAME, nestHost);
stringBuilder.append('\n');
text.add(stringBuilder.toString());
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
stringBuilder.setLength(0);
......@@ -267,6 +276,15 @@ public class Textifier extends Printer {
visitAttribute(attribute);
}
@Override
public void visitNestMember(final String nestMember) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("NESTMEMBER ");
appendDescriptor(INTERNAL_NAME, nestMember);
stringBuilder.append('\n');
text.add(stringBuilder.toString());
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
......
......@@ -147,6 +147,12 @@ public final class TraceClassVisitor extends ClassVisitor {
return new TraceModuleVisitor(super.visitModule(name, flags, version), modulePrinter);
}
@Override
public void visitNestHost(final String nestHost) {
p.visitNestHost(nestHost);
super.visitNestHost(nestHost);
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
p.visitOuterClass(owner, name, descriptor);
......@@ -174,6 +180,12 @@ public final class TraceClassVisitor extends ClassVisitor {
super.visitAttribute(attribute);
}
@Override
public void visitNestMember(final String nestMember) {
p.visitNestMember(nestMember);
super.visitNestMember(nestMember);
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
......
......@@ -400,6 +400,10 @@ public class ClassReader {
int modulePackagesOffset = 0;
// - The string corresponding to the ModuleMainClass attribute, or null.
String moduleMainClass = null;
// - The string corresponding to the NestHost attribute, or null
String nestHostClass = null;
// the offset of the NestMembers attribute, or 0.
int nestMembersOffset = 0;
// - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
// This list in the <i>reverse order</i> or their order in the ClassFile structure.
Attribute attributes = null;
......@@ -418,6 +422,10 @@ public class ClassReader {
innerClassesOffset = currentAttributeOffset;
} else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
enclosingMethodOffset = currentAttributeOffset;
} else if (Constants.NEST_HOST.equals(attributeName)) {
nestHostClass = readClass(currentAttributeOffset, charBuffer);
} else if (Constants.NEST_MEMBERS.equals(attributeName)) {
nestMembersOffset = currentAttributeOffset;
} else if (Constants.SIGNATURE.equals(attributeName)) {
signature = readUTF8(currentAttributeOffset, charBuffer);
} else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
......@@ -486,6 +494,11 @@ public class ClassReader {
readModule(classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
}
// Visit the NestHost attribute
if (nestHostClass != null) {
classVisitor.visitNestHost(nestHostClass);
}
// Visit the EnclosingMethod attribute.
if (enclosingMethodOffset != 0) {
String className = readClass(enclosingMethodOffset, charBuffer);
......@@ -588,6 +601,16 @@ public class ClassReader {
attributes = nextAttribute;
}
// Visit the NestedMembers attribute
if (nestMembersOffset != 0) {
int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
int currentNestMemberOffset = nestMembersOffset + 2;
while (numberOfNestMembers-- > 0) {
classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer));
currentNestMemberOffset += 2;
}
}
// Visit the InnerClasses attribute.
if (innerClassesOffset != 0) {
int numberOfClasses = readUnsignedShort(innerClassesOffset);
......
......@@ -29,9 +29,10 @@ package org.objectweb.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in the following order:
* <tt>visit</tt> [ <tt>visitSource</tt> ] [ <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] (
* <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
* <tt>visit</tt> [ <tt>visitSource</tt> ] [ <tt>visitModule</tt> ][ <tt>visitNestHost</tt> ][
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | <tt>visitTypeAnnotation</tt> |
* <tt>visitAttribute</tt> )* ( <tt>visitNestMember</tt> | <tt>visitInnerClass</tt> |
* <tt>visitField</tt> | <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
......@@ -134,6 +135,21 @@ public abstract class ClassVisitor {
return null;
}
/**
* Visits the nest host class of the current class. A nest is a set of classes of the same package
* that share access to their private members. The host class should list the current class as
* {@link #visitNestMember(String) nest member}. This method must be called only once and only if
* the current class is a member of a nest. A class is implicitly its own nest, so it's invalid to
* call this method with the current class as argument.
*
* @param nestHost the internal name of the host class of the nest.
*/
public void visitNestHost(final String nestHost) {
if (cv != null) {
cv.visitNestHost(nestHost);
}
}
/**
* Visits the enclosing class of the class. This method must be called only if the class has an
* enclosing class.
......@@ -202,6 +218,19 @@ public abstract class ClassVisitor {
}
}
/**
* Visits a member of the nest. A nest is a set of classes of the same package that share access
* to their private members. The nest member should declare the current class as its {@link
* #visitNestMember(String) host class}.
*
* @param nestMember the internal name of a nest member.
*/
public void visitNestMember(String nestMember) {
if (cv != null) {
cv.visitNestMember(nestMember);
}
}
/**
* Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited.
......
......@@ -115,11 +115,20 @@ public class ClassWriter extends ClassVisitor {
*/
private MethodWriter lastMethod;
/** The host_class_index field of the NestHost attribute, or 0. */
private int nestHostClassIndex;
/** The number_of_classes field of the NestMembers attribute, or 0. */
private int numberOfNestMemberClasses;
/** The 'classes' array of the NestMembers attribute, or <tt>null</tt>. */
private ByteVector nestMemberClasses;
/** The number_of_classes field of the InnerClasses attribute, or 0. */
private int numberOfClasses;
private int numberOfInnerClasses;
/** The 'classes' array of the InnerClasses attribute, or <tt>null</tt>. */
private ByteVector classes;
private ByteVector innerClasses;
/** The class_index field of the EnclosingMethod attribute, or 0. */
private int enclosingClassIndex;
......@@ -280,6 +289,11 @@ public class ClassWriter extends ClassVisitor {
version == null ? 0 : symbolTable.addConstantUtf8(version));
}
@Override
public void visitNestHost(final String nestHost) {
nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
}
@Override
public final void visitOuterClass(
final String owner, final String name, final String descriptor) {
......@@ -332,11 +346,20 @@ public class ClassWriter extends ClassVisitor {
firstAttribute = attribute;
}
@Override
public void visitNestMember(final String nestMember) {
if (nestMemberClasses == null) {
nestMemberClasses = new ByteVector();
}
++numberOfNestMemberClasses;
innerClasses.putShort(symbolTable.addConstantClass(nestMember).index);
}
@Override
public final void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
if (classes == null) {
classes = new ByteVector();
if (innerClasses == null) {
innerClasses = new ByteVector();
}
// Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table
// which represents a class or interface C that is not a package member must have exactly one
......@@ -346,12 +369,12 @@ public class ClassWriter extends ClassVisitor {
// the info field. This trick allows duplicate detection in O(1) time.
Symbol nameSymbol = symbolTable.addConstantClass(name);
if (nameSymbol.info == 0) {
++numberOfClasses;
classes.putShort(nameSymbol.index);
classes.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index);
classes.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName));
classes.putShort(access);
nameSymbol.info = numberOfClasses;
++numberOfInnerClasses;
innerClasses.putShort(nameSymbol.index);
innerClasses.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index);
innerClasses.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName));
innerClasses.putShort(access);
nameSymbol.info = numberOfInnerClasses;
} else {
// Compare the inner classes entry nameSymbol.info - 1 with the arguments of this method and
// throw an exception if there is a difference?
......@@ -428,9 +451,9 @@ public class ClassWriter extends ClassVisitor {
}
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
int attributesCount = 0;
if (classes != null) {
if (innerClasses != null) {
++attributesCount;
size += 8 + classes.length;
size += 8 + innerClasses.length;
symbolTable.addConstantUtf8(Constants.INNER_CLASSES);
}
if (enclosingClassIndex != 0) {
......@@ -438,6 +461,16 @@ public class ClassWriter extends ClassVisitor {
size += 10;
symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD);
}
if (nestHostClassIndex != 0) {
++attributesCount;
size += 8;
symbolTable.addConstantUtf8(Constants.NEST_HOST);
}
if (nestMemberClasses != null) {
++attributesCount;
size += 8 + nestMemberClasses.length;
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
}
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
++attributesCount;
size += 6;
......@@ -535,12 +568,12 @@ public class ClassWriter extends ClassVisitor {
}
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
result.putShort(attributesCount);
if (classes != null) {
if (innerClasses != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES))
.putInt(classes.length + 2)
.putShort(numberOfClasses)
.putByteArray(classes.data, 0, classes.length);
.putInt(innerClasses.length + 2)
.putShort(numberOfInnerClasses)
.putByteArray(innerClasses.data, 0, innerClasses.length);
}
if (enclosingClassIndex != 0) {
result
......@@ -549,6 +582,19 @@ public class ClassWriter extends ClassVisitor {
.putShort(enclosingClassIndex)
.putShort(enclosingMethodIndex);
}
if (nestHostClassIndex != 0) {
result
.putShort(symbolTable.addConstantUtf8(Constants.NEST_HOST))
.putInt(2)
.putShort(nestHostClassIndex);
}
if (nestMemberClasses != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.NEST_MEMBERS))
.putInt(nestMemberClasses.length + 2)
.putShort(numberOfNestMemberClasses)
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
}
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) {
result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
}
......
......@@ -31,7 +31,7 @@ package org.objectweb.asm;
* Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
* API.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html">JVMS 6</a>
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
* @author Eric Bruneton
*/
final class Constants implements Opcodes {
......@@ -39,7 +39,7 @@ final class Constants implements Opcodes {
private Constants() {}
// The ClassFile attribute names, in the order they are defined in
// https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7-300.
// https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
static final String CONSTANT_VALUE = "ConstantValue";
static final String CODE = "Code";
......@@ -68,6 +68,8 @@ final class Constants implements Opcodes {
static final String MODULE = "Module";
static final String MODULE_PACKAGES = "ModulePackages";
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
static final String NEST_HOST = "NestHost";
static final String NEST_MEMBERS = "NestMembers";
// ASM specific access flags.
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
......
......@@ -34,7 +34,7 @@ package org.objectweb.asm;