1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/*
2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification
3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *             of Java bytecode.
4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
59f606f95f03a75961498803e24bee6799a7c0885Ying Wang * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it
8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free
9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option)
10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version.
11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT
13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details.
16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along
18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc.,
19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.optimize.peephole;
22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.*;
24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.constant.visitor.*;
25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.editor.*;
26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.*;
27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.visitor.*;
28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.optimize.KeepMarker;
29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.optimize.info.*;
30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.util.*;
31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.*;
33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/**
35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This ClassVisitor inlines the classes that it visits in a given target class,
36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * whenever possible.
37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @see RetargetedInnerClassAttributeRemover
39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @see TargetClassChanger
40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @see ClassReferenceFixer
41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @see MemberReferenceFixer
42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @see AccessFixer
43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune
44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class ClassMerger
46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoextends      SimplifiedVisitor
47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimplements   ClassVisitor,
48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             ConstantVisitor
49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{
50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    //*
51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static final boolean DEBUG = false;
52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /*/
53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static       boolean DEBUG = true;
54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    //*/
55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final ProgramClass targetClass;
58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final boolean      allowAccessModification;
59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final boolean      mergeInterfacesAggressively;
60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final ClassVisitor extraClassVisitor;
61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Creates a new ClassMerger that will merge classes into the given target
65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * class.
66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param targetClass                 the class into which all visited
67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    classes will be merged.
68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param allowAccessModification     specifies whether the access modifiers
69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    of classes can be changed in order to
70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    merge them.
71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param mergeInterfacesAggressively specifies whether interfaces may
72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    be merged aggressively.
73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public ClassMerger(ProgramClass targetClass,
75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                       boolean      allowAccessModification,
76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                       boolean      mergeInterfacesAggressively)
77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this(targetClass, allowAccessModification, mergeInterfacesAggressively, null);
79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Creates a new ClassMerger that will merge classes into the given target
84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * class.
85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param targetClass                 the class into which all visited
86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    classes will be merged.
87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param allowAccessModification     specifies whether the access modifiers
88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    of classes can be changed in order to
89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    merge them.
90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param mergeInterfacesAggressively specifies whether interfaces may
91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    be merged aggressively.
92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * @param extraClassVisitor           an optional extra visitor for all
93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     *                                    merged classes.
94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public ClassMerger(ProgramClass targetClass,
96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                       boolean      allowAccessModification,
97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                       boolean      mergeInterfacesAggressively,
98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                       ClassVisitor extraClassVisitor)
99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this.targetClass                 = targetClass;
101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this.allowAccessModification     = allowAccessModification;
102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this.mergeInterfacesAggressively = mergeInterfacesAggressively;
103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this.extraClassVisitor           = extraClassVisitor;
104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for ClassVisitor.
108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitProgramClass(ProgramClass programClass)
110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        //final String CLASS_NAME = "abc/Def";
112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        //DEBUG = programClass.getName().equals(CLASS_NAME) ||
113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        //        targetClass.getName().equals(CLASS_NAME);
114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // TODO: Remove this when the class merger has stabilized.
116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Catch any unexpected exceptions from the actual visiting method.
117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            visitProgramClass0(programClass);
120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (RuntimeException ex)
122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("Unexpected error while merging classes:");
124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("  Class        = ["+programClass.getName()+"]");
125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("  Target class = ["+targetClass.getName()+"]");
126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.err.println("  Exception    = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (DEBUG)
129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                programClass.accept(new ClassPrinter());
131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                targetClass.accept(new ClassPrinter());
132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            throw ex;
135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public void visitProgramClass0(ProgramClass programClass)
139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (!programClass.equals(targetClass) &&
141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Don't merge classes that must be preserved.
143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !KeepMarker.isKept(programClass) &&
144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !KeepMarker.isKept(targetClass)  &&
145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Only merge classes that haven't been retargeted yet.
147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            getTargetClass(programClass) == null &&
148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            getTargetClass(targetClass)  == null &&
149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Don't merge annotation classes, with all their introspection and
151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // infinite recursion.
152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            (programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_ANNOTATTION) == 0 &&
153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
1549f606f95f03a75961498803e24bee6799a7c0885Ying Wang            // Only merge classes if we can change the access permissioms, or
155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // if they are in the same package, or
156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // if they are public and don't contain or invoke package visible
157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // class members.
158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            (allowAccessModification                                                        ||
159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             ((programClass.getAccessFlags() &
160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               targetClass.getAccessFlags()  &
161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               ClassConstants.INTERNAL_ACC_PUBLIC) != 0 &&
162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              !PackageVisibleMemberContainingClassMarker.containsPackageVisibleMembers(programClass) &&
163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              !PackageVisibleMemberInvokingClassMarker.invokesPackageVisibleMembers(programClass)) ||
164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             ClassUtil.internalPackageName(programClass.getName()).equals(
165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             ClassUtil.internalPackageName(targetClass.getName()))) &&
166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Only merge two classes or two interfaces or two abstract classes,
168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // or a class into an interface with a single implementation.
169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            ((programClass.getAccessFlags() &
170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              (ClassConstants.INTERNAL_ACC_INTERFACE |
171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               ClassConstants.INTERNAL_ACC_ABSTRACT)) ==
172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             (targetClass.getAccessFlags()  &
173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              (ClassConstants.INTERNAL_ACC_INTERFACE |
174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               ClassConstants.INTERNAL_ACC_ABSTRACT)) ||
175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             (isOnlySubClass(programClass, targetClass) &&
176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              (programClass.getSuperClass().equals(targetClass) ||
177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               programClass.getSuperClass().equals(targetClass.getSuperClass())))) &&
178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // One class must not implement the other class indirectly.
180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !indirectlyImplementedInterfaces(programClass).contains(targetClass) &&
181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !targetClass.extendsOrImplements(programClass) &&
182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The two classes must have the same superclasses and interfaces
184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // with static initializers.
185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            initializedSuperClasses(programClass).equals(initializedSuperClasses(targetClass))   &&
186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The two classes must have the same superclasses and interfaces
188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // that are tested with 'instanceof'.
189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            instanceofedSuperClasses(programClass).equals(instanceofedSuperClasses(targetClass)) &&
190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The two classes must have the same superclasses that are caught
192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // as exceptions.
193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            caughtSuperClasses(programClass).equals(caughtSuperClasses(targetClass)) &&
194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The two classes must not both be part of a .class construct.
196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !(DotClassMarker.isDotClassed(programClass) &&
197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              DotClassMarker.isDotClassed(targetClass)) &&
198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The two classes must not introduce any unwanted fields.
200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !introducesUnwantedFields(programClass, targetClass) &&
201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !introducesUnwantedFields(targetClass, programClass) &&
202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The classes must not have clashing constructors.
204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !haveAnyIdenticalInitializers(programClass, targetClass) &&
205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The classes must not introduce abstract methods, unless
207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // explicitly allowed.
208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            (mergeInterfacesAggressively ||
209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             (!introducesUnwantedAbstractMethods(programClass, targetClass) &&
210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              !introducesUnwantedAbstractMethods(targetClass, programClass))) &&
211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The classes must not override each others concrete methods.
213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !overridesAnyMethods(programClass, targetClass) &&
214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !overridesAnyMethods(targetClass, programClass) &&
215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // The classes must not shadow each others non-private methods.
217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !shadowsAnyMethods(programClass, targetClass) &&
218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            !shadowsAnyMethods(targetClass, programClass))
219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (DEBUG)
221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("ClassMerger ["+programClass.getName()+"] -> ["+targetClass.getName()+"]");
223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("  Source interface? ["+((programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]");
224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("  Target interface? ["+((targetClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]");
225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("  Source subclasses ["+programClass.subClasses+"]");
226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("  Target subclasses ["+targetClass.subClasses+"]");
227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("  Source superclass ["+programClass.getSuperClass().getName()+"]");
228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println("  Target superclass ["+targetClass.getSuperClass().getName()+"]");
229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Combine the access flags.
232b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            int targetAccessFlags = targetClass.getAccessFlags();
233b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            int sourceAccessFlags = programClass.getAccessFlags();
234b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            targetClass.u2accessFlags =
236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                ((targetAccessFlags &
237b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                  sourceAccessFlags) &
2389f606f95f03a75961498803e24bee6799a7c0885Ying Wang                 (ClassConstants.INTERNAL_ACC_INTERFACE  |
239b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                  ClassConstants.INTERNAL_ACC_ABSTRACT)) |
240b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                ((targetAccessFlags |
241b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                  sourceAccessFlags) &
2429f606f95f03a75961498803e24bee6799a7c0885Ying Wang                 (ClassConstants.INTERNAL_ACC_PUBLIC     |
243b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                  ClassConstants.INTERNAL_ACC_ANNOTATTION |
244b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                  ClassConstants.INTERNAL_ACC_ENUM));
245b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Copy over the superclass, unless it's the target class itself.
247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            //if (!targetClass.getName().equals(programClass.getSuperName()))
248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            //{
249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            //    targetClass.u2superClass =
250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            //        new ConstantAdder(targetClass).addConstant(programClass, programClass.u2superClass);
251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            //}
252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Copy over the interfaces that aren't present yet and that
254b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // wouldn't cause loops in the class hierarchy.
255b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            programClass.interfaceConstantsAccept(
256b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new ExceptClassConstantFilter(targetClass.getName(),
257b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new ImplementedClassConstantFilter(targetClass,
258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new ImplementingClassConstantFilter(targetClass,
259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new InterfaceAdder(targetClass)))));
260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Copy over the class members.
262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            MemberAdder memberAdder =
2639f606f95f03a75961498803e24bee6799a7c0885Ying Wang                new MemberAdder(targetClass);
264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            programClass.fieldsAccept(memberAdder);
266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            programClass.methodsAccept(memberAdder);
267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Copy over the other attributes.
269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            programClass.attributesAccept(
270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                new AttributeAdder(targetClass, true));
271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Update the optimization information of the target class.
273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            ClassOptimizationInfo info =
274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                ClassOptimizationInfo.getClassOptimizationInfo(targetClass);
275b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (info != null)
276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                info.merge(ClassOptimizationInfo.getClassOptimizationInfo(programClass));
278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
279b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
280b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Remember to replace the inlined class by the target class.
281b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            setTargetClass(programClass, targetClass);
282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Visit the merged class, if required.
284b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (extraClassVisitor != null)
285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                extraClassVisitor.visitProgramClass(programClass);
287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Small utility methods.
293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether a given class is the only subclass of another given class.
296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean isOnlySubClass(Clazz        subClass,
298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                   ProgramClass clazz)
299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // TODO: The list of subclasses is not up to date.
301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return clazz.subClasses != null     &&
302b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               clazz.subClasses.length == 1 &&
303b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               clazz.subClasses[0].equals(subClass);
304b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
305b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
306b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
307b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns the set of indirectly implemented interfaces.
309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private Set indirectlyImplementedInterfaces(Clazz clazz)
311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set set = new HashSet();
313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        ReferencedClassVisitor referencedInterfaceCollector =
315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            new ReferencedClassVisitor(
316b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            new ClassHierarchyTraveler(false, false, true, false,
317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            new ClassCollector(set)));
318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all superclasses and  collect their interfaces.
320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.superClassConstantAccept(referencedInterfaceCollector);
321b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
322b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all interfaces and collect their interfaces.
323b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.interfaceConstantsAccept(referencedInterfaceCollector);
324b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
325b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return set;
326b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
327b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
328b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
329b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
330b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns the set of superclasses and interfaces that are initialized.
331b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
332b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private Set initializedSuperClasses(Clazz clazz)
333b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
334b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set set = new HashSet();
335b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
336b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all superclasses and interfaces, collecting the ones that have
337b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // static initializers.
338b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.hierarchyAccept(true, true, true, false,
3399f606f95f03a75961498803e24bee6799a7c0885Ying Wang                              new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
3409f606f95f03a75961498803e24bee6799a7c0885Ying Wang                                                     ClassConstants.INTERNAL_METHOD_TYPE_INIT,
3419f606f95f03a75961498803e24bee6799a7c0885Ying Wang                              new MemberToClassVisitor(
3429f606f95f03a75961498803e24bee6799a7c0885Ying Wang                              new ClassCollector(set))));
343b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
344b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return set;
345b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
346b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
347b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
348b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
349b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns the set of superclasses and interfaces that are used in
350b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * 'instanceof' tests.
351b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
352b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private Set instanceofedSuperClasses(Clazz clazz)
353b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
354b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set set = new HashSet();
355b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
356b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all superclasses and interfaces, collecting the ones that are
357b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // used in an 'instanceof' test.
358b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.hierarchyAccept(true, true, true, false,
359b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new InstanceofClassFilter(
360b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new ClassCollector(set)));
361b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
362b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return set;
363b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
364b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
365b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
366b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
367b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns the set of superclasses that are caught as exceptions.
368b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
369b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private Set caughtSuperClasses(Clazz clazz)
370b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
371b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set set = new HashSet();
372b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
3739f606f95f03a75961498803e24bee6799a7c0885Ying Wang        // Visit all superclasses, collecting the ones that are caught.
374b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.hierarchyAccept(true, true, false, false,
375b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new CaughtClassFilter(
3769f606f95f03a75961498803e24bee6799a7c0885Ying Wang                              new ClassCollector(set)));
377b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
378b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return set;
379b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
380b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
381b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
382b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
383b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given class would introduce any unwanted fields
384b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * in the target class.
385b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
386b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean introducesUnwantedFields(ProgramClass programClass,
387b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                             ProgramClass targetClass)
388b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
389b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // The class must not have any fields, or it must not be instantiated,
390b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // without any other subclasses.
391b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return
392b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            programClass.u2fieldsCount != 0 &&
393b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            (InstantiationClassMarker.isInstantiated(targetClass) ||
394b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             (targetClass.subClasses != null &&
395b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              !isOnlySubClass(programClass, targetClass)));
396b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
397b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
398b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
399b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
400b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the two given classes have initializers with the same
401b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * descriptors.
402b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
403b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean haveAnyIdenticalInitializers(Clazz clazz, Clazz targetClass)
404b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
405b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        MemberCounter counter = new MemberCounter();
406b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
407b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // TODO: Currently checking shared methods, not just initializers.
408b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // TODO: Allow identical methods.
409b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all methods, counting the ones that are also present in the
410b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // target class.
411b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.methodsAccept(//new MemberNameFilter(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT),
412b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new SimilarMemberVisitor(targetClass, true, false, false, false,
413b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT,
414b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            counter)));
415b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
416b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return counter.getCount() > 0;
417b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
418b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
419b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
420b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
421b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given class would introduce any abstract methods
422b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * in the target class.
423b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
424b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean introducesUnwantedAbstractMethods(Clazz        clazz,
425b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                      ProgramClass targetClass)
426b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
427b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // It's ok if the target class is already abstract and it has at most
428b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // the class as a subclass.
429b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if ((targetClass.getAccessFlags() &
430b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             (ClassConstants.INTERNAL_ACC_ABSTRACT |
431b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato              ClassConstants.INTERNAL_ACC_INTERFACE)) != 0 &&
432b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            (targetClass.subClasses == null ||
433b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato             isOnlySubClass(clazz, targetClass)))
434b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
435b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            return false;
436b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
437b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
438b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        MemberCounter counter   = new MemberCounter();
439b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set           targetSet = new HashSet();
440b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
441b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Collect all abstract methods, and similar abstract methods in the
442b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // class hierarchy of the target class.
443b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.methodsAccept(new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0,
444b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new MultiMemberVisitor(new MemberVisitor[]
445b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            {
446b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                counter,
447b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                new SimilarMemberVisitor(targetClass, true, true, true, false,
448b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                         new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0,
449b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                                         new MemberCollector(targetSet)))
450b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            })));
451b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
452b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return targetSet.size() < counter.getCount();
453b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
454b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
455b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
456b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
457b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given class overrides any methods in the given
458b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * target class.
459b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
460b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean overridesAnyMethods(Clazz clazz, Clazz targetClass)
461b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
462b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        MemberCounter counter = new MemberCounter();
463b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
464b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all non-private non-static methods, counting the ones that are
465b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // being overridden in the class hierarchy of the target class.
466b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT,
467b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)),
468b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)),
469b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new SimilarMemberVisitor(targetClass, true, true, false, false,
470b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT,
471b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                            counter))))));
472b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
473b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return counter.getCount() > 0;
474b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
475b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
476b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
477b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
478b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given class or its subclasses shadow any methods in
479b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * the given target class.
480b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
481b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean shadowsAnyMethods(Clazz clazz, Clazz targetClass)
482b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
483b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        MemberCounter counter = new MemberCounter();
484b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
485b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all private methods, counting the ones that are shadowing
486b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // non-private methods in the class hierarchy of the target class.
487b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.hierarchyAccept(true, false, false, true,
488b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new AllMethodVisitor(
489b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0,
490b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)),
491b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new SimilarMemberVisitor(targetClass, true, true, true, false,
492b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
493b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              counter))))));
494b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
495b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Visit all static methods, counting the ones that are shadowing
496b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // non-private methods in the class hierarchy of the target class.
497b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        clazz.hierarchyAccept(true, false, false, true,
498b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new AllMethodVisitor(
499b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new MemberAccessFilter(ClassConstants.INTERNAL_ACC_STATIC, 0,
500b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)),
501b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new SimilarMemberVisitor(targetClass, true, true, true, false,
502b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
503b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                              counter))))));
504b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
505b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return counter.getCount() > 0;
506b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
507b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
508b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
509b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public static void setTargetClass(Clazz clazz, Clazz targetClass)
510b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
511b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
512b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (info != null)
513b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
514b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            info.setTargetClass(targetClass);
515b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
516b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
517b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
518b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
519b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public static Clazz getTargetClass(Clazz clazz)
520b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
521b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Clazz targetClass = null;
522b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
523b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Return the last target class, if any.
524b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (true)
525b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
526b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            ClassOptimizationInfo info = ClassOptimizationInfo.getClassOptimizationInfo(clazz);
527b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (info == null)
528b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
529b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                return targetClass;
530b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
531b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
532b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            clazz = info.getTargetClass();
533b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (clazz == null)
534b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
535b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                return targetClass;
536b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
537b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
538b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            targetClass = clazz;
539b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
540b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
541b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}