ClassProto.java revision 9d8cf0d67c2d9cce3e8d4cf59f78e0475241ce23
1bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2013, Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * All rights reserved.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Redistribution and use in source and binary forms, with or without
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * modification, are permitted provided that the following conditions are
7bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com * met:
8bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com *
9b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com *     * Redistributions of source code must retain the above copyright
101f2f338e23789f3eef168dcbd8171a28820ba6c1robertphillips@google.com * notice, this list of conditions and the following disclaimer.
1110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com *     * Redistributions in binary form must reproduce the above
12bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com * copyright notice, this list of conditions and the following disclaimer
1310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * in the documentation and/or other materials provided with the
148a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com * distribution.
1510dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com *     * Neither the name of Google Inc. nor the names of its
16acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com * contributors may be used to endorse or promote products derived from
17bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com * this software without specific prior written permission.
1816d1d0b39a78fa4ab4fbd6ed3296cf010ea9a61cscroggo@google.com *
1910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
208b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2110dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2410dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
254ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2610dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com */
31b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com
324ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.compackage org.jf.dexlib2.analysis;
334ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com
344ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.comimport com.google.common.collect.Iterables;
354ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.comimport com.google.common.collect.Lists;
360c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.comimport com.google.common.collect.Maps;
370c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.comimport org.jf.dexlib2.AccessFlags;
380c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.comimport org.jf.dexlib2.analysis.util.TypeProtoUtils;
390c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.comimport org.jf.dexlib2.iface.ClassDef;
40b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport org.jf.dexlib2.iface.Field;
41b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport org.jf.dexlib2.iface.Method;
42b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport org.jf.dexlib2.iface.reference.FieldReference;
43b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport org.jf.dexlib2.iface.reference.MethodReference;
440faac1e8579088a39f38d02ff675f14d7deb608dreed@google.comimport org.jf.dexlib2.util.FieldUtil;
45b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport org.jf.util.ExceptionWithContext;
46b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport org.jf.util.SparseArray;
47b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com
48b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport javax.annotation.Nonnull;
4916d1d0b39a78fa4ab4fbd6ed3296cf010ea9a61cscroggo@google.comimport javax.annotation.Nullable;
50b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.comimport java.util.*;
51b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com
520c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com/**
53b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com * A class "prototype". This contains things like the interfaces, the superclass, the vtable and the instance fields
54b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com * and their offsets.
55bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com */
56f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.compublic class ClassProto implements TypeProto {
57f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Nonnull protected final ClassPath classPath;
58f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Nonnull protected final String type;
59f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Nullable protected ClassDef classDef;
60f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Nullable protected LinkedHashMap<String, ClassDef> interfaces;
61f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Nullable protected Method[] vtable;
62f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Nullable protected SparseArray<FieldReference> instanceFields;
638a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com    protected boolean interfacesFullyResolved = true;
6459f46b81f8bdd1b524f5cc43bc27603f9604c71arobertphillips@google.com
65f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    public ClassProto(@Nonnull ClassPath classPath, @Nonnull String type) {
665af9b2032b552516c9223d9fb22185b022b13c62scroggo@google.com        if (type.charAt(0) != 'L') {
67f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com            throw new ExceptionWithContext("Cannot construct ClassProto for non reference type: %s", type);
68f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com        }
69bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        this.classPath = classPath;
70bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        this.type = type;
714dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
724dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
73664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    @Override public String toString() { return type; }
74a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    @Nonnull @Override public ClassPath getClassPath() { return classPath; }
75a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    @Nonnull @Override public String getType() { return type; }
76664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com
77664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    @Nonnull
78664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com    public ClassDef getClassDef() {
79664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com        if (classDef == null) {
800c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            classDef = classPath.getClassDef(type);
814dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        }
824dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        return classDef;
834dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
844dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
854dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    @Nonnull
864dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    Method[] getVtable() {
874dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        if (vtable == null) {
884dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            vtable = loadVtable();
894dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        }
907ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com        return vtable;
917ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com    }
927ca24437c71af06fc06ab5f6f261b185882fa440scroggo@google.com
93d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    @Nonnull
944dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    SparseArray<FieldReference> getInstanceFields() {
954dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        if (instanceFields == null) {
964dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            instanceFields = loadFields();
974dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        }
984dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        return instanceFields;
994dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
1004dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1014dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    /**
1024dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * Returns true if this class is an interface.
1034dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     *
1044dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * If this class is not defined, then this will throw an UnresolvedClassException
1054dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     *
1064dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     * @return True if this class is an interface
1074dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com     */
1084dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    public boolean isInterface() {
1094dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        ClassDef classDef = getClassDef();
1104dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        return (classDef.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0;
1114dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    }
112a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org
113a2bd2d12ad9504583e9311404fcd82b40df49d30commit-bot@chromium.org    @Nonnull
1144dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com    protected LinkedHashMap<String, ClassDef> getInterfaces() {
1154dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        if (interfaces != null) {
1164dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            return interfaces;
1174dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        }
1184dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1194dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        interfaces = Maps.newLinkedHashMap();
1204dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1214dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        try {
1224dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            for (String interfaceType: getClassDef().getInterfaces()) {
1234dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                if (!interfaces.containsKey(interfaceType)) {
1244dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    ClassDef interfaceDef;
1254dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    try {
1264dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        interfaceDef = classPath.getClassDef(interfaceType);
1274dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        interfaces.put(interfaceType, interfaceDef);
1284dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    } catch (UnresolvedClassException ex) {
1294dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        interfaces.put(interfaceType, null);
1304dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        interfacesFullyResolved = false;
1314dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    }
1324dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1334dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    ClassProto interfaceProto = (ClassProto) classPath.getClass(interfaceType);
1344dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    for (String superInterface: interfaceProto.getInterfaces().keySet()) {
1354dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        if (!interfaces.containsKey(superInterface)) {
1364dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                            interfaces.put(superInterface, interfaceProto.getInterfaces().get(superInterface));
1374dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        }
1384dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    }
1394dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    if (!interfaceProto.interfacesFullyResolved) {
1404dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                        interfacesFullyResolved = false;
1414dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    }
1424dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                }
1434dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            }
1444dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        } catch (UnresolvedClassException ex) {
1454dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            interfacesFullyResolved = false;
1464dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        }
1474dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1484dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        // now add self and super class interfaces, required for common super class lookup
1494dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        // we don't really need ClassDef's for that, so let's just use null
1504dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
1514dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        if (isInterface() && !interfaces.containsKey(getType())) {
1524dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            interfaces.put(getType(), null);
1534dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        }
1544dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
15507adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org        try {
156186c0ccac25229534ec6fb84726043083304d4d1commit-bot@chromium.org            String superclass = getSuperclass();
15707adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org            if (superclass != null) {
1584dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                ClassProto superclassProto = (ClassProto) classPath.getClass(superclass);
15907adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                for (String superclassInterface: superclassProto.getInterfaces().keySet()) {
1604dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    if (!interfaces.containsKey(superclassInterface)) {
16107adb6359fd137ccb633b2c64ee2287c8edfd701commit-bot@chromium.org                        interfaces.put(superclassInterface, null);
1624dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    }
1634dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                }
1644dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            }
16559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        } catch (UnresolvedClassException ex) {
16659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            // TODO: not sure if this is necessary
16759c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            interfacesFullyResolved = false;
16859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        }
16959c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
17059c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        return interfaces;
17159c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    }
17259c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
17359c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    @Nonnull
17459c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    protected LinkedHashMap<String, ClassDef> getInterfacesFull() {
17559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        LinkedHashMap<String, ClassDef> interfaces = getInterfaces();
17659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
17759c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        if (!interfacesFullyResolved) {
17859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            throw new UnresolvedClassException("Interfaces for class %s not fully resolved", getType());
17959c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        }
18059c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        return interfaces;
18159c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    }
18259c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
18359c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    /**
18459c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * Checks if this class implements the given interface.
18559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
18659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * If the interfaces of this class cannot be fully resolved then this
18759c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * method will either return true or throw an UnresolvedClassException
18859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
189bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com     * @param iface The interface to check for
190bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com     * @return true if this class implements the given interface, otherwise false
191a8db8fe39a640bda4b85b9342c3b6b2525142afajunov@chromium.org     */
192a8db8fe39a640bda4b85b9342c3b6b2525142afajunov@chromium.org    @Override
193bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    public boolean implementsInterface(@Nonnull String iface) {
194bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        if (getInterfaces().containsKey(iface)) {
19559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            return true;
19659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        }
19759c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        if (!interfacesFullyResolved) {
19859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            throw new UnresolvedClassException("Interfaces for class %s not fully resolved", getType());
19959c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        }
20059c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        return false;
20159c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    }
20259c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
20359c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    @Nullable @Override
20459c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    public String getSuperclass() {
20559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        return getClassDef().getSuperclass();
20659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    }
20759c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
20859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com    /**
20959c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * This is a helper method for getCommonSuperclass
21059c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
211bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com     * It checks if this class is an interface, and if so, if other implements it.
21259c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
21359c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * If this class is undefined, we go ahead and check if it is listed in other's interfaces. If not, we throw an
21459c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * UndefinedClassException
21559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
21659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * If the interfaces of other cannot be fully resolved, we check the interfaces that can be resolved. If not found,
21759c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * we throw an UndefinedClassException
21859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
21959c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * @param other The class to check the interfaces of
22059c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     * @return true if this class is an interface (or is undefined) other implements this class
22159c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com     *
222bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com     */
223bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    private boolean checkInterface(@Nonnull ClassProto other) {
22477eec248cbd5a0c2f5f8595e62e3bff5ea363f17junov@chromium.org        boolean isResolved = true;
2252e14ba8ceb41c68042ff133fecf0561a2c22efcajunov@chromium.org        boolean isInterface = true;
22677eec248cbd5a0c2f5f8595e62e3bff5ea363f17junov@chromium.org        try {
22715011ee5e4068ab6523e432e435473a822ee7d80scroggo@google.com            isInterface = isInterface();
228d5d158b325f05902ac845f2f7c8c65ffe6074257scroggo@google.com        } catch (UnresolvedClassException ex) {
22915011ee5e4068ab6523e432e435473a822ee7d80scroggo@google.com            isResolved = false;
23015011ee5e4068ab6523e432e435473a822ee7d80scroggo@google.com            // if we don't know if this class is an interface or not,
231bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            // we can still try to call other.implementsInterface(this)
232fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        }
2333b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com        if (isInterface) {
2343b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com            try {
235bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                if (other.implementsInterface(getType())) {
2363b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com                    return true;
2374ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com                }
2387ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com            } catch (UnresolvedClassException ex) {
2394ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com                // There are 2 possibilities here, depending on whether we were able to resolve this class.
2407ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com                // 1. If this class is resolved, then we know it is an interface class. The other class either
241bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                //    isn't defined, or its interfaces couldn't be fully resolved.
2423b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com                //    In this case, we throw an UnresolvedClassException
2437112173c3c4cd1b1e7da8cdf971d71f01dd91299reed@google.com                // 2. If this class is not resolved, we had tried to call implementsInterface anyway. We don't
2447475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com                //    know for sure if this class is an interface or not. We return false, and let processing
245eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org                //    continue in getCommonSuperclass
246bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                if (isResolved) {
2473b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com                    throw ex;
2485a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com                }
2495a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com            }
250bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        }
2513b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com        return false;
2523b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com    }
253bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
254bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    @Override @Nonnull
255bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    public TypeProto getCommonSuperclass(@Nonnull TypeProto other) {
256bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        // use the other type's more specific implementation
2573b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com        if (!(other instanceof ClassProto)) {
2583b45cd53f0c4c9b810b6383f529a72ecfa4e6e7fscroggo@google.com            return other.getCommonSuperclass(this);
2590a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com        }
2600a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com
2610a4805e33f8ddb445a2fd061462e715e1707f049robertphillips@google.com        if (this == other || getType().equals(other.getType())) {
262bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            return this;
2633e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        }
2643e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com
2653e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        if (this.getType().equals("Ljava/lang/Object;")) {
2663e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com            return this;
2673e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        }
268ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org
269ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org        if (other.getType().equals("Ljava/lang/Object;")) {
270e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org            return other;
271e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        }
272e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org
273e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        boolean gotException = false;
27444c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org        try {
27544c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org            if (checkInterface((ClassProto)other)) {
27644c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org                return this;
277ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org            }
278e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com        } catch (UnresolvedClassException ex) {
279e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com            gotException = true;
280e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com        }
281e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com
282e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com        try {
283e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com            if (((ClassProto)other).checkInterface(this)) {
284e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com                return other;
285e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com            }
286ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org        } catch (UnresolvedClassException ex) {
2878f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com            gotException = true;
2888f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com        }
2898f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com        if (gotException) {
2908f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com            return classPath.getUnknownClass();
2918f90a892c5130d4d26b5588e1ff151d01a40688arobertphillips@google.com        }
292bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
293d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        List<TypeProto> thisChain = Lists.<TypeProto>newArrayList(this);
294d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        Iterables.addAll(thisChain, TypeProtoUtils.getSuperclassChain(this));
295d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org
296d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        List<TypeProto> otherChain = Lists.newArrayList(other);
297fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        Iterables.addAll(otherChain, TypeProtoUtils.getSuperclassChain(other));
298fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org
299fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        // reverse them, so that the first entry is either Ljava/lang/Object; or Ujava/lang/Object;
3000c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        thisChain = Lists.reverse(thisChain);
3010c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        otherChain = Lists.reverse(otherChain);
302d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com
303acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        for (int i=Math.min(thisChain.size(), otherChain.size())-1; i>=0; i--) {
3040c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            TypeProto typeProto = thisChain.get(i);
3050c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            if (typeProto.getType().equals(otherChain.get(i).getType())) {
3060c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com                return typeProto;
3070c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            }
3083e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        }
309bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
3100c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        return classPath.getUnknownClass();
311f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    }
312f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com
313f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    @Override
314acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    @Nullable
315bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    public FieldReference getFieldByOffset(int fieldOffset) {
316bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        if (getInstanceFields().size() == 0) {
31774b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org            return null;
318acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        }
319bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        return getInstanceFields().get(fieldOffset);
320bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    }
321acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com
322acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    @Override
323acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    @Nullable
324acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    public MethodReference getMethodByVtableIndex(int vtableIndex) {
325acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        if (vtableIndex < 0 || vtableIndex >= getVtable().length) {
3264469938e92d779dff05e745559e67907bbf21e78reed@google.com            return null;
32716d1d0b39a78fa4ab4fbd6ed3296cf010ea9a61cscroggo@google.com        }
32816d1d0b39a78fa4ab4fbd6ed3296cf010ea9a61cscroggo@google.com        return getVtable()[vtableIndex];
32916d1d0b39a78fa4ab4fbd6ed3296cf010ea9a61cscroggo@google.com    }
33016d1d0b39a78fa4ab4fbd6ed3296cf010ea9a61cscroggo@google.com
331acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    @Nonnull
332acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    private SparseArray<FieldReference> loadFields() {
333b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com        //This is a bit of an "involved" operation. We need to follow the same algorithm that dalvik uses to
3340c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        //arrange fields, so that we end up with the same field offsets (which is needed for deodexing).
3350c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        //See mydroid/dalvik/vm/oo/Class.c - computeFieldOffsets()
3360c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com
3370c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        final byte REFERENCE = 0;
33859c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        final byte WIDE = 1;
33959c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        final byte OTHER = 2;
34059c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com
34159c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        ArrayList<Field> loadedFields = getInstanceFields(getClassDef());
34259c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        Field[] fields = new Field[loadedFields.size()];
343b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com        //the "type" for each field in fields. 0=reference,1=wide,2=other
344b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com        byte[] fieldTypes = new byte[fields.length];
3453e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        for (int i=0;i<fields.length;i++) {
3463e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com            fields[i] = loadedFields.get(i);
3473e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com            fieldTypes[i] = getFieldType(fields[i].getType());
3483e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        }
34958be682c77c76d9a0caf23337f9b357798179b6cscroggo@google.com
35031891584fef10c88b39f6bf19ac5cde0a862b8c4reed@google.com        //The first operation is to move all of the reference fields to the front. To do this, find the first
35131891584fef10c88b39f6bf19ac5cde0a862b8c4reed@google.com        //non-reference field, then find the last reference field, swap them and repeat
352bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        int back = fields.length - 1;
353acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        int front;
354acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        for (front = 0; front<fields.length; front++) {
355acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            if (fieldTypes[front] != REFERENCE) {
356acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                while (back > front) {
357acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                    if (fieldTypes[back] == REFERENCE) {
358acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                        swap(fieldTypes, fields, front, back--);
359acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                        break;
360acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                    }
361acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                    back--;
362bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                }
363bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            }
364bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
3650c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            if (fieldTypes[front] != REFERENCE) {
3660c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com                break;
3670c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            }
3680c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        }
3690c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com
3700c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        int startFieldOffset = 8;
3710c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        String superclassType = getSuperclass();
3720c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        ClassProto superclass = null;
3730c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        if (superclassType != null) {
3740c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            superclass = (ClassProto) classPath.getClass(superclassType);
3750c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            if (superclass != null) {
3763e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com                startFieldOffset = superclass.getNextFieldOffset();
377565254bc9343d0befdfbbb97a3dc6d44c6e18658scroggo@google.com            }
3788b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org        }
3793e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com
38074b7ffda687c66d46ac3cfa4f2baedd4c62e3fbescroggo@google.com        int fieldIndexMod;
3813e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        if ((startFieldOffset % 8) == 0) {
3828b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org            fieldIndexMod = 0;
3833e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        } else {
3843e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com            fieldIndexMod = 1;
3853e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        }
3863e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com
3873e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        //next, we need to group all the wide fields after the reference fields. But the wide fields have to be
3884dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        //8-byte aligned. If we're on an odd field index, we need to insert a 32-bit field. If the next field
3893e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com        //is already a 32-bit field, use that. Otherwise, find the first 32-bit field from the end and swap it in.
390d3ba5cc85e24896f980ed1ba6e3f4495973baeb3scroggo@google.com        //If there are no 32-bit fields, do nothing for now. We'll add padding when calculating the field offsets
391d3ba5cc85e24896f980ed1ba6e3f4495973baeb3scroggo@google.com        if (front < fields.length && (front % 2) != fieldIndexMod) {
392b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com            if (fieldTypes[front] == WIDE) {
393d3ba5cc85e24896f980ed1ba6e3f4495973baeb3scroggo@google.com                //we need to swap in a 32-bit field, so the wide fields will be correctly aligned
394b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com                back = fields.length - 1;
395d5d158b325f05902ac845f2f7c8c65ffe6074257scroggo@google.com                while (back > front) {
396b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com                    if (fieldTypes[back] == OTHER) {
397b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com                        swap(fieldTypes, fields, front++, back);
398b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com                        break;
399b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com                    }
400d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com                    back--;
4014dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                }
402664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com            } else {
403664fab1b3454faea01cbae2f1dc2777c5afb9998scroggo@google.com                //there's already a 32-bit field here that we can use
404d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com                front++;
4054dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            }
4060c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        }
4070c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com
4080c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        //do the swap thing for wide fields
4090c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        back = fields.length - 1;
4100c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com        for (; front<fields.length; front++) {
4110c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com            if (fieldTypes[front] != WIDE) {
4120c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com                while (back > front) {
4130c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com                    if (fieldTypes[back] == WIDE) {
4140c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com                        swap(fieldTypes, fields, front, back--);
415b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com                        break;
4164dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    }
4174dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com                    back--;
418d3ba5cc85e24896f980ed1ba6e3f4495973baeb3scroggo@google.com                }
4194dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com            }
420b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com
421b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com            if (fieldTypes[front] != WIDE) {
422bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                break;
423bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            }
424acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        }
4254dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com
4264dffc596aa9fabd3104e66bc1f9957e8de4cb65dscroggo@google.com        int superFieldCount = 0;
427bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        if (superclass != null) {
428acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            superFieldCount = superclass.instanceFields.size();
429d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        }
430a8db8fe39a640bda4b85b9342c3b6b2525142afajunov@chromium.org
431403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org        //now the fields are in the correct order. Add them to the SparseArray and lookup, and calculate the offsets
432403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org        int totalFieldCount = superFieldCount + fields.length;
433403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org        SparseArray<FieldReference> instanceFields = new SparseArray<FieldReference>(totalFieldCount);
434403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org
435403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org        int fieldOffset;
436403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org
437403f8d7a052269583175e945689824838e5e0ef4commit-bot@chromium.org        if (superclass != null && superFieldCount > 0) {
438acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            for (int i=0; i<superFieldCount; i++) {
439bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                instanceFields.append(superclass.instanceFields.keyAt(i), superclass.instanceFields.valueAt(i));
440acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            }
4415a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com
442fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org            fieldOffset = instanceFields.keyAt(superFieldCount-1);
443b55d118e32062b1ddd88e7fcf8fa86303f887d8freed@google.com
444acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            FieldReference lastSuperField = superclass.instanceFields.valueAt(superFieldCount-1);
445565254bc9343d0befdfbbb97a3dc6d44c6e18658scroggo@google.com            char fieldType = lastSuperField.getType().charAt(0);
446565254bc9343d0befdfbbb97a3dc6d44c6e18658scroggo@google.com            if (fieldType == 'J' || fieldType == 'D') {
447565254bc9343d0befdfbbb97a3dc6d44c6e18658scroggo@google.com                fieldOffset += 8;
448565254bc9343d0befdfbbb97a3dc6d44c6e18658scroggo@google.com            } else {
449d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                fieldOffset += 4;
45010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com            }
45159c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        } else {
45259c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            //the field values start at 8 bytes into the DataObject dalvik structure
45310dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com            fieldOffset = 8;
454d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com        }
4553e26bd0c357d849ff40b092decd7a5c46ec2ada4scroggo@google.com
45610dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com        boolean gotDouble = false;
457d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com        for (int i=0; i<fields.length; i++) {
458d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com            FieldReference field = fields[i];
45910dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com
46010dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com            //add padding to align the wide fields, if needed
461d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com            if (fieldTypes[i] == WIDE && !gotDouble) {
46210dccde54a769b8d472bccf8c1993034b93ef58dscroggo@google.com                if (!gotDouble) {
463bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                    if (fieldOffset % 8 != 0) {
464bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                        assert fieldOffset % 8 == 4;
465bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                        fieldOffset += 4;
46659c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com                    }
4670c3e5fe728ce4b8606819ee919a4b82f4d9efc85scroggo@google.com                    gotDouble = true;
468d9d2967ce1cca98c7992ac034a6b6e0707c56051scroggo@google.com                }
469bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            }
470bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
471acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            instanceFields.append(fieldOffset, field);
472acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            if (fieldTypes[i] == WIDE) {
473acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                fieldOffset += 8;
474acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            } else {
475acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                fieldOffset += 4;
476acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            }
4774469938e92d779dff05e745559e67907bbf21e78reed@google.com        }
4785a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com
4795a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com        return instanceFields;
4805a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com    }
4815a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com
4825a2e879ef8a3720ac3f06fbc13dcdaeb179f30c3scroggo@google.com    private ArrayList<Field> getInstanceFields(ClassDef classDef) {
483acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        ArrayList<Field> instanceFields = Lists.newArrayList();
48459c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com        for (Field field: classDef.getFields()) {
48559c3ab637b7cb23c1afc098a2967518788a671eascroggo@google.com            if (!FieldUtil.isStatic(field)) {
486acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                instanceFields.add(field);
487acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            }
488460a23e6fd6b71c80d5515300c6b989cd3383029scroggo@google.com        }
489acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        return instanceFields;
490acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    }
491acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com
492acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    private byte getFieldType(String fieldType) {
493acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        switch (fieldType.charAt(0)) {
494acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            case '[':
495f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com            case 'L':
496f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com                return 0; //REFERENCE
497f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com            case 'J':
498f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com            case 'D':
499f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com                return 1; //WIDE
500f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com            default:
501f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com                return 2; //OTHER
502f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com        }
503bb6793bd7751f7a4e48c942567cd6c5270661a2freed@google.com    }
504f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com
505f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com    private void swap(byte[] fieldTypes, FieldReference[] fields, int position1, int position2) {
506f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com        byte tempType = fieldTypes[position1];
507f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com        fieldTypes[position1] = fieldTypes[position2];
508f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com        fieldTypes[position2] = tempType;
509f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com
510f5842f773b7e8612a52784b3c35c7455e67cb90areed@google.com        FieldReference tempField = fields[position1];
511bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        fields[position1] = fields[position2];
512bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        fields[position2] = tempField;
513acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    }
514acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com
515acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com    private int getNextFieldOffset() {
516e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        SparseArray<FieldReference> instanceFields = getInstanceFields();
517acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        if (instanceFields.size() == 0) {
518acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            return 8;
519acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        }
520acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com
521e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        int lastItemIndex = instanceFields.size()-1;
522e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        int fieldOffset = instanceFields.keyAt(lastItemIndex);
523bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        FieldReference lastField = instanceFields.valueAt(lastItemIndex);
524bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
525e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        switch (lastField.getType().charAt(0)) {
526e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org            case 'J':
527acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            case 'D':
528acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                return fieldOffset + 8;
529bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            default:
53074b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org                return fieldOffset + 4;
531bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        }
532bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    }
533acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com
534bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    //TODO: check the case when we have a package private method that overrides an interface method
535bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    @Nonnull
536bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    private Method[] loadVtable() {
53731891584fef10c88b39f6bf19ac5cde0a862b8c4reed@google.com        //TODO: it might be useful to keep track of which class's implementation is used for each virtual method. In other words, associate the implementing class type with each vtable entry
538bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        List<Method> virtualMethodList = Lists.newLinkedList();
539bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
540acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        //copy the virtual methods from the superclass
541acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        String superclassType = getSuperclass();
542acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        if (superclassType != null) {
543acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            ClassProto superclass = (ClassProto) classPath.getClass(superclassType);
544acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            for (int i=0; i<superclass.getVtable().length; i++) {
545bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                virtualMethodList.add(superclass.getVtable()[i]);
54674b461961607fa57a150a9282c410ef0cab38764vandebo@chromium.org            }
547fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        }
548fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org
549fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        //iterate over the virtual methods in the current class, and only add them when we don't already have the
550e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        //method (i.e. if it was implemented by the superclass)
551e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        if (!isInterface()) {
552e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org            addToVtable(getClassDef().getVirtualMethods(), virtualMethodList);
553e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org
554bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            for (ClassDef interfaceDef: getInterfacesFull().values()) {
555bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                if (interfaceDef != null) {
556e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org                    addToVtable(interfaceDef.getVirtualMethods(), virtualMethodList);
557acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                }
558acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com            }
559acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        }
560acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com
561fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        Method[] vtable = new Method[virtualMethodList.size()];
562e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        for (int i=0; i<virtualMethodList.size(); i++) {
563fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org            vtable[i] = virtualMethodList.get(i);
564fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        }
565e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org
566e54a23fcfa42b2fc9d320650de72bcb2d9566b2dcommit-bot@chromium.org        return vtable;
567fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org    }
568fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org
569fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org    private void addToVtable(@Nonnull Iterable<? extends Method> localMethods, @Nonnull List<Method> vtable) {
570fbe9c8fbb8e74ad55694f8bb7fa5463708e94a6djunov@chromium.org        List<? extends Method> methods = Lists.newArrayList(localMethods);
571bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        Collections.sort(methods);
572bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
573d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        for (Method virtualMethod: methods) {
574d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org            boolean found = false;
575d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org            for (int i=0; i<vtable.size(); i++) {
576d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org                Method superMethod = vtable.get(i);
577d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org                if (methodSignaturesMatch(superMethod, virtualMethod)) {
578bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                    if (classPath.getApi() < 17 || canAccess(superMethod)) {
579bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                        found = true;
580bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                        vtable.set(i, virtualMethod);
581d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org                        break;
582d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org                    }
583d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org                }
584d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org            }
585d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org            if (!found) {
586bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                vtable.add(virtualMethod);
587bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            }
588bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com        }
589d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org    }
590d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org
591d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org    private boolean methodSignaturesMatch(Method a, Method b) {
592d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        return (a.getName().equals(b.getName())
593bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                && a.getReturnType().equals(b.getReturnType())
594bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com                && a.getParameters().equals(b.getParameters()));
595bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    }
59644c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org
597bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    private boolean canAccess(Method virtualMethod) {
598acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        if (!methodIsPackagePrivate(virtualMethod.getAccessFlags())) {
599d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org            return true;
600d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        }
601d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org
602d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        String otherPackage = getPackage(virtualMethod.getDefiningClass());
603d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        String ourPackage = getPackage(getClassDef().getType());
604d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        return otherPackage.equals(ourPackage);
605d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org    }
606d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org
607d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org    private String getPackage(String classType) {
608d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        int lastSlash = classType.lastIndexOf('/');
609acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        if (lastSlash < 0) {
610bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com            return "";
611d9ea09e1f29b303e6fa36079e99729d2951925b9commit-bot@chromium.org        }
61244c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org        return classType.substring(1, lastSlash);
613bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com    }
614bb6992a9d6e21b3f28068765de0a41c6f2508dfdreed@google.com
61544c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org    private static boolean methodIsPackagePrivate(int accessFlags) {
616acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com        return (accessFlags & (AccessFlags.PRIVATE.getValue() |
61794e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com                AccessFlags.PROTECTED.getValue() |
618acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com                AccessFlags.PUBLIC.getValue())) == 0;
6192b2ede3e713065e1bac461787b0aafb03eaf871fdjsollen@google.com    }
620acd471f47ccfb97cf2f2f00dc01cd1fd45bc1ef2reed@google.com}
62144c48d062f7996b5b46917e1b312a32ad101f326commit-bot@chromium.org