1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25/*
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
29 * file:
30 *
31 * ASM: a very small and fast Java bytecode manipulation framework
32 * Copyright (c) 2000-2011 INRIA, France Telecom
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the copyright holders nor the names of its
44 *    contributors may be used to endorse or promote products derived from
45 *    this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57 * THE POSSIBILITY OF SUCH DAMAGE.
58 */
59package jdk.internal.org.objectweb.asm.tree.analysis;
60
61import java.util.List;
62
63import jdk.internal.org.objectweb.asm.Type;
64
65/**
66 * An extended {@link BasicVerifier} that performs more precise verifications.
67 * This verifier computes exact class types, instead of using a single "object
68 * reference" type (as done in the {@link BasicVerifier}).
69 *
70 * @author Eric Bruneton
71 * @author Bing Ran
72 */
73public class SimpleVerifier extends BasicVerifier {
74
75    /**
76     * The class that is verified.
77     */
78    private final Type currentClass;
79
80    /**
81     * The super class of the class that is verified.
82     */
83    private final Type currentSuperClass;
84
85    /**
86     * The interfaces implemented by the class that is verified.
87     */
88    private final List<Type> currentClassInterfaces;
89
90    /**
91     * If the class that is verified is an interface.
92     */
93    private final boolean isInterface;
94
95    /**
96     * The loader to use for referenced classes.
97     */
98    private ClassLoader loader = getClass().getClassLoader();
99
100    /**
101     * Constructs a new {@link SimpleVerifier}.
102     */
103    public SimpleVerifier() {
104        this(null, null, false);
105    }
106
107    /**
108     * Constructs a new {@link SimpleVerifier} to verify a specific class. This
109     * class will not be loaded into the JVM since it may be incorrect.
110     *
111     * @param currentClass
112     *            the class that is verified.
113     * @param currentSuperClass
114     *            the super class of the class that is verified.
115     * @param isInterface
116     *            if the class that is verified is an interface.
117     */
118    public SimpleVerifier(final Type currentClass,
119            final Type currentSuperClass, final boolean isInterface) {
120        this(currentClass, currentSuperClass, null, isInterface);
121    }
122
123    /**
124     * Constructs a new {@link SimpleVerifier} to verify a specific class. This
125     * class will not be loaded into the JVM since it may be incorrect.
126     *
127     * @param currentClass
128     *            the class that is verified.
129     * @param currentSuperClass
130     *            the super class of the class that is verified.
131     * @param currentClassInterfaces
132     *            the interfaces implemented by the class that is verified.
133     * @param isInterface
134     *            if the class that is verified is an interface.
135     */
136    public SimpleVerifier(final Type currentClass,
137            final Type currentSuperClass,
138            final List<Type> currentClassInterfaces, final boolean isInterface) {
139        this(ASM5, currentClass, currentSuperClass, currentClassInterfaces,
140                isInterface);
141    }
142
143    protected SimpleVerifier(final int api, final Type currentClass,
144            final Type currentSuperClass,
145            final List<Type> currentClassInterfaces, final boolean isInterface) {
146        super(api);
147        this.currentClass = currentClass;
148        this.currentSuperClass = currentSuperClass;
149        this.currentClassInterfaces = currentClassInterfaces;
150        this.isInterface = isInterface;
151    }
152
153    /**
154     * Set the <code>ClassLoader</code> which will be used to load referenced
155     * classes. This is useful if you are verifying multiple interdependent
156     * classes.
157     *
158     * @param loader
159     *            a <code>ClassLoader</code> to use
160     */
161    public void setClassLoader(final ClassLoader loader) {
162        this.loader = loader;
163    }
164
165    @Override
166    public BasicValue newValue(final Type type) {
167        if (type == null) {
168            return BasicValue.UNINITIALIZED_VALUE;
169        }
170
171        boolean isArray = type.getSort() == Type.ARRAY;
172        if (isArray) {
173            switch (type.getElementType().getSort()) {
174            case Type.BOOLEAN:
175            case Type.CHAR:
176            case Type.BYTE:
177            case Type.SHORT:
178                return new BasicValue(type);
179            }
180        }
181
182        BasicValue v = super.newValue(type);
183        if (BasicValue.REFERENCE_VALUE.equals(v)) {
184            if (isArray) {
185                v = newValue(type.getElementType());
186                String desc = v.getType().getDescriptor();
187                for (int i = 0; i < type.getDimensions(); ++i) {
188                    desc = '[' + desc;
189                }
190                v = new BasicValue(Type.getType(desc));
191            } else {
192                v = new BasicValue(type);
193            }
194        }
195        return v;
196    }
197
198    @Override
199    protected boolean isArrayValue(final BasicValue value) {
200        Type t = value.getType();
201        return t != null
202                && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
203    }
204
205    @Override
206    protected BasicValue getElementValue(final BasicValue objectArrayValue)
207            throws AnalyzerException {
208        Type arrayType = objectArrayValue.getType();
209        if (arrayType != null) {
210            if (arrayType.getSort() == Type.ARRAY) {
211                return newValue(Type.getType(arrayType.getDescriptor()
212                        .substring(1)));
213            } else if ("Lnull;".equals(arrayType.getDescriptor())) {
214                return objectArrayValue;
215            }
216        }
217        throw new Error("Internal error");
218    }
219
220    @Override
221    protected boolean isSubTypeOf(final BasicValue value,
222            final BasicValue expected) {
223        Type expectedType = expected.getType();
224        Type type = value.getType();
225        switch (expectedType.getSort()) {
226        case Type.INT:
227        case Type.FLOAT:
228        case Type.LONG:
229        case Type.DOUBLE:
230            return type.equals(expectedType);
231        case Type.ARRAY:
232        case Type.OBJECT:
233            if ("Lnull;".equals(type.getDescriptor())) {
234                return true;
235            } else if (type.getSort() == Type.OBJECT
236                    || type.getSort() == Type.ARRAY) {
237                return isAssignableFrom(expectedType, type);
238            } else {
239                return false;
240            }
241        default:
242            throw new Error("Internal error");
243        }
244    }
245
246    @Override
247    public BasicValue merge(final BasicValue v, final BasicValue w) {
248        if (!v.equals(w)) {
249            Type t = v.getType();
250            Type u = w.getType();
251            if (t != null
252                    && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
253                if (u != null
254                        && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
255                    if ("Lnull;".equals(t.getDescriptor())) {
256                        return w;
257                    }
258                    if ("Lnull;".equals(u.getDescriptor())) {
259                        return v;
260                    }
261                    if (isAssignableFrom(t, u)) {
262                        return v;
263                    }
264                    if (isAssignableFrom(u, t)) {
265                        return w;
266                    }
267                    // TODO case of array classes of the same dimension
268                    // TODO should we look also for a common super interface?
269                    // problem: there may be several possible common super
270                    // interfaces
271                    do {
272                        if (t == null || isInterface(t)) {
273                            return BasicValue.REFERENCE_VALUE;
274                        }
275                        t = getSuperClass(t);
276                        if (isAssignableFrom(t, u)) {
277                            return newValue(t);
278                        }
279                    } while (true);
280                }
281            }
282            return BasicValue.UNINITIALIZED_VALUE;
283        }
284        return v;
285    }
286
287    protected boolean isInterface(final Type t) {
288        if (currentClass != null && t.equals(currentClass)) {
289            return isInterface;
290        }
291        return getClass(t).isInterface();
292    }
293
294    protected Type getSuperClass(final Type t) {
295        if (currentClass != null && t.equals(currentClass)) {
296            return currentSuperClass;
297        }
298        Class<?> c = getClass(t).getSuperclass();
299        return c == null ? null : Type.getType(c);
300    }
301
302    protected boolean isAssignableFrom(final Type t, final Type u) {
303        if (t.equals(u)) {
304            return true;
305        }
306        if (currentClass != null && t.equals(currentClass)) {
307            if (getSuperClass(u) == null) {
308                return false;
309            } else {
310                if (isInterface) {
311                    return u.getSort() == Type.OBJECT
312                            || u.getSort() == Type.ARRAY;
313                }
314                return isAssignableFrom(t, getSuperClass(u));
315            }
316        }
317        if (currentClass != null && u.equals(currentClass)) {
318            if (isAssignableFrom(t, currentSuperClass)) {
319                return true;
320            }
321            if (currentClassInterfaces != null) {
322                for (int i = 0; i < currentClassInterfaces.size(); ++i) {
323                    Type v = currentClassInterfaces.get(i);
324                    if (isAssignableFrom(t, v)) {
325                        return true;
326                    }
327                }
328            }
329            return false;
330        }
331        Class<?> tc = getClass(t);
332        if (tc.isInterface()) {
333            tc = Object.class;
334        }
335        return tc.isAssignableFrom(getClass(u));
336    }
337
338    protected Class<?> getClass(final Type t) {
339        try {
340            if (t.getSort() == Type.ARRAY) {
341                return Class.forName(t.getDescriptor().replace('/', '.'),
342                        false, loader);
343            }
344            return Class.forName(t.getClassName(), false, loader);
345        } catch (ClassNotFoundException e) {
346            throw new RuntimeException(e.toString());
347        }
348    }
349}
350