Package ch.epfl.labos.iu.orm.queryll2.symbolic

Source Code of ch.epfl.labos.iu.orm.queryll2.symbolic.BasicSymbolicInterpreter

package ch.epfl.labos.iu.orm.queryll2.symbolic;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.Value;

import ch.epfl.labos.iu.orm.queryll2.path.MethodSideEffect;
import ch.epfl.labos.iu.orm.queryll2.path.MethodSideEffectCall;


public class BasicSymbolicInterpreter extends InterpreterWithArgs implements Opcodes
{
   public BasicSymbolicInterpreter(int api)
  {
    super(api);
  }

  // Our symbolic execution needs to handle simple aliasing in order to
   // treat constructors properly. The ASM framework doesn't allow the
   // interpreter to change the values of variables other than the ones
   // that are being manipulated by an instruction, but to do aliasing
   // we need to reach in the the stack frame and change those other
   // variables, so we need this frame of variables.
   FrameWithHelpers linkedFrame;
   public void setFrameForAliasingFixups(FrameWithHelpers frame)
   {
      linkedFrame = frame;
   }

   // Keeps track of conditions that must hold for instructions to be executed
   public static interface BranchHandler
   {
      void ifInstruction(AbstractInsnNode insn, TypedValue.ComparisonValue ifTrueValue);
   }
   BranchHandler branchHandler;
   public void setBranchHandler(BranchHandler branchHandler)
   {
      this.branchHandler = branchHandler;
   }
  
   // Keeps track of return value from a path
   public TypedValue returnValue = null;
  
   // Keeps track of other side effects from executing a path
   public List<MethodSideEffect> sideEffects = new ArrayList<>();

   // Keeps track of which methods can be safely called
   public static enum OperationSideEffect
   {
      NONE,   // No side effects
      UNSAFE, // Has unsafe side effects, cancel the analysis
      SAFE    // There are side effects, but they should be safe. Log the side effect
   }
   public static interface MethodChecker
   {
      OperationSideEffect isMethodSafe(MethodSignature m, TypedValue base, List<TypedValue> args);
      OperationSideEffect isStaticMethodSafe(MethodSignature m);
      boolean isFluentChaining(MethodSignature m);
      boolean isPutFieldAllowed();
   }
   MethodChecker methodChecker;
   public void setMethodChecker(MethodChecker methodChecker)
   {
      this.methodChecker = methodChecker;
   }
  
   // Stuff that is called during the symbolic interpretation by Frame
  
   public Value newArg(Type type, int argumentIndex)
   {
      return new TypedValue.ArgValue(type, argumentIndex);
   }

   public Value newThis(Type type)
   {
      return new TypedValue.ThisValue(type);
   }

   public Value newValue(Type type)
   {
      // In practice, this will only be called with type==null for
      // uninitialized stack slot entries
      assert(type == null);
      return new TypedValue(type);
   }

   public Value copyOperation(AbstractInsnNode insn, Value value)
         throws AnalyzerException
   {
      return value;
   }

   public Value merge(Value v, Value w)
   {
      // not used
      return null;
   }

   public Value newOperation(AbstractInsnNode insn) throws AnalyzerException
   {
      switch (insn.getOpcode())
      {
         case ICONST_M1:
         case ICONST_0:
         case ICONST_1:
         case ICONST_2:
         case ICONST_3:
         case ICONST_4:
         case ICONST_5:
            return new ConstantValue.IntegerConstant(insn.getOpcode() - ICONST_M1 - 1);
         case LCONST_0:
         case LCONST_1:
            return new ConstantValue.LongConstant(insn.getOpcode() - LCONST_0);
         case FCONST_0:
         case FCONST_1:
         case FCONST_2:
            return new ConstantValue.FloatConstant(insn.getOpcode() - FCONST_0);
         case DCONST_0:
         case DCONST_1:
            return new ConstantValue.DoubleConstant(insn.getOpcode() - DCONST_0);
         case ACONST_NULL:
            return new ConstantValue.NullConstant();
         case LDC:
         {
            assert(insn instanceof LdcInsnNode);
            LdcInsnNode ldcInsn = (LdcInsnNode)insn;
            Object val = ldcInsn.cst;
            if (val instanceof String)
               return new ConstantValue.StringConstant((String)val);
            else if (val instanceof Integer)
               return new ConstantValue.IntegerConstant(((Integer)val).intValue());
            else if (val instanceof Long)
               return new ConstantValue.LongConstant(((Long)val).longValue());
            else if (val instanceof Float)
               return new ConstantValue.FloatConstant(((Float)val).floatValue());
            else if (val instanceof Double)
               return new ConstantValue.DoubleConstant(((Double)val).doubleValue());
            else if (val instanceof Type)
               return new ConstantValue.ClassConstant((Type)val);
            else
               throw new AnalyzerException(insn, "Unhandled bytecode instruction");
         }
         case NEW:
         {
            assert(insn instanceof TypeInsnNode);
            TypeInsnNode typeInsn = (TypeInsnNode)insn;
            String className = typeInsn.desc;
            return new TypedValue.NewValue(className);
         }
         case BIPUSH:
         case SIPUSH:
         {
            assert(insn instanceof IntInsnNode);
            IntInsnNode intInsn = (IntInsnNode)insn;
            return new ConstantValue.IntegerConstant(intInsn.operand);
         }
         case GETSTATIC:
         {
            assert(insn instanceof FieldInsnNode);
            FieldInsnNode fieldInsn = (FieldInsnNode)insn;
            return new TypedValue.GetStaticFieldValue(fieldInsn.owner, fieldInsn.name, fieldInsn.desc);
         }
         case JSR:
         default:
            throw new AnalyzerException(insn, "Unhandled bytecode instruction");
      }
   }

   public Value unaryOperation(AbstractInsnNode insn, Value value)
      throws AnalyzerException
   {
      switch(insn.getOpcode())
      {
         case IRETURN:
         case LRETURN:
         case FRETURN:
         case DRETURN:
         case ARETURN:
            // Return instructions will be handled in returnOperation()
            return null;
         case IFEQ:
         case IFNE:
         case IFLT:
         case IFGE:
         case IFGT:
         case IFLE:
            return ifOperation(insn, value, new ConstantValue.IntegerConstant(0));
         case IFNULL:
         case IFNONNULL:
            return ifOperation(insn, value, new ConstantValue.NullConstant());
         case CHECKCAST:
         {
            TypeInsnNode typeInsn = (TypeInsnNode)insn;
            return new TypedValue.CastValue(Type.getObjectType(typeInsn.desc), (TypedValue)value);
         }
         case I2L:
         case F2L:
         case D2L:
            return new TypedValue.CastValue(Type.LONG_TYPE, (TypedValue)value);
         case L2I:
         case F2I:
         case D2I:
            return new TypedValue.CastValue(Type.INT_TYPE, (TypedValue)value);
         case I2F:
         case L2F:
         case D2F:
            return new TypedValue.CastValue(Type.FLOAT_TYPE, (TypedValue)value);
         case I2D:
         case L2D:
         case F2D:
            return new TypedValue.CastValue(Type.DOUBLE_TYPE, (TypedValue)value);
         case INEG:
            return new TypedValue.UnaryMathOpValue(TypedValue.UnaryMathOpValue.UnaryOp.neg, Type.INT_TYPE, (TypedValue)value);
         case LNEG:
            return new TypedValue.UnaryMathOpValue(TypedValue.UnaryMathOpValue.UnaryOp.neg, Type.LONG_TYPE, (TypedValue)value);
         case DNEG:
            return new TypedValue.UnaryMathOpValue(TypedValue.UnaryMathOpValue.UnaryOp.neg, Type.DOUBLE_TYPE, (TypedValue)value);
         case GETFIELD:  // this should normally fail, but a subclass can handle it
         case FNEG:
         case IINC:
         case I2B:
         case I2C:
         case I2S:
         case TABLESWITCH:
         case LOOKUPSWITCH:
         case PUTSTATIC:
         case NEWARRAY:
         case ANEWARRAY:
         case ARRAYLENGTH:
         case ATHROW:
         case INSTANCEOF:
         case MONITORENTER:
         case MONITOREXIT:
         default:
            throw new AnalyzerException(insn, "Unhandled bytecode instruction");
      }
   }

   public Value binaryOperation(AbstractInsnNode insn, Value value1,
                                Value value2) throws AnalyzerException
   {
      switch (insn.getOpcode())
      {
         case IF_ICMPEQ:
         case IF_ICMPNE:
         case IF_ICMPLT:
         case IF_ICMPGE:
         case IF_ICMPGT:
         case IF_ICMPLE:
         case IF_ACMPEQ:
         case IF_ACMPNE:
            return ifOperation(insn, value1, value2);
         case ISUB:
         case LSUB:
         case FSUB:
         case DSUB:
            return new TypedValue.MathOpValue(TypedValue.MathOpValue.Op.minus, (TypedValue)value1, (TypedValue)value2);
         case IADD:
         case LADD:
         case FADD:
         case DADD:
            return new TypedValue.MathOpValue(TypedValue.MathOpValue.Op.plus, (TypedValue)value1, (TypedValue)value2);
         case IMUL:
         case LMUL:
         case FMUL:
         case DMUL:
            return new TypedValue.MathOpValue(TypedValue.MathOpValue.Op.mul, (TypedValue)value1, (TypedValue)value2);
         case IDIV:
         case LDIV:
         case FDIV:
         case DDIV:
            return new TypedValue.MathOpValue(TypedValue.MathOpValue.Op.div, (TypedValue)value1, (TypedValue)value2);
         case LCMP:
         case FCMPL:
         case FCMPG:
         case DCMPL:
         case DCMPG:
            return new TypedValue.MathOpValue(TypedValue.MathOpValue.Op.cmp, Type.INT_TYPE, (TypedValue)value1, (TypedValue)value2);
         case IREM:
         case LREM:
            return new TypedValue.MathOpValue(TypedValue.MathOpValue.Op.mod, Type.INT_TYPE, (TypedValue)value1, (TypedValue)value2);
         case IALOAD:
         case LALOAD:
         case FALOAD:
         case DALOAD:
         case AALOAD:
         case BALOAD:
         case CALOAD:
         case SALOAD:
         case FREM:
         case DREM:
         case ISHL:
         case LSHL:
         case ISHR:
         case LSHR:
         case IUSHR:
         case LUSHR:
         case IAND:
         case LAND:
         case IOR:
         case LOR:
         case IXOR:
         case LXOR:
         case PUTFIELD:
         default:
            throw new AnalyzerException(insn, "Unhandled bytecode instruction");
      }
   }

   public Value ternaryOperation(AbstractInsnNode insn, Value value1,
                                 Value value2, Value value3)
         throws AnalyzerException
   {
      switch(insn.getOpcode())
      {
         case IASTORE:
         case LASTORE:
         case FASTORE:
         case DASTORE:
         case AASTORE:
         case BASTORE:
         case CASTORE:
         case SASTORE:
         default:
            throw new AnalyzerException(insn, "Unhandled bytecode instruction");
      }
   }

   public Value naryOperation(AbstractInsnNode insn, List values)
         throws AnalyzerException
   {
      switch(insn.getOpcode())
      {
         case INVOKEVIRTUAL:
         case INVOKESPECIAL:
         case INVOKESTATIC:
         case INVOKEINTERFACE:
         {
            // TODO: Check that methods have no side-effects
           
            assert(insn instanceof MethodInsnNode);
            MethodInsnNode methodInsn = (MethodInsnNode)insn;
            boolean isVirtualCall = (insn.getOpcode() != INVOKESTATIC);
            List<TypedValue> args = new ArrayList<TypedValue>();
            for (int n = (isVirtualCall? 1:0); n < values.size(); n++)
               args.add((TypedValue)values.get(n));
            MethodSignature sig = new MethodSignature(methodInsn.owner, methodInsn.name, methodInsn.desc);
            if (isVirtualCall)
            {
               TypedValue base = (TypedValue)values.get(0);
               if (methodChecker != null)
               {
                  OperationSideEffect sideEffect = methodChecker.isMethodSafe(sig, base, args);
                  if (sideEffect == OperationSideEffect.UNSAFE)
                     throw new AnalyzerException(insn, "Unknown method " + sig + " encountered");
                  else if (sideEffect == OperationSideEffect.SAFE)
                     sideEffects.add(new MethodSideEffectCall(sig, base, args));
               }
               MethodCallValue.VirtualMethodCallValue toReturn;
               toReturn = new MethodCallValue.VirtualMethodCallValue(methodInsn.owner, methodInsn.name, methodInsn.desc, args, base);
               if (toReturn.isConstructor() && linkedFrame != null)
                  linkedFrame.replaceValues(base, toReturn);
               else if (methodChecker != null && methodChecker.isFluentChaining(sig))
                  linkedFrame.replaceValues(base, toReturn);
               return toReturn;
            }
            else
            {
               if (methodChecker != null)
               {
                  OperationSideEffect sideEffect = methodChecker.isStaticMethodSafe(sig);
                  if (sideEffect == OperationSideEffect.UNSAFE)
                     throw new AnalyzerException(insn, "Unknown method " + sig + " encountered");
                  else if (sideEffect == OperationSideEffect.SAFE)
                     sideEffects.add(new MethodSideEffectCall(sig, null, args));
               }
               return new MethodCallValue.StaticMethodCallValue(methodInsn.owner, methodInsn.name, methodInsn.desc, args);
            }
         }
         case INVOKEDYNAMIC:
         {
            assert(insn instanceof InvokeDynamicInsnNode);
            InvokeDynamicInsnNode invokeInsn = (InvokeDynamicInsnNode)insn;
            if (!"java/lang/invoke/LambdaMetafactory".equals(invokeInsn.bsm.getOwner())
                  || !"altMetafactory".equals(invokeInsn.bsm.getName())
                  || !"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;".equals(invokeInsn.bsm.getDesc()))
               throw new AnalyzerException(insn, "Unknown invokedynamic " + invokeInsn.bsm + " encountered");
            // Return the Lambda creation result
            Handle lambdaMethod = (Handle)invokeInsn.bsmArgs[1];
            Type functionalInterface = Type.getReturnType(invokeInsn.desc);
            return new LambdaFactory(functionalInterface, lambdaMethod, new ArrayList<>((List<TypedValue>)values));
         }
         case MULTIANEWARRAY:
         default:
            throw new AnalyzerException(insn, "Unhandled bytecode instruction");
      }
   }

   public void returnOperation(AbstractInsnNode insn, Value value,
                               Value expected) throws AnalyzerException
   {
      switch(insn.getOpcode())
      {
         case IRETURN:
         case LRETURN:
         case FRETURN:
         case DRETURN:
         case ARETURN:
            returnValue = (TypedValue)value;
            break;
         default:
      }
   }

   public Value ifOperation(AbstractInsnNode insn, Value value1,
                            Value value2) throws AnalyzerException
   {
      TypedValue.ComparisonValue.ComparisonOp op;
      switch (insn.getOpcode())
      {
         case IFEQ:
         case IF_ICMPEQ:
            op = TypedValue.ComparisonValue.ComparisonOp.eq;
            break;
         case IFNE:
         case IF_ICMPNE:
            op = TypedValue.ComparisonValue.ComparisonOp.ne;
            break;
         case IFLT:
         case IF_ICMPLT:
            op = TypedValue.ComparisonValue.ComparisonOp.lt;
            break;
         case IFGE:
         case IF_ICMPGE:
            op = TypedValue.ComparisonValue.ComparisonOp.ge;
            break;
         case IFGT:
         case IF_ICMPGT:
            op = TypedValue.ComparisonValue.ComparisonOp.gt;
            break;
         case IFLE:
         case IF_ICMPLE:
            op = TypedValue.ComparisonValue.ComparisonOp.le;
            break;
         case IFNULL:
         case IF_ACMPEQ:
            op = TypedValue.ComparisonValue.ComparisonOp.eq;
            break;
         case IFNONNULL:
         case IF_ACMPNE:
            op = TypedValue.ComparisonValue.ComparisonOp.ne;
            break;
         default:
            throw new AnalyzerException(insn, "Unhandled bytecode instruction");
      }
      TypedValue.ComparisonValue toReturn =
         new TypedValue.ComparisonValue(op, (TypedValue)value1, (TypedValue)value2);
     
      if (branchHandler != null)
         branchHandler.ifInstruction(insn, toReturn);
      return toReturn;
   }
  


}
TOP

Related Classes of ch.epfl.labos.iu.orm.queryll2.symbolic.BasicSymbolicInterpreter

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.