blob: 785d9e4153a2118c94cbc5e3c51f1fa8d7002afc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 Nokia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nokia - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
import java.math.BigInteger;
import java.text.MessageFormat;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
import org.eclipse.cdt.debug.edc.internal.symbols.IEnumeration;
import org.eclipse.cdt.debug.edc.symbols.IType;
import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.core.runtime.CoreException;
public abstract class Instruction {
protected static BigInteger Mask8Bytes = new BigInteger("ffffffffffffffff", 16); //$NON-NLS-1$
protected Interpreter fInterpreter;
/**
* Get instruction size
*
* return instruction size
*/
public abstract int getSize();
/**
* Set instruction's fInterpreter
*
* @param interpreter
*/
public void setInterpreter(Interpreter interpreter) {
fInterpreter = interpreter;
}
/**
* Execute the instruction
* @throws CoreException
*/
public abstract void execute() throws CoreException;
/**
* Get the instruction's context
*
* @return instruction fInterpreter context
*/
protected IDMContext getContext() {
return fInterpreter.getContext();
}
/**
* Push an object on the instruction stack
*
* @param op
*/
protected OperandValue push(OperandValue op) {
fInterpreter.push(op);
return op;
}
/**
* Pop a value from the instruction stack
*
* @return current top of stack, if the stack is not empty, or
* <code>null</code> otherwise
* @throws CoreException
*/
protected OperandValue popValue() throws CoreException {
OperandValue value = null;
if (!fInterpreter.isEmpty())
value = fInterpreter.pop();
if (value == null)
throw EDCDebugger.newCoreException(ASTEvalMessages.Instruction_EmptyStack);
return value;
}
/**
* Push a boolean on the instruction stack
*
* @param value
* - boolean value
*/
protected OperandValue pushNewValue(IType type, boolean value) {
OperandValue op = new OperandValue(value ? 1 : 0, type);
fInterpreter.push(op);
return op;
}
/**
* Push a number on the instruction stack
*
* @param value
* - number value
*/
protected OperandValue pushNewValue(IType type, Number value) {
OperandValue op = new OperandValue(value, type);
fInterpreter.push(op);
return op;
}
/**
* Push a string on the instruction stack
*
* @param value
* - string value
*/
protected OperandValue pushNewValue(IType type, String value) {
OperandValue op = new OperandValue(value, type);
fInterpreter.push(op);
return op;
}
/**
* Convert operands to types expected by getBinaryPromotionType() (e.g.,
* VariableWithValue to its underlying Long)
*
* @param operand
* - original operand
* @return result operand type
* @throws CoreException if value cannot be fetched
*/
protected OperandValue convertForPromotion(OperandValue operand) throws CoreException {
IType type = getBasicType(operand.getValueType());
if (type instanceof ICompositeType) {
throw EDCDebugger.newCoreException(ASTEvalMessages.Instruction_CannotUseCompositeType);
}
if (type instanceof IArrayType && operand.getValueLocation() != null) {
// take address as value
return new OperandValue(operand.getValueLocationAddress(), fInterpreter.getTypeEngine().getPointerSizeType());
}
return operand;
}
/**
* Get result binary operation type given types of the left and right
* operands, according to Java rules
*
* @param left
* - left operand
* @param right
* - right operand
* @return result T_ type
* @throws CoreException
*/
public int getJavaBinaryPromotionType(OperandValue left, OperandValue right) throws CoreException {
int leftType = getValueType(left);
int rightType = getValueType(right);
return fTypeTable[leftType][rightType];
}
/**
* Get result binary operation type given types of the left and right
* operands
*
* @param left
* - left operand T_ type
* @param right
* - right operand T_type
* @return result T_ type
*/
public int getBinaryPromotionType(int left, int right) {
return fTypeTable[left][right];
}
/**
* Get T_ type for a base Java type (e.g., Character or Boolean).
* <p>
* This differs from the actual C type in that we pick the Java
* type that has the same size as the C type. I.e., "char" of size 1
* becomes T_byte and "wchar_t" of size 4 becomes T_int.
*
* @param value
* - base Java type object
* @return corresponding T_ type, or T_undefined if value is not a base type
* @throws CoreException
*/
public int getValueType(OperandValue op) throws CoreException {
Number value = op.getValue();
if (value == null) {
if (op.getStringValue() != null)
return T_String;
}
// respect Java types first, since C types can alias (e.g. int == long)
if (value instanceof Integer)
return T_int;
if (value instanceof Short)
return T_short;
if (value instanceof Byte)
return T_byte;
if (value instanceof Long)
return T_long;
if (value instanceof Float)
return T_float;
if (value instanceof Double)
return T_double;
if (value instanceof BigInteger)
return T_BigInt;
return getJavaValueType(op.getValueType());
}
/**
* Get T_ type corresponding to the given C type. This is used for promotion.
* Note: in this interpretation, long long maps to T_BigInt.
*
* @param type the basic type
* @return corresponding T_ type, or T_undefined if value is not a base type
* @throws CoreException
*/
public int getCValueType(OperandValue op) throws CoreException {
if (op.getStringValue() != null) {
return T_String;
}
IType type_ = getBasicType(op.getValueType());
if (!(type_ instanceof ICPPBasicType))
return T_undefined;
ICPPBasicType type = (ICPPBasicType) type_;
switch (type.getBaseType()) {
case ICPPBasicType.t_bool:
return T_boolean;
case ICPPBasicType.t_char:
return T_char;
case ICPPBasicType.t_float:
return T_float;
case ICPPBasicType.t_double:
if (type.isLong())
assert(false); // TODO; need long double type
return T_double;
case ICPPBasicType.t_int:
if (type.isLongLong())
return T_BigInt;
if (type.isLong())
return T_long;
if (type.isShort())
return T_short;
return T_int;
case ICPPBasicType.t_unspecified:
return T_undefined;
case ICPPBasicType.t_void:
return T_void;
}
return T_undefined;
}
/**
* Get result binary operation type given types of the left and right
* operands. This uses the C rules for type promotion.
*
* @param left
* - left type
* @param right
* - right type
* @return result type or <code>null</code> if an undefined promotion
*/
public IType getBinaryPromotionType(OperandValue leftOp, OperandValue rightOp) throws CoreException {
int leftType = getCValueType(leftOp);
int rightType = getCValueType(rightOp);
int promoted = getBinaryPromotionType(leftType, rightType);
if (promoted == T_null || promoted == T_undefined || promoted == T_void)
throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.Instruction_UnhandledTypeCombination,
leftOp.getValueType().getName(), rightOp.getValueType().getName()));
// promoted type loses qualifier bits and enum-ness
if (leftType == promoted)
return getBasicType(leftOp.getValueType());
if (rightType == promoted)
return getBasicType(rightOp.getValueType());
// we're here because the promoted type is bigger than either of the
// incoming types (e.g. short + float -> double)
boolean isSigned = true;
switch (promoted) {
case T_char:
return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_CHAR, isSigned);
case T_short:
return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_SHORT, isSigned);
case T_int:
return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_INT, isSigned);
case T_long:
return fInterpreter.getTypeEngine().getIntegerTypeFor(TypeUtils.BASIC_TYPE_LONG, isSigned);
case T_float:
return fInterpreter.getTypeEngine().getFloatTypeOfSize(TypeUtils.BASIC_TYPE_FLOAT);
case T_double:
return fInterpreter.getTypeEngine().getFloatTypeOfSize(TypeUtils.BASIC_TYPE_DOUBLE);
// TODO: long double
case T_byte: // should not happen
case T_null: // should not happen
case T_Object: // should not happen
case T_String: // should not happen
default:
assert(false);
throw EDCDebugger.newCoreException(ASTEvalMessages.UnhandledTypeCode + promoted);
}
}
/**
* Get the stripped down basic type that promotion rules work with.
* Ignore const/volatile/... qualifiers, demote enums to ints, etc.
* @param type
* @return adjusted type
*/
private IType getBasicType(IType type) {
type = TypeUtils.getStrippedType(type);
if (type instanceof IEnumeration) {
// discover the appropriate integer to hold this
int byteSize = ((IEnumeration) type).getByteSize();
type = fInterpreter.getTypeEngine().getIntegerTypeOfSize(byteSize, true);
}
return type;
}
/**
* Get T_ type for a base Java type that can hold a given type
* (e.g., Character or Boolean).
* <p>
* This differs from the actual C type in that we pick the Java
* type that has a compatible size as the C type. I.e., "char" of size 1
* becomes T_byte and "wchar_t" of size 4 becomes T_int. (An actual
* target may have larger or smaller primitive types than Java.)
* <p>
* Note: when we do unsigned math, we go up one type size in order to handle
* unsigned math properly.
*
* @param value
* - base Java type object
* @return corresponding T_ type, T_string, or T_undefined if value is not a base or string type
*/
public int getJavaValueType(IType type_) {
type_ = getBasicType(type_);
if (!(type_ instanceof ICPPBasicType)) {
if (type_ instanceof IArrayType && type_.getType() instanceof ICPPBasicType
&& ((((ICPPBasicType) type_.getType()).getBaseType() == ICPPBasicType.t_char
|| ((ICPPBasicType) type_.getType()).getBaseType() == ICPPBasicType.t_wchar_t))) {
return T_String;
}
return T_undefined;
}
ICPPBasicType type = (ICPPBasicType) type_;
switch (type.getBaseType()) {
case ICPPBasicType.t_bool:
return T_boolean;
case ICPPBasicType.t_char:
return T_char;
case ICPPBasicType.t_float:
return T_float;
case ICPPBasicType.t_double:
if (type.isLong())
assert(false); // TODO
return T_double;
case ICPPBasicType.t_unspecified:
return T_undefined;
case ICPPBasicType.t_void:
return T_void;
case ICPPBasicType.t_int:
if (type.isLongLong()) {
if (type.getByteSize() > 8 || (type.getByteSize() == 8 && type.isUnsigned()))
return T_BigInt; // java long cannot handle unsigned 8-byte math
else
return T_long;
}
if (type.isLong()) {
if (type.getByteSize() > 8 || (type.getByteSize() == 8 && type.isUnsigned()))
return T_BigInt; // java long cannot handle unsigned 8-byte math
else
return T_long;
}
switch (type.getByteSize()) {
case 1:
if (type.isUnsigned())
return T_short;
else
return T_byte;
case 2:
if (type.isUnsigned())
return T_int;
else
return T_short;
case 4:
if (type.isUnsigned())
return T_int;
else
return T_short;
}
if (type.isLong()) {
if (type.isUnsigned() && type.getByteSize() > 8)
return T_BigInt;
else
return T_long;
}
}
return T_undefined;
}
static public final int T_undefined = 0;
static public final int T_Object = 1;
static public final int T_char = 2;
static public final int T_byte = 3;
static public final int T_short = 4;
static public final int T_boolean = 5;
static public final int T_void = 6;
static public final int T_long = 7;
static public final int T_double = 8;
static public final int T_float = 9;
static public final int T_int = 10;
static public final int T_String = 11;
static public final int T_null = 12;
static public final int T_BigInt = 13;
private static final int[][] fTypeTable = {
// undefined object char byte short boolean void
/* undefined */ { T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined,
// long double float int String null BigInteger
T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined},
// undefined object char byte short boolean void
/* object */ { T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined,
// long double float int String null BigInteger
T_undefined, T_undefined, T_undefined, T_undefined, T_String, T_undefined, T_undefined },
// undefined object char byte short boolean void
/* char */ { T_undefined, T_undefined, T_int, T_int, T_int, T_undefined, T_undefined,
// long double float int String null BigInteger
T_long, T_double, T_float, T_int, T_String, T_undefined, T_BigInt },
// undefined object char byte short boolean void
/* byte */ { T_undefined, T_undefined, T_int, T_int, T_int, T_undefined, T_undefined,
// long double float int String null BigInteger
T_long, T_double, T_float, T_int, T_String, T_undefined, T_BigInt },
// undefined object char byte short boolean void
/* short */ { T_undefined, T_undefined, T_int, T_int, T_int, T_undefined, T_undefined,
// long double float int String null BigInteger
T_long, T_double, T_float, T_int, T_String, T_undefined, T_BigInt },
// undefined object char byte short boolean void
/* boolean */ { T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_boolean, T_undefined,
// long double float int String null BigInteger
T_undefined, T_undefined, T_undefined, T_undefined, T_String, T_undefined, T_undefined },
// undefined object char byte short boolean void
/* void */ { T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined,
// long double float int String null BigInteger
T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined },
// undefined object char byte short boolean void
/* long */ { T_undefined, T_undefined, T_long, T_long, T_long, T_undefined, T_undefined,
// long double float int String null BigInteger
T_long, T_double, T_float, T_long, T_String, T_undefined, T_BigInt },
// undefined object char byte short boolean void
/* double */ { T_undefined, T_undefined, T_double, T_double, T_double, T_undefined, T_undefined,
// long double float int String null BigInteger
T_double, T_double, T_double, T_double, T_String, T_undefined, T_double },
// undefined object char byte short boolean void
/* float */ { T_undefined, T_undefined, T_float, T_float, T_float, T_undefined, T_undefined,
// long double float int String null BigInteger
T_float, T_double, T_float, T_float, T_String, T_undefined, T_float },
// undefined object char byte short boolean void
/* int */ { T_undefined, T_undefined, T_int, T_int, T_int, T_undefined, T_undefined,
// long double float int String null BigInteger
T_long, T_double, T_float, T_int, T_String, T_undefined, T_BigInt },
// undefined object char byte short boolean void
/* String */ { T_undefined, T_String, T_String, T_String, T_String, T_String, T_undefined,
// long double float int String null BigInteger
T_String, T_String, T_String, T_String, T_String, T_String, T_undefined },
// undefined object char byte short boolean void
/* null */ { T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined, T_undefined,
// long double float int String null BigInteger
T_undefined, T_undefined, T_undefined, T_undefined, T_String, T_undefined, T_undefined },
// undefined object char byte short boolean void
/* BigInteger */{ T_undefined, T_undefined, T_BigInt, T_BigInt, T_BigInt, T_undefined, T_undefined,
// long double float int String null BigInteger
T_BigInt, T_double, T_float, T_BigInt, T_undefined, T_undefined, T_BigInt },
};
}