1 /*
   2  * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.jdi;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Iterator;
  30 import java.util.List;
  31 import java.util.Map;
  32 import java.util.Set;
  33 
  34 import com.sun.jdi.ArrayReference;
  35 import com.sun.jdi.ArrayType;
  36 import com.sun.jdi.ClassLoaderReference;
  37 import com.sun.jdi.ClassNotLoadedException;
  38 import com.sun.jdi.InterfaceType;
  39 import com.sun.jdi.Method;
  40 import com.sun.jdi.PrimitiveType;
  41 import com.sun.jdi.ReferenceType;
  42 import com.sun.jdi.Type;
  43 import com.sun.jdi.VirtualMachine;
  44 
  45 public class ArrayTypeImpl extends ReferenceTypeImpl
  46     implements ArrayType
  47 {
  48     protected ArrayTypeImpl(VirtualMachine aVm, long aRef) {
  49         super(aVm, aRef);
  50     }
  51 
  52     public ArrayReference newInstance(int length) {
  53         try {
  54             return (ArrayReference)JDWP.ArrayType.NewInstance.
  55                                        process(vm, this, length).newArray;
  56         } catch (JDWPException exc) {
  57             throw exc.toJDIException();
  58         }
  59     }
  60 
  61     public String componentSignature() {
  62         return signature().substring(1); // Just skip the leading '['
  63     }
  64 
  65     public String componentTypeName() {
  66         JNITypeParser parser = new JNITypeParser(componentSignature());
  67         return parser.typeName();
  68     }
  69 
  70     Type type() throws ClassNotLoadedException {
  71         return findType(componentSignature());
  72     }
  73 
  74     @Override
  75     void addVisibleMethods(Map<String, Method> map, Set<InterfaceType> seenInterfaces) {
  76         // arrays don't have methods
  77     }
  78 
  79     public List<Method> allMethods() {
  80         return new ArrayList<>(0);   // arrays don't have methods
  81     }
  82 
  83     /*
  84      * Find the type object, if any, of a component type of this array.
  85      * The component type does not have to be immediate; e.g. this method
  86      * can be used to find the component Foo of Foo[][]. This method takes
  87      * advantage of the property that an array and its component must have
  88      * the same class loader. Since array set operations don't have an
  89      * implicit enclosing type like field and variable set operations,
  90      * this method is sometimes needed for proper type checking.
  91      */
  92     Type findComponentType(String signature) throws ClassNotLoadedException {
  93         byte tag = (byte)signature.charAt(0);
  94         if (PacketStream.isObjectTag(tag)) {
  95             // It's a reference type
  96             JNITypeParser parser = new JNITypeParser(componentSignature());
  97             List<ReferenceType> list = vm.classesByName(parser.typeName());
  98             Iterator<ReferenceType> iter = list.iterator();
  99             while (iter.hasNext()) {
 100                 ReferenceType type = iter.next();
 101                 ClassLoaderReference cl = type.classLoader();
 102                 if ((cl == null)?
 103                          (classLoader() == null) :
 104                          (cl.equals(classLoader()))) {
 105                     return type;
 106                 }
 107             }
 108             // Component class has not yet been loaded
 109             throw new ClassNotLoadedException(componentTypeName());
 110         } else {
 111             // It's a primitive type
 112             return vm.primitiveTypeMirror(tag);
 113         }
 114     }
 115 
 116     public Type componentType() throws ClassNotLoadedException {
 117         return findComponentType(componentSignature());
 118     }
 119 
 120     static boolean isComponentAssignable(Type destination, Type source) {
 121         if (source instanceof PrimitiveType) {
 122             // Assignment of primitive arrays requires identical
 123             // component types.
 124             return source.equals(destination);
 125         } else {
 126             if (destination instanceof PrimitiveType) {
 127                 return false;
 128             }
 129 
 130             ReferenceTypeImpl refSource = (ReferenceTypeImpl)source;
 131             ReferenceTypeImpl refDestination = (ReferenceTypeImpl)destination;
 132             // Assignment of object arrays requires availability
 133             // of widening conversion of component types
 134             return refSource.isAssignableTo(refDestination);
 135         }
 136     }
 137 
 138     /*
 139      * Return true if an instance of the  given reference type
 140      * can be assigned to a variable of this type
 141      */
 142     boolean isAssignableTo(ReferenceType destType) {
 143         if (destType instanceof ArrayType) {
 144             try {
 145                 Type destComponentType = ((ArrayType)destType).componentType();
 146                 return isComponentAssignable(destComponentType, componentType());
 147             } catch (ClassNotLoadedException e) {
 148                 // One or both component types has not yet been
 149                 // loaded => can't assign
 150                 return false;
 151             }
 152         } else if (destType instanceof InterfaceType) {
 153             // Only valid InterfaceType assignee is Cloneable
 154             return destType.name().equals("java.lang.Cloneable");
 155         } else {
 156             // Only valid ClassType assignee is Object
 157             return destType.name().equals("java.lang.Object");
 158         }
 159     }
 160 
 161     List<ReferenceType> inheritedTypes() {
 162         return new ArrayList<ReferenceType>(0);
 163     }
 164 
 165     void getModifiers() {
 166         if (modifiers != -1) {
 167             return;
 168         }
 169         /*
 170          * For object arrays, the return values for Interface
 171          * Accessible.isPrivate(), Accessible.isProtected(),
 172          * etc... are the same as would be returned for the
 173          * component type.  Fetch the modifier bits from the
 174          * component type and use those.
 175          *
 176          * For primitive arrays, the modifiers are always
 177          *   VMModifiers.FINAL | VMModifiers.PUBLIC
 178          *
 179          * Reference com.sun.jdi.Accessible.java.
 180          */
 181         try {
 182             Type t = componentType();
 183             if (t instanceof PrimitiveType) {
 184                 modifiers = VMModifiers.FINAL | VMModifiers.PUBLIC;
 185             } else {
 186                 ReferenceType rt = (ReferenceType)t;
 187                 modifiers = rt.modifiers();
 188             }
 189         } catch (ClassNotLoadedException cnle) {
 190             cnle.printStackTrace();
 191         }
 192     }
 193 
 194     public String toString() {
 195        return "array class " + name() + " (" + loaderString() + ")";
 196     }
 197 
 198     /*
 199      * Save a pointless trip over the wire for these methods
 200      * which have undefined results for arrays.
 201      */
 202     public boolean isPrepared() { return true; }
 203     public boolean isVerified() { return true; }
 204     public boolean isInitialized() { return true; }
 205     public boolean failedToInitialize() { return false; }
 206     public boolean isAbstract() { return false; }
 207 
 208     /*
 209      * Defined always to be true for arrays
 210      */
 211     public boolean isFinal() { return true; }
 212 
 213     /*
 214      * Defined always to be false for arrays
 215      */
 216     public boolean isStatic() { return false; }
 217 }