1 /* 2 * Copyright (c) 1998, 2011, 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 com.sun.jdi.*; 29 30 import java.util.List; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.Iterator; 34 35 public class ArrayReferenceImpl extends ObjectReferenceImpl 36 implements ArrayReference 37 { 38 int length = -1; 39 ArrayReferenceImpl(VirtualMachine aVm,long aRef)40 ArrayReferenceImpl(VirtualMachine aVm,long aRef) { 41 super(aVm,aRef); 42 } 43 invokableReferenceType(Method method)44 protected ClassTypeImpl invokableReferenceType(Method method) { 45 // The method has to be a method on Object since 46 // arrays don't have methods nor any other 'superclasses' 47 // So, use the ClassTypeImpl for Object instead of 48 // the ArrayTypeImpl for the array itself. 49 return (ClassTypeImpl)method.declaringType(); 50 } 51 arrayType()52 ArrayTypeImpl arrayType() { 53 return (ArrayTypeImpl)type(); 54 } 55 56 /** 57 * Return array length. 58 * Need not be synchronized since it cannot be provably stale. 59 */ length()60 public int length() { 61 if(length == -1) { 62 try { 63 length = JDWP.ArrayReference.Length. 64 process(vm, this).arrayLength; 65 } catch (JDWPException exc) { 66 throw exc.toJDIException(); 67 } 68 } 69 return length; 70 } 71 getValue(int index)72 public Value getValue(int index) { 73 List<Value> list = getValues(index, 1); 74 return list.get(0); 75 } 76 getValues()77 public List<Value> getValues() { 78 return getValues(0, -1); 79 } 80 81 /** 82 * Validate that the range to set/get is valid. 83 * length of -1 (meaning rest of array) has been converted 84 * before entry. 85 */ validateArrayAccess(int index, int length)86 private void validateArrayAccess(int index, int length) { 87 // because length can be computed from index, 88 // index must be tested first for correct error message 89 if ((index < 0) || (index > length())) { 90 throw new IndexOutOfBoundsException( 91 "Invalid array index: " + index); 92 } 93 if (length < 0) { 94 throw new IndexOutOfBoundsException( 95 "Invalid array range length: " + length); 96 } 97 if (index + length > length()) { 98 throw new IndexOutOfBoundsException( 99 "Invalid array range: " + 100 index + " to " + (index + length - 1)); 101 } 102 } 103 104 @SuppressWarnings("unchecked") cast(Object x)105 private static <T> T cast(Object x) { 106 return (T)x; 107 } 108 getValues(int index, int length)109 public List<Value> getValues(int index, int length) { 110 if (length == -1) { // -1 means the rest of the array 111 length = length() - index; 112 } 113 validateArrayAccess(index, length); 114 if (length == 0) { 115 return new ArrayList<Value>(); 116 } 117 118 List<Value> vals; 119 try { 120 vals = cast(JDWP.ArrayReference.GetValues.process(vm, this, index, length).values); 121 } catch (JDWPException exc) { 122 throw exc.toJDIException(); 123 } 124 125 return vals; 126 } 127 setValue(int index, Value value)128 public void setValue(int index, Value value) 129 throws InvalidTypeException, 130 ClassNotLoadedException { 131 List<Value> list = new ArrayList<Value>(1); 132 list.add(value); 133 setValues(index, list, 0, 1); 134 } 135 setValues(List<? extends Value> values)136 public void setValues(List<? extends Value> values) 137 throws InvalidTypeException, 138 ClassNotLoadedException { 139 setValues(0, values, 0, -1); 140 } 141 setValues(int index, List<? extends Value> values, int srcIndex, int length)142 public void setValues(int index, List<? extends Value> values, 143 int srcIndex, int length) 144 throws InvalidTypeException, 145 ClassNotLoadedException { 146 147 if (length == -1) { // -1 means the rest of the array 148 // shorter of, the rest of the array and rest of 149 // the source values 150 length = Math.min(length() - index, 151 values.size() - srcIndex); 152 } 153 validateMirrorsOrNulls(values); 154 validateArrayAccess(index, length); 155 156 if ((srcIndex < 0) || (srcIndex > values.size())) { 157 throw new IndexOutOfBoundsException( 158 "Invalid source index: " + srcIndex); 159 } 160 if (srcIndex + length > values.size()) { 161 throw new IndexOutOfBoundsException( 162 "Invalid source range: " + 163 srcIndex + " to " + 164 (srcIndex + length - 1)); 165 } 166 167 boolean somethingToSet = false;; 168 ValueImpl[] setValues = new ValueImpl[length]; 169 170 for (int i = 0; i < length; i++) { 171 ValueImpl value = (ValueImpl)values.get(srcIndex + i); 172 173 try { 174 // Validate and convert if necessary 175 setValues[i] = 176 ValueImpl.prepareForAssignment(value, 177 new Component()); 178 somethingToSet = true; 179 } catch (ClassNotLoadedException e) { 180 /* 181 * Since we got this exception, 182 * the component must be a reference type. 183 * This means the class has not yet been loaded 184 * through the defining class's class loader. 185 * If the value we're trying to set is null, 186 * then setting to null is essentially a 187 * no-op, and we should allow it without an 188 * exception. 189 */ 190 if (value != null) { 191 throw e; 192 } 193 } 194 } 195 if (somethingToSet) { 196 try { 197 JDWP.ArrayReference.SetValues. 198 process(vm, this, index, setValues); 199 } catch (JDWPException exc) { 200 throw exc.toJDIException(); 201 } 202 } 203 } 204 toString()205 public String toString() { 206 return "instance of " + arrayType().componentTypeName() + 207 "[" + length() + "] (id=" + uniqueID() + ")"; 208 } 209 typeValueKey()210 byte typeValueKey() { 211 return JDWP.Tag.ARRAY; 212 } 213 validateAssignment(ValueContainer destination)214 void validateAssignment(ValueContainer destination) 215 throws InvalidTypeException, ClassNotLoadedException { 216 try { 217 super.validateAssignment(destination); 218 } catch (ClassNotLoadedException e) { 219 /* 220 * An array can be used extensively without the 221 * enclosing loader being recorded by the VM as an 222 * initiating loader of the array type. In addition, the 223 * load of an array class is fairly harmless as long as 224 * the component class is already loaded. So we relax the 225 * rules a bit and allow the assignment as long as the 226 * ultimate component types are assignable. 227 */ 228 boolean valid = false; 229 JNITypeParser destParser = new JNITypeParser( 230 destination.signature()); 231 JNITypeParser srcParser = new JNITypeParser( 232 arrayType().signature()); 233 int destDims = destParser.dimensionCount(); 234 if (destDims <= srcParser.dimensionCount()) { 235 /* 236 * Remove all dimensions from the destination. Remove 237 * the same number of dimensions from the source. 238 * Get types for both and check to see if they are 239 * compatible. 240 */ 241 String destComponentSignature = 242 destParser.componentSignature(destDims); 243 Type destComponentType = 244 destination.findType(destComponentSignature); 245 String srcComponentSignature = 246 srcParser.componentSignature(destDims); 247 Type srcComponentType = 248 arrayType().findComponentType(srcComponentSignature); 249 valid = ArrayTypeImpl.isComponentAssignable(destComponentType, 250 srcComponentType); 251 } 252 253 if (!valid) { 254 throw new InvalidTypeException("Cannot assign " + 255 arrayType().name() + 256 " to " + 257 destination.typeName()); 258 } 259 } 260 } 261 262 /* 263 * Represents an array component to other internal parts of this 264 * implementation. This is not exposed at the JDI level. Currently, 265 * this class is needed only for type checking so it does not even 266 * reference a particular component - just a generic component 267 * of this array. In the future we may need to expand its use. 268 */ 269 class Component implements ValueContainer { type()270 public Type type() throws ClassNotLoadedException { 271 return arrayType().componentType(); 272 } typeName()273 public String typeName() { 274 return arrayType().componentTypeName(); 275 } signature()276 public String signature() { 277 return arrayType().componentSignature(); 278 } findType(String signature)279 public Type findType(String signature) throws ClassNotLoadedException { 280 return arrayType().findComponentType(signature); 281 } 282 } 283 } 284