/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.tree.analysis;
import java.util.List;
import jdk.internal.org.objectweb.asm.Type;
/**
* An extended {@link BasicVerifier} that performs more precise verifications. This verifier
* computes exact class types, instead of using a single "object reference" type (as done in {@link
* BasicVerifier}).
*
* @author Eric Bruneton
* @author Bing Ran
*/
public class SimpleVerifier extends BasicVerifier {
/** The type of the class that is verified. */
private final Type currentClass;
/** The type of the super class of the class that is verified. */
private final Type currentSuperClass;
/** The types of the interfaces directly implemented by the class that is verified. */
private final List<Type> currentClassInterfaces;
/** Whether the class that is verified is an interface. */
private final boolean isInterface;
/** The loader to use to load the referenced classes. */
private ClassLoader loader = getClass().getClassLoader();
/**
* Constructs a new {@link SimpleVerifier}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
*/
public SimpleVerifier() {
this(null, null, false);
}
/**
* Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
* loaded into the JVM since it may be incorrect. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
*
* @param currentClass the type of the class to be verified.
* @param currentSuperClass the type of the super class of the class to be verified.
* @param isInterface whether the class to be verifier is an interface.
*/
public SimpleVerifier(
final Type currentClass, final Type currentSuperClass, final boolean isInterface) {
this(currentClass, currentSuperClass, null, isInterface);
}
/**
* Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
* loaded into the JVM since it may be incorrect. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #SimpleVerifier(int, Type, Type, List, boolean)} version.
*
* @param currentClass the type of the class to be verified.
* @param currentSuperClass the type of the super class of the class to be verified.
* @param currentClassInterfaces the types of the interfaces directly implemented by the class to
* be verified.
* @param isInterface whether the class to be verifier is an interface.
*/
public SimpleVerifier(
final Type currentClass,
final Type currentSuperClass,
final List<Type> currentClassInterfaces,
final boolean isInterface) {
this(ASM7, currentClass, currentSuperClass, currentClassInterfaces, isInterface);
if (getClass() != SimpleVerifier.class) {
throw new IllegalStateException();
}
}
/**
* Constructs a new {@link SimpleVerifier} to verify a specific class. This class will not be
* loaded into the JVM since it may be incorrect.
*
* @param api the ASM API version supported by this verifier. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
* @param currentClass the type of the class to be verified.
* @param currentSuperClass the type of the super class of the class to be verified.
* @param currentClassInterfaces the types of the interfaces directly implemented by the class to
* be verified.
* @param isInterface whether the class to be verifier is an interface.
*/
protected SimpleVerifier(
final int api,
final Type currentClass,
final Type currentSuperClass,
final List<Type> currentClassInterfaces,
final boolean isInterface) {
super(api);
this.currentClass = currentClass;
this.currentSuperClass = currentSuperClass;
this.currentClassInterfaces = currentClassInterfaces;
this.isInterface = isInterface;
}
/**
* Sets the <code>ClassLoader</code> to be used in {@link #getClass}.
*
* @param loader the <code>ClassLoader</code> to use.
*/
public void setClassLoader(final ClassLoader loader) {
this.loader = loader;
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
boolean isArray = type.getSort() == Type.ARRAY;
if (isArray) {
switch (type.getElementType().getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
return new BasicValue(type);
default:
break;
}
}
BasicValue value = super.newValue(type);
if (BasicValue.REFERENCE_VALUE.equals(value)) {
if (isArray) {
value = newValue(type.getElementType());
StringBuilder descriptor = new StringBuilder();
for (int i = 0; i < type.getDimensions(); ++i) {
descriptor.append('[');
}
descriptor.append(value.getType().getDescriptor());
value = new BasicValue(Type.getType(descriptor.toString()));
} else {
value = new BasicValue(type);
}
}
return value;
}
@Override
protected boolean isArrayValue(final BasicValue value) {
Type type = value.getType();
return type != null && (type.getSort() == Type.ARRAY || type.equals(NULL_TYPE));
}
@Override
protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
Type arrayType = objectArrayValue.getType();
if (arrayType != null) {
if (arrayType.getSort() == Type.ARRAY) {
return newValue(Type.getType(arrayType.getDescriptor().substring(1)));
} else if (arrayType.equals(NULL_TYPE)) {
return objectArrayValue;
}
}
throw new AssertionError();
}
@Override
protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
Type expectedType = expected.getType();
Type type = value.getType();
switch (expectedType.getSort()) {
case Type.INT:
case Type.FLOAT:
case Type.LONG:
case Type.DOUBLE:
return type.equals(expectedType);
case Type.ARRAY:
case Type.OBJECT:
if (type.equals(NULL_TYPE)) {
return true;
} else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
if (isAssignableFrom(expectedType, type)) {
return true;
} else if (getClass(expectedType).isInterface()) {
// The merge of class or interface types can only yield class types (because it is not
// possible in general to find an unambiguous common super interface, due to multiple
// inheritance). Because of this limitation, we need to relax the subtyping check here
// if 'value' is an interface.
return Object.class.isAssignableFrom(getClass(type));
} else {
return false;
}
} else {
return false;
}
default:
throw new AssertionError();
}
}
@Override
public BasicValue merge(final BasicValue value1, final BasicValue value2) {
if (!value1.equals(value2)) {
Type type1 = value1.getType();
Type type2 = value2.getType();
if (type1 != null
&& (type1.getSort() == Type.OBJECT || type1.getSort() == Type.ARRAY)
&& type2 != null
&& (type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY)) {
if (type1.equals(NULL_TYPE)) {
return value2;
}
if (type2.equals(NULL_TYPE)) {
return value1;
}
if (isAssignableFrom(type1, type2)) {
return value1;
}
if (isAssignableFrom(type2, type1)) {
return value2;
}
int numDimensions = 0;
if (type1.getSort() == Type.ARRAY
&& type2.getSort() == Type.ARRAY
&& type1.getDimensions() == type2.getDimensions()
&& type1.getElementType().getSort() == Type.OBJECT
&& type2.getElementType().getSort() == Type.OBJECT) {
numDimensions = type1.getDimensions();
type1 = type1.getElementType();
type2 = type2.getElementType();
}
do {
if (type1 == null || isInterface(type1)) {
return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
}
type1 = getSuperClass(type1);
if (isAssignableFrom(type1, type2)) {
return newArrayValue(type1, numDimensions);
}
} while (true);
}
return BasicValue.UNINITIALIZED_VALUE;
}
return value1;
}
private BasicValue newArrayValue(final Type type, final int dimensions) {
if (dimensions == 0) {
return newValue(type);
} else {
StringBuilder descriptor = new StringBuilder();
for (int i = 0; i < dimensions; ++i) {
descriptor.append('[');
}
descriptor.append(type.getDescriptor());
return newValue(Type.getType(descriptor.toString()));
}
}
/**
* Returns whether the given type corresponds to the type of an interface. The default
* implementation of this method loads the class and uses the reflection API to return its result
* (unless the given type corresponds to the class being verified).
*
* @param type a type.
* @return whether 'type' corresponds to an interface.
*/
protected boolean isInterface(final Type type) {
if (currentClass != null && currentClass.equals(type)) {
return isInterface;
}
return getClass(type).isInterface();
}
/**
* Returns the type corresponding to the super class of the given type. The default implementation
* of this method loads the class and uses the reflection API to return its result (unless the
* given type corresponds to the class being verified).
*
* @param type a type.
* @return the type corresponding to the super class of 'type'.
*/
protected Type getSuperClass(final Type type) {
if (currentClass != null && currentClass.equals(type)) {
return currentSuperClass;
}
Class<?> superClass = getClass(type).getSuperclass();
return superClass == null ? null : Type.getType(superClass);
}
/**
* Returns whether the class corresponding to the first argument is either the same as, or is a
* superclass or superinterface of the class corresponding to the second argument. The default
* implementation of this method loads the classes and uses the reflection API to return its
* result (unless the result can be computed from the class being verified, and the types of its
* super classes and implemented interfaces).
*
* @param type1 a type.
* @param type2 another type.
* @return whether the class corresponding to 'type1' is either the same as, or is a superclass or
* superinterface of the class corresponding to 'type2'.
*/
protected boolean isAssignableFrom(final Type type1, final Type type2) {
if (type1.equals(type2)) {
/**代码未完, 请加载全部代码(NowJava.com).**/