docs: @Override
      public void visit(final String name, final Object value) {
          ++size;
          if (named) {
              bv.putShort(cw.newUTF8(name));
          }
          if (value instanceof String) {
              bv.put12('s', cw.newUTF8((String) value));
          } else if (value instanceof Byte) {
              bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
          } else if (value instanceof Boolean) {
              int v = ((Boolean) value).booleanValue() ? 1 : 0;
              bv.put12('Z', cw.newInteger(v).index);
          } else if (value instanceof Character) {
              bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
          } else if (value instanceof Short) {
              bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
          } else if (value instanceof Type) {
              bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
          } else if (value instanceof byte[]) {
              byte[] v = (byte[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('B', cw.newInteger(v[i]).index);
              }
          } else if (value instanceof boolean[]) {
              boolean[] v = (boolean[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
              }
          } else if (value instanceof short[]) {
              short[] v = (short[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('S', cw.newInteger(v[i]).index);
              }
          } else if (value instanceof char[]) {
              char[] v = (char[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('C', cw.newInteger(v[i]).index);
              }
          } else if (value instanceof int[]) {
              int[] v = (int[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('I', cw.newInteger(v[i]).index);
              }
          } else if (value instanceof long[]) {
              long[] v = (long[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('J', cw.newLong(v[i]).index);
              }
          } else if (value instanceof float[]) {
              float[] v = (float[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('F', cw.newFloat(v[i]).index);
              }
          } else if (value instanceof double[]) {
              double[] v = (double[]) value;
              bv.put12('[', v.length);
              for (int i = 0; i < v.length; i++) {
                  bv.put12('D', cw.newDouble(v[i]).index);
              }
          } else {
              Item i = cw.newConstItem(value);
              bv.put12(".s.IFJDCS".charAt(i.type), i.index);
          }
      }
  
      @Override
      public void visitEnum(final String name, final String desc,
              final String value) {
          ++size;
          if (named) {
              bv.putShort(cw.newUTF8(name));
          }
          bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
      }
  
      @Override
      public AnnotationVisitor visitAnnotation(final String name,
              final String desc) {
          ++size;
          if (named) {
              bv.putShort(cw.newUTF8(name));
          }
          // write tag and type, and reserve space for values count
          bv.put12('@', cw.newUTF8(desc)).putShort(0);
          return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
      }
  
      @Override
      public AnnotationVisitor visitArray(final String name) {
          ++size;
          if (named) {
              bv.putShort(cw.newUTF8(name));
          }
          // write tag, and reserve space for array size
          bv.put12('[', 0);
          return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
      }
  
      @Override
      public void visitEnd() {
          if (parent != null) {
              byte[] data = parent.data;
              data[offset] = (byte) (size >>> 8);
              data[offset + 1] = (byte) size;
          }
      }
  
      // ------------------------------------------------------------------------
      // Utility methods
      // ------------------------------------------------------------------------
  
      /**
       * Returns the size of this annotation writer list.
       * 
       * @return the size of this annotation writer list.
       */
      int getSize() {
          int size = 0;
          AnnotationWriter aw = this;
          while (aw != null) {
              size += aw.bv.length;
              aw = aw.next;
          }
          return size;
      }
  
      /**
       * Puts the annotations of this annotation writer list into the given byte
       * vector.
       * 
       * @param out
       *            where the annotations must be put.
       */
      void put(final ByteVector out) {
          int n = 0;
          int size = 2;
          AnnotationWriter aw = this;
          AnnotationWriter last = null;
          while (aw != null) {
              ++n;
              size += aw.bv.length;
              aw.visitEnd(); // in case user forgot to call visitEnd
              aw.prev = last;
              last = aw;
              aw = aw.next;
          }
          out.putInt(size);
          out.putShort(n);
          aw = last;
          while (aw != null) {
              out.putByteArray(aw.bv.data, 0, aw.bv.length);
              aw = aw.prev;
          }
      }
  
      /**
       * Puts the given annotation lists into the given byte vector.
       * 
       * @param panns
       *            an array of annotation writer lists.
       * @param off
       *            index of the first annotation to be written.
       * @param out
       *            where the annotations must be put.
       */
      static void put(final AnnotationWriter[] panns, final int off,
              final ByteVector out) {
          int size = 1 + 2 * (panns.length - off);
          for (int i = off; i < panns.length; ++i) {
              size += panns[i] == null ? 0 : panns[i].getSize();
          }
          out.putInt(size).putByte(panns.length - off);
          for (int i = off; i < panns.length; ++i) {
              AnnotationWriter aw = panns[i];
              AnnotationWriter last = null;
              int n = 0;
              while (aw != null) {
                  ++n;
                  aw.visitEnd(); // in case user forgot to call visitEnd
                  aw.prev = last;
                  last = aw;
                  aw = aw.next;
              }
              out.putShort(n);
              aw = last;
              while (aw != null) {
                  out.putByteArray(aw.bv.data, 0, aw.bv.length);
                  aw = aw.prev;
              }
          }
      }
  
      /**
       * Puts the given type reference and type path into the given bytevector.
       * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
       * 
       * @param typeRef
       *            a reference to the annotated type. 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 out
       *            where the type reference and type path must be put.
       */
      static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
          switch (typeRef >>> 24) {
          case 0x00: // CLASS_TYPE_PARAMETER
          case 0x01: // METHOD_TYPE_PARAMETER
          case 0x16: // METHOD_FORMAL_PARAMETER
              out.putShort(typeRef >>> 16);
              break;
          case 0x13: // FIELD
          case 0x14: // METHOD_RETURN
          case 0x15: // METHOD_RECEIVER
              out.putByte(typeRef >>> 24);
              break;
          case 0x47: // CAST
          case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
          case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
          case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
          case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
              out.putInt(typeRef);
              break;
          // case 0x10: // CLASS_EXTENDS
          // case 0x11: // CLASS_TYPE_PARAMETER_BOUND
          // case 0x12: // METHOD_TYPE_PARAMETER_BOUND
          // case 0x17: // THROWS
          // case 0x42: // EXCEPTION_PARAMETER
          // case 0x43: // INSTANCEOF
          // case 0x44: // NEW
          // case 0x45: // CONSTRUCTOR_REFERENCE
          // case 0x46: // METHOD_REFERENCE
          default:
              out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
              break;
          }
          if (typePath == null) {
              out.putByte(0);
          } else {
              int length = typePath.b[typePath.offset] * 2 + 1;
              out.putByteArray(typePath.b, typePath.offset, length);
          }
      }
  }