/* * Copyright (c) 2007, 2011, 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. * * 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.max.tele; import java.lang.reflect.*; import java.util.*; import com.sun.max.jdwp.vm.core.*; import com.sun.max.jdwp.vm.proxy.*; /** * An implementation of a value as seen by the JDWP server. * */ final class VMValueImpl implements VMValue { public static final VMValue VOID_VALUE = new VMValueImpl(); private static Map<Object, ObjectProvider> objectProviderCache = new IdentityHashMap<Object, ObjectProvider>(); private Type type; private Object value; private VMValueImpl() { type = Type.VOID; value = null; } public boolean isVoid() { return type == null; } public Byte asByte() { return type == Type.BYTE ? (Byte) value : null; } public Character asChar() { return type == Type.CHAR ? (Character) value : null; } public Short asShort() { return type == Type.SHORT ? (Short) value : null; } public Integer asInt() { return type == Type.INT ? (Integer) value : null; } public Float asFloat() { return type == Type.FLOAT ? (Float) value : null; } public Double asDouble() { return type == Type.DOUBLE ? (Double) value : null; } public Long asLong() { return type == Type.LONG ? (Long) value : null; } public Boolean asBoolean() { return type == Type.BOOLEAN ? (Boolean) value : null; } public Provider asProvider() { return type == Type.PROVIDER ? (Provider) value : null; } public Object asJavaObject() { if (value instanceof FakeObjectProvider) { return ((FakeObjectProvider) value).innerObject(); } return value; } /** * Creates a JDWP value object that encapsulates a Java object living on the JDWP server side. * @param object the object that should be encapsulated in a JDWP value object * @param vm represents the VM in which this value should live * @param expectedClass the expected class that the faked value should have * @return a JDWP value object rpresenting the Java object */ public static VMValue fromJavaObject(Object object, VMAccess vm, Class expectedClass) { final VMValueImpl value = new VMValueImpl(); value.value = object; if (object == null) { value.type = Type.PROVIDER; } else if (expectedClass == Byte.TYPE) { value.type = Type.BYTE; } else if (expectedClass == Character.TYPE) { value.type = Type.CHAR; } else if (expectedClass == Short.TYPE) { value.type = Type.SHORT; } else if (expectedClass == Integer.TYPE) { value.type = Type.INT; } else if (expectedClass == Float.TYPE) { value.type = Type.FLOAT; } else if (expectedClass == Double.TYPE) { value.type = Type.DOUBLE; } else if (expectedClass == Long.TYPE) { value.type = Type.LONG; } else if (expectedClass == Boolean.TYPE) { value.type = Type.BOOLEAN; } else if (object instanceof ObjectProvider) { value.type = Type.PROVIDER; } else { // No matching type found => get fake object provider value.type = Type.PROVIDER; value.value = findFakeObjectProvider(object, vm); } return value; } /** * Looks up a JDWP object provider that encapsulates a certain Java object. If no object provider is found, a new one is generated. * @param object the object for which an object provider instance should be looked up * @param vm the VM in which this object provider lives * @return an ObjectProvider object encapsulating the given object */ private static ObjectProvider findFakeObjectProvider(Object object, VMAccess vm) { assert object != null; if (!objectProviderCache.containsKey(object)) { objectProviderCache.put(object, createFakeObjectProvider(object, vm)); } return objectProviderCache.get(object); } /** * Creates a new object provider encapsulating a certain Java object. * @param object the object that should be encapsulated in an ObjectProvider object * @param vm the VM in which the object provider should live in * @return an ObjectProvider object encapsulating the given object */ private static ObjectProvider createFakeObjectProvider(Object object, VMAccess vm) { assert object != null; final ReferenceTypeProvider type = vm.getReferenceType(object.getClass()); assert type != null : "The reference type for class " + object.getClass() + " could not be found!"; if (type instanceof ArrayTypeProvider) { final ArrayTypeProvider arrayType = (ArrayTypeProvider) type; return new FakeArrayProvider(object, arrayType, vm); } if (object instanceof String) { return new FakeStringProvider((String) object, type); } return new FakeObjectProvider(object, type); } @Override public String toString() { return "VMValue(" + type + "): " + value; } private static class FakeStringProvider extends FakeObjectProvider implements StringProvider { private String stringValue; public FakeStringProvider(String stringValue, ReferenceTypeProvider type) { super(stringValue, type); this.stringValue = stringValue; } public String stringValue() { return stringValue; } } private static class FakeObjectProvider implements ObjectProvider { private Object innerObject; private ReferenceTypeProvider type; public FakeObjectProvider(Object innerObject, ReferenceTypeProvider type) { assert innerObject != null : "The inner object must not be null, otherwise the object is a valid value for an object provider anyway!"; this.innerObject = innerObject; this.type = type; } public ReferenceTypeProvider getReferenceType() { return type; } Object innerObject() { return innerObject; } } private static class FakeArrayProvider extends FakeObjectProvider implements ArrayProvider { private ArrayTypeProvider arrayType; private VMAccess vm; public FakeArrayProvider(Object innerObject, ArrayTypeProvider arrayType, VMAccess vm) { super(innerObject, arrayType); this.arrayType = arrayType; this.vm = vm; } public ArrayTypeProvider getArrayType() { return arrayType; } public VMValue getValue(int i) { final Class klass = innerObject().getClass().getComponentType(); assert klass != null; // Create values for array elements lazily. return vm.createJavaObjectValue(Array.get(innerObject(), i), klass); } public int length() { return Array.getLength(innerObject()); } public void setValue(int i, VMValue value) { final Class klass = innerObject().getClass().getComponentType(); assert klass != null; Array.set(innerObject(), i, value.asJavaObject()); } } }