1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 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.optimize;
22
23import proguard.classfile.*;
24import proguard.classfile.editor.ClassReferenceFixer;
25import proguard.classfile.util.*;
26import proguard.classfile.visitor.MemberVisitor;
27import proguard.evaluation.value.Value;
28import proguard.optimize.evaluation.StoringInvocationUnit;
29
30/**
31 * This MemberVisitor specializes parameters in the descriptors of the
32 * methods that it visits.
33 *
34 * @see StoringInvocationUnit
35 * @see ClassReferenceFixer
36 * @author Eric Lafortune
37 */
38public class MemberDescriptorSpecializer
39extends      SimplifiedVisitor
40implements   MemberVisitor
41{
42    private static final boolean DEBUG = false;
43
44
45    private final MemberVisitor extraParameterMemberVisitor;
46
47
48    /**
49     * Creates a new MethodDescriptorShrinker.
50     */
51    public MemberDescriptorSpecializer()
52    {
53        this(null);
54    }
55
56
57    /**
58     * Creates a new MethodDescriptorShrinker with an extra visitor.
59     * @param extraParameterMemberVisitor an optional extra visitor for all
60     *                                    class members whose parameters have
61     *                                    been specialized.
62     */
63    public MemberDescriptorSpecializer(MemberVisitor extraParameterMemberVisitor)
64    {
65        this.extraParameterMemberVisitor = extraParameterMemberVisitor;
66    }
67
68
69    // Implementations for MemberVisitor.
70
71    public void visitProgramField(ProgramClass programClass, ProgramField programField)
72    {
73        Value parameterValue = StoringInvocationUnit.getFieldValue(programField);
74        if (parameterValue.computationalType() == Value.TYPE_REFERENCE)
75        {
76            Clazz referencedClass = parameterValue.referenceValue().getReferencedClass();
77            if (programField.referencedClass != referencedClass)
78            {
79                if (DEBUG)
80                {
81                    System.out.println("MemberDescriptorSpecializer: "+programClass.getName()+"."+programField.getName(programClass)+" "+programField.getDescriptor(programClass));
82                    System.out.println("  "+programField.referencedClass.getName()+" -> "+referencedClass.getName());
83                }
84
85                programField.referencedClass = referencedClass;
86
87                // Visit the field, if required.
88                if (extraParameterMemberVisitor != null)
89                {
90                    extraParameterMemberVisitor.visitProgramField(programClass, programField);
91                }
92            }
93        }
94    }
95
96
97    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
98    {
99        // All parameters of non-static methods are shifted by one in the local
100        // variable frame.
101        int firstParameterIndex =
102            (programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
103                0 : 1;
104
105        int parameterCount =
106            ClassUtil.internalMethodParameterCount(programMethod.getDescriptor(programClass));
107
108        int classIndex = 0;
109
110        // Go over the parameters.
111        for (int parameterIndex = firstParameterIndex; parameterIndex < parameterCount; parameterIndex++)
112        {
113            Value parameterValue = StoringInvocationUnit.getMethodParameterValue(programMethod, parameterIndex);
114             if (parameterValue.computationalType() == Value.TYPE_REFERENCE)
115             {
116                 Clazz referencedClass = parameterValue.referenceValue().getReferencedClass();
117                 if (programMethod.referencedClasses[classIndex] != referencedClass)
118                 {
119                     if (DEBUG)
120                     {
121                         System.out.println("MemberDescriptorSpecializer: "+programClass.getName()+"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass));
122                         System.out.println("  "+programMethod.referencedClasses[classIndex].getName()+" -> "+referencedClass.getName());
123                     }
124
125                     programMethod.referencedClasses[classIndex] = referencedClass;
126
127                     // Visit the method, if required.
128                     if (extraParameterMemberVisitor != null)
129                     {
130                         extraParameterMemberVisitor.visitProgramMethod(programClass, programMethod);
131                     }
132                 }
133
134                 classIndex++;
135             }
136        }
137    }
138}
139