283 lines · 10.2 KB · Java
RawDownload
/* * Copyright (c) 1998, 2004, 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 com.sun.jdi.*; import java.util.List;import java.util.ArrayList;import java.util.Arrays;import java.util.Iterator; public class ArrayReferenceImpl extends ObjectReferenceImpl    implements ArrayReference{    int length = -1;     ArrayReferenceImpl(VirtualMachine aVm,long aRef) {        super(aVm,aRef);    }     protected ClassTypeImpl invokableReferenceType(Method method) {        // The method has to be a method on Object since        // arrays don't have methods nor any other 'superclasses'        // So, use the ClassTypeImpl for Object instead of        // the ArrayTypeImpl for the array itself.        return (ClassTypeImpl)method.declaringType();    }     ArrayTypeImpl arrayType() {        return (ArrayTypeImpl)type();    }     /**     * Return array length.     * Need not be synchronized since it cannot be provably stale.     */    public int length() {        if(length == -1) {            try {                length = JDWP.ArrayReference.Length.                    process(vm, this).arrayLength;            } catch (JDWPException exc) {                throw exc.toJDIException();            }        }        return length;    }     public Value getValue(int index) {        List list = getValues(index, 1);        return (Value)list.get(0);    }     public List<Value> getValues() {        return getValues(0, -1);    }     /**     * Validate that the range to set/get is valid.     * length of -1 (meaning rest of array) has been converted     * before entry.     */    private void validateArrayAccess(int index, int length) {        // because length can be computed from index,        // index must be tested first for correct error message        if ((index < 0) || (index > length())) {            throw new IndexOutOfBoundsException(                        "Invalid array index: " + index);        }        if (length < 0) {            throw new IndexOutOfBoundsException(                        "Invalid array range length: " + length);        }        if (index + length > length()) {            throw new IndexOutOfBoundsException(                        "Invalid array range: " +                        index + " to " + (index + length - 1));        }    }     @SuppressWarnings("unchecked")    private static <T> T cast(Object x) {        return (T)x;    }     public List<Value> getValues(int index, int length) {        if (length == -1) { // -1 means the rest of the array           length = length() - index;        }        validateArrayAccess(index, length);        if (length == 0) {            return new ArrayList<Value>();        }         List<Value> vals;        try {            vals = cast(JDWP.ArrayReference.GetValues.process(vm, this, index, length).values);        } catch (JDWPException exc) {            throw exc.toJDIException();        }         return vals;    }     public void setValue(int index, Value value)            throws InvalidTypeException,                   ClassNotLoadedException {        List<Value> list = new ArrayList<Value>(1);        list.add(value);        setValues(index, list, 0, 1);    }     public void setValues(List<? extends Value> values)            throws InvalidTypeException,                   ClassNotLoadedException {        setValues(0, values, 0, -1);    }     public void setValues(int index, List<? extends Value> values,                          int srcIndex, int length)            throws InvalidTypeException,                   ClassNotLoadedException {         if (length == -1) { // -1 means the rest of the array            // shorter of, the rest of the array and rest of            // the source values            length = Math.min(length() - index,                              values.size() - srcIndex);        }        validateMirrorsOrNulls(values);        validateArrayAccess(index, length);         if ((srcIndex < 0) || (srcIndex > values.size())) {            throw new IndexOutOfBoundsException(                        "Invalid source index: " + srcIndex);        }        if (srcIndex + length > values.size()) {            throw new IndexOutOfBoundsException(                        "Invalid source range: " +                        srcIndex + " to " +                        (srcIndex + length - 1));        }         boolean somethingToSet = false;;        ValueImpl[] setValues = new ValueImpl[length];         for (int i = 0; i < length; i++) {            ValueImpl value = (ValueImpl)values.get(srcIndex + i);             try {                // Validate and convert if necessary                setValues[i] =                  ValueImpl.prepareForAssignment(value,                                                 new Component());                somethingToSet = true;            } catch (ClassNotLoadedException e) {                /*                 * Since we got this exception,                 * the component must be a reference type.                 * This means the class has not yet been loaded                 * through the defining class's class loader.                 * If the value we're trying to set is null,                 * then setting to null is essentially a                 * no-op, and we should allow it without an                 * exception.                 */                if (value != null) {                    throw e;                }            }        }        if (somethingToSet) {            try {                JDWP.ArrayReference.SetValues.                    process(vm, this, index, setValues);            } catch (JDWPException exc) {                throw exc.toJDIException();            }        }    }     public String toString() {        return "instance of " + arrayType().componentTypeName() +               "[" + length() + "] (id=" + uniqueID() + ")";    }     byte typeValueKey() {        return JDWP.Tag.ARRAY;    }     void validateAssignment(ValueContainer destination)                            throws InvalidTypeException, ClassNotLoadedException {        try {            super.validateAssignment(destination);        } catch (ClassNotLoadedException e) {            /*             * An array can be used extensively without the             * enclosing loader being recorded by the VM as an             * initiating loader of the array type. In addition, the             * load of an array class is fairly harmless as long as             * the component class is already loaded. So we relax the             * rules a bit and allow the assignment as long as the             * ultimate component types are assignable.             */            boolean valid = false;            JNITypeParser destParser = new JNITypeParser(                                       destination.signature());            JNITypeParser srcParser = new JNITypeParser(                                       arrayType().signature());            int destDims = destParser.dimensionCount();            if (destDims <= srcParser.dimensionCount()) {                /*                 * Remove all dimensions from the destination. Remove                 * the same number of dimensions from the source.                 * Get types for both and check to see if they are                 * compatible.                 */                String destComponentSignature =                    destParser.componentSignature(destDims);                Type destComponentType =                    destination.findType(destComponentSignature);                String srcComponentSignature =                    srcParser.componentSignature(destDims);                Type srcComponentType =                    arrayType().findComponentType(srcComponentSignature);                valid = ArrayTypeImpl.isComponentAssignable(destComponentType,                                                          srcComponentType);            }             if (!valid) {                throw new InvalidTypeException("Cannot assign " +                                               arrayType().name() +                                               " to " +                                               destination.typeName());            }        }    }     /*     * Represents an array component to other internal parts of this     * implementation. This is not exposed at the JDI level. Currently,     * this class is needed only for type checking so it does not even     * reference a particular component - just a generic component     * of this array. In the future we may need to expand its use.     */    class Component implements ValueContainer {        public Type type() throws ClassNotLoadedException {            return arrayType().componentType();        }        public String typeName() {            return arrayType().componentTypeName();        }        public String signature() {            return arrayType().componentSignature();        }        public Type findType(String signature) throws ClassNotLoadedException {            return arrayType().findComponentType(signature);        }    }}