001: /*
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.objectweb.asm.tree.analysis;
031:
032: import java.util.List;
033:
034: import org.objectweb.asm.Type;
035:
036: /**
037: * An extended {@link BasicVerifier} that performs more precise verifications.
038: * This verifier computes exact class types, instead of using a single "object
039: * reference" type (as done in the {@link BasicVerifier}).
040: *
041: * @author Eric Bruneton
042: * @author Bing Ran
043: */
044: @SuppressWarnings("unchecked")
045: public class SimpleVerifier extends BasicVerifier {
046:
047: /**
048: * The class that is verified.
049: */
050: private final Type currentClass;
051:
052: /**
053: * The super class of the class that is verified.
054: */
055: private final Type currentSuperClass;
056:
057: /**
058: * The interfaces implemented by the class that is verified.
059: */
060: private final List currentClassInterfaces;
061:
062: /**
063: * If the class that is verified is an interface.
064: */
065: private final boolean isInterface;
066:
067: /**
068: * Constructs a new {@link SimpleVerifier}.
069: */
070: public SimpleVerifier() {
071: this (null, null, false);
072: }
073:
074: /**
075: * Constructs a new {@link SimpleVerifier} to verify a specific class. This
076: * class will not be loaded into the JVM since it may be incorrect.
077: *
078: * @param currentClass the class that is verified.
079: * @param currentSuperClass the super class of the class that is verified.
080: * @param isInterface if the class that is verified is an interface.
081: */
082: public SimpleVerifier(final Type currentClass,
083: final Type currentSuperClass, final boolean isInterface) {
084: this (currentClass, currentSuperClass, null, isInterface);
085: }
086:
087: /**
088: * Constructs a new {@link SimpleVerifier} to verify a specific class. This
089: * class will not be loaded into the JVM since it may be incorrect.
090: *
091: * @param currentClass the class that is verified.
092: * @param currentSuperClass the super class of the class that is verified.
093: * @param currentClassInterfaces the interfaces implemented by the class
094: * that is verified.
095: * @param isInterface if the class that is verified is an interface.
096: */
097: public SimpleVerifier(final Type currentClass,
098: final Type currentSuperClass,
099: final List currentClassInterfaces, final boolean isInterface) {
100: this .currentClass = currentClass;
101: this .currentSuperClass = currentSuperClass;
102: this .currentClassInterfaces = currentClassInterfaces;
103: this .isInterface = isInterface;
104: }
105:
106: public Value newValue(final Type type) {
107: if (type == null) {
108: return BasicValue.UNINITIALIZED_VALUE;
109: }
110:
111: boolean isArray = type.getSort() == Type.ARRAY;
112: if (isArray) {
113: switch (type.getElementType().getSort()) {
114: case Type.BOOLEAN:
115: case Type.CHAR:
116: case Type.BYTE:
117: case Type.SHORT:
118: return new BasicValue(type);
119: }
120: }
121:
122: Value v = super .newValue(type);
123: if (v == BasicValue.REFERENCE_VALUE) {
124: if (isArray) {
125: v = newValue(type.getElementType());
126: String desc = ((BasicValue) v).getType()
127: .getDescriptor();
128: for (int i = 0; i < type.getDimensions(); ++i) {
129: desc = "[" + desc;
130: }
131: v = new BasicValue(Type.getType(desc));
132: } else {
133: v = new BasicValue(type);
134: }
135: }
136: return v;
137: }
138:
139: protected boolean isArrayValue(final Value value) {
140: Type t = ((BasicValue) value).getType();
141: return t != null
142: && (t.getDescriptor().equals("Lnull;") || t.getSort() == Type.ARRAY);
143: }
144:
145: protected Value getElementValue(final Value objectArrayValue)
146: throws AnalyzerException {
147: Type arrayType = ((BasicValue) objectArrayValue).getType();
148: if (arrayType != null) {
149: if (arrayType.getSort() == Type.ARRAY) {
150: return newValue(Type.getType(arrayType.getDescriptor()
151: .substring(1)));
152: } else if (arrayType.getDescriptor().equals("Lnull;")) {
153: return objectArrayValue;
154: }
155: }
156: throw new Error("Internal error");
157: }
158:
159: protected boolean isSubTypeOf(final Value value,
160: final Value expected) {
161: Type expectedType = ((BasicValue) expected).getType();
162: Type type = ((BasicValue) value).getType();
163: switch (expectedType.getSort()) {
164: case Type.INT:
165: case Type.FLOAT:
166: case Type.LONG:
167: case Type.DOUBLE:
168: return type == expectedType;
169: case Type.ARRAY:
170: case Type.OBJECT:
171: if (type.getDescriptor().equals("Lnull;")) {
172: return true;
173: } else if (type.getSort() == Type.OBJECT
174: || type.getSort() == Type.ARRAY) {
175: return isAssignableFrom(expectedType, type);
176: } else {
177: return false;
178: }
179: default:
180: throw new Error("Internal error");
181: }
182: }
183:
184: public Value merge(final Value v, final Value w) {
185: if (!v.equals(w)) {
186: Type t = ((BasicValue) v).getType();
187: Type u = ((BasicValue) w).getType();
188: if (t != null
189: && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
190: if (u != null
191: && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
192: if (t.getDescriptor().equals("Lnull;")) {
193: return w;
194: }
195: if (u.getDescriptor().equals("Lnull;")) {
196: return v;
197: }
198: if (isAssignableFrom(t, u)) {
199: return v;
200: }
201: if (isAssignableFrom(u, t)) {
202: return w;
203: }
204: // TODO case of array classes of the same dimension
205: // TODO should we look also for a common super interface?
206: // problem: there may be several possible common super
207: // interfaces
208: do {
209: if (t == null || isInterface(t)) {
210: return BasicValue.REFERENCE_VALUE;
211: }
212: t = getSuperClass(t);
213: if (isAssignableFrom(t, u)) {
214: return newValue(t);
215: }
216: } while (true);
217: }
218: }
219: return BasicValue.UNINITIALIZED_VALUE;
220: }
221: return v;
222: }
223:
224: protected boolean isInterface(final Type t) {
225: if (currentClass != null && t.equals(currentClass)) {
226: return isInterface;
227: }
228: return getClass(t).isInterface();
229: }
230:
231: protected Type getSuperClass(final Type t) {
232: if (currentClass != null && t.equals(currentClass)) {
233: return currentSuperClass;
234: }
235: Class c = getClass(t).getSuperclass();
236: return c == null ? null : Type.getType(c);
237: }
238:
239: protected boolean isAssignableFrom(final Type t, final Type u) {
240: if (t.equals(u)) {
241: return true;
242: }
243: if (currentClass != null && t.equals(currentClass)) {
244: if (getSuperClass(u) == null) {
245: return false;
246: } else {
247: return isAssignableFrom(t, getSuperClass(u));
248: }
249: }
250: if (currentClass != null && u.equals(currentClass)) {
251: if (isAssignableFrom(t, currentSuperClass)) {
252: return true;
253: }
254: if (currentClassInterfaces != null) {
255: for (int i = 0; i < currentClassInterfaces.size(); ++i) {
256: Type v = (Type) currentClassInterfaces.get(i);
257: if (isAssignableFrom(t, v)) {
258: return true;
259: }
260: }
261: }
262: return false;
263: }
264: return getClass(t).isAssignableFrom(getClass(u));
265: }
266:
267: protected Class getClass(final Type t) {
268: try {
269: if (t.getSort() == Type.ARRAY) {
270: return Class.forName(t.getDescriptor()
271: .replace('/', '.'));
272: }
273: return Class.forName(t.getClassName());
274: } catch (ClassNotFoundException e) {
275: throw new RuntimeException(e.toString());
276: }
277: }
278: }
|