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