/**
  * Visits an annotation on the type of the field.
  *
  * @param typeRef a reference to the annotated type. The sort of this type reference must be
  *     {@link TypeReference#FIELD FIELD}. See {@link TypeReference}.
  * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
  *     static inner type within 'typeRef'. May be <tt>null</tt> if the annotation targets
  *     'typeRef' as a whole.
  * @param desc the class descriptor of the annotation class.
  * @param visible <tt>true</tt> if the annotation is visible at runtime.
  * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
  *     interested in visiting this annotation.
  */
 public AnnotationVisitor visitTypeAnnotation(
     int typeRef, TypePath typePath, String desc, boolean visible) {
   if (api < Opcodes.ASM5) {
     throw new RuntimeException();
   }
   if (fv != null) {
     return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
   }
   return null;
 }
 @Override
 public Object visitVarDec(VarDec varDec, Object arg) throws Exception {
   // System.out.println(varDec.type.getJVMType());
   if (varDec.type.getJVMType().startsWith("Ljava/util/List"))
     fv = cw.visitField(ACC_STATIC, varDec.identToken.getText(), emptyList, null, null);
   else
     fv =
         cw.visitField(
             ACC_STATIC, varDec.identToken.getText(), varDec.type.getJVMType(), null, null);
   fv.visitEnd();
   return null;
   // throw new UnsupportedOperationException("code generation not yet implemented");
 }
  public byte[] buildClass(ClassDefinition core)
      throws IOException, IntrospectionException, SecurityException, IllegalArgumentException,
          ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
          InvocationTargetException, InstantiationException, NoSuchFieldException {

    Class coreKlazz = core.getDefinedClass();
    String coreName = coreKlazz.getName();
    String wrapperName = coreName + "Wrapper";

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    FieldVisitor fv;
    MethodVisitor mv;

    cw.visit(
        V1_5,
        ACC_PUBLIC + ACC_SUPER,
        BuildUtils.getInternalType(wrapperName),
        BuildUtils.getTypeDescriptor(coreName)
            + "Lorg/drools/factmodel/traits/CoreWrapper<"
            + BuildUtils.getTypeDescriptor(coreName)
            + ">;",
        BuildUtils.getInternalType(coreName),
        new String[] {
          Type.getInternalName(CoreWrapper.class), Type.getInternalName(Externalizable.class)
        });

    {
      fv = cw.visitField(ACC_PRIVATE, "core", BuildUtils.getTypeDescriptor(coreName), null, null);
      fv.visitEnd();
    }
    {
      fv =
          cw.visitField(
              ACC_PRIVATE,
              TraitableBean.MAP_FIELD_NAME,
              Type.getDescriptor(Map.class),
              "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;",
              null);
      fv.visitEnd();
    }
    {
      fv =
          cw.visitField(
              ACC_PRIVATE,
              TraitableBean.TRAITSET_FIELD_NAME,
              Type.getDescriptor(Map.class),
              "Ljava/util/Map<Ljava/lang/String;Lorg/drools/factmodel/traits/Thing;>;",
              null);
      fv.visitEnd();
    }

    {
      mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
      mv.visitCode();

      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(INVOKESPECIAL, BuildUtils.getInternalType(coreName), "<init>", "()V");

      //            mv.visitVarInsn( ALOAD, 0 );
      //            mv.visitTypeInsn( NEW, Type.getInternalName( HashMap.class ) );
      //            mv.visitInsn( DUP );
      //            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( HashMap.class ),
      // "<init>", "()V" );
      //            mv.visitFieldInsn( PUTFIELD,
      //                    BuildUtils.getInternalType( wrapperName ),
      //                    TraitableBean.MAP_FIELD_NAME,
      //                    Type.getDescriptor( Map.class ) );

      //            mv.visitVarInsn( ALOAD, 0 );
      //            mv.visitTypeInsn( NEW, Type.getInternalName( VetoableTypedMap.class ) );
      //            mv.visitInsn( DUP );
      //            mv.visitTypeInsn( NEW, Type.getInternalName( HashMap.class ) );
      //            mv.visitInsn( DUP );
      //            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( HashMap.class ),
      // "<init>", "()V" );
      //            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( VetoableTypedMap.class
      // ), "<init>", "(" + Type.getDescriptor( Map.class ) + ")V" );
      //            mv.visitFieldInsn( PUTFIELD,
      //                    BuildUtils.getInternalType( wrapperName ),
      //                    TraitableBean.TRAITSET_FIELD_NAME,
      //                    Type.getDescriptor( Map.class ) );

      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getCore")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getCore",
                "()" + Type.getDescriptor(Object.class),
                "()" + BuildUtils.getTypeDescriptor(coreName),
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            "core",
            BuildUtils.getTypeDescriptor(coreName));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getDynamicProperties")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getDynamicProperties",
                "()" + Type.getDescriptor(Map.class),
                "()Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.MAP_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "setDynamicProperties",
                "(" + Type.getDescriptor(Map.class) + ")V",
                "(Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)V",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.MAP_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getTraitMap")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getTraitMap",
                "()" + Type.getDescriptor(Map.class),
                "()Ljava/util/Map<Ljava/lang/String;Lorg/drools/factmodel/traits/Thing;>;",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        Label l0 = new Label();
        mv.visitJumpInsn(IFNONNULL, l0);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitTypeInsn(NEW, Type.getInternalName(VetoableTypedMap.class));
        mv.visitInsn(DUP);
        mv.visitTypeInsn(NEW, Type.getInternalName(HashMap.class));
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(HashMap.class), "<init>", "()V");
        mv.visitMethodInsn(
            INVOKESPECIAL,
            Type.getInternalName(VetoableTypedMap.class),
            "<init>",
            "(" + Type.getDescriptor(Map.class) + ")V");
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitLabel(l0);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "setTraitMap", Map.class)) {
      {
        mv = cw.visitMethod(ACC_PUBLIC, "setTraitMap", "(Ljava/util/Map;)V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitTypeInsn(NEW, Type.getInternalName(VetoableTypedMap.class));
        mv.visitInsn(DUP);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKESPECIAL,
            Type.getInternalName(VetoableTypedMap.class),
            "<init>",
            "(" + Type.getDescriptor(Map.class) + ")V");
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "addTrait", String.class, Thing.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "addTrait",
                "(" + Type.getDescriptor(String.class) + Type.getDescriptor(Thing.class) + ")V",
                "(" + Type.getDescriptor(String.class) + Type.getDescriptor(Thing.class) + ")V",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VetoableTypedMap.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ALOAD, 2);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            Type.getInternalName(VetoableTypedMap.class),
            "putSafe",
            "("
                + Type.getDescriptor(String.class)
                + Type.getDescriptor(Thing.class)
                + ")"
                + Type.getDescriptor(Thing.class));
        mv.visitInsn(POP);
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getTrait", String.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getTrait",
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "get",
            "(" + Type.getDescriptor(Object.class) + ")" + Type.getDescriptor(Object.class));
        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Thing.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "hasTrait", String.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC, "hasTrait", "(" + Type.getDescriptor(String.class) + ")Z", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "containsKey",
            "(" + Type.getDescriptor(Object.class) + ")Z");
        mv.visitInsn(IRETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "removeTrait", String.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "removeTrait",
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "remove",
            "(" + Type.getDescriptor(Object.class) + ")" + Type.getDescriptor(Object.class));
        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Thing.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getTraits")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getTraits",
                "()" + Type.getDescriptor(Collection.class),
                "()Ljava/util/Collection<Ljava/lang/String;>;",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "keySet",
            "()" + Type.getDescriptor(Set.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "writeExternal",
              "(" + Type.getDescriptor(ObjectOutput.class) + ")V",
              null,
              new String[] {Type.getInternalName(IOException.class)});
      mv.visitCode();

      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          BuildUtils.getInternalType(wrapperName),
          "getCore",
          "()" + Type.getDescriptor(Object.class));
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectOutput.class),
          "writeObject",
          "(" + Type.getDescriptor(Object.class) + ")V");

      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.MAP_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectOutput.class),
          "writeObject",
          "(" + Type.getDescriptor(Object.class) + ")V");

      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectOutput.class),
          "writeObject",
          "(" + Type.getDescriptor(Object.class) + ")V");

      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "readExternal",
              "(" + Type.getDescriptor(ObjectInput.class) + ")V",
              null,
              new String[] {
                Type.getInternalName(IOException.class),
                Type.getInternalName(ClassNotFoundException.class)
              });
      mv.visitCode();

      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectInput.class),
          "readObject",
          "()" + Type.getDescriptor(Object.class));
      mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(coreName));
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          "core",
          BuildUtils.getTypeDescriptor(coreName));

      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectInput.class),
          "readObject",
          "()" + Type.getDescriptor(Object.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Map.class));
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.MAP_FIELD_NAME,
          Type.getDescriptor(Map.class));

      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectInput.class),
          "readObject",
          "()" + Type.getDescriptor(Object.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Map.class));
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));

      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC, "init", "(" + BuildUtils.getTypeDescriptor(coreName) + ")V", null, null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          "core",
          BuildUtils.getTypeDescriptor(coreName));
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }

    Method[] ms = coreKlazz.getMethods();
    for (Method method : ms) {
      if (Modifier.isFinal(method.getModifiers())) {
        continue;
      }

      String signature = TraitFactory.buildSignature(method);
      {
        mv = cw.visitMethod(ACC_PUBLIC, method.getName(), signature, null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            "core",
            BuildUtils.getTypeDescriptor(coreName));
        int j = 1;
        for (Class arg : method.getParameterTypes()) {
          mv.visitVarInsn(BuildUtils.varType(arg.getName()), j++);
        }
        mv.visitMethodInsn(
            INVOKEVIRTUAL, BuildUtils.getInternalType(coreName), method.getName(), signature);

        mv.visitInsn(BuildUtils.returnType(method.getReturnType().getName()));
        int stack = TraitFactory.getStackSize(method);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC,
              "init",
              "(" + Type.getDescriptor(Object.class) + ")V",
              null,
              null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(coreName));
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          BuildUtils.getInternalType(wrapperName),
          "init",
          "(" + BuildUtils.getTypeDescriptor(coreName) + ")V");
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "denyTrait",
              "(" + Type.getDescriptor(Class.class) + ")V",
              null,
              new String[] {Type.getInternalName(LogicalTypeInconsistencyException.class)});
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VetoableTypedMap.class));
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          Type.getInternalName(VetoableTypedMap.class),
          "addToVetoable",
          "(" + Type.getDescriptor(Class.class) + ")V");
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC, "allowTrait", "(" + Type.getDescriptor(Class.class) + ")V", null, null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VetoableTypedMap.class));
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          Type.getInternalName(VetoableTypedMap.class),
          "removeFromVetoable",
          "(" + Type.getDescriptor(Class.class) + ")V");
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    cw.visitEnd();

    return cw.toByteArray();
  }
 /**
  * Visits an annotation of the field.
  *
  * @param desc the class descriptor of the annotation class.
  * @param visible <tt>true</tt> if the annotation is visible at runtime.
  * @return a visitor to visit the annotation values, or <tt>null</tt> if this visitor is not
  *     interested in visiting this annotation.
  */
 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
   if (fv != null) {
     return fv.visitAnnotation(desc, visible);
   }
   return null;
 }
 /**
  * Visits the end of the field. This method, which is the last one to be called, is used to inform
  * the visitor that all the annotations and attributes of the field have been visited.
  */
 public void visitEnd() {
   if (fv != null) {
     fv.visitEnd();
   }
 }
 /**
  * Visits a non standard attribute of the field.
  *
  * @param attr an attribute.
  */
 public void visitAttribute(Attribute attr) {
   if (fv != null) {
     fv.visitAttribute(attr);
   }
 }
  public static <T> byte[] createTargetSetterClass(
      String className,
      DelayedCellSetterFactory<T, ?>[] delayedCellSetters,
      CellSetter<T>[] setters,
      Type type,
      boolean ignoreException,
      int maxMethodSize)
      throws Exception {

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    FieldVisitor fv;
    MethodVisitor mv;

    final String targetType = AsmUtils.toType(type);
    final String classType = AsmUtils.toType(className);

    cw.visit(
        V1_6,
        ACC_FINAL + ACC_PUBLIC + ACC_SUPER,
        classType,
        "L" + CSV_CELL_MAPPER_TYPE + "<L" + targetType + ";>;",
        CSV_CELL_MAPPER_TYPE,
        null);

    // declare fields
    for (int i = 0; i < delayedCellSetters.length; i++) {
      if (delayedCellSetters[i] != null) {
        fv =
            cw.visitField(
                ACC_PROTECTED + ACC_FINAL,
                "delayedCellSetter" + i,
                AsmUtils.toDeclaredLType(DELAYED_CELL_SETTER_TYPE),
                "L" + DELAYED_CELL_SETTER_TYPE + "<L" + targetType + ";*>;",
                null);
        fv.visitEnd();
      }
    }

    for (int i = 0; i < setters.length; i++) {
      if (setters[i] != null) {
        fv =
            cw.visitField(
                ACC_PROTECTED + ACC_FINAL,
                "setter" + i,
                AsmUtils.toDeclaredLType(CELL_SETTER_TYPE),
                "L" + CELL_SETTER_TYPE + "<L" + targetType + ";>;",
                null);
        fv.visitEnd();
      }
    }
    appendInit(delayedCellSetters, setters, cw, targetType, classType, maxMethodSize);

    appendDelayedCellValue(delayedCellSetters, ignoreException, cw, classType);
    append_delayedCellValue(delayedCellSetters, cw, classType, maxMethodSize);

    appendCellValue(setters, ignoreException, cw, classType);
    append_cellValue(delayedCellSetters, setters, cw, classType, maxMethodSize);

    appendApplyDelayedSetter(delayedCellSetters, ignoreException, cw, classType, maxMethodSize);
    appendApplyDelayedCellSetterN(delayedCellSetters, cw, classType);

    appendGetDelayedCellSetter(delayedCellSetters, cw, targetType, classType, maxMethodSize);
    appendPeekDelayedCellSetterValue(delayedCellSetters, cw, classType, maxMethodSize);

    cw.visitEnd();

    return AsmUtils.writeClassToFile(className, cw.toByteArray());
  }
 @Override
 public int hashCode() {
   return fieldVisitor.hashCode();
 }
 @Override
 public boolean equals(Object other) {
   return this == other
       || !(other == null || getClass() != other.getClass())
           && fieldVisitor.equals(((OnField) other).fieldVisitor);
 }
 @Override
 public AnnotationVisitor visit(
     String annotationTypeDescriptor, boolean visible, int typeReference, String typePath) {
   return fieldVisitor.visitTypeAnnotation(
       typeReference, TypePath.fromString(typePath), annotationTypeDescriptor, visible);
 }
 @Override
 public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible) {
   return fieldVisitor.visitAnnotation(annotationTypeDescriptor, visible);
 }
 protected void injectFieldTable(ClassWriter classWriter) {
   FieldVisitor fieldVisitor =
       classWriter.visitField(
           ACC_PRIVATE + ACC_FINAL, "fieldTable", "[Ljava/lang/reflect/Field;", null, null);
   fieldVisitor.visitEnd();
 }
Exemple #13
0
  private static byte[] compileBytes(
      Rule rule,
      Class helperClass,
      String helperName,
      String compiledHelperName,
      boolean compileToBytecode)
      throws Exception {
    ClassWriter cw = new ClassWriter(0);
    FieldVisitor fv;
    MethodVisitor mv;
    AnnotationVisitor av0;
    // create the class as a subclass of the rule helper class, appending Compiled to the front
    // of the class name and a unique number to the end of the class helperName
    // also ensure it implements the HelperAdapter interface
    //
    // public class foo.bar.Compiled_<helper>_<NNN> extends foo.bar.<helper> implements
    // HelperAdapter

    cw.visit(
        V1_5,
        ACC_PUBLIC + ACC_SUPER,
        compiledHelperName,
        null,
        helperName,
        new String[] {"org/jboss/byteman/rule/helper/HelperAdapter"});
    // we need to install the source file name
    {
      String fullFileName = rule.getFile();
      int idx = fullFileName.lastIndexOf(java.io.File.separatorChar);
      String basicFileName = (idx < 0 ? fullFileName : fullFileName.substring(idx + 1));
      String debug = "// compiled from: " + fullFileName + "\n// generated by Byteman\n";
      cw.visitSource(basicFileName, debug);
    }
    {
      // we need a Hashmap field to hold the bindings
      //
      // private HashMap<String, Object> bindingMap;

      fv =
          cw.visitField(
              ACC_PRIVATE,
              "bindingMap",
              "Ljava/util/HashMap;",
              "Ljava/util/HashMap<Ljava/lang/String;Ljava/lang/Object;>;",
              null);
      fv.visitEnd();
    }
    {
      // and a rule field to hold the rule
      //
      // private Rule rule;

      fv =
          cw.visitField(
              ACC_PRIVATE,
              "rule",
              "Lorg/jboss/byteman/rule/Rule;",
              "Lorg/jboss/byteman/rule/Rule;",
              null);
      fv.visitEnd();
    }
    {
      // we need a constructor which takes a Rule as argument
      // if the helper implements a constructor which takes a Rule as argument then we invoke it
      // otherwise we invoke the empty helper constructor

      Constructor superConstructor = null;
      try {
        superConstructor = helperClass.getDeclaredConstructor(Rule.class);
      } catch (NoSuchMethodException e) {
        // hmm, ok see if there is an empty constructor
      } catch (SecurityException e) {
        throw new CompileException(
            "Compiler.compileBytes : unable to access constructor for helper class "
                + helperClass.getCanonicalName());
      }
      boolean superWantsRule = (superConstructor != null);
      if (!superWantsRule) {
        try {
          superConstructor = helperClass.getDeclaredConstructor();
        } catch (NoSuchMethodException e) {
          throw new CompileException(
              "Compiler.compileBytes : no valid constructor found for helper class "
                  + helperClass.getCanonicalName());
        } catch (SecurityException e) {
          throw new CompileException(
              "Compiler.compileBytes : unable to access constructor for helper class "
                  + helperClass.getCanonicalName());
        }
      }
      //
      //  public Compiled<helper>_<NNN>()Rule rule)
      mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/jboss/byteman/rule/Rule;)V", null, null);
      mv.visitCode();
      // super();
      //
      // or
      //
      // super(Rule);
      if (superWantsRule) {
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKESPECIAL, helperName, "<init>", "(Lorg/jboss/byteman/rule/Rule;)V");
      } else {
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, helperName, "<init>", "()V");
      }
      // bindingMap = new HashMap<String, Object);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitTypeInsn(NEW, "java/util/HashMap");
      mv.visitInsn(DUP);
      mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V");
      mv.visitFieldInsn(PUTFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
      // this.rule = rule
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitFieldInsn(PUTFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
      // return;
      mv.visitInsn(RETURN);
      mv.visitMaxs(3, 2);
      mv.visitEnd();
    }
    {
      // create the execute method
      //
      // public void execute(Bindings bindings, Object recipient, Object[] args) throws
      // ExecuteException
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "execute",
              "(Ljava/lang/Object;[Ljava/lang/Object;)V",
              null,
              new String[] {"org/jboss/byteman/rule/exception/ExecuteException"});
      mv.visitCode();
      // if (Transformer.isVerbose())
      mv.visitMethodInsn(INVOKESTATIC, "org/jboss/byteman/agent/Transformer", "isVerbose", "()Z");
      Label l0 = new Label();
      mv.visitJumpInsn(IFEQ, l0);
      // then
      // System.out.println(rule.getName() + " execute");
      mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
      mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
      mv.visitInsn(DUP);
      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
      mv.visitMethodInsn(
          INVOKEVIRTUAL, "org/jboss/byteman/rule/Rule", "getName", "()Ljava/lang/String;");
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          "java/lang/StringBuilder",
          "append",
          "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
      mv.visitLdcInsn(" execute()");
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          "java/lang/StringBuilder",
          "append",
          "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
      mv.visitMethodInsn(
          INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
      // end if
      mv.visitLabel(l0);

      Bindings bindings = rule.getBindings();
      Iterator<Binding> iterator = bindings.iterator();

      while (iterator.hasNext()) {
        Binding binding = iterator.next();
        String name = binding.getName();
        if (binding.isAlias()) {
          // lookups and updates will use the aliased name
          continue;
        }
        if (binding.isHelper()) {
          // bindingMap.put(name, this);
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
          mv.visitLdcInsn(name);
          mv.visitVarInsn(ALOAD, 0);
          mv.visitMethodInsn(
              INVOKEVIRTUAL,
              "java/util/HashMap",
              "put",
              "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
          mv.visitInsn(POP);
        } else if (binding.isRecipient()) {
          // bindingMap.put(name, recipient);
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
          mv.visitLdcInsn(name);
          mv.visitVarInsn(ALOAD, 1);
          mv.visitMethodInsn(
              INVOKEVIRTUAL,
              "java/util/HashMap",
              "put",
              "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
          mv.visitInsn(POP);
          // } else if (binding.isParam() || binding.isLocalVar() || binding.isReturn() ||
          //             binding.isThrowable() || binding.isParamCount() || binding.isParamArray())
          // {
        } else if (!binding.isBindVar()) {
          // bindingMap.put(name, args[binding.getCallArrayIndex()]);
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
          mv.visitLdcInsn(name);
          mv.visitVarInsn(ALOAD, 2);
          mv.visitLdcInsn(binding.getCallArrayIndex());
          mv.visitInsn(AALOAD);
          mv.visitMethodInsn(
              INVOKEVIRTUAL,
              "java/util/HashMap",
              "put",
              "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
          mv.visitInsn(POP);
        }
      }

      // execute0()
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(INVOKEVIRTUAL, compiledHelperName, "execute0", "()V");

      // now restore update bindings

      iterator = bindings.iterator();

      while (iterator.hasNext()) {
        Binding binding = iterator.next();
        if (binding.isAlias()) {
          continue;
        }
        String name = binding.getName();

        if (binding.isUpdated()) {
          // if (binding.isParam() || binding.isLocalVar() || binding.isReturn()) {
          if (!binding.isBindVar()) {
            int idx = binding.getCallArrayIndex();
            // Object value = bindingMap.get(name);
            // args[idx] = value;
            mv.visitVarInsn(ALOAD, 2); // args
            mv.visitLdcInsn(idx);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(
                INVOKEVIRTUAL,
                "java/util/HashMap",
                "get",
                "(Ljava/lang/Object;)Ljava/lang/Object;");
            mv.visitInsn(AASTORE);
          }
        }
      }

      // return
      mv.visitInsn(RETURN);
      mv.visitMaxs(4, 3);
      mv.visitEnd();
    }
    {
      // create the setBinding method
      //
      // public void setBinding(String name, Object value)
      mv =
          cw.visitMethod(
              ACC_PUBLIC, "setBinding", "(Ljava/lang/String;Ljava/lang/Object;)V", null, null);
      mv.visitCode();
      //  bindingMap.put(name, value);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          "java/util/HashMap",
          "put",
          "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
      mv.visitInsn(POP);
      // return
      mv.visitInsn(RETURN);
      mv.visitMaxs(3, 3);
      mv.visitEnd();
    }
    {
      // create the getBinding method
      //
      // public Object getBinding(String name)
      mv =
          cw.visitMethod(
              ACC_PUBLIC, "getBinding", "(Ljava/lang/String;)Ljava/lang/Object;", null, null);
      mv.visitCode();
      // {TOS} <== bindingMap.get(name);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEVIRTUAL, "java/util/HashMap", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
      // return {TOS}
      mv.visitInsn(ARETURN);
      mv.visitMaxs(2, 2);
      mv.visitEnd();
    }
    {
      // create the getName method
      //
      // public String getName()
      mv = cw.visitMethod(ACC_PUBLIC, "getName", "()Ljava/lang/String;", null, null);
      mv.visitCode();
      // {TOS} <== rule.getName()
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
      mv.visitMethodInsn(
          INVOKEVIRTUAL, "org/jboss/byteman/rule/Rule", "getName", "()Ljava/lang/String;");
      // return {TOS}
      mv.visitInsn(ARETURN);
      mv.visitMaxs(1, 1);
      mv.visitEnd();
    }
    // create the getAccessibleField method
    //
    // public Object getAccessibleField(Object owner, int fieldIndex)
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "getAccessibleField",
              "(Ljava/lang/Object;I)Ljava/lang/Object;",
              null,
              null);
      mv.visitCode();
      // {TOS} <== rule.getAccessibleField(owner, fieldIndex);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ILOAD, 2);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          "org/jboss/byteman/rule/Rule",
          "getAccessibleField",
          "(Ljava/lang/Object;I)Ljava/lang/Object;");
      // return {TOS}
      mv.visitInsn(ARETURN);
      mv.visitMaxs(3, 3);
      mv.visitEnd();
    }

    // create the setAccessibleField method
    //
    // public void setAccessibleField(Object owner, Object value, int fieldIndex)
    // rule.setAccessibleField(owner, value, fieldIndex);
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "setAccessibleField",
              "(Ljava/lang/Object;Ljava/lang/Object;I)V",
              null,
              null);
      mv.visitCode();
      // rule.setAccessibleField(owner, value, fieldIndex);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ILOAD, 3);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          "org/jboss/byteman/rule/Rule",
          "setAccessibleField",
          "(Ljava/lang/Object;Ljava/lang/Object;I)V");
      // return
      mv.visitInsn(RETURN);
      mv.visitMaxs(4, 4);
      mv.visitEnd();
    }

    // create the invokeAccessibleMethod method
    //
    // public Object invokeAccessibleMethod(Object target, Object[] args, int methodIndex)
    // {TOS} <==  rule.invokeAccessibleMethod(target, args, methodIndex);
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "invokeAccessibleMethod",
              "(Ljava/lang/Object;[Ljava/lang/Object;I)Ljava/lang/Object;",
              null,
              null);
      mv.visitCode();
      // rule.invokeAccessibleMethod(target, args, fieldIndex);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 2);
      mv.visitVarInsn(ILOAD, 3);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          "org/jboss/byteman/rule/Rule",
          "invokeAccessibleMethod",
          "(Ljava/lang/Object;[Ljava/lang/Object;I)Ljava/lang/Object;");
      // return {TOS}
      mv.visitInsn(ARETURN);
      mv.visitMaxs(4, 4);
      mv.visitEnd();
    }
    if (compileToBytecode) {
      // we generate a single execute0 method if we want to run compiled and get
      // the event, condiiton and action to insert the relevant bytecode to implement
      // bind(), test() and fire()

      {
        // create the execute0() method
        //
        // private void execute0()
        mv =
            cw.visitMethod(
                ACC_PRIVATE,
                "execute0",
                "()V",
                null,
                new String[] {"org/jboss/byteman/rule/exception/ExecuteException"});
        mv.visitCode();
        CompileContext compileContext = new CompileContext(mv);
        // make sure we set the first line number before generating any code
        compileContext.notifySourceLine(rule.getLine());
        compileContext.addLocalCount(3); // for this and 2 object args
        // bind();
        rule.getEvent().compile(mv, compileContext);
        // if (test())
        rule.getCondition().compile(mv, compileContext);
        Label l0 = new Label();
        mv.visitJumpInsn(IFEQ, l0);
        compileContext.addStackCount(-1);
        // then
        rule.getAction().compile(mv, compileContext);
        // fire();
        // end if
        mv.visitLabel(l0);
        // this will match the ENDRULE line
        compileContext.notifySourceEnd();
        // return
        mv.visitInsn(RETURN);
        // need to specify correct Maxs values
        mv.visitMaxs(compileContext.getStackMax(), compileContext.getLocalMax());
        mv.visitEnd();
      }
    } else {
      // we generate the following methods if we want to run interpreted
      {
        // create the execute0() method
        //
        // private void execute0()
        mv =
            cw.visitMethod(
                ACC_PRIVATE,
                "execute0",
                "()V",
                null,
                new String[] {"org/jboss/byteman/rule/exception/ExecuteException"});
        mv.visitCode();
        // bind();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, compiledHelperName, "bind", "()V");
        // if (test())
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, compiledHelperName, "test", "()Z");
        Label l0 = new Label();
        mv.visitJumpInsn(IFEQ, l0);
        // then
        // fire();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, compiledHelperName, "fire", "()V");
        // end if
        mv.visitLabel(l0);
        // return
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
      }
      {
        // create the bind method
        //
        // private void bind()
        mv =
            cw.visitMethod(
                ACC_PRIVATE,
                "bind",
                "()V",
                null,
                new String[] {"org/jboss/byteman/rule/exception/ExecuteException"});
        mv.visitCode();
        // rule.getEvent().interpret(this);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            "org/jboss/byteman/rule/Rule",
            "getEvent",
            "()Lorg/jboss/byteman/rule/Event;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            "org/jboss/byteman/rule/Event",
            "interpret",
            "(Lorg/jboss/byteman/rule/helper/HelperAdapter;)Ljava/lang/Object;");
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
      }
      {
        // create the test method
        //
        // private boolean test()
        mv =
            cw.visitMethod(
                ACC_PRIVATE,
                "test",
                "()Z",
                null,
                new String[] {"org/jboss/byteman/rule/exception/ExecuteException"});
        mv.visitCode();
        // {TOS} <== rule.getCondition().interpret(this);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            "org/jboss/byteman/rule/Rule",
            "getCondition",
            "()Lorg/jboss/byteman/rule/Condition;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            "org/jboss/byteman/rule/Condition",
            "interpret",
            "(Lorg/jboss/byteman/rule/helper/HelperAdapter;)Ljava/lang/Object;");
        mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
        // unbox the returned Boolean
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
        // return {TOS}
        mv.visitInsn(IRETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
      }
      {
        // create the fire method
        //
        // private void fire()
        mv =
            cw.visitMethod(
                ACC_PRIVATE,
                "fire",
                "()V",
                null,
                new String[] {"org/jboss/byteman/rule/exception/ExecuteException"});
        mv.visitCode();
        // rule.getAction().interpret(this);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, compiledHelperName, "rule", "Lorg/jboss/byteman/rule/Rule;");
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            "org/jboss/byteman/rule/Rule",
            "getAction",
            "()Lorg/jboss/byteman/rule/Action;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            "org/jboss/byteman/rule/Action",
            "interpret",
            "(Lorg/jboss/byteman/rule/helper/HelperAdapter;)Ljava/lang/Object;");
        // return
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
      }
    }

    cw.visitEnd();

    return cw.toByteArray();
  }
 private void addField(String name, int modifiers, String type) {
   final FieldVisitor fv = cv.visitField(modifiers, name, type, null, null);
   fv.visitEnd();
 }