blob: 0c8c106e6c33d1a87dd1970a3f351b7ce1479493 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.tools.jdi;
27
28import com.sun.jdi.*;
29
30import java.util.List;
31import java.util.ArrayList;
32import java.util.Arrays;
33import java.util.Iterator;
34
35public class ArrayReferenceImpl extends ObjectReferenceImpl
36 implements ArrayReference
37{
38 int length = -1;
39
40 ArrayReferenceImpl(VirtualMachine aVm,long aRef) {
41 super(aVm,aRef);
42 }
43
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
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 */
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
72 public Value getValue(int index) {
73 List list = getValues(index, 1);
74 return (Value)list.get(0);
75 }
76
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 */
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")
105 private static <T> T cast(Object x) {
106 return (T)x;
107 }
108
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
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
136 public void setValues(List<? extends Value> values)
137 throws InvalidTypeException,
138 ClassNotLoadedException {
139 setValues(0, values, 0, -1);
140 }
141
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
205 public String toString() {
206 return "instance of " + arrayType().componentTypeName() +
207 "[" + length() + "] (id=" + uniqueID() + ")";
208 }
209
210 byte typeValueKey() {
211 return JDWP.Tag.ARRAY;
212 }
213
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 {
270 public Type type() throws ClassNotLoadedException {
271 return arrayType().componentType();
272 }
273 public String typeName() {
274 return arrayType().componentTypeName();
275 }
276 public String signature() {
277 return arrayType().componentSignature();
278 }
279 public Type findType(String signature) throws ClassNotLoadedException {
280 return arrayType().findComponentType(signature);
281 }
282 }
283}