com.android.dx.cf.code.OneLocalsArray Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.cf.code;
import com.android.dex.util.ExceptionWithContext;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.type.Type;
import com.android.dx.rop.type.TypeBearer;
import com.android.dx.util.Hex;
/**
* Representation of an array of local variables, with Java semantics.
*
* Note: For the most part, the documentation for this class
* ignores the distinction between {@link com.android.dx.rop.type.Type} and {@link
* com.android.dx.rop.type.TypeBearer}.
*/
public class OneLocalsArray extends LocalsArray {
/** {@code non-null;} actual array */
private final TypeBearer[] locals;
/**
* Constructs an instance. The locals array initially consists of
* all-uninitialized values (represented as {@code null}s).
*
* @param maxLocals {@code >= 0;} the maximum number of locals this instance
* can refer to
*/
public OneLocalsArray(int maxLocals) {
super(maxLocals != 0);
locals = new TypeBearer[maxLocals];
}
/** {@inheritDoc} */
public OneLocalsArray copy() {
OneLocalsArray result = new OneLocalsArray(locals.length);
System.arraycopy(locals, 0, result.locals, 0, locals.length);
return result;
}
/** {@inheritDoc} */
public void annotate(ExceptionWithContext ex) {
for (int i = 0; i < locals.length; i++) {
TypeBearer type = locals[i];
String s = (type == null) ? "" : type.toString();
ex.addContext("locals[" + Hex.u2(i) + "]: " + s);
}
}
/** {@inheritDoc} */
public String toHuman() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < locals.length; i++) {
TypeBearer type = locals[i];
String s = (type == null) ? "" : type.toString();
sb.append("locals[" + Hex.u2(i) + "]: " + s + "\n");
}
return sb.toString();
}
/** {@inheritDoc} */
public void makeInitialized(Type type) {
int len = locals.length;
if (len == 0) {
// We have to check for this before checking for immutability.
return;
}
throwIfImmutable();
Type initializedType = type.getInitializedType();
for (int i = 0; i < len; i++) {
if (locals[i] == type) {
locals[i] = initializedType;
}
}
}
/** {@inheritDoc} */
public int getMaxLocals() {
return locals.length;
}
/** {@inheritDoc} */
public void set(int idx, TypeBearer type) {
throwIfImmutable();
try {
type = type.getFrameType();
} catch (NullPointerException ex) {
// Elucidate the exception
throw new NullPointerException("type == null");
}
if (idx < 0) {
throw new IndexOutOfBoundsException("idx < 0");
}
// Make highest possible out-of-bounds check happen first.
if (type.getType().isCategory2()) {
locals[idx + 1] = null;
}
locals[idx] = type;
if (idx != 0) {
TypeBearer prev = locals[idx - 1];
if ((prev != null) && prev.getType().isCategory2()) {
locals[idx - 1] = null;
}
}
}
/** {@inheritDoc} */
public void set(RegisterSpec spec) {
set(spec.getReg(), spec);
}
/** {@inheritDoc} */
public void invalidate(int idx) {
throwIfImmutable();
locals[idx] = null;
}
/** {@inheritDoc} */
public TypeBearer getOrNull(int idx) {
return locals[idx];
}
/** {@inheritDoc} */
public TypeBearer get(int idx) {
TypeBearer result = locals[idx];
if (result == null) {
return throwSimException(idx, "invalid");
}
return result;
}
/** {@inheritDoc} */
public TypeBearer getCategory1(int idx) {
TypeBearer result = get(idx);
Type type = result.getType();
if (type.isUninitialized()) {
return throwSimException(idx, "uninitialized instance");
}
if (type.isCategory2()) {
return throwSimException(idx, "category-2");
}
return result;
}
/** {@inheritDoc} */
public TypeBearer getCategory2(int idx) {
TypeBearer result = get(idx);
if (result.getType().isCategory1()) {
return throwSimException(idx, "category-1");
}
return result;
}
/** {@inheritDoc} */
@Override
public LocalsArray merge(LocalsArray other) {
if (other instanceof OneLocalsArray) {
return merge((OneLocalsArray)other);
} else { //LocalsArraySet
// LocalsArraySet knows how to merge me.
return other.merge(this);
}
}
/**
* Merges this OneLocalsArray instance with another OneLocalsArray
* instance. A more-refined version of {@link #merge(LocalsArray) merge}
* which is called by that method when appropriate.
*
* @param other locals array with which to merge
* @return this instance if merge was a no-op, or a new instance if
* the merge resulted in a change.
*/
public OneLocalsArray merge(OneLocalsArray other) {
try {
return Merger.mergeLocals(this, other);
} catch (SimException ex) {
ex.addContext("underlay locals:");
annotate(ex);
ex.addContext("overlay locals:");
other.annotate(ex);
throw ex;
}
}
/** {@inheritDoc} */
@Override
public LocalsArraySet mergeWithSubroutineCaller
(LocalsArray other, int predLabel) {
LocalsArraySet result = new LocalsArraySet(getMaxLocals());
return result.mergeWithSubroutineCaller(other, predLabel);
}
/**{@inheritDoc}*/
@Override
protected OneLocalsArray getPrimary() {
return this;
}
/**
* Throws a properly-formatted exception.
*
* @param idx the salient local index
* @param msg {@code non-null;} useful message
* @return never (keeps compiler happy)
*/
private static TypeBearer throwSimException(int idx, String msg) {
throw new SimException("local " + Hex.u2(idx) + ": " + msg);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy