OneLocalsArray.java revision 99409883d9c4c0ffb49b070ce307bb33a9dfe9f1
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.cf.code;
18
19import com.android.dx.rop.code.RegisterSpec;
20import com.android.dx.rop.type.Type;
21import com.android.dx.rop.type.TypeBearer;
22import com.android.dx.util.ExceptionWithContext;
23import com.android.dx.util.Hex;
24import com.android.dx.util.MutabilityControl;
25
26/**
27 * Representation of an array of local variables, with Java semantics.
28 *
29 * <p><b>Note:</b> For the most part, the documentation for this class
30 * ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link
31 * com.android.dx.rop.type.TypeBearer}.</p>
32 */
33public class OneLocalsArray extends LocalsArray {
34    /** {@code non-null;} actual array */
35    private final TypeBearer[] locals;
36
37    /**
38     * Constructs an instance. The locals array initially consists of
39     * all-uninitialized values (represented as {@code null}s).
40     *
41     * @param maxLocals {@code >= 0;} the maximum number of locals this instance
42     * can refer to
43     */
44    public OneLocalsArray(int maxLocals) {
45        super(maxLocals != 0);
46        locals = new TypeBearer[maxLocals];
47    }
48
49    /** @inheritDoc */
50    public OneLocalsArray copy() {
51        OneLocalsArray result = new OneLocalsArray(locals.length);
52
53        System.arraycopy(locals, 0, result.locals, 0, locals.length);
54
55        return result;
56    }
57
58    /** @inheritDoc */
59    public void annotate(ExceptionWithContext ex) {
60        for (int i = 0; i < locals.length; i++) {
61            TypeBearer type = locals[i];
62            String s = (type == null) ? "<invalid>" : type.toString();
63            ex.addContext("locals[" + Hex.u2(i) + "]: " + s);
64        }
65    }
66
67    /** {@inheritDoc*/
68    public String toHuman() {
69        StringBuilder sb = new StringBuilder();
70
71        for (int i = 0; i < locals.length; i++) {
72            TypeBearer type = locals[i];
73            String s = (type == null) ? "<invalid>" : type.toString();
74            sb.append("locals[" + Hex.u2(i) + "]: " + s + "\n");
75        }
76
77        return sb.toString();
78    }
79
80    /** @inheritDoc */
81    public void makeInitialized(Type type) {
82        int len = locals.length;
83
84        if (len == 0) {
85            // We have to check for this before checking for immutability.
86            return;
87        }
88
89        throwIfImmutable();
90
91        Type initializedType = type.getInitializedType();
92
93        for (int i = 0; i < len; i++) {
94            if (locals[i] == type) {
95                locals[i] = initializedType;
96            }
97        }
98    }
99
100    /** @inheritDoc */
101    public int getMaxLocals() {
102        return locals.length;
103    }
104
105    /** @inheritDoc */
106    public void set(int idx, TypeBearer type) {
107        throwIfImmutable();
108
109        try {
110            type = type.getFrameType();
111        } catch (NullPointerException ex) {
112            // Elucidate the exception
113            throw new NullPointerException("type == null");
114        }
115
116        if (idx < 0) {
117            throw new IndexOutOfBoundsException("idx < 0");
118        }
119
120        // Make highest possible out-of-bounds check happen first.
121        if (type.getType().isCategory2()) {
122            locals[idx + 1] = null;
123        }
124
125        locals[idx] = type;
126
127        if (idx != 0) {
128            TypeBearer prev = locals[idx - 1];
129            if ((prev != null) && prev.getType().isCategory2()) {
130                locals[idx - 1] = null;
131            }
132        }
133    }
134
135    /** @inheritDoc */
136    public void set(RegisterSpec spec) {
137        set(spec.getReg(), spec);
138    }
139
140    /** @inheritDoc */
141    public void invalidate(int idx) {
142        throwIfImmutable();
143        locals[idx] = null;
144    }
145
146    /** @inheritDoc */
147    public TypeBearer getOrNull(int idx) {
148        return locals[idx];
149    }
150
151    /** @inheritDoc */
152    public TypeBearer get(int idx) {
153        TypeBearer result = locals[idx];
154
155        if (result == null) {
156            return throwSimException(idx, "invalid");
157        }
158
159        return result;
160    }
161
162    /** @inheritDoc */
163    public TypeBearer getCategory1(int idx) {
164        TypeBearer result = get(idx);
165        Type type = result.getType();
166
167        if (type.isUninitialized()) {
168            return throwSimException(idx, "uninitialized instance");
169        }
170
171        if (type.isCategory2()) {
172            return throwSimException(idx, "category-2");
173        }
174
175        return result;
176    }
177
178    /** @inheritDoc */
179    public TypeBearer getCategory2(int idx) {
180        TypeBearer result = get(idx);
181
182        if (result.getType().isCategory1()) {
183            return throwSimException(idx, "category-1");
184        }
185
186        return result;
187    }
188
189    /** @inheritDoc */
190    @Override
191    public LocalsArray merge(LocalsArray other) {
192        if (other instanceof OneLocalsArray) {
193            return merge((OneLocalsArray)other);
194        } else { //LocalsArraySet
195            // LocalsArraySet knows how to merge me.
196            return other.merge(this);
197        }
198    }
199
200    /**
201     * Merges this OneLocalsArray instance with another OneLocalsArray
202     * instance. A more-refined version of {@link #merge(LocalsArray) merge}
203     * which is called by that method when appropriate.
204     *
205     * @param other locals array with which to merge
206     * @return this instance if merge was a no-op, or a new instance if
207     * the merge resulted in a change.
208     */
209    public OneLocalsArray merge(OneLocalsArray other) {
210        try {
211            return Merger.mergeLocals(this, other);
212        } catch (SimException ex) {
213            ex.addContext("underlay locals:");
214            annotate(ex);
215            ex.addContext("overlay locals:");
216            other.annotate(ex);
217            throw ex;
218        }
219    }
220
221    /** @inheritDoc */
222    @Override
223    public LocalsArraySet mergeWithSubroutineCaller
224            (LocalsArray other, int predLabel) {
225
226        LocalsArraySet result = new LocalsArraySet(getMaxLocals());
227        return result.mergeWithSubroutineCaller(other, predLabel);
228    }
229
230    /**{@inheritDoc}*/
231    @Override
232    protected OneLocalsArray getPrimary() {
233        return this;
234    }
235
236    /**
237     * Throws a properly-formatted exception.
238     *
239     * @param idx the salient local index
240     * @param msg {@code non-null;} useful message
241     * @return never (keeps compiler happy)
242     */
243    private static TypeBearer throwSimException(int idx, String msg) {
244        throw new SimException("local " + Hex.u2(idx) + ": " + msg);
245    }
246}
247