@Override
 public BasicValue copyOperation(final AbstractInsnNode insn, final BasicValue value)
     throws AnalyzerException {
   Value expected;
   switch (insn.getOpcode()) {
     case ILOAD:
     case ISTORE:
       expected = BasicValue.INT_VALUE;
       break;
     case FLOAD:
     case FSTORE:
       expected = BasicValue.FLOAT_VALUE;
       break;
     case LLOAD:
     case LSTORE:
       expected = BasicValue.LONG_VALUE;
       break;
     case DLOAD:
     case DSTORE:
       expected = BasicValue.DOUBLE_VALUE;
       break;
     case ALOAD:
       if (!value.isReference()) {
         throw new AnalyzerException(insn, null, "an object reference", value);
       }
       return value;
     case ASTORE:
       if (!value.isReference() && !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
         throw new AnalyzerException(insn, null, "an object reference or a return address", value);
       }
       return value;
     default:
       return value;
   }
   if (!expected.equals(value)) {
     throw new AnalyzerException(insn, null, expected, value);
   }
   return value;
 }
 @Override
 public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
     throws AnalyzerException {
   BasicValue expected;
   switch (insn.getOpcode()) {
     case INEG:
     case IINC:
     case I2F:
     case I2L:
     case I2D:
     case I2B:
     case I2C:
     case I2S:
     case IFEQ:
     case IFNE:
     case IFLT:
     case IFGE:
     case IFGT:
     case IFLE:
     case TABLESWITCH:
     case LOOKUPSWITCH:
     case IRETURN:
     case NEWARRAY:
     case ANEWARRAY:
       expected = BasicValue.INT_VALUE;
       break;
     case FNEG:
     case F2I:
     case F2L:
     case F2D:
     case FRETURN:
       expected = BasicValue.FLOAT_VALUE;
       break;
     case LNEG:
     case L2I:
     case L2F:
     case L2D:
     case LRETURN:
       expected = BasicValue.LONG_VALUE;
       break;
     case DNEG:
     case D2I:
     case D2F:
     case D2L:
     case DRETURN:
       expected = BasicValue.DOUBLE_VALUE;
       break;
     case GETFIELD:
       expected = newValue(Type.getObjectType(((FieldInsnNode) insn).owner));
       break;
     case CHECKCAST:
       if (!value.isReference()) {
         throw new AnalyzerException(insn, null, "an object reference", value);
       }
       return super.unaryOperation(insn, value);
     case ARRAYLENGTH:
       if (!isArrayValue(value)) {
         throw new AnalyzerException(insn, null, "an array reference", value);
       }
       return super.unaryOperation(insn, value);
     case ARETURN:
     case ATHROW:
     case INSTANCEOF:
     case MONITORENTER:
     case MONITOREXIT:
     case IFNULL:
     case IFNONNULL:
       if (!value.isReference()) {
         throw new AnalyzerException(insn, null, "an object reference", value);
       }
       return super.unaryOperation(insn, value);
     case PUTSTATIC:
       expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
       break;
     default:
       throw new Error("Internal error.");
   }
   if (!isSubTypeOf(value, expected)) {
     throw new AnalyzerException(insn, null, expected, value);
   }
   return super.unaryOperation(insn, value);
 }
 protected boolean isSubTypeOf(final BasicValue value, final BasicValue expected) {
   return value.equals(expected);
 }
 protected boolean isArrayValue(final BasicValue value) {
   return value.isReference();
 }