Package com.google.code.vimsztool.debug

Source Code of com.google.code.vimsztool.debug.ExpressionEval

package com.google.code.vimsztool.debug;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.google.code.vimsztool.exception.ExpressionEvalException;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ArrayType;
import com.sun.jdi.BooleanType;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.IntegerValue;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.PrimitiveType;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Type;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;

public class ExpressionEval {

  private static String[] primitiveTypeNames = { "boolean", "byte", "char",
      "short", "int", "long", "float", "double" };
 
  private static int getMaxLength(List<String> names) {
    int max = 0;
    if (names == null || names.size() ==0) return 0;
    for (String name : names ) {
      int len = name.length();
      if (len > max) max = len;
    }
    return max;
  }
 
  public static String eval(List<Expression> exps) {
    if (exps ==null || exps.size() == 0) return "";
    StringBuilder sb = new StringBuilder();
    int count = 0;
    List<String> oriExps = new ArrayList<String>();
    for (Expression exp : exps ) {
      oriExps.add(exp.getOriExp());
    }
    int maxLen = getMaxLength(oriExps)+2;
   
    for (Expression exp :exps) {
      count ++;
      sb.append(padStr(maxLen,exp.getOriExp())).append(":");
      try {
        Value value = getJdiValue(exp);
        sb.append(getPrettyPrintStr(value)).append("\n");
      } catch (ExpressionEvalException e) {
        sb.append("exception in calc the value");
      }
    }
    return sb.toString();
  }
 
  public static String executeEvalCmd(String debugCmd,String debugCmdArgs) {
    String actionResult = null;
    try {
      if (debugCmd.equals("eval") || debugCmd.equals("print")) {
        String exp = debugCmdArgs.substring(debugCmd.length()+1);
        actionResult =  eval(exp);
      } else if (debugCmd.equals("inspect")) {
        String exp = debugCmdArgs.substring(debugCmd.length()+1);
        actionResult =  inspect(exp);
      } else if (debugCmd.equals("locals")) {
        actionResult = variables();
      } else if (debugCmd.equals("fields")) {
        actionResult = fields();
      } else if (debugCmd.equals("reftype")) {
        String exp = debugCmdArgs.substring(debugCmd.length()+1);
        actionResult = reftype(exp);
      }
      return actionResult;
    } catch (ExpressionEvalException e) {
      return e.getMessage();
    }
  }
 
 
  private static ThreadReference checkAndGetCurrentThread() {
    Debugger debugger = Debugger.getInstance();
    if (debugger.getVm() == null ) {
      throw new ExpressionEvalException("no virtual machine connected.");
    }
   
    SuspendThreadStack threadStack = SuspendThreadStack.getInstance();
    ThreadReference threadRef = threadStack.getCurThreadRef();
    if (threadRef == null ) {
      throw new ExpressionEvalException("no suspend thread.");
    }
    return threadRef;
  }
 
  private static String padStr(int maxLen, String origStr) {
    if (origStr  == null) return "";
    int len = origStr.length();
    if (len >= maxLen ) return origStr;
    for (int i=0; i< (maxLen-len); i++) {
      origStr = origStr + " ";
    }
    return origStr;
  }
 
  public static String fields() {
    ThreadReference threadRef = checkAndGetCurrentThread();
    SuspendThreadStack threadStack = SuspendThreadStack.getInstance();
    StringBuilder sb = new StringBuilder();
    try {
      StackFrame stackFrame = threadRef.frame(threadStack.getCurFrame());
      ObjectReference thisObj = stackFrame.thisObject();
      Map<Field, Value> values = thisObj.getValues(thisObj.referenceType().visibleFields());
      List<String> fieldNames = new ArrayList<String>();
      for (Field field : values.keySet()) {
        fieldNames.add(field.name());
      }
      int maxLen = getMaxLength(fieldNames)+2;
      for (Field field : values.keySet()) {
        sb.append(padStr(maxLen,field.name())).append(":");
        sb.append(getPrettyPrintStr(values.get(field)));
        sb.append("\n");
        //stackFrame = threadRef.frame(0);
      }
    } catch (IncompatibleThreadStateException e) {
    }

    return sb.toString();
  }

  public static String variables() {
    ThreadReference threadRef = checkAndGetCurrentThread();
    SuspendThreadStack threadStack = SuspendThreadStack.getInstance();
    int curFrame = threadStack.getCurFrame();
    StringBuilder sb = new StringBuilder();
    try {
      List<String> varNames = new ArrayList<String>();
      for (LocalVariable var : threadRef.frame(curFrame).visibleVariables()) {
        varNames.add(var.name());
      }
      int maxLen = getMaxLength(varNames)+2;
      for (LocalVariable var : threadRef.frame(curFrame).visibleVariables()) {
        Value value = threadRef.frame(curFrame).getValue(var);
        sb.append(padStr(maxLen,var.name())).append(":");
        sb.append(getPrettyPrintStr(value));
        sb.append("\n");
      }
    } catch (AbsentInformationException e) {
      e.printStackTrace();
    } catch (IncompatibleThreadStateException e) {
      e.printStackTrace();
    }
    return sb.toString();
  }
 
  public static String reftype(String expXmlStr) {
    List<Expression> exps = Expression.parseExpXmlStr(expXmlStr);
    if (exps ==null || exps.size() == 0) return "";
    Value value = getJdiValue(exps.get(0));
    return value.type().name();
  }

  public static String inspect(String expXmlStr) {
    List<Expression> exps = Expression.parseExpXmlStr(expXmlStr);
    if (exps ==null || exps.size() == 0) return "";
    Expression exp = exps.get(0);
    Value value = getJdiValue(exp);
   
    StringBuilder sb = new StringBuilder();
    if (value instanceof ObjectReference) {
      sb.append(exp.getOriExp()).append(" = ");
      sb.append(value.type().name()).append("\n");
     
      ObjectReference objRef = (ObjectReference) value;
      Map<Field, Value> values = objRef.getValues(objRef.referenceType().visibleFields());
      List<String> fieldNames = new ArrayList<String>();
      for (Field field : values.keySet()) {
        if (field.isStatic()) continue;
        fieldNames.add(field.name());
      }
      int maxLen = getMaxLength(fieldNames)+2;
      for (Field field : values.keySet()) {
        sb.append("    ");
        sb.append(padStr(maxLen,field.name())).append(":");
        sb.append(getPrettyPrintStr(values.get(field)));
        sb.append("\n");
      }
    }
    return sb.toString();
  }

  public static String eval(String expXmlStr) {
    List<Expression> exps = Expression.parseExpXmlStr(expXmlStr);
    return eval(exps);
  }
 
  public static Value getJdiValue(Expression exp) {
    ThreadReference threadRef = checkAndGetCurrentThread();
    try {
      SuspendThreadStack threadStack = SuspendThreadStack.getInstance();
      StackFrame stackFrame = threadRef.frame(threadStack.getCurFrame());
      ObjectReference thisObj = stackFrame.thisObject();
      Value value = eval(threadRef, exp, thisObj,false);
      return value;
    } catch (IncompatibleThreadStateException e) {
      throw new ExpressionEvalException("eval expression error, caused by : " + e.getMessage());
    }
  }

  public static Value eval(ThreadReference threadRef, Expression exp,
      ObjectReference thisObj,boolean hasParents) {

    if (exp == null)
      return null;
    VirtualMachine vm = threadRef.virtualMachine();
    String expType = exp.getExpType();
    String expName = exp.getName();

    if (expType.equals(Expression.EXP_TYPE_BOOL)) {
      if (expName.equals("true"))
        return vm.mirrorOf(true);
      else
        return vm.mirrorOf(false);
    } else if (expType.equals(Expression.EXP_TYPE_STR)) {
      return vm.mirrorOf(expName);
    } else if (expType.equals(Expression.EXP_TYPE_NULL)) {
      return null;
    } else if (expType.equals(Expression.EXP_TYPE_NUM)) {
      if (expName.indexOf(".") > -1) {
        return vm.mirrorOf(Float.parseFloat(expName));
      } else {
        return vm.mirrorOf(Integer.parseInt(expName));
      }
    }

    Value basicExpValue = null;
    if (!exp.isMethod()) {
      basicExpValue = findValueInFrame(threadRef, expName,thisObj,hasParents);
    } else {
      List<Expression> params = exp.getParams();
      List<Value> arguments = new ArrayList<Value>();
      if (params.size() != 0) {
        for (Expression param : params) {
          Value paramValue = eval(threadRef, param, thisObj,false);
          arguments.add(paramValue);
        }
      }
      basicExpValue = invoke((ObjectReference) thisObj, expName, arguments);
    }
     
    if (exp.isArrayExp()) {
      if (basicExpValue instanceof ArrayReference) {
        ArrayReference array = (ArrayReference)basicExpValue;
        Value arrayIdxValue = eval(threadRef, exp.getArrayIdxExp(), thisObj,false);
        if (arrayIdxValue instanceof IntegerValue ) {
          int idx = ((IntegerValue)arrayIdxValue).value();
          basicExpValue = array.getValue(idx);
        else {
          throw new ExpressionEvalException("eval expression error, array index is not int type.");
        }
      }
    }

    List<Expression> members = exp.getMembers();
    if (members.size() == 0)
      return basicExpValue;
    if (exp.isStaticMember()) {
      Expression memberExp = members.get(0);
      List<Expression> params = memberExp.getParams();
      List<Value> arguments = new ArrayList<Value>();
      if (params.size() != 0) {
        for (Expression param : params) {
          Value paramValue = eval(threadRef, param, thisObj,false);
          arguments.add(paramValue);
        }
      }
      List<ReferenceType> refTypes = vm.classesByName(exp.getName());
      if (refTypes == null || refTypes.size() == 0) {
        throw new ExpressionEvalException("eval expression error, type '" + exp.getName() + "' can't be found ");
      }
       
      basicExpValue = invoke(refTypes.get(0), memberExp.getName(), arguments);
      if (members.size() > 1) {
        for (int i = 1; i < members.size(); i++) {
          Expression member = members.get(i);
          basicExpValue = eval(threadRef, member, (ObjectReference) basicExpValue,true);
        }
      }
    } else {

      for (Expression member : members) {
        basicExpValue = eval(threadRef, member,
            (ObjectReference) basicExpValue,true);
      }
    }
    return basicExpValue;
  }

  public static Value findValueInFrame(ThreadReference threadRef, String name,
      ObjectReference thisObj, boolean hasParents)  {
   
    Value value = null;
    try {
      SuspendThreadStack threadStack = SuspendThreadStack.getInstance();
      StackFrame stackFrame = threadRef.frame(threadStack.getCurFrame());
      if (!hasParents) {
        LocalVariable localVariable;
        localVariable = stackFrame.visibleVariableByName(name);
        if (localVariable != null) {
          return stackFrame.getValue(localVariable);
        }
      }
     
      ReferenceType refType = stackFrame.location().declaringType();
      if (thisObj != null ) {
        refType = thisObj.referenceType();
      }
      Field field = refType.fieldByName(name);
      if (field == null ) {
        throw new ExpressionEvalException("eval expression error, field '" + name +"' can't be found.");
      }
      if (thisObj != null) {
        value = thisObj.getValue(field);
      } else {
        value = refType.getValue(field);
      }
    } catch (IncompatibleThreadStateException e) {
      throw new ExpressionEvalException("eval expression error, caused by:" + e.getMessage());
    } catch (AbsentInformationException e) {
      throw new ExpressionEvalException("eval expression error, caused by:" + e.getMessage());
    }
    return value;
  }

  public static String getPrettyPrintStr(Value var) {
    if (var == null)
      return "null";
    if (var instanceof ArrayReference) {
      StringBuilder sb = new StringBuilder("[");
      ArrayReference arrayObj = (ArrayReference) var;
      if (arrayObj.length() == 0)
        return "[]";
      List<Value> values = arrayObj.getValues();
      for (Value value : values) {
        sb.append(getPrettyPrintStr(value)).append(",");
      }
      sb.deleteCharAt(sb.length() - 1);
      sb.append("]");
      return sb.toString();
    } else if (var instanceof ObjectReference) {
      Value strValue = invoke((ObjectReference) var, "toString",
          new ArrayList());
      return strValue.toString();
    } else {
      return var.toString();
    }
  }
 
  public static Value invoke(Object invoker, String methodName, List args) {
    SuspendThreadStack threadStack = SuspendThreadStack.getInstance();
    ThreadReference threadRef = threadStack.getCurThreadRef();
    Value value = null;
    Method matchedMethod = null;
    List<Method> methods = null;
    ClassType refType = null;
    ObjectReference obj  = null;
    if (invoker instanceof ClassType) {
      refType = (ClassType)invoker;
        methods = refType.methodsByName(methodName);
    } else {
       obj = (ObjectReference)invoker;
       methods = obj.referenceType().methodsByName(methodName);
    }
    if (methods == null || methods.size() == 0) {
      throw new ExpressionEvalException("eval expression error, method '" + methodName + "' can't be found");
    }
    if (methods.size() == 1) {
      matchedMethod = methods.get(0);
    } else {
      matchedMethod = findMatchedMethod(methods, args);
    }
    try {
        if (invoker instanceof ClassType) {
         ClassType clazz = (ClassType)refType;
         value = clazz.invokeMethod(threadRef, matchedMethod, args,
          ObjectReference.INVOKE_SINGLE_THREADED);
        } else {
          value = obj.invokeMethod(threadRef, matchedMethod, args,
            ObjectReference.INVOKE_SINGLE_THREADED);
        }
    } catch (InvalidTypeException e) {
      e.printStackTrace();
      throw new ExpressionEvalException("eval expression error, caused by :" + e.getMessage());
    } catch (ClassNotLoadedException e) {
      e.printStackTrace();
      throw new ExpressionEvalException("eval expression error, caused by :" + e.getMessage());
    } catch (IncompatibleThreadStateException e) {
      e.printStackTrace();
      throw new ExpressionEvalException("eval expression error, caused by :" + e.getMessage());
    } catch (InvocationException e) {
      e.printStackTrace();
      throw new ExpressionEvalException("eval expression error, caused by :" + e.getMessage());
    }
    return value;
  }


  private static Method findMatchedMethod(List<Method> methods, List arguments) {
    for (Method method : methods) {
      try {
        List argTypes = method.argumentTypes();
        if (argumentsMatch(argTypes, arguments))
          return method;
      } catch (ClassNotLoadedException e) {
      }
    }
    return null;
  }

  private static boolean isPrimitiveType(String name) {
    for (String primitiveType : primitiveTypeNames) {
      if (primitiveType.equals(name))
        return true;
    }
    return false;
  }

  private static boolean argumentsMatch(List argTypes, List arguments) {
    if (argTypes.size() != arguments.size()) {
      return false;
    }
    Iterator typeIter = argTypes.iterator();
    Iterator valIter = arguments.iterator();
    while (typeIter.hasNext()) {
      Type argType = (Type) typeIter.next();
      Value value = (Value) valIter.next();
      if (value == null) {
        if (isPrimitiveType(argType.name()))
          return false;
      }
      if (!value.type().equals(argType)) {
        if (isAssignableTo(value.type(), argType)) {
          return true;
        } else {
          return false;
        }
      }
    }
    return true;
  }

  private static boolean isAssignableTo(Type fromType, Type toType) {

    if (fromType.equals(toType))
      return true;
    if (fromType instanceof BooleanType && toType instanceof BooleanType)
      return true;
    if (toType instanceof BooleanType)
      return false;
    if (fromType instanceof PrimitiveType
        && toType instanceof PrimitiveType)
      return true;
    if (toType instanceof PrimitiveType)
      return false;

    if (fromType instanceof ArrayType) {
      return isArrayAssignableTo((ArrayType) fromType, toType);
    }
    List interfaces;
    if (fromType instanceof ClassType) {
      ClassType superclazz = ((ClassType) fromType).superclass();
      if ((superclazz != null) && isAssignableTo(superclazz, toType)) {
        return true;
      }
      interfaces = ((ClassType) fromType).interfaces();
    } else {
      interfaces = ((InterfaceType) fromType).superinterfaces();
    }
    Iterator iter = interfaces.iterator();
    while (iter.hasNext()) {
      InterfaceType interfaze = (InterfaceType) iter.next();
      if (isAssignableTo(interfaze, toType)) {
        return true;
      }
    }
    return false;
  }

  static boolean isArrayAssignableTo(ArrayType fromType, Type toType) {
    if (toType instanceof ArrayType) {
      try {
        Type toComponentType = ((ArrayType) toType).componentType();
        return isComponentAssignable(fromType.componentType(),
            toComponentType);
      } catch (ClassNotLoadedException e) {
        return false;
      }
    }
    if (toType instanceof InterfaceType) {
      return toType.name().equals("java.lang.Cloneable");
    }
    return toType.name().equals("java.lang.Object");
  }

  private static boolean isComponentAssignable(Type fromType, Type toType) {
    if (fromType instanceof PrimitiveType) {
      return fromType.equals(toType);
    }
    if (toType instanceof PrimitiveType) {
      return false;
    }
    return isAssignableTo(fromType, toType);
  }

}
TOP

Related Classes of com.google.code.vimsztool.debug.ExpressionEval

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.