class MethodWriter {
        protected ByteStream output;
        protected ConstPoolWriter constPool;
        private int methodCount;
        protected int codeIndex;
        protected int throwsIndex;
        protected int stackIndex;

        private int startPos;
        private boolean isAbstract;
        private int catchPos;
        private int catchCount;

        MethodWriter(ConstPoolWriter cp) {
            output = new ByteStream(256);
            constPool = cp;
            methodCount = 0;
            codeIndex = 0;
            throwsIndex = 0;
            stackIndex = 0;
        }

        /**
         * Starts Adding a new method.
         *
         * @param accessFlags       access flags.
         * @param name              the method name.
         * @param descriptor        the method signature.
         * @param exceptions        throws clause.  It may be null.
         *                          The class names must be the JVM-internal
         *                          representations like <code>java/lang/Exception</code>.
         * @param aw                attributes to the <code>Method_info</code>.                         
         */
        public void begin(int accessFlags, String name, String descriptor,
                        String[] exceptions, AttributeWriter aw) {
            int nameIndex = constPool.addUtf8Info(name);
            int descIndex = constPool.addUtf8Info(descriptor);
            int[] intfs;
            if (exceptions == null)
                intfs = null;
            else
                intfs = constPool.addClassInfo(exceptions);

            begin(accessFlags, nameIndex, descIndex, intfs, aw);
        }

        /**
         * Starts adding a new method.
         *
         * @param accessFlags       access flags.
         * @param name              the method name.  an index indicating its <code>CONSTANT_Utf8_info</code>.
         * @param descriptor        the field type.  an index indicating its <code>CONSTANT_Utf8_info</code>.
         * @param exceptions        throws clause.  indexes indicating <code>CONSTANT_Class_info</code>s.
         *                          It may be null.
         * @param aw                attributes to the <code>Method_info</code>.                         
         */
        public void begin(int accessFlags, int name, int descriptor, int[] exceptions, AttributeWriter aw) {
            ++methodCount;
            output.writeShort(accessFlags);
            output.writeShort(name);
            output.writeShort(descriptor);
            isAbstract = (accessFlags & AccessFlag.ABSTRACT) != 0;

            int attrCount = isAbstract ? 0 : 1;
            if (exceptions != null)
                ++attrCount;

            writeAttribute(output, aw, attrCount);

            if (exceptions != null)
                writeThrows(exceptions);

            if (!isAbstract) {
                if (codeIndex == 0)
                    codeIndex = constPool.addUtf8Info(CodeAttribute.tag);

                startPos = output.getPos();
                output.writeShort(codeIndex);
                output.writeBlank(12);   // attribute_length, maxStack, maxLocals, code_lenth
            }

            catchPos = -1;
            catchCount = 0;
        }

        private void writeThrows(int[] exceptions) {<FILL_FUNCTION_BODY>}

        /**
         * Appends an 8bit value of bytecode.
         *
         * @see Opcode
         */
        public void add(int b) {
            output.write(b);
        }

        /**
         * Appends a 16bit value of bytecode.
         */
        public void add16(int b) {
            output.writeShort(b);
        }

        /**
         * Appends a 32bit value of bytecode.
         */
        public void add32(int b) {
            output.writeInt(b);
        }

        /**
         * Appends a invokevirtual, inovkespecial, or invokestatic bytecode.
         *
         * @see Opcode
         */
        public void addInvoke(int opcode, String targetClass, String methodName,
                              String descriptor) {
            int target = constPool.addClassInfo(targetClass);
            int nt = constPool.addNameAndTypeInfo(methodName, descriptor);
            int method = constPool.addMethodrefInfo(target, nt);
            add(opcode);
            add16(method);
        }

        /**
         * Ends appending bytecode.
         */
        public void codeEnd(int maxStack, int maxLocals) {
            if (!isAbstract) {
                output.writeShort(startPos + 6, maxStack);
                output.writeShort(startPos + 8, maxLocals);
                output.writeInt(startPos + 10, output.getPos() - startPos - 14);  // code_length
                catchPos = output.getPos();
                catchCount = 0;
                output.writeShort(0);   // number of catch clauses
            }
        }

        /**
         * Appends an <code>exception_table</code> entry to the
         * <code>Code_attribute</code>.  This method is available
         * only after the <code>codeEnd</code> method is called.
         *
         * @param catchType     an index indicating a <code>CONSTANT_Class_info</code>.
         */
        public void addCatch(int startPc, int endPc, int handlerPc, int catchType) {
            ++catchCount;
            output.writeShort(startPc);
            output.writeShort(endPc);
            output.writeShort(handlerPc);
            output.writeShort(catchType);
        }

        /**
         * Ends adding a new method.  The <code>add</code> method must be
         * called before the <code>end</code> method is called.
         *
         * @param smap              a stack map table.  may be null.
         * @param aw                attributes to the <code>Code_attribute</code>.
         *                          may be null.
         */
        public void end(StackMapTable.Writer smap, AttributeWriter aw) {
            if (isAbstract)
                return;

            // exception_table_length
            output.writeShort(catchPos, catchCount);

            int attrCount = smap == null ? 0 : 1;
            writeAttribute(output, aw, attrCount);

            if (smap != null) {
                if (stackIndex == 0)
                    stackIndex = constPool.addUtf8Info(StackMapTable.tag);

                output.writeShort(stackIndex);
                byte[] data = smap.toByteArray();
                output.writeInt(data.length);
                output.write(data);
            }

            // Code attribute_length
            output.writeInt(startPos + 2, output.getPos() - startPos - 6);
        }

        /**
         * Returns the length of the bytecode that has been added so far.
         *
         * @return      the length in bytes.
         * @since 3.19
         */
        public int size() { return output.getPos() - startPos - 14; } 

        int numOfMethods() { return methodCount; }

        int dataSize() { return output.size(); }

        /**
         * Writes the added methods.
         */
        void write(OutputStream out) throws IOException {
            output.writeTo(out);
        }
    }

            if (throwsIndex == 0)
                throwsIndex = constPool.addUtf8Info(ExceptionsAttribute.tag);

            output.writeShort(throwsIndex);
            output.writeInt(exceptions.length * 2 + 2);
            output.writeShort(exceptions.length);
            for (int i = 0; i < exceptions.length; i++)
                output.writeShort(exceptions[i]);
        
<no_super_class>