1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2008 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.file;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.Constant;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstArray;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstLiteralBits;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.Zeroes;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.AnnotatedOutput;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ByteArrayAnnotatedOutput;
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Hex;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Writers;
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.PrintWriter;
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.Writer;
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList;
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Arrays;
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Collections;
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.List;
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.HashMap;
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Representation of all the parts of a Dalvik class that are generally
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * "inflated" into an in-memory representation at runtime. Instances of
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * this class are represented in a compact streamable form in a
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code dex} file, as opposed to a random-access form.
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class ClassDataItem extends OffsettedItem {
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} what class this data is for, just for listing generation */
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final CstType thisClass;
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of static fields */
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ArrayList<EncodedField> staticFields;
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of initial values for static fields */
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final HashMap<EncodedField, Constant> staticValues;
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of instance fields */
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ArrayList<EncodedField> instanceFields;
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of direct methods */
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ArrayList<EncodedMethod> directMethods;
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of virtual methods */
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ArrayList<EncodedMethod> virtualMethods;
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code null-ok;} static initializer list; set in {@link #addContents} */
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private CstArray staticValuesConstant;
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code null-ok;} encoded form, ready for writing to a file; set during
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@link #place0}
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private byte[] encodedForm;
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance. Its sets of members are initially
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * empty.
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param thisClass {@code non-null;} what class this data is for, just
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * for listing generation
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public ClassDataItem(CstType thisClass) {
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        super(1, -1);
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (thisClass == null) {
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("thisClass == null");
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.thisClass = thisClass;
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.staticFields = new ArrayList<EncodedField>(20);
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.staticValues = new HashMap<EncodedField, Constant>(40);
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.instanceFields = new ArrayList<EncodedField>(20);
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.directMethods = new ArrayList<EncodedMethod>(20);
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.virtualMethods = new ArrayList<EncodedMethod>(20);
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.staticValuesConstant = null;
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public ItemType itemType() {
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return ItemType.TYPE_CLASS_DATA_ITEM;
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public String toHuman() {
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return toString();
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Returns whether this instance is empty.
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code true} if this instance is empty or
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code false} if at least one element has been added to it
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public boolean isEmpty() {
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return staticFields.isEmpty() && instanceFields.isEmpty()
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            && directMethods.isEmpty() && virtualMethods.isEmpty();
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Adds a static field.
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param field {@code non-null;} the field to add
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param value {@code null-ok;} initial value for the field, if any
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void addStaticField(EncodedField field, Constant value) {
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (field == null) {
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("field == null");
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (staticValuesConstant != null) {
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new UnsupportedOperationException(
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "static fields already sorted");
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        staticFields.add(field);
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        staticValues.put(field, value);
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Adds an instance field.
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param field {@code non-null;} the field to add
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void addInstanceField(EncodedField field) {
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (field == null) {
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("field == null");
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        instanceFields.add(field);
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Adds a direct ({@code static} and/or {@code private}) method.
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param method {@code non-null;} the method to add
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void addDirectMethod(EncodedMethod method) {
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (method == null) {
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("method == null");
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        directMethods.add(method);
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Adds a virtual method.
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param method {@code non-null;} the method to add
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void addVirtualMethod(EncodedMethod method) {
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (method == null) {
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("method == null");
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        virtualMethods.add(method);
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets all the methods in this class. The returned list is not linked
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * in any way to the underlying lists contained in this instance, but
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the objects contained in the list are shared.
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} list of all methods
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public ArrayList<EncodedMethod> getMethods() {
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = directMethods.size() + virtualMethods.size();
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz);
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        result.addAll(directMethods);
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        result.addAll(virtualMethods);
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Prints out the contents of this instance, in a debugging-friendly
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * way.
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to output to
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param verbose whether to be verbose with the output
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void debugPrint(Writer out, boolean verbose) {
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        PrintWriter pw = Writers.printWriterFor(out);
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = staticFields.size();
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            pw.println("  sfields[" + i + "]: " + staticFields.get(i));
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sz = instanceFields.size();
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            pw.println("  ifields[" + i + "]: " + instanceFields.get(i));
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sz = directMethods.size();
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            pw.println("  dmeths[" + i + "]:");
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            directMethods.get(i).debugPrint(pw, verbose);
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        sz = virtualMethods.size();
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            pw.println("  vmeths[" + i + "]:");
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            virtualMethods.get(i).debugPrint(pw, verbose);
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void addContents(DexFile file) {
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!staticFields.isEmpty()) {
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            getStaticValuesConstant(); // Force the fields to be sorted.
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (EncodedField field : staticFields) {
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                field.addContents(file);
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!instanceFields.isEmpty()) {
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Collections.sort(instanceFields);
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (EncodedField field : instanceFields) {
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                field.addContents(file);
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!directMethods.isEmpty()) {
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Collections.sort(directMethods);
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (EncodedMethod method : directMethods) {
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                method.addContents(file);
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!virtualMethods.isEmpty()) {
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Collections.sort(virtualMethods);
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (EncodedMethod method : virtualMethods) {
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                method.addContents(file);
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets a {@link CstArray} corresponding to {@link #staticValues} if
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * it contains any non-zero non-{@code null} values.
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code null-ok;} the corresponding constant or {@code null} if
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * there are no values to encode
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public CstArray getStaticValuesConstant() {
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((staticValuesConstant == null) && (staticFields.size() != 0)) {
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            staticValuesConstant = makeStaticValuesConstant();
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return staticValuesConstant;
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets a {@link CstArray} corresponding to {@link #staticValues} if
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * it contains any non-zero non-{@code null} values.
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code null-ok;} the corresponding constant or {@code null} if
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * there are no values to encode
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private CstArray makeStaticValuesConstant() {
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // First sort the statics into their final order.
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Collections.sort(staticFields);
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Get the size of staticValues minus any trailing zeros/nulls (both
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * nulls per se as well as instances of CstKnownNull).
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = staticFields.size();
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        while (size > 0) {
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            EncodedField field = staticFields.get(size - 1);
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Constant cst = staticValues.get(field);
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (cst instanceof CstLiteralBits) {
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // Note: CstKnownNull extends CstLiteralBits.
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (((CstLiteralBits) cst).getLongBits() != 0) {
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else if (cst != null) {
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            size--;
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (size == 0) {
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return null;
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // There is something worth encoding, so build up a result.
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CstArray.List list = new CstArray.List(size);
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            EncodedField field = staticFields.get(i);
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Constant cst = staticValues.get(field);
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (cst == null) {
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                cst = Zeroes.zeroFor(field.getRef().getType());
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            list.set(i, cst);
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        list.setImmutable();
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new CstArray(list);
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    protected void place0(Section addedTo, int offset) {
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Encode the data and note the size.
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput();
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeOutput(addedTo.getFile(), out);
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodedForm = out.toByteArray();
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        setWriteSize(encodedForm.length);
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Writes out the encoded form of this instance.
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code non-null;} file this instance is part of
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to write to
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void encodeOutput(DexFile file, AnnotatedOutput out) {
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        boolean annotates = out.annotates();
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotates) {
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.annotate(0, offsetString() + " class data for " +
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    thisClass.toHuman());
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeSize(file, out, "static_fields", staticFields.size());
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeSize(file, out, "instance_fields", instanceFields.size());
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeSize(file, out, "direct_methods", directMethods.size());
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeSize(file, out, "virtual_methods", virtualMethods.size());
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeList(file, out, "static_fields", staticFields);
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeList(file, out, "instance_fields", instanceFields);
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeList(file, out, "direct_methods", directMethods);
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        encodeList(file, out, "virtual_methods", virtualMethods);
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotates) {
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.endAnnotation();
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #encodeOutput}, which writes out the given
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * size value, annotating it as well (if annotations are enabled).
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code non-null;} file this instance is part of
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to write to
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param label {@code non-null;} the label for the purposes of annotation
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param size {@code >= 0;} the size to write
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void encodeSize(DexFile file, AnnotatedOutput out,
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            String label, int size) {
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (out.annotates()) {
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.annotate(String.format("  %-21s %08x", label + "_size:",
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            size));
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        out.writeUnsignedLeb128(size);
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #encodeOutput}, which writes out the given
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * list. It also annotates the items (if any and if annotations
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * are enabled).
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code non-null;} file this instance is part of
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to write to
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param label {@code non-null;} the label for the purposes of annotation
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param list {@code non-null;} the list in question
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void encodeList(DexFile file, AnnotatedOutput out,
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            String label, ArrayList<? extends EncodedMember> list) {
397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int size = list.size();
398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int lastIndex = 0;
399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (size == 0) {
401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return;
402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (out.annotates()) {
405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.annotate(0, "  " + label + ":");
406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < size; i++) {
409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastIndex = list.get(i).encode(file, out, lastIndex, i);
410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@inheritDoc} */
414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    @Override
415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void writeTo0(DexFile file, AnnotatedOutput out) {
416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        boolean annotates = out.annotates();
417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (annotates) {
419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * The output is to be annotated, so redo the work previously
421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * done by place0(), except this time annotations will actually
422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * get emitted.
423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            encodeOutput(file, out);
425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.write(encodedForm);
427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
430