/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
abstract class LValue {
// The JDI Value object for this LValue. Once we have this Value,
// we have to remember it since after we return the LValue object
// to the ExpressionParser, it might decide that it needs
// the 'toString' value for the LValue in which case it will
// call getMassagedValue to get this toString value. At that
// point, we don't want to call JDI a 2nd time to get the Value
// for the LValue. This is especially wrong when the LValue
// represents a member function. We would end up calling it
// a 2nd time.
//
// Unfortunately, there are several levels of calls to
// value in the debuggee.
throws ParseException, InvalidTypeException,
try {
} catch (InvalidTypeException exc) {
throw new ParseException(
"Attempt to set value of incorrect type" +
exc);
} catch (ClassNotLoadedException exc) {
throw new ParseException(
exc);
}
}
}
try {
} catch (IncompatibleThreadStateException exc) {
throw new ParseException("Thread not suspended");
}
}
if ((val instanceof ArrayReference) &&
}
}
// Return the Value for this LValue that would be used to concatenate
// to a String. IE, if it is an Object, call toString in the debuggee.
// If vv is an ObjectReference, then we have to
// do the implicit call to toString().
if (vv instanceof ObjectReference &&
!(vv instanceof StringReference) &&
!(vv instanceof ArrayReference)) {
try {
} catch (IncompatibleThreadStateException exc) {
throw new ParseException("Thread not suspended");
}
return toStringMember.interiorGetValue();
}
return vv;
}
try {
} catch (InvocationException e) {
throw new ParseException("Unable to complete expression. Exception " +
e.exception() + " thrown");
} catch (IncompatibleThreadStateException itse) {
throw new ParseException("Unable to complete expression. Thread " +
"not suspended for method invoke");
} catch (InvalidTypeException ite) {
throw new ParseException("Unable to complete expression. Method " +
"argument type mismatch");
} catch (ClassNotLoadedException tnle) {
throw new ParseException("Unable to complete expression. Method " +
" not yet loaded");
}
return value;
}
int index;
if ( (indexValue instanceof IntegerValue) ||
(indexValue instanceof ShortValue) ||
(indexValue instanceof ByteValue) ||
(indexValue instanceof CharValue) ) {
} else {
throw new ParseException("Array index must be a integer type");
}
}
try {
return interiorGetValue().toString();
} catch (ParseException e) {
return "<Parse Exception>";
}
}
/*
* TO DO: Note that this currently fails to find superclass
* or implemented interface fields. This is due to a temporary
* limititation of RefType.fieldByName. Once that method is
* fixed, superclass fields will be found.
*/
}
}
/***
System.err.println("fieldByName: " + refType.name() + " " +
name + " " +
kind + " " +
(field != null));
***/
return field;
}
}
}
return list;
}
static {
}
/*
* Return SAME, DIFFERENT or ASSIGNABLE.
* SAME means each arg type is the same as type of the corr. arg.
* ASSIGNABLE means that not all the pairs are the same, but
* for those that aren't, at least the argType is assignable
* from the type of the argument value.
* DIFFERENT means that in at least one pair, the
* argType is not assignable from the type of the argument value.
* IE, one is an Apple and the other is an Orange.
*/
return DIFFERENT;
}
// If any pair aren't the same, change the
// result to ASSIGNABLE. If any pair aren't
// assignable, return DIFFERENT
// Null values can be passed to any non-primitive argument
return DIFFERENT;
}
// Else, we will assume that a null value
// exactly matches an object type.
}
result = ASSIGNABLE;
} else {
return DIFFERENT;
}
}
}
return result;
}
// These is...AssignableTo methods are based on similar code in the JDI
// implementations of ClassType, ArrayType, and InterfaceType
if (fromType instanceof PrimitiveType) {
// Assignment of primitive arrays requires identical
// component types.
}
if (toType instanceof PrimitiveType) {
return false;
}
// Assignment of object arrays requires availability
// of widening conversion of component types
}
try {
} catch (ClassNotLoadedException e) {
// One or both component types has not yet been
// loaded => can't assign
return false;
}
}
if (toType instanceof InterfaceType) {
// Only valid InterfaceType assignee is Cloneable
}
// Only valid ClassType assignee is Object
}
return true;
}
// If one is boolean, so must be the other.
if (fromType instanceof BooleanType) {
if (toType instanceof BooleanType) {
return true;
}
return false;
}
if (toType instanceof BooleanType) {
return false;
}
// Other primitive types are intermixable only with each other.
if (fromType instanceof PrimitiveType) {
if (toType instanceof PrimitiveType) {
return true;
}
return false;
}
if (toType instanceof PrimitiveType) {
return false;
}
// neither one is primitive.
}
return true;
}
} else {
// fromType must be an InterfaceType
}
return true;
}
}
return false;
}
throws ParseException {
// If there is only one method to call, we'll just choose
// that without looking at the args. If they aren't right
// the invoke will return a better error message than we
// could generate here.
}
// Resolving overloads is beyond the scope of this exercise.
// So, we will look for a method that matches exactly the
// types of the arguments. If we can't find one, then
// if there is exactly one method whose param types are assignable
// from the arg types, we will use that. Otherwise,
// it is an error. We won't guess which of multiple possible
// methods to call. And, since casts aren't implemented,
// the user can't use them to pick a particular overload to call.
// IE, the user is out of luck in this case.
int assignableCount = 0;
try {
} catch (ClassNotLoadedException ee) {
// This probably won't happen for the
// method that we are really supposed to
// call.
continue;
}
return mm;
}
continue;
}
// Else, it is assignable. Remember it.
}
// At this point, we didn't find an exact match,
// but we found one for which the args are assignable.
//
if (assignableCount == 1) {
return retVal;
}
throw new ParseException("Arguments match multiple methods");
}
throw new ParseException("Arguments match no method");
}
}
}
return jdiValue;
}
}
}
}
if (!(value instanceof ObjectReference)) {
throw new ParseException(
"Cannot access field of primitive type: " + value);
}
/*
* Can't tell yet whether this LValue will be accessed as a
* field or method, so we keep track of all the possibilities
*/
throw new ParseException("No instance field or method with the name "
}
}
return jdiValue;
}
if (matchingMethod == null) {
if (matchingField == null) {
}
} else {
}
}
if (matchingMethod != null) {
throw new ParseException("Cannot assign to a method invocation");
}
}
if (matchingMethod != null) {
throw new ParseException("Invalid consecutive invocations");
}
}
}
/*
* Can't tell yet whether this LValue will be accessed as a
* field or method, so we keep track of all the possibilities
*/
throw new ParseException("No static field or method with the name "
}
}
return jdiValue;
}
if (matchingMethod == null) {
} else {
throw new InvalidTypeException("Cannot invoke static method on " +
}
}
throws ParseException, InvalidTypeException,
if (matchingMethod != null) {
throw new ParseException("Cannot assign to a method invocation");
}
throw new ParseException(
"Cannot set interface field: " + refType);
}
}
if (matchingMethod != null) {
throw new ParseException("Invalid consecutive invocations");
}
}
}
/*
* Since one can code "int myLen = myArray.length;",
* one might expect that these JDI calls would get a Value
* object for the length of an array in the debugee:
* Field xxx = ArrayType.fieldByName("length")
* Value lenVal= ArrayReference.getValue(xxx)
*
* However, this doesn't work because the array length isn't
* really stored as a field, and can't be accessed as such
* via JDI. Instead, the arrayRef.length() method has to be
* used.
*/
}
}
return jdiValue;
}
}
throw new ParseException("Array element is not a method");
}
}
final int index;
if (!(value instanceof ArrayReference)) {
throw new ParseException(
"Must be array type: " + value);
}
}
}
return jdiValue;
}
}
throw new ParseException("Array element is not a method");
}
}
}
}
return jdiValue;
}
}
throw new ParseException("Constant is not a method");
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
return new LValueConstant(null);
}
if (frameGetter == null) {
throw new ParseException("No current thread");
} else {
try {
if (thisObject==null) {
throw new ParseException(
"No 'this'. In native or static method");
} else {
return new LValueConstant(thisObject);
}
} catch (IncompatibleThreadStateException exc) {
throw new ParseException("Thread not suspended");
}
}
}
}
throw new ParseException("More than one class named: " +
}
throw new ParseException("Cannot create instance of interface " +
}
if (!method.isConstructor()) {
}
}
try {
} catch (InvocationException ie) {
} catch (IncompatibleThreadStateException exc) {
throw new ParseException("Thread not suspended");
} catch (Exception e) {
/*
* TO DO: Better error handling
*/
}
return new LValueConstant(newObject);
}
throws ParseException {
if (!izer.hasMoreTokens()) {
return lval;
} else {
}
}
// check local variables
if (frameGetter != null) {
try {
try {
} catch (AbsentInformationException e) {
}
} else {
if (thisObject != null) {
// check if it is a field of 'this'
try {
} catch (ParseException exc) {
}
}
}
}
// check for class name
while (izer.hasMoreTokens()) {
throw new ParseException("More than one class named: " +
first);
} else {
}
}
}
} catch (IncompatibleThreadStateException exc) {
throw new ParseException("Thread not suspended");
}
}
}
) throws ParseException {
return "null";
}
if (val instanceof StringReference) {
}
}
if ( !(right instanceof PrimitiveValue) ||
!(left instanceof PrimitiveValue) ) {
} else {
"' must be primitive");
}
}
// can compare any numeric doubles
boolean res;
} else {
}
}
) throws ParseException {
if ((right instanceof StringReference) ||
(left instanceof StringReference)) {
// If one is an ObjectRef, we will need to invoke
// toString on it, so we need the thread.
}
}
if ((right instanceof ObjectReference) ||
(left instanceof ObjectReference)) {
} else {
throw new ParseException("Invalid operation '" +
op + "' on an Object");
}
}
if ((right instanceof BooleanValue) ||
(left instanceof BooleanValue)) {
throw new ParseException("Invalid operation '" +
op + "' on a Boolean");
}
// from here on, we know it is a integer kind of type
if ((primRight instanceof DoubleValue) ||
(primLeft instanceof DoubleValue)) {
double res;
} else {
}
}
if ((primRight instanceof FloatValue) ||
(primLeft instanceof FloatValue)) {
float res;
} else {
}
}
long res;
} else {
}
} else {
int res;
} else {
}
}
}
}