DynamicMemberReferenceInitializer.java revision cfead78069f3dc32998dc118ee08cab3867acea2
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2011 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 */
21package proguard.classfile.util;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.CodeAttribute;
25import proguard.classfile.attribute.visitor.AttributeVisitor;
26import proguard.classfile.constant.*;
27import proguard.classfile.constant.visitor.ConstantVisitor;
28import proguard.classfile.instruction.*;
29import proguard.classfile.instruction.visitor.InstructionVisitor;
30import proguard.classfile.visitor.*;
31import proguard.util.StringMatcher;
32
33/**
34 * This InstructionVisitor initializes any constant
35 * <code>Class.get[Declared]{Field,Method}</code> references of all instructions
36 * it visits. More specifically, it fills out the references of string constant
37 * pool entries that refer to a class member in the program class pool or in the
38 * library class pool.
39 * <p>
40 * It optionally prints notes if on usage of
41 * <code>(SomeClass)Class.forName(variable).newInstance()</code>.
42 * <p>
43 * The class hierarchy and references must be initialized before using this
44 * visitor.
45 *
46 * @see ClassSuperHierarchyInitializer
47 * @see ClassReferenceInitializer
48 *
49 * @author Eric Lafortune
50 */
51public class DynamicMemberReferenceInitializer
52extends      SimplifiedVisitor
53implements   InstructionVisitor,
54             ConstantVisitor,
55             AttributeVisitor,
56             MemberVisitor
57{
58    /*
59    private static       boolean DEBUG      = true;
60    /*/
61    private static final boolean DEBUG      = false;
62    //*/
63
64    public static final int CLASS_INDEX       = InstructionSequenceMatcher.X;
65    public static final int MEMBER_NAME_INDEX = InstructionSequenceMatcher.Y;
66    public static final int TYPE_CLASS_INDEX = InstructionSequenceMatcher.Z;
67
68    public static final int PARAMETER0_CLASS_INDEX = InstructionSequenceMatcher.A;
69    public static final int PARAMETER1_CLASS_INDEX = InstructionSequenceMatcher.B;
70    public static final int PARAMETER2_CLASS_INDEX = InstructionSequenceMatcher.C;
71    public static final int PARAMETER3_CLASS_INDEX = InstructionSequenceMatcher.D;
72
73
74    private final Constant[] GET_FIELD_CONSTANTS = new Constant[]
75    {
76        new MethodrefConstant(1, 2, null, null),
77        new ClassConstant(3, null),
78        new NameAndTypeConstant(4, 5),
79        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
80        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_FIELD),
81        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_FIELD),
82    };
83
84    private final Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[]
85    {
86        new MethodrefConstant(1, 2, null, null),
87        new ClassConstant(3, null),
88        new NameAndTypeConstant(4, 5),
89        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
90        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD),
91        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD),
92    };
93
94    private final Constant[] GET_CONSTRUCTOR_CONSTANTS = new Constant[]
95    {
96        new MethodrefConstant(1, 2, null, null),
97        new ClassConstant(3, null),
98        new NameAndTypeConstant(4, 5),
99        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
100        new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_CONSTRUCTOR),
101        new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_CONSTRUCTOR),
102    };
103
104    private final Constant[] GET_DECLARED_CONSTRUCTOR_CONSTANTS = new Constant[]
105    {
106        new MethodrefConstant(1, 2, null, null),
107        new ClassConstant(3, null),
108        new NameAndTypeConstant(4, 5),
109        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
110        new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_NAME_CLASS_GET_DECLARED_CONSTRUCTOR),
111        new Utf8Constant(ClassConstants.INTERNAL_CONSTRUCTOR_TYPE_CLASS_GET_DECLARED_CONSTRUCTOR),
112    };
113
114    private final Constant[] GET_METHOD_CONSTANTS = new Constant[]
115    {
116        new MethodrefConstant(1, 2, null, null),
117        new ClassConstant(3, null),
118        new NameAndTypeConstant(4, 5),
119        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
120        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_METHOD),
121        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_METHOD),
122    };
123
124    private final Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[]
125    {
126        new MethodrefConstant(1, 2, null, null),
127        new ClassConstant(3, null),
128        new NameAndTypeConstant(4, 5),
129        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS),
130        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD),
131        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD),
132    };
133
134    private final Constant[] NEW_INTEGER_UPDATER_CONSTANTS = new Constant[]
135    {
136        new MethodrefConstant(1, 2, null, null),
137        new ClassConstant(3, null),
138        new NameAndTypeConstant(4, 5),
139        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_INTEGER_FIELD_UPDATER),
140        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
141        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_INTEGER_UPDATER),
142    };
143
144    private final Constant[] NEW_LONG_UPDATER_CONSTANTS = new Constant[]
145    {
146        new MethodrefConstant(1, 2, null, null),
147        new ClassConstant(3, null),
148        new NameAndTypeConstant(4, 5),
149        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_LONG_FIELD_UPDATER),
150        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
151        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_LONG_UPDATER),
152    };
153
154    private final Constant[] NEW_REFERENCE_UPDATER_CONSTANTS = new Constant[]
155    {
156        new MethodrefConstant(1, 2, null, null),
157        new ClassConstant(3, null),
158        new NameAndTypeConstant(4, 5),
159        new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_UTIL_CONCURRENT_ATOMIC_ATOMIC_REFERENCE_FIELD_UPDATER),
160        new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_NEW_UPDATER),
161        new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_NEW_REFERENCE_UPDATER),
162    };
163
164    // SomeClass.class.get[Declared]Field("someField").
165    private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[]
166    {
167        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
168        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
169        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
170    };
171
172//    // SomeClass.class.get[Declared]Constructor(new Class[] {}).
173//    private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
174//    {
175//        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
176//        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
177//        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
178//        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
179//    };
180//
181//    // SomeClass.class.get[Declared]Constructor(new Class[] { A.class }).
182//    private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
183//    {
184//        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
185//        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
186//        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
187//        new SimpleInstruction(InstructionConstants.OP_DUP),
188//        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
189//        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
190//        new SimpleInstruction(InstructionConstants.OP_AASTORE),
191//        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
192//    };
193//
194//    // SomeClass.class.get[Declared]Constructor(new Class[] { A.class, B.class }).
195//    private final Instruction[] CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
196//    {
197//        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
198//        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
199//        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
200//        new SimpleInstruction(InstructionConstants.OP_DUP),
201//        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
202//        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
203//        new SimpleInstruction(InstructionConstants.OP_AASTORE),
204//        new SimpleInstruction(InstructionConstants.OP_DUP),
205//        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
206//        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
207//        new SimpleInstruction(InstructionConstants.OP_AASTORE),
208//        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
209//    };
210
211    // SomeClass.class.get[Declared]Method("someMethod", new Class[] {}).
212    private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[]
213    {
214        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
215        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
216        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
217        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
218        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
219    };
220
221    // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }).
222    private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[]
223    {
224        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
225        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
226        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
227        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
228        new SimpleInstruction(InstructionConstants.OP_DUP),
229        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
230        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
231        new SimpleInstruction(InstructionConstants.OP_AASTORE),
232        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
233    };
234
235    // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
236    private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[]
237    {
238        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
239        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
240        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
241        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
242        new SimpleInstruction(InstructionConstants.OP_DUP),
243        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
244        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
245        new SimpleInstruction(InstructionConstants.OP_AASTORE),
246        new SimpleInstruction(InstructionConstants.OP_DUP),
247        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
248        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
249        new SimpleInstruction(InstructionConstants.OP_AASTORE),
250        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
251    };
252
253    // AtomicIntegerFieldUpdater.newUpdater(A.class, "someField").
254    // AtomicLongFieldUpdater.newUpdater(A.class, "someField").
255    private final Instruction[] CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS = new Instruction[]
256    {
257        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
258        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
259        new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
260    };
261
262    // AtomicReferenceFieldUpdater.newUpdater(A.class, B.class, "someField").
263    private final Instruction[] CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS = new Instruction[]
264    {
265        new ConstantInstruction(InstructionConstants.OP_LDC, CLASS_INDEX),
266        new ConstantInstruction(InstructionConstants.OP_LDC, TYPE_CLASS_INDEX),
267        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
268        new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
269    };
270
271    // get[Declared]Field("someField").
272    private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[]
273    {
274        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
275        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
276    };
277
278//    // get[Declared]Constructor(new Class[] {}).
279//    private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS0 = new Instruction[]
280//    {
281//        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
282//        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
283//        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
284//    };
285
286    // get[Declared]Constructor(new Class[] { A.class }).
287    private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS1 = new Instruction[]
288    {
289        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
290        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
291        new SimpleInstruction(InstructionConstants.OP_DUP),
292        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
293        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
294        new SimpleInstruction(InstructionConstants.OP_AASTORE),
295        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
296    };
297
298    // get[Declared]Constructor(new Class[] { A.class, B.class }).
299    private final Instruction[] GET_CONSTRUCTOR_INSTRUCTIONS2 = new Instruction[]
300    {
301        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
302        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
303        new SimpleInstruction(InstructionConstants.OP_DUP),
304        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
305        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
306        new SimpleInstruction(InstructionConstants.OP_AASTORE),
307        new SimpleInstruction(InstructionConstants.OP_DUP),
308        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
309        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
310        new SimpleInstruction(InstructionConstants.OP_AASTORE),
311        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
312    };
313
314    // get[Declared]Method("someMethod", new Class[] {}).
315    private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[]
316    {
317        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
318        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
319        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
320        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
321    };
322
323    // get[Declared]Method("someMethod", new Class[] { A.class }).
324    private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[]
325    {
326        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
327        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
328        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
329        new SimpleInstruction(InstructionConstants.OP_DUP),
330        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
331        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
332        new SimpleInstruction(InstructionConstants.OP_AASTORE),
333        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
334    };
335
336    // get[Declared]Method("someMethod", new Class[] { A.class, B.class }).
337    private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[]
338    {
339        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
340        new SimpleInstruction(InstructionConstants.OP_ICONST_2),
341        new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1),
342        new SimpleInstruction(InstructionConstants.OP_DUP),
343        new SimpleInstruction(InstructionConstants.OP_ICONST_0),
344        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER0_CLASS_INDEX),
345        new SimpleInstruction(InstructionConstants.OP_AASTORE),
346        new SimpleInstruction(InstructionConstants.OP_DUP),
347        new SimpleInstruction(InstructionConstants.OP_ICONST_1),
348        new ConstantInstruction(InstructionConstants.OP_LDC, PARAMETER1_CLASS_INDEX),
349        new SimpleInstruction(InstructionConstants.OP_AASTORE),
350        new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0),
351    };
352
353    // AtomicIntegerFieldUpdater.newUpdater(..., "someField").
354    // AtomicLongFieldUpdater.newUpdater(..., "someField").
355    // AtomicReferenceFieldUpdater.newUpdater(..., "someField").
356    private final Instruction[] NEW_UPDATER_INSTRUCTIONS = new Instruction[]
357    {
358        new ConstantInstruction(InstructionConstants.OP_LDC, MEMBER_NAME_INDEX),
359        new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 0),
360    };
361
362
363    private final ClassPool      programClassPool;
364    private final ClassPool      libraryClassPool;
365    private final WarningPrinter notePrinter;
366    private final StringMatcher  noteFieldExceptionMatcher;
367    private final StringMatcher  noteMethodExceptionMatcher;
368
369
370    private final InstructionSequenceMatcher constantGetFieldMatcher =
371        new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
372                                       CONSTANT_GET_FIELD_INSTRUCTIONS);
373
374    private final InstructionSequenceMatcher constantGetDeclaredFieldMatcher =
375        new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
376                                       CONSTANT_GET_FIELD_INSTRUCTIONS);
377
378//    private final InstructionSequenceMatcher constantGetConstructorMatcher0 =
379//        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
380//                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
381//
382//    private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher0 =
383//        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
384//                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS0);
385//
386//    private final InstructionSequenceMatcher constantGetConstructorMatcher1 =
387//        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
388//                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
389//
390//    private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher1 =
391//        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
392//                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS1);
393//
394//    private final InstructionSequenceMatcher constantGetConstructorMatcher2 =
395//        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
396//                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
397//
398//    private final InstructionSequenceMatcher constantGetDeclaredConstructorMatcher2 =
399//        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
400//                                       CONSTANT_GET_CONSTRUCTOR_INSTRUCTIONS2);
401
402    private final InstructionSequenceMatcher constantGetMethodMatcher0 =
403        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
404                                       CONSTANT_GET_METHOD_INSTRUCTIONS0);
405
406    private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 =
407        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
408                                       CONSTANT_GET_METHOD_INSTRUCTIONS0);
409
410    private final InstructionSequenceMatcher constantGetMethodMatcher1 =
411        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
412                                       CONSTANT_GET_METHOD_INSTRUCTIONS1);
413
414    private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 =
415        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
416                                       CONSTANT_GET_METHOD_INSTRUCTIONS1);
417
418    private final InstructionSequenceMatcher constantGetMethodMatcher2 =
419        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
420                                       CONSTANT_GET_METHOD_INSTRUCTIONS2);
421
422    private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 =
423        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
424                                       CONSTANT_GET_METHOD_INSTRUCTIONS2);
425
426    private final InstructionSequenceMatcher constantGetIntegerUpdaterMatcher =
427        new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
428                                       CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
429
430    private final InstructionSequenceMatcher constantGetLongUpdaterMatcher =
431        new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
432                                       CONSTANT_NEW_PRIMITIVE_UPDATER_INSTRUCTIONS);
433
434    private final InstructionSequenceMatcher constantGetReferenceUpdaterMatcher =
435        new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
436                                       CONSTANT_NEW_REFERENCE_UPDATER_INSTRUCTIONS);
437
438    private final InstructionSequenceMatcher getFieldMatcher =
439        new InstructionSequenceMatcher(GET_FIELD_CONSTANTS,
440                                       GET_FIELD_INSTRUCTIONS);
441
442    private final InstructionSequenceMatcher getDeclaredFieldMatcher =
443        new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS,
444                                       GET_FIELD_INSTRUCTIONS);
445
446//    private final InstructionSequenceMatcher getConstructorMatcher0 =
447//        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
448//                                       GET_CONSTRUCTOR_INSTRUCTIONS0);
449//
450//    private final InstructionSequenceMatcher getDeclaredConstructorMatcher0 =
451//        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
452//                                       GET_CONSTRUCTOR_INSTRUCTIONS0);
453
454    private final InstructionSequenceMatcher getConstructorMatcher1 =
455        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
456                                       GET_CONSTRUCTOR_INSTRUCTIONS1);
457
458    private final InstructionSequenceMatcher getDeclaredConstructorMatcher1 =
459        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
460                                       GET_CONSTRUCTOR_INSTRUCTIONS1);
461
462    private final InstructionSequenceMatcher getConstructorMatcher2 =
463        new InstructionSequenceMatcher(GET_CONSTRUCTOR_CONSTANTS,
464                                       GET_CONSTRUCTOR_INSTRUCTIONS2);
465
466    private final InstructionSequenceMatcher getDeclaredConstructorMatcher2 =
467        new InstructionSequenceMatcher(GET_DECLARED_CONSTRUCTOR_CONSTANTS,
468                                       GET_CONSTRUCTOR_INSTRUCTIONS2);
469
470    private final InstructionSequenceMatcher getMethodMatcher0 =
471        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
472                                       GET_METHOD_INSTRUCTIONS0);
473
474    private final InstructionSequenceMatcher getDeclaredMethodMatcher0 =
475        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
476                                       GET_METHOD_INSTRUCTIONS0);
477
478    private final InstructionSequenceMatcher getMethodMatcher1 =
479        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
480                                       GET_METHOD_INSTRUCTIONS1);
481
482    private final InstructionSequenceMatcher getDeclaredMethodMatcher1 =
483        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
484                                       GET_METHOD_INSTRUCTIONS1);
485
486    private final InstructionSequenceMatcher getMethodMatcher2 =
487        new InstructionSequenceMatcher(GET_METHOD_CONSTANTS,
488                                       GET_METHOD_INSTRUCTIONS2);
489
490    private final InstructionSequenceMatcher getDeclaredMethodMatcher2 =
491        new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS,
492                                       GET_METHOD_INSTRUCTIONS2);
493
494    private final InstructionSequenceMatcher getIntegerUpdaterMatcher =
495        new InstructionSequenceMatcher(NEW_INTEGER_UPDATER_CONSTANTS,
496                                       NEW_UPDATER_INSTRUCTIONS);
497
498    private final InstructionSequenceMatcher getLongUpdaterMatcher =
499        new InstructionSequenceMatcher(NEW_LONG_UPDATER_CONSTANTS,
500                                       NEW_UPDATER_INSTRUCTIONS);
501
502    private final InstructionSequenceMatcher getReferenceUpdaterMatcher =
503        new InstructionSequenceMatcher(NEW_REFERENCE_UPDATER_CONSTANTS,
504                                       NEW_UPDATER_INSTRUCTIONS);
505
506    private final MemberFinder memberFinder = new MemberFinder();
507
508
509    // Fields acting as parameters for the visitors.
510    private Clazz   referencedClass;
511    private String descriptor;
512    private boolean isDeclared;
513    private boolean isField;
514
515
516
517    /**
518     * Creates a new DynamicMemberReferenceInitializer.
519     */
520    public DynamicMemberReferenceInitializer(ClassPool      programClassPool,
521                                             ClassPool      libraryClassPool,
522                                             WarningPrinter notePrinter,
523                                             StringMatcher  noteFieldExceptionMatcher,
524                                             StringMatcher  noteMethodExceptionMatcher)
525    {
526        this.programClassPool           = programClassPool;
527        this.libraryClassPool           = libraryClassPool;
528        this.notePrinter                = notePrinter;
529        this.noteFieldExceptionMatcher  = noteFieldExceptionMatcher;
530        this.noteMethodExceptionMatcher = noteMethodExceptionMatcher;
531    }
532
533
534    // Implementations for InstructionVisitor.
535
536    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
537    {
538        // Try to match the SomeClass.class.getField("someField") construct.
539        matchGetMember(clazz, method, codeAttribute, offset, instruction,
540                       constantGetFieldMatcher,
541                       getFieldMatcher, true, false, null, null);
542
543        // Try to match the SomeClass.class.getDeclaredField("someField") construct.
544        matchGetMember(clazz, method, codeAttribute, offset, instruction,
545                       constantGetDeclaredFieldMatcher,
546                       getDeclaredFieldMatcher, true, true, null, null);
547
548//        // Try to match the SomeClass.class.getConstructor(new Class[]
549//        // {}) construct.
550//        matchGetMember(clazz, method, codeAttribute, offset, instruction,
551//                       cnull, //onstantGetConstructorMatcher0,
552//                       getConstructorMatcher0, false, false,
553//                       ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
554//
555//        // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
556//        // {}) construct.
557//        matchGetMember(clazz, method, codeAttribute, offset, instruction,
558//                       null, //constantGetDeclaredConstructorMatcher0,
559//                       getDeclaredConstructorMatcher0, false, true,
560//                       ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
561
562        // Try to match the SomeClass.class.getConstructor(new Class[]
563        // { A.class }) construct.
564        matchGetMember(clazz, method, codeAttribute, offset, instruction,
565                       null, //constantGetConstructorMatcher1,
566                       getConstructorMatcher1, false, false,
567                       ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
568
569        // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
570        // { A.class }) construct.
571        matchGetMember(clazz, method, codeAttribute, offset, instruction,
572                       null, //constantGetDeclaredConstructorMatcher1,
573                       getDeclaredConstructorMatcher1, false, true,
574                       ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
575
576        // Try to match the SomeClass.class.getConstructor(new Class[]
577        // { A.class, B.class }) construct.
578        matchGetMember(clazz, method, codeAttribute, offset, instruction,
579                       null, //constantGetConstructorMatcher2,
580                       getConstructorMatcher2, false, false,
581                       ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
582
583        // Try to match the SomeClass.class.getDeclaredConstructor(new Class[]
584        // { A.class, B.class }) construct.
585        matchGetMember(clazz, method, codeAttribute, offset, instruction,
586                       null, //constantGetDeclaredConstructorMatcher2,
587                       getDeclaredConstructorMatcher2, false, true,
588                       ClassConstants.INTERNAL_METHOD_NAME_INIT, null);
589
590        // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
591        // {}) construct.
592        matchGetMember(clazz, method, codeAttribute, offset, instruction,
593                       constantGetMethodMatcher0,
594                       getMethodMatcher0, false, false, null, null);
595
596        // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
597        // new Class[] {}) construct.
598        matchGetMember(clazz, method, codeAttribute, offset, instruction,
599                       constantGetDeclaredMethodMatcher0,
600                       getDeclaredMethodMatcher0, false, true, null, null);
601
602        // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
603        // { A.class }) construct.
604        matchGetMember(clazz, method, codeAttribute, offset, instruction,
605                       constantGetMethodMatcher1,
606                       getMethodMatcher1, false, false, null, null);
607
608        // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
609        //  new Class[] { A.class }) construct.
610        matchGetMember(clazz, method, codeAttribute, offset, instruction,
611                       constantGetDeclaredMethodMatcher1,
612                       getDeclaredMethodMatcher1, false, true, null, null);
613
614        // Try to match the SomeClass.class.getMethod("someMethod", new Class[]
615        // { A.class, B.class }) construct.
616        matchGetMember(clazz, method, codeAttribute, offset, instruction,
617                       constantGetMethodMatcher2,
618                       getMethodMatcher2, false, false, null, null);
619
620        // Try to match the SomeClass.class.getDeclaredMethod("someMethod",
621        // new Class[] { A.class, B.class }) construct.
622        matchGetMember(clazz, method, codeAttribute, offset, instruction,
623                       constantGetDeclaredMethodMatcher2,
624                       getDeclaredMethodMatcher2, false, true, null, null);
625
626        // Try to match the AtomicIntegerFieldUpdater.newUpdater(
627        // SomeClass.class, "someField") construct.
628        matchGetMember(clazz, method, codeAttribute, offset, instruction,
629                       constantGetIntegerUpdaterMatcher,
630                       getIntegerUpdaterMatcher, true, false, null,
631                       "" + ClassConstants.INTERNAL_TYPE_INT);
632
633        // Try to match the AtomicLongFieldUpdater.newUpdater(
634        // SomeClass.class, "someField") construct.
635        matchGetMember(clazz, method, codeAttribute, offset, instruction,
636                       constantGetLongUpdaterMatcher,
637                       getLongUpdaterMatcher, true, false, null,
638                       "" + ClassConstants.INTERNAL_TYPE_LONG);
639
640        // Try to match the AtomicReferenceFieldUpdater.newUpdater(
641        // SomeClass.class, SomeClass.class, "someField") construct.
642        matchGetMember(clazz, method, codeAttribute, offset, instruction,
643                       constantGetReferenceUpdaterMatcher,
644                       getReferenceUpdaterMatcher, true, false, null, null);
645    }
646
647
648    /**
649     * Tries to match the next instruction and fills out the string constant
650     * or prints out a note accordingly.
651     */
652    private void matchGetMember(Clazz                      clazz,
653                                Method                     method,
654                                CodeAttribute              codeAttribute,
655                                int                        offset,
656                                Instruction                instruction,
657                                InstructionSequenceMatcher constantSequenceMatcher,
658                                InstructionSequenceMatcher variableSequenceMatcher,
659                                boolean                    isField,
660                                boolean                    isDeclared,
661                                String                     defaultName,
662                                String                     defaultDescriptor)
663    {
664        if (constantSequenceMatcher != null)
665        {
666            // Try to match the next instruction in the constant sequence.
667            instruction.accept(clazz, method, codeAttribute, offset,
668                               constantSequenceMatcher);
669
670            // Did we find a match to fill out the string constant?
671            if (constantSequenceMatcher.isMatching())
672            {
673                initializeStringReference(clazz,
674                                          constantSequenceMatcher,
675                                          isField,
676                                          isDeclared,
677                                          defaultDescriptor);
678
679                // Don't look for the dynamic construct.
680                variableSequenceMatcher.reset();
681            }
682        }
683
684        // Try to match the next instruction in the variable sequence.
685        instruction.accept(clazz, method, codeAttribute, offset,
686                           variableSequenceMatcher);
687
688        // Did we find a match to print out a note?
689        if (variableSequenceMatcher.isMatching())
690        {
691            // Print out a note about the dynamic invocation.
692            printDynamicInvocationNote(clazz,
693                                       variableSequenceMatcher,
694                                       isField,
695                                       isDeclared,
696                                       defaultName,
697                                       defaultDescriptor);
698        }
699    }
700
701
702    /**
703     * Initializes the reference of the matched string constant to the
704     * referenced class member and its class.
705     */
706    private void initializeStringReference(Clazz                      clazz,
707                                           InstructionSequenceMatcher constantSequenceMatcher,
708                                           boolean                    isField,
709                                           boolean                    isDeclared,
710                                           String                     defaultDescriptor)
711    {
712        this.isField    = isField;
713        this.isDeclared = isDeclared;
714
715        // Get the member's class.
716        int classIndex = constantSequenceMatcher.matchedConstantIndex(CLASS_INDEX);
717        clazz.constantPoolEntryAccept(classIndex, this);
718
719        // Get the field's reference type, if applicable.
720        int typeClassIndex = constantSequenceMatcher.matchedConstantIndex(TYPE_CLASS_INDEX);
721        descriptor = typeClassIndex <= 0 ? defaultDescriptor :
722            ClassUtil.internalTypeFromClassName(clazz.getClassName(typeClassIndex));
723
724        // Fill out the matched string constant.
725        int memberNameIndex = constantSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
726        clazz.constantPoolEntryAccept(memberNameIndex, this);
727    }
728
729
730    // Implementations for ConstantVisitor.
731
732    /**
733     * Remembers the referenced class.
734     */
735    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
736    {
737        if (DEBUG)
738        {
739            System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched class ["+classConstant.getName(clazz)+"]");
740        }
741
742        // Remember the referenced class.
743        referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ?
744            null :
745            classConstant.referencedClass;
746    }
747
748
749    /**
750     * Fills out the link to the referenced class member.
751     */
752    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
753    {
754        if (referencedClass != null)
755        {
756            String name = stringConstant.getString(clazz);
757
758            if (DEBUG)
759            {
760                System.out.println("DynamicMemberReferenceInitializer: ["+clazz.getName()+"] matched string ["+name+"]");
761            }
762
763            // See if we can find the referenced class member locally, or
764            // somewhere in the hierarchy.
765            Member referencedMember = isDeclared ? isField ?
766                (Member)referencedClass.findField(name, descriptor) :
767                (Member)referencedClass.findMethod(name, descriptor) :
768                (Member)memberFinder.findMember(clazz,
769                                                referencedClass,
770                                                name,
771                                                descriptor,
772                                                isField);
773            if (referencedMember != null)
774            {
775                stringConstant.referencedMember = referencedMember;
776                stringConstant.referencedClass  = isDeclared ?
777                    referencedClass :
778                    memberFinder.correspondingClass();
779            }
780        }
781    }
782
783
784    // Small utility methods.
785
786    /**
787     * Prints out a note on the matched dynamic invocation, if necessary.
788     */
789    private void printDynamicInvocationNote(Clazz                      clazz,
790                                            InstructionSequenceMatcher noteSequenceMatcher,
791                                            boolean                    isField,
792                                            boolean                    isDeclared,
793                                            String                     defaultName,
794                                            String                     defaultDescriptor)
795    {
796        // Print out a note about the dynamic invocation.
797        if (notePrinter != null &&
798            notePrinter.accepts(clazz.getName()))
799        {
800            // Is the class member name in the list of exceptions?
801            StringMatcher noteExceptionMatcher = isField ?
802                noteFieldExceptionMatcher :
803                noteMethodExceptionMatcher;
804
805            int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(MEMBER_NAME_INDEX);
806            String memberName = memberNameIndex <= 0 ? defaultName :
807                clazz.getStringString(memberNameIndex);
808
809            if (noteExceptionMatcher == null ||
810                !noteExceptionMatcher.matches(memberName))
811            {
812                // Compose the external member name and partial descriptor.
813                String externalMemberDescription = memberName;
814
815                if (!isField)
816                {
817                    externalMemberDescription += '(';
818                    for (int count = 0; count < 2; count++)
819                    {
820                        int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(
821                            PARAMETER0_CLASS_INDEX + count);
822                        if (memberArgumentIndex > 0)
823                        {
824                            if (count > 0)
825                            {
826                                externalMemberDescription += ',';
827                            }
828                            String className = clazz.getClassName(memberArgumentIndex);
829                            externalMemberDescription += ClassUtil.isInternalArrayType(className) ?
830                                ClassUtil.externalType(className) :
831                                ClassUtil.externalClassName(className);
832                        }
833                    }
834                    externalMemberDescription += ')';
835                }
836
837                // Print out the actual note.
838                notePrinter.print(clazz.getName(),
839                                  "Note: " +
840                                  ClassUtil.externalClassName(clazz.getName()) +
841                                  " accesses a " +
842                                  (isDeclared ? "declared " : "") +
843                                  (isField    ? "field" :
844                                   memberName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ?
845                                                "constructor" : "method") +
846                                  " '" +
847                                  externalMemberDescription +
848                                  "' dynamically");
849
850                // Print out notes about potential candidates.
851                ClassVisitor classVisitor;
852
853                if (isField)
854                {
855                    classVisitor = defaultDescriptor == null ?
856                       new AllFieldVisitor(
857                       new MemberNameFilter(memberName, this)) :
858                       new AllFieldVisitor(
859                       new MemberNameFilter(memberName,
860                       new MemberDescriptorFilter(defaultDescriptor, this)));
861                }
862                else
863                {
864                    // Compose the partial method descriptor.
865                    String methodDescriptor = "(";
866                    for (int count = 0; count < 2; count++)
867                    {
868                        int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(PARAMETER0_CLASS_INDEX + count);
869                        if (memberArgumentIndex > 0)
870                        {
871                            String className = clazz.getClassName(memberArgumentIndex);
872                            methodDescriptor += ClassUtil.isInternalArrayType(className) ?
873                                className :
874                                ClassUtil.internalTypeFromClassName(className);
875                        }
876                    }
877                    methodDescriptor += ")L***;";
878
879                    classVisitor =
880                        new AllMethodVisitor(
881                        new MemberNameFilter(memberName,
882                        new MemberDescriptorFilter(methodDescriptor, this)));
883                }
884
885                programClassPool.classesAcceptAlphabetically(classVisitor);
886                libraryClassPool.classesAcceptAlphabetically(classVisitor);
887            }
888        }
889    }
890
891
892    // Implementations for MemberVisitor.
893
894    public void visitProgramField(ProgramClass programClass, ProgramField programField)
895    {
896        if (notePrinter.accepts(programClass.getName()))
897        {
898            System.out.println("      Maybe this is program field '" +
899                               ClassUtil.externalFullClassDescription(0, programClass.getName()) +
900                               " { " +
901                               ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) +
902                               "; }'");
903        }
904    }
905
906
907    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
908    {
909        if (notePrinter.accepts(programClass.getName()))
910        {
911            System.out.println("      Maybe this is program method '" +
912                               ClassUtil.externalFullClassDescription(0, programClass.getName()) +
913                               " { " +
914                               ClassUtil.externalFullMethodDescription(programClass.getName(), 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) +
915                               "; }'");
916        }
917    }
918
919
920    public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
921    {
922        if (notePrinter.accepts(libraryClass.getName()))
923        {
924            System.out.println("      Maybe this is library field '" +
925                               ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
926                               " { " +
927                               ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) +
928                               "; }'");
929        }
930    }
931
932
933    public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
934    {
935        if (notePrinter.accepts(libraryClass.getName()))
936        {
937            System.out.println("      Maybe this is library method '" +
938                               ClassUtil.externalFullClassDescription(0, libraryClass.getName()) +
939                               " { " +
940                               ClassUtil.externalFullMethodDescription(libraryClass.getName(), 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) +
941                               "; }'");
942        }
943    }
944}