Package org.cojen.classfile.attribute

Source Code of org.cojen.classfile.attribute.CodeAttr

/*
*  Copyright 2004-2010 Brian S O'Neill
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package org.cojen.classfile.attribute;

import java.util.ArrayList;
import java.util.List;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.cojen.classfile.Attribute;
import org.cojen.classfile.AttributeFactory;
import org.cojen.classfile.CodeBuffer;
import org.cojen.classfile.ConstantPool;
import org.cojen.classfile.ExceptionHandler;
import org.cojen.classfile.LocalVariable;
import org.cojen.classfile.Location;
import org.cojen.classfile.MethodInfo;

/**
* This class corresponds to the Code_attribute structure as defined in <i>The
* Java Virtual Machine Specification</i>. To make it easier to create bytecode
* for the CodeAttr, use the CodeBuilder.
*
* @author Brian S O'Neill
* @see org.cojen.classfile.Opcode
* @see org.cojen.classfile.CodeBuilder
*/
public class CodeAttr extends Attribute {

    private CodeBuffer mCodeBuffer;
    private List<Attribute> mAttributes = new ArrayList<Attribute>(2);
   
    private LineNumberTableAttr mLineNumberTable;
    private LocalVariableTableAttr mLocalVariableTable;

    private LineNumberTableAttr mOldLineNumberTable;
    private LocalVariableTableAttr mOldLocalVariableTable;

    private StackMapTableAttr mOldStackMapTable;
    private StackMapTableAttr mStackMapTable;

    public CodeAttr(ConstantPool cp) {
        super(cp, CODE);
    }

    public CodeAttr(ConstantPool cp, String name) {
        super(cp, name);
    }
   
    public CodeAttr(ConstantPool cp, String name, int length,
                    DataInput din, AttributeFactory attrFactory)
        throws IOException
    {
        super(cp, name);

        final int maxStackDepth = din.readUnsignedShort();
        final int maxLocals = din.readUnsignedShort();

        final byte[] byteCodes = new byte[din.readInt()];
        din.readFully(byteCodes);

        int exceptionHandlerCount = din.readUnsignedShort();
        final ExceptionHandler[] handlers =
            new ExceptionHandler[exceptionHandlerCount];

        for (int i=0; i<exceptionHandlerCount; i++) {
            handlers[i] = ExceptionHandler.readFrom(cp, din);
        }
       
        mCodeBuffer = new CodeBuffer() {
            public int getMaxStackDepth() {
                return maxStackDepth;
            }
           
            public int getMaxLocals() {
                return maxLocals;
            }
           
            public byte[] getByteCodes() {
                return byteCodes.clone();
            }
           
            public ExceptionHandler[] getExceptionHandlers() {
                return handlers.clone();
            }
        };

        int attributeCount = din.readUnsignedShort();
        for (int i=0; i<attributeCount; i++) {
            addAttribute(Attribute.readFrom(cp, din, attrFactory));
        }
    }

    /**
     * Returns null if no CodeBuffer is defined for this CodeAttr.
     */
    public CodeBuffer getCodeBuffer() {
        return mCodeBuffer;
    }

    /**
     * As a side effect of calling this method, new line number and local
     * variable tables are created.
     */
    public void setCodeBuffer(CodeBuffer code) {
        mCodeBuffer = code;
        mOldLineNumberTable = mLineNumberTable;
        mOldLocalVariableTable = mLocalVariableTable;
        mOldStackMapTable = mStackMapTable;
        mAttributes.remove(mLineNumberTable);
        mAttributes.remove(mLocalVariableTable);
        mAttributes.remove(mStackMapTable);
        mLineNumberTable = null;
        mLocalVariableTable = null;
        mStackMapTable = null;
    }
   
    /**
     * Returns the line number in the source code from the given bytecode
     * address (start_pc).
     *
     * @return -1 if no line number is mapped for the start_pc.
     */
    public int getLineNumber(Location start) {
        LineNumberTableAttr table = mOldLineNumberTable;
        if (table == null) {
            table = mLineNumberTable;
        }

        if (table == null || start.getLocation() < 0) {
            return -1;
        } else {
            return table.getLineNumber(start);
        }
    }

    /**
     * Returns local variable info at the given location, for the given number.
     *
     * @return null if unknown
     */
    public LocalVariable getLocalVariable(Location useLocation, int number) {
        int useLoc = useLocation.getLocation();
        if (useLoc < 0) {
            return null;
        } else {
            return getLocalVariable(useLoc, number);
        }
    }

    /**
     * Returns local variable info at the given location, for the given number.
     *
     * @return null if unknown
     */
    public LocalVariable getLocalVariable(int useLocation, int number) {
        LocalVariableTableAttr table = mOldLocalVariableTable;
        if (table == null) {
            table = mLocalVariableTable;
        }

        if (table == null) {
            return null;
        } else {
            return table.getLocalVariable(useLocation, number);
        }
    }

    /**
     * Map a bytecode address (start_pc) to a line number in the source code
     * as a debugging aid.
     */
    public void mapLineNumber(Location start, int line_number) {
        if (mLineNumberTable == null) {
            addAttribute(new LineNumberTableAttr(getConstantPool()));
        }
        mLineNumberTable.addEntry(start, line_number);
    }

    /**
     * Indicate a local variable's use information be recorded in the
     * ClassFile as a debugging aid. If the LocalVariable doesn't provide
     * both a start and end location, then its information is not recorded.
     * This method should be called at most once per LocalVariable instance.
     */
    public void localVariableUse(LocalVariable localVar) {
        if (mLocalVariableTable == null) {
            addAttribute(new LocalVariableTableAttr(getConstantPool()));
        }
        mLocalVariableTable.addEntry(localVar);
    }

    public StackMapTableAttr getStackMapTable() {
        return mStackMapTable;
    }

    public void setInitialStackMapFrame(MethodInfo method) {
        if (mStackMapTable == null) {
            mStackMapTable = new StackMapTableAttr(getConstantPool());
        }
        mStackMapTable.setInitialFrame(method);
    }

    public void addAttribute(Attribute attr) {
        if (attr instanceof LineNumberTableAttr) {
            if (mLineNumberTable != null) {
                mAttributes.remove(mLineNumberTable);
            }
            mLineNumberTable = (LineNumberTableAttr)attr;
        } else if (attr instanceof LocalVariableTableAttr) {
            if (mLocalVariableTable != null) {
                mAttributes.remove(mLocalVariableTable);
            }
            mLocalVariableTable = (LocalVariableTableAttr)attr;
        } else if (attr instanceof StackMapTableAttr) {
            if (mStackMapTable != null) {
                mAttributes.remove(mStackMapTable);
            }
            mStackMapTable = (StackMapTableAttr)attr;
        }

        mAttributes.add(attr);
    }
   
    public Attribute[] getAttributes() {
        return mAttributes.toArray(new Attribute[mAttributes.size()]);
    }

    /**
     * Returns the length (in bytes) of this object in the class file.
     */
    public int getLength() {
        int length = 12;

        if (mCodeBuffer != null) {
            length += mCodeBuffer.getByteCodes().length;
            ExceptionHandler[] handlers = mCodeBuffer.getExceptionHandlers();
            if (handlers != null) {
                length += 8 * handlers.length;
            }
        }
       
        int size = mAttributes.size();
        for (int i=0; i<size; i++) {
            length += mAttributes.get(i).getLength();
            length += 6; // attributes have an intial 6 byte length
        }
       
        return length;
    }

    public void writeDataTo(DataOutput dout) throws IOException {
        if (mCodeBuffer == null) {
            throw new IllegalStateException("CodeAttr has no CodeBuffer set");
        }

        ExceptionHandler[] handlers = mCodeBuffer.getExceptionHandlers();
       
        dout.writeShort(mCodeBuffer.getMaxStackDepth());
        dout.writeShort(mCodeBuffer.getMaxLocals());
       
        byte[] byteCodes = mCodeBuffer.getByteCodes();
        dout.writeInt(byteCodes.length);
        dout.write(byteCodes);

        if (handlers != null) {
            int exceptionHandlerCount = handlers.length;
            dout.writeShort(exceptionHandlerCount);

            for (int i=0; i<exceptionHandlerCount; i++) {
                handlers[i].writeTo(dout);
            }
        } else {
            dout.writeShort(0);
        }
       
        int size = mAttributes.size();
        dout.writeShort(size);
        for (int i=0; i<size; i++) {
            Attribute attr = mAttributes.get(i);
            attr.writeTo(dout);
        }

        mOldLineNumberTable = null;
        mOldLocalVariableTable = null;
        mOldStackMapTable = null;
    }
}
TOP

Related Classes of org.cojen.classfile.attribute.CodeAttr

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.