package jetbrains.mps.debugger.java.runtime.evaluation; /*Generated by MPS */ import jetbrains.mps.debugger.java.api.evaluation.EvaluationUtils; import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import com.intellij.openapi.application.ApplicationManager; import com.sun.jdi.Value; import com.sun.jdi.ArrayReference; import org.jetbrains.annotations.NotNull; import com.sun.jdi.ThreadReference; import jetbrains.mps.debugger.java.api.evaluation.EvaluationException; import com.sun.jdi.ClassType; import com.sun.jdi.Method; import java.util.List; import jetbrains.mps.debugger.java.api.evaluation.proxies.MirrorUtil; import com.sun.jdi.InvocationException; import com.sun.jdi.InvalidTypeException; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.VirtualMachine; import jetbrains.mps.debugger.java.api.evaluation.InvalidEvaluatedExpressionException; import com.sun.jdi.Field; import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.Nullable; import com.sun.jdi.Type; import com.sun.jdi.ArrayType; import com.sun.jdi.InterfaceType; import jetbrains.mps.debugger.java.api.evaluation.proxies.IValueProxy; import com.sun.jdi.StackFrame; import com.sun.jdi.LocalVariable; import com.sun.jdi.AbsentInformationException; import jetbrains.mps.debugger.java.api.evaluation.proxies.IObjectValueProxy; import jetbrains.mps.debugger.java.api.evaluation.proxies.IterableProxy; import jetbrains.mps.debugger.java.api.evaluation.proxies.IArrayValueProxy; import jetbrains.mps.debugger.java.api.evaluation.proxies.IterableArrayProxy; import com.sun.jdi.ClassObjectReference; import jetbrains.mps.debugger.java.api.evaluation.proxies.PrimitiveValueProxy; import com.sun.jdi.PrimitiveValue; import com.sun.jdi.BooleanValue; import com.sun.jdi.ShortValue; import com.sun.jdi.ByteValue; import com.sun.jdi.CharValue; import com.sun.jdi.DoubleValue; import com.sun.jdi.FloatValue; import com.sun.jdi.IntegerValue; import com.sun.jdi.LongValue; import jetbrains.mps.internal.collections.runtime.ListSequence; import com.sun.jdi.ObjectReference; public class EvaluationUtilsImpl extends EvaluationUtils { private static final Logger LOG = LogManager.getLogger(EvaluationUtilsImpl.class); public EvaluationUtilsImpl() { } @Override public void dispose() { synchronized (LOCK) { INSTANCE = null; } } @Override public void init() { synchronized (LOCK) { INSTANCE = this; } } public void assertEvaluating() { // todo real check LOG.assertLog(!(ApplicationManager.getApplication().isDispatchThread()), "Evaluation should be invoked in evaluation command rather than in edt."); } @Override public Value getArrayElementAt(ArrayReference array, int index) { assertEvaluating(); return array.getValue(index); } private Value invokeStaticInternal(String className, String methodName, String jniSignature, @NotNull final ThreadReference threadReference, Object... args) throws EvaluationException { assertEvaluating(); final ClassType referenceType = (ClassType) findClassType(className, threadReference.virtualMachine()); final Method method = findMethod(referenceType, methodName, jniSignature); final List<Value> argValues = MirrorUtil.getInstance().getValues(threadReference.virtualMachine(), args); return EvaluationUtils.handleInvocationExceptions(new EvaluationUtils.ThreadInvocatable<Value>(threadReference) { @Override public Value invoke() throws InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException { return referenceType.invokeMethod(threadReference, method, argValues, 0); } }); } private Value getStaticFieldValueInternal(String className, String fieldName, @NotNull final VirtualMachine machine) throws InvalidEvaluatedExpressionException { assertEvaluating(); ClassType referenceType = (ClassType) findClassType(className, machine); Field field = findField(referenceType, fieldName); assert field.isStatic(); return referenceType.getValue(field); } private Value invokeConstructorInternal(String className, String jniSignature, @NotNull final ThreadReference threadReference, Object... args) throws EvaluationException { // TODO duplication in code assertEvaluating(); final ClassType referenceType = (ClassType) findClassType(className, threadReference.virtualMachine()); final Method constructor = findConstructor(referenceType, jniSignature); final List<Value> argValues = MirrorUtil.getInstance().getValues(threadReference.virtualMachine(), args); return EvaluationUtils.handleInvocationExceptions(new EvaluationUtils.ThreadInvocatable<Value>(threadReference) { @Override public Value invoke() throws InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException { return referenceType.newInstance(threadReference, constructor, argValues, 0); } }); } @NotNull @Override public Field findField(ClassType referenceType, String fieldName) throws InvalidEvaluatedExpressionException { assertEvaluating(); Field field = referenceType.fieldByName(fieldName); if (field == null) { throw new InvalidEvaluatedExpressionException("Could not find field " + fieldName + " in " + referenceType.name() + "."); } return field; } @Override public List<Field> findFields(ClassType referenceType) { return referenceType.fields(); } @NotNull @Override public Method findConstructor(ClassType referenceType, String jniSignature) throws InvalidEvaluatedExpressionException { assertEvaluating(); List<Method> methods = referenceType.methodsByName("<init>", jniSignature); if (methods.size() == 0) { throw new InvalidEvaluatedExpressionException("Could not find constructor with signature " + jniSignature + " in " + referenceType.name() + "."); } Method constructor = null; for (Method m : methods) { if (m.isConstructor()) { constructor = m; break; } } if (constructor == null) { throw new InvalidEvaluatedExpressionException("Could not find constructor with signature " + jniSignature + " in " + referenceType.name() + "."); } return constructor; } @NotNull @Override public Method findMethod(ClassType referenceType, String methodsName, String jniSignature) throws InvalidEvaluatedExpressionException { assertEvaluating(); List<Method> methods = referenceType.methodsByName(methodsName, jniSignature); if (methods.size() == 0) { throw new InvalidEvaluatedExpressionException("Could not find method " + methodsName + " with signature " + jniSignature + " in " + referenceType.name() + "."); } return methods.get(0); } @NotNull @Override public ReferenceType findClassType(String className, VirtualMachine virtualMachine) throws InvalidEvaluatedExpressionException { assertEvaluating(); ReferenceType classType = findClassTypeSilently(className, virtualMachine); if (classType == null) { throw new InvalidEvaluatedExpressionException("Could not find class " + className + "."); } return classType; } @Nullable @Override public ReferenceType findClassTypeSilently(String className, VirtualMachine virtualMachine) throws InvalidEvaluatedExpressionException { assertEvaluating(); // apparently, classesByName works for both dot and slash (ie for java.lang.String and for java/lang/String) // even for java.lang/String List<ReferenceType> classes = virtualMachine.classesByName(className); if (classes.size() == 0) { return null; } return classes.get(0); } @Nullable @Override public Type findTypeSilently(String typeSignature, VirtualMachine virtualMachine) throws InvalidEvaluatedExpressionException { if ("Z".equals(typeSignature)) { return virtualMachine.mirrorOf(true).type(); } else if ("B".equals(typeSignature)) { return virtualMachine.mirrorOf((byte) 1).type(); } else if ("C".equals(typeSignature)) { return virtualMachine.mirrorOf('C').type(); } else if ("S".equals(typeSignature)) { return virtualMachine.mirrorOf((short) 1).type(); } else if ("I".equals(typeSignature)) { return virtualMachine.mirrorOf(1).type(); } else if ("J".equals(typeSignature)) { return virtualMachine.mirrorOf((long) 1).type(); } else if ("F".equals(typeSignature)) { return virtualMachine.mirrorOf((float) 1.0).type(); } else if ("D".equals(typeSignature)) { return virtualMachine.mirrorOf((double) 1.0).type(); } else if (typeSignature.startsWith("[")) { try { return createArrayProxy(EvaluationUtils.JAVA_LANG_OBJECT, virtualMachine, 0).getJDIValue().type(); } catch (EvaluationException e) { LOG.error(e); return findClassTypeSilently(JAVA_LANG_OBJECT, virtualMachine); } } return findClassTypeSilently(typeSignature.substring(1, typeSignature.length() - 1), virtualMachine); } @Override public boolean instanceOf(final Type what, final String jniSignature, final VirtualMachine machine) throws EvaluationException { assertEvaluating(); if (jniSignature.equals(EvaluationUtils.JAVA_LANG_OBJECT)) { // o_O // this is kinda not true when what is of primitive type return true; } if (what.signature().equals(jniSignature)) { return true; } return EvaluationUtils.handleInvocationExceptions(new EvaluationUtils.Invocatable<Boolean>() { @Override public Boolean invoke() throws InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, EvaluationException { if (jniSignature.startsWith("[")) { if (!((what instanceof ArrayType))) { return false; } return EvaluationUtilsImpl.this.instanceOf(((ArrayType) what).componentType(), jniSignature.substring(1), machine); } else if (jniSignature.startsWith("L")) { if (!((what instanceof ClassType))) { return false; } ReferenceType type = findClassTypeSilently(jniSignature.substring(1, jniSignature.length() - 1), machine); if (type == null) { return false; } ClassType whatClassType = (ClassType) what; if (type instanceof InterfaceType) { return whatClassType.allInterfaces().contains((InterfaceType) type); } do { if (type.equals(whatClassType)) { return true; } whatClassType = whatClassType.superclass(); } while (whatClassType != null); return false; } return false; } }); } @NotNull @Override public IValueProxy getVariableValue(String varName, StackFrame stackFrame) throws EvaluationException { assert stackFrame != null; assertEvaluating(); LocalVariable localVariable; try { localVariable = stackFrame.visibleVariableByName(varName); } catch (AbsentInformationException ex) { throw new EvaluationException(ex); } if (localVariable == null) { throw new EvaluationException("variable not found: " + varName); } Value v = stackFrame.getValue(localVariable); return MirrorUtil.getInstance().getValueProxy(v); } @NotNull @Override public <T extends IValueProxy> Iterable<T> toIterableProxy(IObjectValueProxy valueProxy, ThreadReference threadReference) { assertEvaluating(); return new IterableProxy<T>(valueProxy, threadReference); } @NotNull @Override public <T extends IValueProxy> Iterable<T> toIterableProxyFromArray(IArrayValueProxy valueProxy) { assertEvaluating(); return new IterableArrayProxy<T>(valueProxy); } @NotNull @Override public IValueProxy invokeStaticMethod(String className, String name, String jniSignature, ThreadReference threadReference, Object... args) throws EvaluationException { assertEvaluating(); return MirrorUtil.getInstance().getValueProxy(invokeStaticInternal(className, name, jniSignature, threadReference, args)); } @NotNull @Override public IValueProxy getStaticField(String className, String fieldName, VirtualMachine machine) throws InvalidEvaluatedExpressionException { assertEvaluating(); return MirrorUtil.getInstance().getValueProxy(getStaticFieldValueInternal(className, fieldName, machine)); } @NotNull @Override public IObjectValueProxy invokeConstructorProxy(String className, String jniSignature, ThreadReference threadReference, Object... args) throws EvaluationException { assertEvaluating(); return (IObjectValueProxy) MirrorUtil.getInstance().getValueProxy(invokeConstructorInternal(className, jniSignature, threadReference, args)); } @Override public IArrayValueProxy createArrayProxy(String className, VirtualMachine machine, int size) throws EvaluationException { assertEvaluating(); List<ReferenceType> referenceTypes = machine.classesByName(className + "["); if (referenceTypes.isEmpty()) { throw new EvaluationException("Could not find type " + className + "[]"); } ArrayType arrayType = null; for (ReferenceType referenceType : referenceTypes) { if (referenceType instanceof ArrayType) { arrayType = (ArrayType) referenceType; break; } } if (arrayType == null) { throw new EvaluationException("Could not find type " + className + "[]"); } ArrayReference arrayReference = arrayType.newInstance(size); return (IArrayValueProxy) MirrorUtil.getInstance().getValueProxy(arrayReference); } @Override public final IArrayValueProxy createArrayProxyFromValues(String className, VirtualMachine machine, Object... args) throws EvaluationException { assertEvaluating(); if (args == null) { // array of one element -- null return createArrayProxy(className, machine, 1); } else { IArrayValueProxy array = createArrayProxy(className, machine, args.length); List<Value> values = MirrorUtil.getInstance().getValues(machine, args); for (int i = 0; i < values.size(); i++) { array.setElement(values.get(i), i); } return array; } } @NotNull @Override public IValueProxy getClass(String className, VirtualMachine machine) throws InvalidEvaluatedExpressionException { assertEvaluating(); ClassType referenceType = (ClassType) findClassType(className, machine); ClassObjectReference classObject = referenceType.classObject(); return MirrorUtil.getInstance().getValueProxy(classObject); } @NotNull @Override public IObjectValueProxy boxValue(PrimitiveValueProxy primitiveValueProxy, ThreadReference threadReference) throws EvaluationException { assertEvaluating(); PrimitiveValue primitiveValue = primitiveValueProxy.getPrimitiveValue(); if (primitiveValue instanceof BooleanValue) { return (IObjectValueProxy) invokeStaticMethod(Boolean.class.getName(), "valueOf", "(Z)Ljava/lang/Boolean;", threadReference, primitiveValue.booleanValue()); } if (primitiveValue instanceof ShortValue) { return (IObjectValueProxy) invokeStaticMethod(Short.class.getName(), "valueOf", "(S)Ljava/lang/Short;", threadReference, primitiveValue.shortValue()); } if (primitiveValue instanceof ByteValue) { return (IObjectValueProxy) invokeStaticMethod(Byte.class.getName(), "valueOf", "(B)Ljava/lang/Byte;", threadReference, primitiveValue.byteValue()); } if (primitiveValue instanceof CharValue) { return (IObjectValueProxy) invokeStaticMethod(Character.class.getName(), "valueOf", "(C)Ljava/lang/Character;", threadReference, primitiveValue.charValue()); } if (primitiveValue instanceof DoubleValue) { return (IObjectValueProxy) invokeStaticMethod(Double.class.getName(), "valueOf", "(D)Ljava/lang/Double;", threadReference, primitiveValue.doubleValue()); } if (primitiveValue instanceof FloatValue) { return (IObjectValueProxy) invokeStaticMethod(Float.class.getName(), "valueOf", "(F)Ljava/lang/Float;", threadReference, primitiveValue.floatValue()); } if (primitiveValue instanceof IntegerValue) { return (IObjectValueProxy) invokeStaticMethod(Integer.class.getName(), "valueOf", "(I)Ljava/lang/Integer;", threadReference, primitiveValue.intValue()); } if (primitiveValue instanceof LongValue) { return (IObjectValueProxy) invokeStaticMethod(Long.class.getName(), "valueOf", "(J)Ljava/lang/Long;", threadReference, primitiveValue.longValue()); } throw new UnsupportedOperationException("Cant box " + primitiveValue); } @Override public PrimitiveValueProxy unboxValue(IObjectValueProxy valueProxy, ThreadReference threadReference) throws EvaluationException { assertEvaluating(); Type type = valueProxy.getJDIValue().type(); if (type.name().equals(Boolean.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("booleanValue", "()Z", threadReference); } if (type.name().equals(Short.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("shortValue", "()S", threadReference); } if (type.name().equals(Byte.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("byteValue", "()B", threadReference); } if (type.name().equals(Character.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("charValue", "()C", threadReference); } if (type.name().equals(Double.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("doubleValue", "()D", threadReference); } if (type.name().equals(Float.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("floatValue", "()F", threadReference); } if (type.name().equals(Integer.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("intValue", "()I", threadReference); } if (type.name().equals(Long.class.getName())) { return (PrimitiveValueProxy) valueProxy.invokeMethod("longValue", "()J", threadReference); } throw new UnsupportedOperationException("Cant unbox value of type" + type); } @Override public String getStringPresentation(@NotNull final Value value, @NotNull final ThreadReference threadReference) { assertEvaluating(); try { return MirrorUtil.getInstance().getJavaValue(value).toString(); } catch (UnsupportedOperationException e) { if (value instanceof ArrayReference) { ArrayReference array = (ArrayReference) value; StringBuffer buffer = new StringBuffer(); buffer.append("["); int length = array.length(); int i = 0; for (Value item : ListSequence.fromList(array.getValues())) { buffer.append(getStringPresentation(item, threadReference)); if (i < length - 1) { buffer.append(", "); } i++; } buffer.append("]"); return buffer.toString(); } else { return EvaluationUtils.consumeEvaluationException(new EvaluationUtils.EvaluationInvocatable<String>() { @Override public String invoke() throws EvaluationException { ObjectReference object = (ObjectReference) value; IObjectValueProxy valueProxy = (IObjectValueProxy) MirrorUtil.getInstance().getValueProxy(object); IValueProxy result = valueProxy.invokeMethod("toString", "()Ljava/lang/String;", threadReference); return getStringPresentation(result.getJDIValue(), threadReference); } }, null); } } } }