/** Returns the reference/primitive class to store the */
  private static String findReferenceDesc(String desc) {
    Type type = Type.getType(desc);

    switch (type.getSort()) {
      case Type.ARRAY:
        return "Lorg/multiverse/transactional/refs/BasicRef;";
      case Type.BOOLEAN:
        return "Lorg/multiverse/transactional/refs/BooleanRef;";
      case Type.BYTE:
        return "Lorg/multiverse/transactional/refs/ByteRef;";
      case Type.CHAR:
        return "Lorg/multiverse/transactional/refs/CharRef;";
      case Type.DOUBLE:
        return "Lorg/multiverse/transactional/refs/DoubleRef;";
      case Type.FLOAT:
        return "Lorg/multiverse/transactional/refs/FloatRef;";
      case Type.INT:
        return "Lorg/multiverse/transactional/refs/IntRef;";
      case Type.LONG:
        return "Lorg/multiverse/transactional/refs/LongRef;";
      case Type.SHORT:
        return "Lorg/multiverse/transactional/refs/ShortRef;";
      case Type.OBJECT:
        return "Lorg/multiverse/transactional/refs/BasicRef;";
      default:
        throw new IllegalStateException("Unhandeled sort: " + type.getSort());
    }
  }
예제 #2
0
  private Type getMirrorType(final Type type) {
    int numDimensions = 0;
    final Type basicType;

    if (type.getSort() == Type.ARRAY) {
      numDimensions = type.getDimensions();
      basicType = type.getElementType();
    } else {
      basicType = type;
    }

    if (basicType.getSort() != Type.OBJECT) {
      return type;
    }

    final Mirror mirror = getMirror(basicType.getInternalName());

    if (mirror.isClassMirror()) {
      final StringBuilder name = new StringBuilder();

      for (int i = 0; i < numDimensions; ++i) {
        name.append('[');
      }
      name.append('L').append(mirror.getTranslatedName()).append(';');

      return Type.getType(name.toString());
    }

    return type;
  }
예제 #3
0
 public boolean isTypeImmutable(String desc) {
   Type type = Type.getType(desc);
   if (IMMUTABLE_TYPE_SORTS.contains(type.getSort())) {
     return true;
   }
   if (type.getSort() != Type.OBJECT) {
     return false;
   }
   if (Sets.union(EXTERNAL_IMMUTABLE_CLASSES, immutableClasses).contains(type.getInternalName())) {
     return true;
   }
   return false;
 }
예제 #4
0
 /**
  * Insert the necessary methods to unbox a primitive type (if the given type is a primitive).
  *
  * @param mv The method visitor
  * @param type The type to unbox
  */
 public static void visitUnboxingMethod(MethodVisitor mv, Type type) {
   if (type.getSort() == Type.BOOLEAN) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
   } else if (type.getSort() == Type.INT) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
   } else if (type.getSort() == Type.BYTE) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
   } else if (type.getSort() == Type.SHORT) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
   } else if (type.getSort() == Type.LONG) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
   } else if (type.getSort() == Type.FLOAT) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
   } else if (type.getSort() == Type.DOUBLE) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
   } else if (type.getSort() == Type.CHAR) {
     mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
     mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
   } else {
     mv.visitTypeInsn(CHECKCAST, type.getInternalName());
   }
 }
예제 #5
0
 private String getDescriptor(Type type) {
   if (type.getSort() == Type.OBJECT) {
     String name = type.getInternalName();
     int index = name.lastIndexOf('/');
     return name.substring(index + 1);
   }
   if (type.getSort() == Type.ARRAY) {
     StringBuilder sb = new StringBuilder(getDescriptor(type.getElementType()));
     for (int dim = type.getDimensions(); dim > 0; --dim) {
       sb.append("[]");
     }
     return sb.toString();
   }
   return type.getClassName();
 }
예제 #6
0
  private boolean classIsDefinitelyMutable(ClassNode klass) {
    if (superClassIsDefinitelyMutable(klass.superName)) {
      log.add("Mutable parent: " + klass.name + " < " + klass.superName);
      return true;
    }

    for (FieldNode field : klass.fields) {
      if ((field.access & Opcodes.ACC_STATIC) != 0) {
        continue;
      }
      if ((field.access & Opcodes.ACC_FINAL) == 0) {
        log.add("Non-final field: " + klass.name + "#" + field.name + ":" + field.desc);
        return true;
      }
      if (field.name.contains("$")) {
        // Generated fields are assumed to be effectively immutable.
        // This could, in principle, miss an issue like a static reference to a
        // seemingly-immutable inner class object that maintains a hidden reference
        // to its mutable outer object, but that seems unlikely.
        continue;
      }

      Type type = Type.getType(field.desc);

      if (IMMUTABLE_TYPE_SORTS.contains(type.getSort())) {
        continue;
      }

      if (type.getSort() != Type.OBJECT) {
        log.add("Odd sort: " + klass.name + "#" + field.name + ":" + field.desc);
        return true;
      }

      if (allClasses.keySet().contains(type.getInternalName())) {
        if (classesWithMutableDescendents.contains(type.getInternalName())) {
          log.add("Internal mutable field: " + klass.name + "#" + field.name + ":" + field.desc);
          return true;
        }
      } else {
        if (!EXTERNAL_IMMUTABLE_CLASSES.contains(type.getInternalName())) {
          log.add("External mutable field: " + klass.name + "#" + field.name + ":" + field.desc);
          return true;
        }
      }
    }

    return false;
  }
 /**
  * Creates a new local variable of the given type.
  *
  * @param type the type of the local variable to be created.
  * @return the identifier of the newly created local variable.
  */
 public int newLocal(final Type type) {
   Object t;
   switch (type.getSort()) {
     case Type.BOOLEAN:
     case Type.CHAR:
     case Type.BYTE:
     case Type.SHORT:
     case Type.INT:
       t = Opcodes.INTEGER;
       break;
     case Type.FLOAT:
       t = Opcodes.FLOAT;
       break;
     case Type.LONG:
       t = Opcodes.LONG;
       break;
     case Type.DOUBLE:
       t = Opcodes.DOUBLE;
       break;
     case Type.ARRAY:
       t = type.getDescriptor();
       break;
       // case Type.OBJECT:
     default:
       t = type.getInternalName();
       break;
   }
   int local = newLocalMapping(type);
   setLocalType(local, type);
   setFrameLocal(local, t);
   return local;
 }
예제 #8
0
 public static Class<?> getClassForType(Type type) {
   checkArgNotNull(type, "type");
   switch (type.getSort()) {
     case Type.BOOLEAN:
       return boolean.class;
     case Type.BYTE:
       return byte.class;
     case Type.CHAR:
       return char.class;
     case Type.DOUBLE:
       return double.class;
     case Type.FLOAT:
       return float.class;
     case Type.INT:
       return int.class;
     case Type.LONG:
       return long.class;
     case Type.SHORT:
       return short.class;
     case Type.VOID:
       return void.class;
     case Type.OBJECT:
     case Type.ARRAY:
       return getClassForInternalName(type.getInternalName());
   }
   throw new IllegalStateException(); // should be unreachable
 }
예제 #9
0
 /**
  * Emits code boxing value of basic type.
  *
  * @param mv output method visitor
  * @param type input data type (must be basic type!)
  */
 public void emitAutoboxing(SpyMethodVisitor mv, Type type) {
   switch (type.getSort()) {
     case Type.INT:
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
       break;
     case Type.LONG:
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
       break;
     case Type.FLOAT:
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
       break;
     case Type.DOUBLE:
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
       break;
     case Type.SHORT:
       mv.visitInsn(I2S);
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
       break;
     case Type.BYTE:
       mv.visitInsn(I2B);
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
       break;
     case Type.BOOLEAN:
       mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
       break;
     case Type.CHAR:
       mv.visitMethodInsn(
           INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
       break;
   }
 }
예제 #10
0
  /**
   * Pushes the default value for the given type onto the stack (ie. 0 for scalars, null for refs).
   */
  public void pushDefaultValue(Type aType) {
    switch (aType.getSort()) {
      case Type.BOOLEAN:
      case Type.BYTE:
      case Type.CHAR:
      case Type.SHORT:
      case Type.INT:
        pushInt(0);
        break;

      case Type.FLOAT:
        pushFloat(0);
        break;

      case Type.LONG:
        pushLong(0);
        break;

      case Type.DOUBLE:
        pushDouble(0);
        break;

      case Type.OBJECT:
      case Type.ARRAY:
        ACONST_NULL();
        break;

      case Type.VOID:
        break;

      default:
        throw new RuntimeException("Not handled: " + aType);
    }
  }
예제 #11
0
 private Expression pushDefaultValue(Type type) {
   switch (type.getSort()) {
     case BOOLEAN:
       return value(false);
     case CHAR:
       return value((char) 0);
     case BYTE:
       return value((byte) 0);
     case SHORT:
       return value((short) 0);
     case INT:
       return value(0);
     case Type.LONG:
       return value(0L);
     case Type.FLOAT:
       return value(0f);
     case Type.DOUBLE:
       return value(0d);
     case ARRAY:
     case OBJECT:
       return nullRef(type);
     default:
       throw new IllegalArgumentException();
   }
 }
예제 #12
0
 private ClassMetadata getClassMetadata(
     ClassMetadataResolver resolver, Type type, boolean ignoreArray) {
   if (type.getSort() == Type.ARRAY) {
     return resolver.resolve(
         type.getElementType().getClassName(), ignoreArray ? 0 : type.getDimensions());
   } else {
     return resolver.resolve(type.getClassName(), 0);
   }
 }
예제 #13
0
 private void addType(Type t) {
   switch (t.getSort()) {
     case Type.ARRAY:
       addType(t.getElementType());
       break;
     case Type.OBJECT:
       addName(t.getInternalName());
       break;
   }
 }
예제 #14
0
 private void addType(final Type t) {
   switch (t.getSort()) {
     case Type.ARRAY:
       addType(t.getElementType());
       break;
     case Type.OBJECT:
       addName(t.getClassName().replace('.', '/'));
       break;
   }
 }
예제 #15
0
 /**
  * Inspects the given type recursively and add it as outgoing reference if necessary
  *
  * @param type Referenced type
  */
 private void inspectType(Type type) {
   switch (type.getSort()) {
     case Type.ARRAY:
       inspectType(type.getElementType());
       break;
     case Type.OBJECT:
       String typeName = refactor(type.getClassName());
       checkReference(typeName);
       break;
   }
 }
예제 #16
0
  /**
   * Fetches return value or thrown exception. If return value is of basic type, it is automatically
   * boxed.
   *
   * @param mv output method visitor
   * @param type return data type
   * @return number of JVM stack slots emitted code consumes
   */
  public int emitFetchRetVal(SpyMethodVisitor mv, Type type) {

    if (Type.VOID == type.getSort()) {
      mv.visitInsn(ACONST_NULL);
      return 1;
    }

    mv.visitInsn(DUP);
    emitAutoboxing(mv, type);
    mv.visitVarInsn(ASTORE, mv.getRetValProbeSlot());

    return type.getSize();
  }
 private void addType(final Type type) {
   switch (type.getSort()) {
     case Type.ARRAY:
       addType(type.getElementType());
       break;
     case Type.OBJECT:
       addPackage(type.getInternalName());
       break;
     case Type.METHOD:
       addMethodTypes(type.getDescriptor());
       break;
   }
 }
 void addType(final Type t) {
   switch (t.getSort()) {
     case Type.ARRAY:
       addType(t.getElementType());
       break;
     case Type.OBJECT:
       addName(t.getInternalName());
       break;
     case Type.METHOD:
       addMethodDesc(t.getDescriptor());
       break;
   }
 }
예제 #19
0
  private static boolean appendTypeName(StringBuilder tpl, Type type, String sourceClass) {
    switch (type.getSort()) {
      case Type.BOOLEAN:
        tpl.append("boolean");
        return false;
      case Type.CHAR:
        tpl.append("char");
        return false;
      case Type.BYTE:
        tpl.append("byte");
        return false;
      case Type.SHORT:
        tpl.append("short");
        return false;
      case Type.INT:
        tpl.append("int");
        return false;
      case Type.FLOAT:
        tpl.append("float");
        return false;
      case Type.LONG:
        tpl.append("long");
        return false;
      case Type.DOUBLE:
        tpl.append("double");
        return false;
      case Type.ARRAY:
        EventProxy.appendTypeName(tpl, type.getElementType(), sourceClass);
        return true;
      case Type.OBJECT:
        String typeName = type.getClassName();
        typeName = typeName.substring(typeName.lastIndexOf('.') + 1);
        tpl.append(typeName);
        if (typeName.endsWith("ReturnEventInfo"))
          tpl.append('<').append(sourceClass).append(", ?>");
        else if (typeName.endsWith("EventInfo")) tpl.append('<').append(sourceClass).append('>');
        return false;
    }

    tpl.append("Object");

    return false;
  }
예제 #20
0
 public JavaType convertAsmType(org.objectweb.asm.Type asmType) {
   JavaType result;
   switch (asmType.getSort()) {
     case org.objectweb.asm.Type.OBJECT:
       result = getClassSymbol(asmType.getInternalName()).type;
       break;
     case org.objectweb.asm.Type.BYTE:
       result = symbols.byteType;
       break;
     case org.objectweb.asm.Type.CHAR:
       result = symbols.charType;
       break;
     case org.objectweb.asm.Type.SHORT:
       result = symbols.shortType;
       break;
     case org.objectweb.asm.Type.INT:
       result = symbols.intType;
       break;
     case org.objectweb.asm.Type.LONG:
       result = symbols.longType;
       break;
     case org.objectweb.asm.Type.FLOAT:
       result = symbols.floatType;
       break;
     case org.objectweb.asm.Type.DOUBLE:
       result = symbols.doubleType;
       break;
     case org.objectweb.asm.Type.BOOLEAN:
       result = symbols.booleanType;
       break;
     case org.objectweb.asm.Type.ARRAY:
       result = new ArrayJavaType(convertAsmType(asmType.getElementType()), symbols.arrayClass);
       break;
     case org.objectweb.asm.Type.VOID:
       result = symbols.voidType;
       break;
     default:
       throw new IllegalArgumentException(asmType.toString());
   }
   return result;
 }
예제 #21
0
 /**
  * Insert the necessary methods to box a primitive type (if the given type is a primitive object).
  *
  * @param mv The method visitor
  * @param type The type to unbox
  */
 public static void visitBoxingMethod(MethodVisitor mv, Type type) {
   if (type.getSort() == Type.BOOLEAN) {
     mv.visitMethodInsn(
         INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
   } else if (type.getSort() == Type.INT) {
     mv.visitMethodInsn(
         INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
   } else if (type.getSort() == Type.BYTE) {
     mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
   } else if (type.getSort() == Type.SHORT) {
     mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
   } else if (type.getSort() == Type.LONG) {
     mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
   } else if (type.getSort() == Type.FLOAT) {
     mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
   } else if (type.getSort() == Type.DOUBLE) {
     mv.visitMethodInsn(
         INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
   } else if (type.getSort() == Type.CHAR) {
     mv.visitMethodInsn(
         INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
   }
 }
예제 #22
0
 public static int getLoadingOpcode(Type argType) {
   checkArgNotNull(argType, "argType");
   switch (argType.getSort()) {
     case Type.BOOLEAN:
     case Type.BYTE:
     case Type.CHAR:
     case Type.SHORT:
     case Type.INT:
       return Opcodes.ILOAD;
     case Type.DOUBLE:
       return Opcodes.DLOAD;
     case Type.FLOAT:
       return Opcodes.FLOAD;
     case Type.LONG:
       return Opcodes.LLOAD;
     case Type.OBJECT:
     case Type.ARRAY:
       return Opcodes.ALOAD;
     default:
       throw new IllegalStateException();
   }
 }
예제 #23
0
  private static void insertGetObject(
      ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
    int maxStack = 6;
    MethodVisitor mv =
        cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, null);
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
      maxStack--;
      Label[] labels = new Label[fields.size()];
      for (int i = 0, n = labels.length; i < n; i++) labels[i] = new Label();
      Label defaultLabel = new Label();
      mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

      for (int i = 0, n = labels.length; i < n; i++) {
        Field field = fields.get(i);

        mv.visitLabel(labels[i]);
        mv.visitFrame(F_SAME, 0, null, 0, null);
        if (!Modifier.isStatic(field.getModifiers())) {
          mv.visitVarInsn(ALOAD, 1);
          mv.visitTypeInsn(CHECKCAST, classNameInternal);
        }
        mv.visitFieldInsn(
            Modifier.isStatic(field.getModifiers()) ? GETSTATIC : GETFIELD,
            classNameInternal,
            field.getName(),
            Type.getDescriptor(field.getType()));

        Type fieldType = Type.getType(field.getType());
        switch (fieldType.getSort()) {
          case Type.BOOLEAN:
            mv.visitMethodInsn(
                INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
            break;
          case Type.BYTE:
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
            break;
          case Type.CHAR:
            mv.visitMethodInsn(
                INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
            break;
          case Type.SHORT:
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
            break;
          case Type.INT:
            mv.visitMethodInsn(
                INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
            break;
          case Type.FLOAT:
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
            break;
          case Type.LONG:
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
            break;
          case Type.DOUBLE:
            mv.visitMethodInsn(
                INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
            break;
        }

        mv.visitInsn(ARETURN);
      }

      mv.visitLabel(defaultLabel);
      mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 3);
    mv.visitEnd();
  }
  private InsnList fixInstructions(MethodNode originalMethod, CloneMap cloneMap) {
    InsnList instructions = new InsnList();

    for (int k = 0; k < originalMethod.instructions.size(); k++) {
      AbstractInsnNode originalInsn = originalMethod.instructions.get(k);
      switch (originalInsn.getOpcode()) {
          // the put on the field granular field is transformed to a fieldref.set
        case PUTFIELD:
          {
            FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn;
            ClassMetadata ownerMetadata =
                metadataRepository.loadClassMetadata(classLoader, fieldInsn.owner);
            FieldMetadata fieldMetadata = ownerMetadata.getFieldMetadata(fieldInsn.name);
            Type originalFieldType = Type.getType(fieldMetadata.getDesc());

            if (fieldMetadata.hasFieldGranularity()) {

              boolean fieldIsCategory2 = isCategory2(fieldMetadata.getDesc());

              if (fieldIsCategory2) {
                // value(category2), owner,..

                instructions.add(new InsnNode(DUP2_X1));
                // [value(category2), owner, value(category2),...]

                instructions.add(new InsnNode(POP2));
                // [owner, value(category2), ...]
              } else {
                // [value(category1), owner,
                instructions.add(new InsnNode(SWAP));
                // [owner, value(category1),..
              }

              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              instructions.add(
                  new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc));

              if (fieldIsCategory2) {
                // [owner, value(category2),..

                instructions.add(new InsnNode(DUP_X2));
                // [owner, value(category2), owner

                instructions.add(new InsnNode(POP));
                // [value(category2), owner
              } else {
                // [owner, value(category1)
                instructions.add(new InsnNode(SWAP));
                // [value(category1), owner..
              }

              // call the set
              if (originalFieldType.getSort() == Type.ARRAY
                  || originalFieldType.getSort() == Type.OBJECT) {
                String objectDesc = Type.getDescriptor(Object.class);
                MethodInsnNode methodInsn =
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "set",
                        format("(%s)%s", objectDesc, objectDesc));
                instructions.add(methodInsn);
              } else {
                MethodInsnNode methodInsn =
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "set",
                        format("(%s)%s", fieldMetadata.getDesc(), fieldMetadata.getDesc()));
                instructions.add(methodInsn);
              }

              // pop the unused return value of the set.
              if (fieldIsCategory2) {
                instructions.add(new InsnNode(POP2));
              } else {
                instructions.add(new InsnNode(POP));
              }
            } else {
              instructions.add(originalInsn.clone(cloneMap));
            }
          }
          break;
          // the get on the field granular field is transformed to a fieldref.get
        case GETFIELD:
          {
            FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn;
            FieldMetadata fieldMetadata =
                metadataRepository
                    .loadClassMetadata(classLoader, fieldInsn.owner)
                    .getFieldMetadata(fieldInsn.name);
            if (!fieldMetadata.hasFieldGranularity()) {
              // if it is not getter on a field granular field
              instructions.add(originalInsn.clone(cloneMap));
            } else {
              // it is a getter on a field granular field.
              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              // place the fieldref on the stack.
              instructions.add(
                  new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc));

              Type originalFieldType = Type.getType(fieldMetadata.getDesc());
              if (originalFieldType.getSort() == Type.ARRAY
                  || originalFieldType.getSort() == Type.OBJECT) {
                instructions.add(
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "get",
                        format("()%s", getDescriptor(Object.class))));

                if (!originalFieldType.equals(Type.getType(Object.class))) {
                  instructions.add(
                      new TypeInsnNode(CHECKCAST, originalFieldType.getInternalName()));
                }
              } else {
                instructions.add(
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "get",
                        format("()%s", fieldMetadata.getDesc())));
              }
            }
          }
          break;
        default:
          instructions.add(originalInsn.clone(cloneMap));
          break;
      }
    }

    return instructions;
  }
예제 #25
0
 /*
  * (non-Javadoc)
  *
  * @see org.objectweb.asm.MethodAdapter#visitLdcInsn(java.lang.Object)
  */
 @Override
 public void visitLdcInsn(Object cst) {
   if (cst == null) {
     this.visitInsn(ACONST_NULL);
   } else if (cst instanceof Integer) {
     int value = (Integer) cst;
     if (value >= -1 && value <= 5) {
       super.visitInsn(ICONST_0 + value);
     } else if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
       super.visitIntInsn(BIPUSH, value);
     } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
       super.visitIntInsn(SIPUSH, value);
     } else {
       super.visitLdcInsn(cst);
     }
   } else if (cst instanceof Long) {
     long value = (Long) cst;
     if (value == 0L || value == 1L) {
       super.visitInsn(LCONST_0 + ((int) value));
     } else {
       super.visitLdcInsn(cst);
     }
   } else if (cst instanceof Float) {
     float value = (Float) cst;
     if (value == 0.0F) {
       super.visitInsn(FCONST_0);
     } else if (value == 1.0F) {
       super.visitInsn(FCONST_1);
     } else if (value == 2.0F) {
       super.visitInsn(FCONST_2);
     } else {
       super.visitLdcInsn(cst);
     }
   } else if (cst instanceof Double) {
     double value = (Double) cst;
     if (value == 0.0D) {
       super.visitInsn(DCONST_0);
     } else if (value == 1.0D) {
       super.visitInsn(DCONST_1);
     } else {
       super.visitLdcInsn(cst);
     }
   } else if (cst instanceof Type) {
     Type t = (Type) cst;
     switch (t.getSort()) {
       case Type.BOOLEAN:
         super.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.BYTE:
         super.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.CHAR:
         super.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.DOUBLE:
         super.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.FLOAT:
         super.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.INT:
         super.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.LONG:
         super.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;");
         break;
       case Type.SHORT:
         super.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;");
         break;
       default:
         super.visitLdcInsn(cst);
     }
   } else {
     super.visitLdcInsn(cst);
   }
 }
예제 #26
0
  private static void insertSetObject(
      ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
    int maxStack = 6;
    MethodVisitor mv =
        cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, null);
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
      maxStack--;
      Label[] labels = new Label[fields.size()];
      for (int i = 0, n = labels.length; i < n; i++) labels[i] = new Label();
      Label defaultLabel = new Label();
      mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

      for (int i = 0, n = labels.length; i < n; i++) {
        Field field = fields.get(i);
        Type fieldType = Type.getType(field.getType());

        mv.visitLabel(labels[i]);
        mv.visitFrame(F_SAME, 0, null, 0, null);
        if (!Modifier.isStatic(field.getModifiers())) {
          mv.visitVarInsn(ALOAD, 1);
          mv.visitTypeInsn(CHECKCAST, classNameInternal);
        }
        mv.visitVarInsn(ALOAD, 3);

        switch (fieldType.getSort()) {
          case Type.BOOLEAN:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
            break;
          case Type.BYTE:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
            break;
          case Type.CHAR:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
            break;
          case Type.SHORT:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
            break;
          case Type.INT:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
            break;
          case Type.FLOAT:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
            break;
          case Type.LONG:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
            break;
          case Type.DOUBLE:
            mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
            break;
          case Type.ARRAY:
            mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor());
            break;
          case Type.OBJECT:
            mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName());
            break;
        }

        mv.visitFieldInsn(
            Modifier.isStatic(field.getModifiers()) ? PUTSTATIC : PUTFIELD,
            classNameInternal,
            field.getName(),
            fieldType.getDescriptor());
        mv.visitInsn(RETURN);
      }

      mv.visitLabel(defaultLabel);
      mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    mv = insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 4);
    mv.visitEnd();
  }
예제 #27
0
  private static void insertGetPrimitive(
      ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) {
    int maxStack = 6;
    final String getterMethodName;
    final String typeNameInternal = primitiveType.getDescriptor();
    final int returnValueInstruction;
    switch (primitiveType.getSort()) {
      case Type.BOOLEAN:
        getterMethodName = "getBoolean";
        returnValueInstruction = IRETURN;
        break;
      case Type.BYTE:
        getterMethodName = "getByte";
        returnValueInstruction = IRETURN;
        break;
      case Type.CHAR:
        getterMethodName = "getChar";
        returnValueInstruction = IRETURN;
        break;
      case Type.SHORT:
        getterMethodName = "getShort";
        returnValueInstruction = IRETURN;
        break;
      case Type.INT:
        getterMethodName = "getInt";
        returnValueInstruction = IRETURN;
        break;
      case Type.FLOAT:
        getterMethodName = "getFloat";
        returnValueInstruction = FRETURN;
        break;
      case Type.LONG:
        getterMethodName = "getLong";
        returnValueInstruction = LRETURN;
        break;
      case Type.DOUBLE:
        getterMethodName = "getDouble";
        returnValueInstruction = DRETURN;
        break;
      default:
        getterMethodName = "get";
        returnValueInstruction = ARETURN;
        break;
    }
    MethodVisitor mv =
        cw.visitMethod(
            ACC_PUBLIC, getterMethodName, "(Ljava/lang/Object;I)" + typeNameInternal, null, null);
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
      maxStack--;
      Label[] labels = new Label[fields.size()];
      Label labelForInvalidTypes = new Label();
      boolean hasAnyBadTypeLabel = false;
      for (int i = 0, n = labels.length; i < n; i++) {
        if (Type.getType(fields.get(i).getType()).equals(primitiveType)) labels[i] = new Label();
        else {
          labels[i] = labelForInvalidTypes;
          hasAnyBadTypeLabel = true;
        }
      }
      Label defaultLabel = new Label();
      mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

      for (int i = 0, n = labels.length; i < n; i++) {
        Field field = fields.get(i);
        if (!labels[i].equals(labelForInvalidTypes)) {
          mv.visitLabel(labels[i]);
          mv.visitFrame(F_SAME, 0, null, 0, null);
          if (!Modifier.isStatic(field.getModifiers())) {
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, classNameInternal);
          }
          mv.visitFieldInsn(
              Modifier.isStatic(field.getModifiers()) ? GETSTATIC : GETFIELD,
              classNameInternal,
              field.getName(),
              typeNameInternal);
          mv.visitInsn(returnValueInstruction);
        }
      }
      // Rest of fields: different type
      if (hasAnyBadTypeLabel) {
        mv.visitLabel(labelForInvalidTypes);
        mv.visitFrame(F_SAME, 0, null, 0, null);
        insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
      }
      // Default: field not found
      mv.visitLabel(defaultLabel);
      mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    mv = insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 3);
    mv.visitEnd();
  }
  private GaMethod toMethod(
      ClassLoader loader, Class<?> clazz, String methodName, String methodDesc)
      throws ClassNotFoundException, NoSuchMethodException {
    final org.objectweb.asm.Type asmType = org.objectweb.asm.Type.getMethodType(methodDesc);

    // to arg types
    final Class<?>[] argsClasses = new Class<?>[asmType.getArgumentTypes().length];
    for (int index = 0; index < argsClasses.length; index++) {

      // asm class descriptor to jvm class
      final Class<?> argumentClass;
      final Type argumentAsmType = asmType.getArgumentTypes()[index];
      switch (argumentAsmType.getSort()) {
        case Type.BOOLEAN:
          {
            argumentClass = boolean.class;
            break;
          }
        case Type.CHAR:
          {
            argumentClass = char.class;
            break;
          }
        case Type.BYTE:
          {
            argumentClass = byte.class;
            break;
          }
        case Type.SHORT:
          {
            argumentClass = short.class;
            break;
          }
        case Type.INT:
          {
            argumentClass = int.class;
            break;
          }
        case Type.FLOAT:
          {
            argumentClass = float.class;
            break;
          }
        case Type.LONG:
          {
            argumentClass = long.class;
            break;
          }
        case Type.DOUBLE:
          {
            argumentClass = double.class;
            break;
          }
        case Type.ARRAY:
          {
            argumentClass = toClass(loader, argumentAsmType.getInternalName());
            break;
          }
        case Type.VOID:
          {
            argumentClass = void.class;
            break;
          }
        case Type.OBJECT:
        case Type.METHOD:
        default:
          {
            argumentClass = toClass(loader, argumentAsmType.getClassName());
            break;
          }
      }

      argsClasses[index] = argumentClass;
    }

    // to method or constructor
    if (GaCheckUtils.isEquals(methodName, "<init>")) {
      return GaMethod.newInit(toConstructor(clazz, argsClasses));
    } else {
      return GaMethod.newMethod(toMethod(clazz, methodName, argsClasses));
    }
  }