KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > util > DynamicMemberReferenceInitializer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.classfile.util;
22
23 import proguard.classfile.instruction.visitor.InstructionVisitor;
24 import proguard.classfile.instruction.*;
25 import proguard.classfile.constant.visitor.ConstantVisitor;
26 import proguard.classfile.constant.*;
27 import proguard.classfile.attribute.visitor.*;
28 import proguard.classfile.attribute.*;
29 import proguard.classfile.*;
30 import proguard.util.ClassNameListMatcher;
31
32 /**
33  * This InstructionVisitor initializes any constant
34  * <code>Class.get[Declared]{Field,Method}</code> references of all instructions
35  * it visits. More specifically, it fills out the references of string constant
36  * pool entries that refer to a class member in the program class pool or in the
37  * library class pool.
38  * <p>
39  * It optionally prints notes if on usage of
40  * <code>(SomeClass)Class.forName(variable).newInstance()</code>.
41  * <p>
42  * The class hierarchy and references must be initialized before using this
43  * visitor.
44  *
45  * @see ClassSuperHierarchyInitializer
46  * @see ClassReferenceInitializer
47  *
48  * @author Eric Lafortune
49  */

50 public class DynamicMemberReferenceInitializer
51 extends SimplifiedVisitor
52 implements InstructionVisitor,
53              ConstantVisitor,
54              AttributeVisitor
55 {
56     public static final int X = InstructionSequenceMatcher.X;
57     public static final int Y = InstructionSequenceMatcher.Y;
58     public static final int Z = InstructionSequenceMatcher.Z;
59
60     public static final int A = InstructionSequenceMatcher.A;
61     public static final int B = InstructionSequenceMatcher.B;
62     public static final int C = InstructionSequenceMatcher.C;
63     public static final int D = InstructionSequenceMatcher.D;
64
65
66     private Constant[] GET_FIELD_CONSTANTS = new Constant[]
67     {
68         new MethodrefConstant(1, 2, null, null),
69         new ClassConstant(3, null),
70         new NameAndTypeConstant(4, 5),
71         new Utf8Constant(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS),
72         new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_FIELD),
73         new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_FIELD),
74     };
75
76     private Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[]
77     {
78         new MethodrefConstant(1, 2, null, null),
79         new ClassConstant(3, null),
80         new NameAndTypeConstant(4, 5),
81         new Utf8Constant(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS),
82         new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD),
83         new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD),
84     };
85
86     private Constant[] GET_METHOD_CONSTANTS = new Constant[]
87     {
88         new MethodrefConstant(1, 2, null, null),
89         new ClassConstant(3, null),
90         new NameAndTypeConstant(4, 5),
91         new Utf8Constant(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS),
92         new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_METHOD),
93         new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_METHOD),
94     };
95
96     private Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[]
97     {
98         new MethodrefConstant(1, 2, null, null),
99         new ClassConstant(3, null),
100         new NameAndTypeConstant(4, 5),
101         new Utf8Constant(ClassConstants.INTERNAL_CLASS_NAME_JAVA_LANG_CLASS),
102         new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD),
103         new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD),
104     };
105
106     // SomeClass.class.get[Declared]Field("someField").
107
private Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[]
108     {
109         new ConstantInstruction(InstructionConstants.OP_LDC, X),
110         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
111         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
112     };
113
114     // SomeClass.class.get[Declared]Method("someMethod", new Class[] {}).
115
private Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[]
116     {
117         new ConstantInstruction(InstructionConstants.OP_LDC, X),
118         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
119         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
120         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
121         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
122     };
123
124     // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }).
125
private Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[]
126     {
127         new ConstantInstruction(InstructionConstants.OP_LDC, X),
128         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
129         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
130         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
131         new SimpleInstruction(InstructionConstants.OP_DUP),
132         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
133         new ConstantInstruction(InstructionConstants.OP_LDC, A),
134         new SimpleInstruction(InstructionConstants.OP_AASTORE),
135         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
136     };
137
138     // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
139
private Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[]
140     {
141         new ConstantInstruction(InstructionConstants.OP_LDC, X),
142         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
143         new SimpleInstruction(InstructionConstants.OP_ICONST_2),
144         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
145         new SimpleInstruction(InstructionConstants.OP_DUP),
146         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
147         new ConstantInstruction(InstructionConstants.OP_LDC, A),
148         new SimpleInstruction(InstructionConstants.OP_AASTORE),
149         new SimpleInstruction(InstructionConstants.OP_DUP),
150         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
151         new ConstantInstruction(InstructionConstants.OP_LDC, B),
152         new SimpleInstruction(InstructionConstants.OP_AASTORE),
153         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
154     };
155
156     // get[Declared]Field("someField").
157
private Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[]
158     {
159         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
160         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
161     };
162
163     // get[Declared]Method("someMethod", new Class[] {}).
164
private Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[]
165     {
166         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
167         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
168         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
169         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
170     };
171
172     // get[Declared]Method("someMethod", new Class[] { A.class }).
173
private Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[]
174     {
175         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
176         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
177         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
178         new SimpleInstruction(InstructionConstants.OP_DUP),
179         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
180         new ConstantInstruction(InstructionConstants.OP_LDC, A),
181         new SimpleInstruction(InstructionConstants.OP_AASTORE),
182         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
183     };
184
185     // get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
186
private Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[]
187     {
188         new ConstantInstruction(InstructionConstants.OP_LDC, Y),
189         new SimpleInstruction(InstructionConstants.OP_ICONST_2),
190         new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
191         new SimpleInstruction(InstructionConstants.OP_DUP),
192         new SimpleInstruction(InstructionConstants.OP_ICONST_0),
193         new ConstantInstruction(InstructionConstants.OP_LDC, A),
194         new SimpleInstruction(InstructionConstants.OP_AASTORE),
195         new SimpleInstruction(InstructionConstants.OP_DUP),
196         new SimpleInstruction(InstructionConstants.OP_ICONST_1),
197         new ConstantInstruction(InstructionConstants.OP_LDC, B),
198         new SimpleInstruction(InstructionConstants.OP_AASTORE),
199         new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
200     };
201
202
203     private WarningPrinter notePrinter;
204     private ClassNameListMatcher noteFieldExceptionMatcher;
205     private ClassNameListMatcher noteMethodExceptionMatcher;
206
207
208     private InstructionSequenceMatcher constantGetFieldMatcher =
209         new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
210                                        CONSTANT_GET_FIELD_INSTRUCTIONS);
211
212     private InstructionSequenceMatcher constantGetDeclaredFieldMatcher =
213         new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
214                                        CONSTANT_GET_FIELD_INSTRUCTIONS);
215
216     private InstructionSequenceMatcher constantGetMethodMatcher0 =
217         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
218                                        CONSTANT_GET_METHOD_INSTRUCTIONS0);
219
220     private InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 =
221         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
222                                        CONSTANT_GET_METHOD_INSTRUCTIONS0);
223
224     private InstructionSequenceMatcher constantGetMethodMatcher1 =
225         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
226                                        CONSTANT_GET_METHOD_INSTRUCTIONS1);
227
228     private InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 =
229         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
230                                        CONSTANT_GET_METHOD_INSTRUCTIONS1);
231
232     private InstructionSequenceMatcher constantGetMethodMatcher2 =
233         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
234                                        CONSTANT_GET_METHOD_INSTRUCTIONS2);
235
236     private InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 =
237         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
238                                        CONSTANT_GET_METHOD_INSTRUCTIONS2);
239
240     private InstructionSequenceMatcher getFieldMatcher =
241         new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
242                                        GET_FIELD_INSTRUCTIONS);
243
244     private InstructionSequenceMatcher getDeclaredFieldMatcher =
245         new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
246                                        GET_FIELD_INSTRUCTIONS);
247
248     private InstructionSequenceMatcher getMethodMatcher0 =
249         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
250                                        GET_METHOD_INSTRUCTIONS0);
251
252     private InstructionSequenceMatcher getDeclaredMethodMatcher0 =
253         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
254                                        GET_METHOD_INSTRUCTIONS0);
255
256     private InstructionSequenceMatcher getMethodMatcher1 =
257         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
258                                        GET_METHOD_INSTRUCTIONS1);
259
260     private InstructionSequenceMatcher getDeclaredMethodMatcher1 =
261         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
262                                        GET_METHOD_INSTRUCTIONS1);
263
264     private InstructionSequenceMatcher getMethodMatcher2 =
265         new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
266                                        GET_METHOD_INSTRUCTIONS2);
267
268     private InstructionSequenceMatcher getDeclaredMethodMatcher2 =
269         new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
270                                        GET_METHOD_INSTRUCTIONS2);
271
272     private MemberFinder memberFinder = new MemberFinder();
273
274
275     // Fields acting as parameters for the visitors.
276
private Clazz referencedClass;
277     private boolean isDeclared;
278     private boolean isField;
279
280
281
282     /**
283      * Creates a new DynamicMemberReferenceInitializer.
284      */

285     public DynamicMemberReferenceInitializer(WarningPrinter notePrinter,
286                                              ClassNameListMatcher noteFieldExceptionMatcher,
287                                              ClassNameListMatcher noteMethodExceptionMatcher)
288     {
289         this.notePrinter = notePrinter;
290         this.noteFieldExceptionMatcher = noteFieldExceptionMatcher;
291         this.noteMethodExceptionMatcher = noteMethodExceptionMatcher;
292     }
293
294
295     // Implementations for InstructionVisitor.
296

297     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
298     {
299         // Try to match the SomeClass.class.getField("someField") construct.
300
matchGetMember(clazz, method, codeAttribute, offset, instruction,
301                        constantGetFieldMatcher,
302                        getFieldMatcher, true, false);
303
304         // Try to match the SomeClass.class.getDeclaredField("someField") construct.
305
matchGetMember(clazz, method, codeAttribute, offset, instruction,
306                        constantGetDeclaredFieldMatcher,
307                        getDeclaredFieldMatcher, true, true);
308
309         // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
310
// {}) construct.
311
matchGetMember(clazz, method, codeAttribute, offset, instruction,
312                        constantGetMethodMatcher0,
313                        getMethodMatcher0, false, false);
314
315         // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
316
// new Class[] {}) construct.
317
matchGetMember(clazz, method, codeAttribute, offset, instruction,
318                        constantGetDeclaredMethodMatcher0,
319                        getDeclaredMethodMatcher0, false, true);
320
321         // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
322
// { A.class }) construct.
323
matchGetMember(clazz, method, codeAttribute, offset, instruction,
324                        constantGetMethodMatcher1,
325                        getMethodMatcher1, false, false);
326
327         // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
328
// new Class[] { A.class }) construct.
329
matchGetMember(clazz, method, codeAttribute, offset, instruction,
330                        constantGetDeclaredMethodMatcher1,
331                        getDeclaredMethodMatcher1, false, true);
332
333         // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
334
// { A.class, B.class }) construct.
335
matchGetMember(clazz, method, codeAttribute, offset, instruction,
336                        constantGetMethodMatcher2,
337                        getMethodMatcher2, false, false);
338
339         // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
340
// new Class[] { A.class, B.class }) construct.
341
matchGetMember(clazz, method, codeAttribute, offset, instruction,
342                        constantGetDeclaredMethodMatcher2,
343                        getDeclaredMethodMatcher2, false, true);
344     }
345
346
347     /**
348      * Tries to match the next instruction and fills out the string constant
349      * or prints out a note accordingly.
350      */

351     private void matchGetMember(Clazz clazz,
352                                 Method method,
353                                 CodeAttribute codeAttribute,
354                                 int offset,
355                                 Instruction instruction,
356                                 InstructionSequenceMatcher constantSequenceMatcher,
357                                 InstructionSequenceMatcher variableSequenceMatcher,
358                                 boolean isField,
359                                 boolean isDeclared)
360     {
361         // Try to match the next instruction in the constant sequence.
362
instruction.accept(clazz, method, codeAttribute, offset,
363                            constantSequenceMatcher);
364
365         // Did we find a match to fill out the string constant?
366
if (constantSequenceMatcher.isMatching())
367         {
368             this.isField = isField;
369             this.isDeclared = isDeclared;
370
371             // Get the member's class.
372
clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(X), this);
373
374             // Fill out the matched string constant.
375
clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(Y), this);
376
377             // Don't look for the dynamic construct.
378
variableSequenceMatcher.reset();
379         }
380
381         // Try to match the next instruction in the variable sequence.
382
instruction.accept(clazz, method, codeAttribute, offset,
383                            variableSequenceMatcher);
384
385         // Did we find a match to print out a note?
386
if (variableSequenceMatcher.isMatching())
387         {
388             // Print out a note about the dynamic invocation.
389
printDynamicInvocationNote(clazz,
390                                        variableSequenceMatcher,
391                                        isField,
392                                        isDeclared);
393         }
394     }
395
396
397     // Implementations for ConstantVisitor.
398

399     /**
400      * Remembers the referenced class.
401      */

402     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
403     {
404         // Remember the referenced class.
405
referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
406             null :
407             classConstant.referencedClass;
408     }
409
410
411     /**
412      * Fills out the link to the referenced class member.
413      */

414     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
415     {
416         if (referencedClass != null)
417         {
418             String JavaDoc name = stringConstant.getString(clazz);
419
420             // See if we can find the referenced class member locally, or
421
// somewhere in the hierarchy.
422
Member referencedMember = isDeclared ? isField ?
423                 (Member)referencedClass.findField(name, null) :
424                 (Member)referencedClass.findMethod(name, null) :
425                 (Member)memberFinder.findMember(clazz,
426                                                 referencedClass,
427                                                 name,
428                                                 null,
429                                                 isField);
430             if (referencedMember != null)
431             {
432                 stringConstant.referencedMember = referencedMember;
433                 stringConstant.referencedClass = isDeclared ?
434                     referencedClass :
435                     memberFinder.correspondingClass();
436             }
437         }
438     }
439
440
441     // Small utility methods.
442

443     /**
444      * Prints out a note on the matched dynamic invocation, if necessary.
445      */

446     private void printDynamicInvocationNote(Clazz clazz,
447                                             InstructionSequenceMatcher noteSequenceMatcher,
448                                             boolean isField,
449                                             boolean isDeclared)
450     {
451         // Print out a note about the dynamic invocation.
452
if (notePrinter != null)
453         {
454             // Is the class member name in the list of exceptions?
455
ClassNameListMatcher noteExceptionMatcher = isField ?
456                 noteFieldExceptionMatcher :
457                 noteMethodExceptionMatcher;
458
459             int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(Y);
460             String JavaDoc memberName = clazz.getStringString(memberNameIndex);
461
462             if (noteExceptionMatcher == null ||
463                 !noteExceptionMatcher.matches(memberName))
464             {
465                 String JavaDoc memberDescription = memberName;
466
467                 // Compose the method arguments, if necessary.
468
if (!isField)
469                 {
470                     memberDescription += '(';
471                     for (int count = 0; count < 2; count++)
472                     {
473                         int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count);
474                         if (memberArgumentIndex > 0)
475                         {
476                             if (count > 0)
477                             {
478                                 memberDescription += ',';
479                             }
480                             String JavaDoc className = clazz.getClassName(memberArgumentIndex);
481                             memberDescription += ClassUtil.isInternalArrayType(className) ?
482                                 ClassUtil.externalType(className) :
483                                 ClassUtil.externalClassName(className);
484                         }
485                     }
486                     memberDescription += ')';
487                 }
488
489                 // Print out the actual note.
490
notePrinter.print("Note: " +
491                                   ClassUtil.externalClassName(clazz.getName()) +
492                                   " accesses a " +
493                                   (isDeclared ? "declared " : "") +
494                                   (isField ? "field" : "method") +
495                                   " '" +
496                                   memberDescription +
497                                   "' dynamically");
498             }
499         }
500     }
501 }
502
Popular Tags