blob: aa19f75c6a8e253029ec203fedb0cb0639045de7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdi.internal;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdi.internal.jdwp.JdwpID;
import org.eclipse.jdi.internal.jdwp.JdwpObjectID;
import com.sun.jdi.ArrayType;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.InternalException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.PrimitiveType;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.Type;
import com.sun.jdi.Value;
import com.sun.jdi.VoidType;
/**
* this class implements the corresponding interfaces declared by the JDI
* specification. See the com.sun.jdi package for more information.
*
*/
public abstract class ValueImpl extends MirrorImpl implements Value {
/**
* Creates new ValueImpl.
*/
protected ValueImpl(String description, VirtualMachineImpl vmImpl) {
super(description, vmImpl);
}
/**
* @returns type of value.
*/
@Override
public abstract Type type();
/**
* @returns type of value.
*/
public abstract byte getTag();
/**
* @return Reads JDWP representation and returns new instance.
*/
public static ValueImpl readWithTag(MirrorImpl target, DataInputStream in)
throws IOException {
byte tag = target.readByte("object tag", JdwpID.tagMap(), in); //$NON-NLS-1$
return readWithoutTag(target, tag, in);
}
/**
* @return Reads JDWP representation and returns new instance.
*/
public static ValueImpl readWithoutTag(MirrorImpl target, int type,
DataInputStream in) throws IOException {
VirtualMachineImpl vmImpl = target.virtualMachineImpl();
// See also ArrayReference Impl.
switch (type) {
case ArrayReferenceImpl.tag:
return ArrayReferenceImpl.read(target, in);
case ClassLoaderReferenceImpl.tag:
return ClassLoaderReferenceImpl.read(target, in);
case ClassObjectReferenceImpl.tag:
return ClassObjectReferenceImpl.read(target, in);
case StringReferenceImpl.tag:
return StringReferenceImpl.read(target, in);
case ObjectReferenceImpl.tag:
return ObjectReferenceImpl.readObjectRefWithoutTag(target, in);
case ThreadGroupReferenceImpl.tag:
return ThreadGroupReferenceImpl.read(target, in);
case ThreadReferenceImpl.tag:
return ThreadReferenceImpl.read(target, in);
case BooleanValueImpl.tag:
return BooleanValueImpl.read(target, in);
case ByteValueImpl.tag:
return ByteValueImpl.read(target, in);
case CharValueImpl.tag:
return CharValueImpl.read(target, in);
case DoubleValueImpl.tag:
return DoubleValueImpl.read(target, in);
case FloatValueImpl.tag:
return FloatValueImpl.read(target, in);
case IntegerValueImpl.tag:
return IntegerValueImpl.read(target, in);
case LongValueImpl.tag:
return LongValueImpl.read(target, in);
case ShortValueImpl.tag:
return ShortValueImpl.read(target, in);
case VoidValueImpl.tag:
return new VoidValueImpl(vmImpl);
case 0:
return null;
default:
throw new InternalException(
JDIMessages.ValueImpl_Invalid_Value_tag_encountered___1
+ type);
}
}
/**
* Writes value with value tag.
*/
public void writeWithTag(MirrorImpl target, DataOutputStream out)
throws IOException {
target.writeByte(getTag(), "tag", JdwpID.tagMap(), out); //$NON-NLS-1$
write(target, out);
}
/**
* Writes value without value tag.
*/
public abstract void write(MirrorImpl target, DataOutputStream out)
throws IOException;
/**
* Writes null value without value tag.
*/
public static void writeNull(MirrorImpl target, DataOutputStream out)
throws IOException {
JdwpObjectID nullID = new JdwpObjectID(target.virtualMachineImpl());
nullID.write(out);
if (target.fVerboseWriter != null) {
target.fVerboseWriter.println("objectReference", nullID.value()); //$NON-NLS-1$
}
}
/**
* Writes null value with value tag.
*/
public static void writeNullWithTag(MirrorImpl target, DataOutputStream out)
throws IOException {
target.writeByte(ObjectReferenceImpl.tag, "tag", JdwpID.tagMap(), out); //$NON-NLS-1$
writeNull(target, out);
}
/**
* Check the type and the vm of each values, according to the associated
* type. For primitive values, convert the value for match the given type if
* needed. The two list must have the same size.
*
* @return the (converted) values.
* @see checkValue(Value, Type, VirtualMachineImpl)
*/
protected static List<Value> checkValues(List<?extends Value> values, List<Type> types,
VirtualMachineImpl vm) throws InvalidTypeException {
List<Value> result = new ArrayList<>(values.size());
Iterator<? extends Value> iterValues = values.iterator();
Iterator<Type> iterTypes = types.iterator();
while (iterValues.hasNext()) {
Value value = iterValues.next();
Type type = iterTypes.next();
result.add(checkValue(value, type, vm));
}
return result;
}
/**
* Check the type and the vm of the given value. In case of primitive value,
* the value is converted if needed.
*
* @return the (converted) value.
* @throws InvalidTypeException
* if the given value is no assignment compatible with the given
* type.
* @see checkPrimitiveValue(PrimitiveValueImpl, PrimitiveTypeImpl,
* PrimitiveTypeImpl)
*/
public static ValueImpl checkValue(Value value, Type type,
VirtualMachineImpl vm) throws InvalidTypeException {
if (value == null) {
if (!(type instanceof PrimitiveType)) {
return null;
}
} else {
vm.checkVM(value);
TypeImpl valueType = (TypeImpl) value.type();
if (valueType instanceof PrimitiveType
&& type instanceof PrimitiveType) {
return checkPrimitiveValue((PrimitiveValueImpl) value,
(PrimitiveTypeImpl) valueType, (PrimitiveTypeImpl) type);
}
if (valueType instanceof ReferenceType
&& type instanceof ReferenceType) {
checkReferenceType((ReferenceType) valueType,
(ReferenceType) type);
return (ValueImpl) value;
}
if (valueType instanceof VoidType && type instanceof VoidType) {
return (VoidValueImpl) value;
}
}
throw new InvalidTypeException(
MessageFormat
.format(JDIMessages.ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1,
new Object[] {
value != null ? value.type().name()
: "null", type.name() })); //$NON-NLS-1$
}
/**
*/
private static void checkReferenceType(ReferenceType valueType,
ReferenceType type) throws InvalidTypeException {
if (valueType instanceof ArrayType) {
if (type instanceof ArrayType) {
try {
Type valueComponentType = ((ArrayType) valueType)
.componentType();
Type componentType = ((ArrayType) type).componentType();
if (valueComponentType instanceof PrimitiveType) {
if (valueComponentType.equals(componentType)) {
return;
}
} else if (valueComponentType instanceof ReferenceType
&& componentType instanceof ReferenceType) {
checkReferenceType((ReferenceType) valueComponentType,
(ReferenceType) componentType);
return;
}
} catch (ClassNotLoadedException e) {
// should not append
}
} else {
// an array can be assigned to an object
if (type.signature().equals("Ljava/lang/Object;")) { //$NON-NLS-1$
return;
}
}
} else {
if (type instanceof ClassType) {
if (valueType instanceof ClassType) {
ClassType superClass = (ClassType) valueType;
while (superClass != null) {
if (superClass.equals(type)) {
return;
}
superClass = superClass.superclass();
}
} else if (valueType instanceof InterfaceType) {
// an interface can be assigned to an object
if (type.signature().equals("Ljava/lang/Object;")) { //$NON-NLS-1$
return;
}
}
} else if (type instanceof InterfaceType) {
if (valueType instanceof InterfaceType) {
if (checkInterfaceType((InterfaceType) valueType,
(InterfaceType) type)) {
return;
}
} else {
for (InterfaceType interfaceType : ((ClassType) valueType).allInterfaces()) {
if (checkInterfaceType(interfaceType,
(InterfaceType) type)) {
return;
}
}
}
}
}
throw new InvalidTypeException(
MessageFormat
.format(JDIMessages.ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1,
new Object[] { valueType.name(), type.name() }));
}
private static boolean checkInterfaceType(InterfaceType valueType,
InterfaceType type) {
if (valueType.equals(type)) {
return true;
}
for (InterfaceType interfaceType : valueType.superinterfaces()) {
if (checkInterfaceType(interfaceType, type)) {
return true;
}
}
return false;
}
/**
* Check the type of the given value, and convert the value to the given
* type if needed (see Java Language Spec, section 5.2).
*
* @return the (converted) value.
* @throws InvalidTypeException
* if the given value is no assignment compatible with the given
* type.
*/
protected static ValueImpl checkPrimitiveValue(PrimitiveValueImpl value,
PrimitiveTypeImpl valueType, PrimitiveTypeImpl type)
throws InvalidTypeException {
char valueTypeSignature = valueType.signature().charAt(0);
char typeSignature = type.signature().charAt(0);
if (valueTypeSignature == typeSignature) {
return value;
}
VirtualMachineImpl vm = value.virtualMachineImpl();
switch (typeSignature) {
case 'D':
if (valueTypeSignature != 'Z') {
return new DoubleValueImpl(vm, Double.valueOf(value.doubleValue()));
}
break;
case 'F':
if (valueTypeSignature != 'Z' && valueTypeSignature != 'D') {
return new FloatValueImpl(vm, Float.valueOf(value.floatValue()));
}
break;
case 'J':
if (valueTypeSignature != 'Z' && valueTypeSignature != 'D'
&& valueTypeSignature != 'F') {
return new LongValueImpl(vm, Long.valueOf(value.longValue()));
}
break;
case 'I':
if (valueTypeSignature == 'B' || valueTypeSignature == 'C'
|| valueTypeSignature == 'S') {
return new IntegerValueImpl(vm, Integer.valueOf(value.intValue()));
}
break;
case 'S':
if (valueTypeSignature == 'B') {
return new ShortValueImpl(vm, Short.valueOf(value.shortValue()));
}
break;
}
throw new InvalidTypeException(
MessageFormat
.format(JDIMessages.ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1,
new Object[] { valueType.name(), type.name() }));
}
}