/*
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* 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.
*/
package com.sun.tools.jdi;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ArrayType;
import com.sun.jdi.ClassLoaderReference;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.Method;
import com.sun.jdi.PrimitiveType;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.Type;
import com.sun.jdi.VirtualMachine;
public class ArrayTypeImpl extends ReferenceTypeImpl
implements ArrayType
{
protected ArrayTypeImpl(VirtualMachine aVm, long aRef) {
super(aVm, aRef);
}
public ArrayReference newInstance(int length) {
try {
return (ArrayReference)JDWP.ArrayType.NewInstance.
process(vm, this, length).newArray;
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
public String componentSignature() {
return signature().substring(1); // Just skip the leading '['
}
public String componentTypeName() {
JNITypeParser parser = new JNITypeParser(componentSignature());
return parser.typeName();
}
Type type() throws ClassNotLoadedException {
return findType(componentSignature());
}
@Override
void addVisibleMethods(Map<String, Method> map, Set<InterfaceType> seenInterfaces) {
// arrays don't have methods
}
public List<Method> allMethods() {
return new ArrayList<>(0); // arrays don't have methods
}
/*
* Find the type object, if any, of a component type of this array.
* The component type does not have to be immediate; e.g. this method
* can be used to find the component Foo of Foo[][]. This method takes
* advantage of the property that an array and its component must have
* the same class loader. Since array set operations don't have an
* implicit enclosing type like field and variable set operations,
* this method is sometimes needed for proper type checking.
*/
Type findComponentType(String signature) throws ClassNotLoadedException {
byte tag = (byte)signature.charAt(0);
if (PacketStream.isObjectTag(tag)) {
// It's a reference type
JNITypeParser parser = new JNITypeParser(componentSignature());
List<ReferenceType> list = vm.classesByName(parser.typeName());
Iterator<ReferenceType> iter = list.iterator();
while (iter.hasNext()) {
ReferenceType type = iter.next();
ClassLoaderReference cl = type.classLoader();
if ((cl == null)?
(classLoader() == null) :
(cl.equals(classLoader()))) {
return type;
}
}
// Component class has not yet been loaded
throw new ClassNotLoadedException(componentTypeName());
} else {
// It's a primitive type
return vm.primitiveTypeMirror(tag);
}
}
public Type componentType() throws ClassNotLoadedException {
return findComponentType(componentSignature());
}
static boolean isComponentAssignable(Type destination, Type source) {
if (source instanceof PrimitiveType) {
// Assignment of primitive arrays requires identical
// component types.
return source.equals(destination);
} else {
if (destination instanceof PrimitiveType) {
return false;
}
ReferenceTypeImpl refSource = (ReferenceTypeImpl)source;
ReferenceTypeImpl refDestination = (ReferenceTypeImpl)destination;
// Assignment of object arrays requires availability
// of widening conversion of component types
return refSource.isAssignableTo(refDestination);
}
}
/*
* Return true if an instance of the given reference type
* can be assigned to a variable of this type
*/
boolean isAssignableTo(ReferenceType destType) {
if (destType instanceof ArrayType) {
try {
Type destComponentType = ((ArrayType)destType).componentType();
return isComponentAssignable(destComponentType, componentType());
} catch (ClassNotLoadedException e) {
// One or both component types has not yet been
// loaded => can't assign
return false;
}
} else if (destType instanceof InterfaceType) {
// Only valid InterfaceType assignee is Cloneable
return destType.name().equals("java.lang.Cloneable");
} else {
// Only valid ClassType assignee is Object
return destType.name().equals("java.lang.Object");
}
}
List<ReferenceType> inheritedTypes() {
return new ArrayList<ReferenceType>(0);
}
void getModifiers() {
if (modifiers != -1) {
return;
}
/*
* For object arrays, the return values for Interface
* Accessible.isPrivate(), Accessible.isProtected(),
* etc... are the same as would be returned for the
* component type. Fetch the modifier bits from the
* component type and use those.
*
* For primitive arrays, the modifiers are always
* VMModifiers.FINAL | VMModifiers.PUBLIC
*
* Reference com.sun.jdi.Accessible.java.
*/
try {
Type t = componentType();
if (t instanceof PrimitiveType) {
modifiers = VMModifiers.FINAL | VMModifiers.PUBLIC;
} else {
ReferenceType rt = (ReferenceType)t;
modifiers = rt.modifiers();
}
} catch (ClassNotLoadedException cnle) {
cnle.printStackTrace();
}
}
public String toString() {
return "array class " + name() + " (" + loaderString() + ")";
}
/*
* Save a pointless trip over the wire for these methods
* which have undefined results for arrays.
*/
public boolean isPrepared() { return true; }
public boolean isVerified() { return true; }
public boolean isInitialized() { return true; }
public boolean failedToInitialize() { return false; }
public boolean isAbstract() { return false; }
/*
* Defined always to be true for arrays
*/
public boolean isFinal() { return true; }
/*
* Defined always to be false for arrays
*/
public boolean isStatic() { return false; }
}