blob: 110dc43712211a5627874f51d2c90e199df491b4 [file] [log] [blame]
/*
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
* Copyright (c) 2002-2011 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package proguard.classfile.util;
import proguard.classfile.*;
import proguard.classfile.attribute.CodeAttribute;
import proguard.classfile.attribute.visitor.AttributeVisitor;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.InstructionVisitor;
import proguard.classfile.visitor.*;
import proguard.util.StringMatcher;
/**
* This InstructionVisitor initializes any constant
* <code>Class.get[Declared]{Field,Method}</code> references of all instructions
* it visits. More specifically, it fills out the references of string constant
* pool entries that refer to a class member in the program class pool or in the
* library class pool.
* <p>
* It optionally prints notes if on usage of
* <code>(SomeClass)Class.forName(variable).newInstance()</code>.
* <p>
* The class hierarchy and references must be initialized before using this
* visitor.
*
* @see ClassSuperHierarchyInitializer
* @see ClassReferenceInitializer
*
* @author Eric Lafortune
*/
public class DynamicMemberReferenceInitializer
extends SimplifiedVisitor
implements InstructionVisitor,
ConstantVisitor,
AttributeVisitor,
MemberVisitor
{
/*
private static boolean DEBUG = true;
/*/
private static final boolean DEBUG = false;
//*/
public static final int CLASS_INDEX = InstructionSequenceMatcher.X;
public static final int MEMBER_NAME_INDEX = InstructionSequenceMatcher.Y;
public static final int TYPE_CLASS_INDEX = InstructionSequenceMatcher.Z;
public static final int PARAMETER0_CLASS_INDEX = InstructionSequenceMatcher.A;
public static final int PARAMETER1_CLASS_INDEX = InstructionSequenceMatcher.B;
public static final int PARAMETER2_CLASS_INDEX = InstructionSequenceMatcher.C;
public static final int PARAMETER3_CLASS_INDEX = InstructionSequenceMatcher.D;
private final Constant[] GET_FIELD_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_FIELD),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_FIELD),
};
private final Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD),
};
private final Constant[] GET_CONSTRUCTOR_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR),
new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR),
};
private final Constant[] GET_DECLARED_CONSTRUCTOR_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR),
new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR),
};
private final Constant[] GET_METHOD_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_METHOD),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_METHOD),
};
private final Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD),
};
private final Constant[] NEW_INTEGER_UPDATER_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INTEGER_UPDATER),
};
private final Constant[] NEW_LONG_UPDATER_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_LONG_UPDATER),
};
private final Constant[] NEW_REFERENCE_UPDATER_CONSTANTS = new Constant[]
{
new MethodrefConstant(1, 2, null, null),
new ClassConstant(3, null),
new NameAndTypeConstant(4, 5),
new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_REFERENCE_UPDATER),
};
// SomeClass.class.get[Declared]Field("someField").
private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// // SomeClass.class.get[Declared]Constructor(new Class[] {}).
// private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
// {
// new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
// };
//
// // SomeClass.class.get[Declared]Constructor(new Class[] { A.class }).
// private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
// {
// new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
// new SimpleInstruction(InstructionConstants.OP_ICONST_1),
// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
// new SimpleInstruction(InstructionConstants.OP_DUP),
// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
// new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
// new SimpleInstruction(InstructionConstants.OP_AASTORE),
// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
// };
//
// // SomeClass.class.get[Declared]Constructor(new Class[] { A.class, B.class }).
// private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
// {
// new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
// new SimpleInstruction(InstructionConstants.OP_ICONST_2),
// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
// new SimpleInstruction(InstructionConstants.OP_DUP),
// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
// new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
// new SimpleInstruction(InstructionConstants.OP_AASTORE),
// new SimpleInstruction(InstructionConstants.OP_DUP),
// new SimpleInstruction(InstructionConstants.OP_ICONST_1),
// new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
// new SimpleInstruction(InstructionConstants.OP_AASTORE),
// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
// };
// SomeClass.class.get[Declared]Method("someMethod", new Class[] {}).
private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }).
private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_2),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// AtomicIntegerFieldUpdater.newUpdater(A.class, "someField").
// AtomicLongFieldUpdater.newUpdater(A.class, "someField").
private final Instruction[] CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
};
// AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "someField").
private final Instruction[] CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, TYPE_CLASS_INDEX),
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
};
// get[Declared]Field("someField").
private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// // get[Declared]Constructor(new Class[] {}).
// private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
// {
// new SimpleInstruction(InstructionConstants.OP_ICONST_0),
// new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
// new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
// };
// get[Declared]Constructor(new Class[] { A.class }).
private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
{
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// get[Declared]Constructor(new Class[] { A.class, B.class }).
private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
{
new SimpleInstruction(InstructionConstants.OP_ICONST_2),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// get[Declared]Method("someMethod", new Class[] {}).
private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// get[Declared]Method("someMethod", new Class[] { A.class }).
private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new SimpleInstruction(InstructionConstants.OP_ICONST_2),
new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_0),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new SimpleInstruction(InstructionConstants.OP_DUP),
new SimpleInstruction(InstructionConstants.OP_ICONST_1),
new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
new SimpleInstruction(InstructionConstants.OP_AASTORE),
new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
};
// AtomicIntegerFieldUpdater.newUpdater(..., "someField").
// AtomicLongFieldUpdater.newUpdater(..., "someField").
// AtomicReferenceFieldUpdater.newUpdater(..., "someField").
private final Instruction[] NEW_UPDATER_INSTRUCTIONS = new Instruction[]
{
new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
};
private final ClassPool programClassPool;
private final ClassPool libraryClassPool;
private final WarningPrinter notePrinter;
private final StringMatcher noteFieldExceptionMatcher;
private final StringMatcher noteMethodExceptionMatcher;
private final InstructionSequenceMatcher constantGetFieldMatcher =
new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
CONSTANT_GET_FIELD_INSTRUCTIONS);
private final InstructionSequenceMatcher constantGetDeclaredFieldMatcher =
new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
CONSTANT_GET_FIELD_INSTRUCTIONS);
// private final InstructionSequenceMatcher constantGetConstructorMatcher0 =
// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
//
// private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher0 =
// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
//
// private final InstructionSequenceMatcher constantGetConstructorMatcher1 =
// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
//
// private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher1 =
// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
//
// private final InstructionSequenceMatcher constantGetConstructorMatcher2 =
// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
//
// private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher2 =
// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
// CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
private final InstructionSequenceMatcher constantGetMethodMatcher0 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS0);
private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 =
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS0);
private final InstructionSequenceMatcher constantGetMethodMatcher1 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS1);
private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 =
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS1);
private final InstructionSequenceMatcher constantGetMethodMatcher2 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS2);
private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 =
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
CONSTANT_GET_METHOD_INSTRUCTIONS2);
private final InstructionSequenceMatcher constantGetIntegerUpdaterMatcher =
new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
private final InstructionSequenceMatcher constantGetLongUpdaterMatcher =
new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
private final InstructionSequenceMatcher constantGetReferenceUpdaterMatcher =
new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS);
private final InstructionSequenceMatcher getFieldMatcher =
new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
GET_FIELD_INSTRUCTIONS);
private final InstructionSequenceMatcher getDeclaredFieldMatcher =
new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
GET_FIELD_INSTRUCTIONS);
// private final InstructionSequenceMatcher getConstructorMatcher0 =
// new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
// GET_CONSTRUCTOR_INSTRUCTIONS0);
//
// private final InstructionSequenceMatcher getDeclaredConstructorMatcher0 =
// new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
// GET_CONSTRUCTOR_INSTRUCTIONS0);
private final InstructionSequenceMatcher getConstructorMatcher1 =
new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
GET_CONSTRUCTOR_INSTRUCTIONS1);
private final InstructionSequenceMatcher getDeclaredConstructorMatcher1 =
new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
GET_CONSTRUCTOR_INSTRUCTIONS1);
private final InstructionSequenceMatcher getConstructorMatcher2 =
new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
GET_CONSTRUCTOR_INSTRUCTIONS2);
private final InstructionSequenceMatcher getDeclaredConstructorMatcher2 =
new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
GET_CONSTRUCTOR_INSTRUCTIONS2);
private final InstructionSequenceMatcher getMethodMatcher0 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS0);
private final InstructionSequenceMatcher getDeclaredMethodMatcher0 =
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS0);
private final InstructionSequenceMatcher getMethodMatcher1 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS1);
private final InstructionSequenceMatcher getDeclaredMethodMatcher1 =
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS1);
private final InstructionSequenceMatcher getMethodMatcher2 =
new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS2);
private final InstructionSequenceMatcher getDeclaredMethodMatcher2 =
new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
GET_METHOD_INSTRUCTIONS2);
private final InstructionSequenceMatcher getIntegerUpdaterMatcher =
new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
NEW_UPDATER_INSTRUCTIONS);
private final InstructionSequenceMatcher getLongUpdaterMatcher =
new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
NEW_UPDATER_INSTRUCTIONS);
private final InstructionSequenceMatcher getReferenceUpdaterMatcher =
new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
NEW_UPDATER_INSTRUCTIONS);
private final MemberFinder memberFinder = new MemberFinder();
// Fields acting as parameters for the visitors.
private Clazz referencedClass;
private String descriptor;
private boolean isDeclared;
private boolean isField;
/**
* Creates a new DynamicMemberReferenceInitializer.
*/
public DynamicMemberReferenceInitializer(ClassPool programClassPool,
ClassPool libraryClassPool,
WarningPrinter notePrinter,
StringMatcher noteFieldExceptionMatcher,
StringMatcher noteMethodExceptionMatcher)
{
this.programClassPool = programClassPool;
this.libraryClassPool = libraryClassPool;
this.notePrinter = notePrinter;
this.noteFieldExceptionMatcher = noteFieldExceptionMatcher;
this.noteMethodExceptionMatcher = noteMethodExceptionMatcher;
}
// Implementations for InstructionVisitor.
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
{
// Try to match the SomeClass.class.getField("someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetFieldMatcher,
getFieldMatcher, true, false, null, null);
// Try to match the SomeClass.class.getDeclaredField("someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredFieldMatcher,
getDeclaredFieldMatcher, true, true, null, null);
// // Try to match the SomeClass.class.getConstructor(new Class[]
// // {}) construct.
// matchGetMember(clazz, method, codeAttribute, offset, instruction,
// cnull, //onstantGetConstructorMatcher0,
// getConstructorMatcher0, false, false,
// ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
//
// // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
// // {}) construct.
// matchGetMember(clazz, method, codeAttribute, offset, instruction,
// null, //constantGetDeclaredConstructorMatcher0,
// getDeclaredConstructorMatcher0, false, true,
// ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
// Try to match the SomeClass.class.getConstructor(new Class[]
// { A.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
null, //constantGetConstructorMatcher1,
getConstructorMatcher1, false, false,
ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
// Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
// { A.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
null, //constantGetDeclaredConstructorMatcher1,
getDeclaredConstructorMatcher1, false, true,
ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
// Try to match the SomeClass.class.getConstructor(new Class[]
// { A.class, B.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
null, //constantGetConstructorMatcher2,
getConstructorMatcher2, false, false,
ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
// Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
// { A.class, B.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
null, //constantGetDeclaredConstructorMatcher2,
getDeclaredConstructorMatcher2, false, true,
ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
// Try to match the SomeClass.class.getMethod("someMethod", new Class[]
// {}) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetMethodMatcher0,
getMethodMatcher0, false, false, null, null);
// Try to match the SomeClass.class.getDeclaredMethod("someMethod",
// new Class[] {}) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredMethodMatcher0,
getDeclaredMethodMatcher0, false, true, null, null);
// Try to match the SomeClass.class.getMethod("someMethod", new Class[]
// { A.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetMethodMatcher1,
getMethodMatcher1, false, false, null, null);
// Try to match the SomeClass.class.getDeclaredMethod("someMethod",
// new Class[] { A.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredMethodMatcher1,
getDeclaredMethodMatcher1, false, true, null, null);
// Try to match the SomeClass.class.getMethod("someMethod", new Class[]
// { A.class, B.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetMethodMatcher2,
getMethodMatcher2, false, false, null, null);
// Try to match the SomeClass.class.getDeclaredMethod("someMethod",
// new Class[] { A.class, B.class }) construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetDeclaredMethodMatcher2,
getDeclaredMethodMatcher2, false, true, null, null);
// Try to match the AtomicIntegerFieldUpdater.newUpdater(
// SomeClass.class, "someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetIntegerUpdaterMatcher,
getIntegerUpdaterMatcher, true, false, null,
"" + ClassConstants.INTERNAL_TYPE_INT);
// Try to match the AtomicLongFieldUpdater.newUpdater(
// SomeClass.class, "someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetLongUpdaterMatcher,
getLongUpdaterMatcher, true, false, null,
"" + ClassConstants.INTERNAL_TYPE_LONG);
// Try to match the AtomicReferenceFieldUpdater.newUpdater(
// SomeClass.class, SomeClass.class, "someField") construct.
matchGetMember(clazz, method, codeAttribute, offset, instruction,
constantGetReferenceUpdaterMatcher,
getReferenceUpdaterMatcher, true, false, null, null);
}
/**
* Tries to match the next instruction and fills out the string constant
* or prints out a note accordingly.
*/
private void matchGetMember(Clazz clazz,
Method method,
CodeAttribute codeAttribute,
int offset,
Instruction instruction,
InstructionSequenceMatcher constantSequenceMatcher,
InstructionSequenceMatcher variableSequenceMatcher,
boolean isField,
boolean isDeclared,
String defaultName,
String defaultDescriptor)
{
if (constantSequenceMatcher != null)
{
// Try to match the next instruction in the constant sequence.
instruction.accept(clazz, method, codeAttribute, offset,
constantSequenceMatcher);
// Did we find a match to fill out the string constant?
if (constantSequenceMatcher.isMatching())
{
initializeStringReference(clazz,
constantSequenceMatcher,
isField,
isDeclared,
defaultDescriptor);
// Don't look for the dynamic construct.
variableSequenceMatcher.reset();
}
}
// Try to match the next instruction in the variable sequence.
instruction.accept(clazz, method, codeAttribute, offset,
variableSequenceMatcher);
// Did we find a match to print out a note?
if (variableSequenceMatcher.isMatching())
{
// Print out a note about the dynamic invocation.
printDynamicInvocationNote(clazz,
variableSequenceMatcher,
isField,
isDeclared,
defaultName,
defaultDescriptor);
}
}
/**
* Initializes the reference of the matched string constant to the
* referenced class member and its class.
*/
private void initializeStringReference(Clazz clazz,
InstructionSequenceMatcher constantSequenceMatcher,
boolean isField,
boolean isDeclared,
String defaultDescriptor)
{
this.isField = isField;
this.isDeclared = isDeclared;
// Get the member's class.
int classIndex = constantSequenceMatcher.matchedConstantIndex(CLASS_INDEX);
clazz.constantPoolEntryAccept(classIndex, this);
// Get the field's reference type, if applicable.
int typeClassIndex = constantSequenceMatcher.matchedConstantIndex(TYPE_CLASS_INDEX);
descriptor = typeClassIndex <= 0 ? defaultDescriptor :
ClassUtil.internalTypeFromClassName(clazz.getClassName(typeClassIndex));
// Fill out the matched string constant.
int memberNameIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
clazz.constantPoolEntryAccept(memberNameIndex, this);
}
// Implementations for ConstantVisitor.
/**
* Remembers the referenced class.
*/
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
if (DEBUG)
{
System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched class ["+classConstant.getName(clazz)+"]");
}
// Remember the referenced class.
referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
null :
classConstant.referencedClass;
}
/**
* Fills out the link to the referenced class member.
*/
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
if (referencedClass != null)
{
String name = stringConstant.getString(clazz);
if (DEBUG)
{
System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched string ["+name+"]");
}
// See if we can find the referenced class member locally, or
// somewhere in the hierarchy.
Member referencedMember = isDeclared ? isField ?
(Member)referencedClass.findField(name, descriptor) :
(Member)referencedClass.findMethod(name, descriptor) :
(Member)memberFinder.findMember(clazz,
referencedClass,
name,
descriptor,
isField);
if (referencedMember != null)
{
stringConstant.referencedMember = referencedMember;
stringConstant.referencedClass = isDeclared ?
referencedClass :
memberFinder.correspondingClass();
}
}
}
// Small utility methods.
/**
* Prints out a note on the matched dynamic invocation, if necessary.
*/
private void printDynamicInvocationNote(Clazz clazz,
InstructionSequenceMatcher noteSequenceMatcher,
boolean isField,
boolean isDeclared,
String defaultName,
String defaultDescriptor)
{
// Print out a note about the dynamic invocation.
if (notePrinter != null &&
notePrinter.accepts(clazz.getName()))
{
// Is the class member name in the list of exceptions?
StringMatcher noteExceptionMatcher = isField ?
noteFieldExceptionMatcher :
noteMethodExceptionMatcher;
int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
String memberName = memberNameIndex <= 0 ? defaultName :
clazz.getStringString(memberNameIndex);
if (noteExceptionMatcher == null ||
!noteExceptionMatcher.matches(memberName))
{
// Compose the external member name and partial descriptor.
String externalMemberDescription = memberName;
if (!isField)
{
externalMemberDescription += '(';
for (int count = 0; count < 2; count++)
{
int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(
PARAMETER0_CLASS_INDEX + count);
if (memberArgumentIndex > 0)
{
if (count > 0)
{
externalMemberDescription += ',';
}
String className = clazz.getClassName(memberArgumentIndex);
externalMemberDescription += ClassUtil.isInternalArrayType(className) ?
ClassUtil.externalType(className) :
ClassUtil.externalClassName(className);
}
}
externalMemberDescription += ')';
}
// Print out the actual note.
notePrinter.print(clazz.getName(),
"Note: " +
ClassUtil.externalClassName(clazz.getName()) +
" accesses a " +
(isDeclared ? "declared " : "") +
(isField ? "field" :
memberName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ?
"constructor" : "method") +
" '" +
externalMemberDescription +
"' dynamically");
// Print out notes about potential candidates.
ClassVisitor classVisitor;
if (isField)
{
classVisitor = defaultDescriptor == null ?
new AllFieldVisitor(
new MemberNameFilter(memberName, this)) :
new AllFieldVisitor(
new MemberNameFilter(memberName,
new MemberDescriptorFilter(defaultDescriptor, this)));
}
else
{
// Compose the partial method descriptor.
String methodDescriptor = "(";
for (int count = 0; count < 2; count++)
{
int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(PARAMETER0_CLASS_INDEX + count);
if (memberArgumentIndex > 0)
{
String className = clazz.getClassName(memberArgumentIndex);
methodDescriptor += ClassUtil.isInternalArrayType(className) ?
className :
ClassUtil.internalTypeFromClassName(className);
}
}
methodDescriptor += ")L***;";
classVisitor =
new AllMethodVisitor(
new MemberNameFilter(memberName,
new MemberDescriptorFilter(methodDescriptor, this)));
}
programClassPool.classesAcceptAlphabetically(classVisitor);
libraryClassPool.classesAcceptAlphabetically(classVisitor);
}
}
}
// Implementations for MemberVisitor.
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
if (notePrinter.accepts(programClass.getName()))
{
System.out.println(" Maybe this is program field '" +
ClassUtil.externalFullClassDescription(0, programClass.getName()) +
" { " +
ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) +
"; }'");
}
}
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
if (notePrinter.accepts(programClass.getName()))
{
System.out.println(" Maybe this is program method '" +
ClassUtil.externalFullClassDescription(0, programClass.getName()) +
" { " +
ClassUtil.externalFullMethodDescription(programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
"; }'");
}
}
public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
{
if (notePrinter.accepts(libraryClass.getName()))
{
System.out.println(" Maybe this is library field '" +
ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
" { " +
ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) +
"; }'");
}
}
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
if (notePrinter.accepts(libraryClass.getName()))
{
System.out.println(" Maybe this is library method '" +
ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
" { " +
ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
"; }'");
}
}
}