⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stackmapattribute.java

📁 jboss规则引擎
💻 JAVA
字号:
/**
 * ASM: a very small and fast Java bytecode manipulation framework
 * Copyright (c) 2000-2005 INRIA, France Telecom
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.drools.asm.attrs;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.drools.asm.Attribute;
import org.drools.asm.ByteVector;
import org.drools.asm.ClassReader;
import org.drools.asm.ClassWriter;
import org.drools.asm.Label;

/**
 * StackMapAttribute is used by CDLC preverifier. Definition is given in
 * appendix "CLDC Byte Code Typechecker Specification" from CDLC 1.1
 * specification. <p> <i>Note that this implementation does not calculate
 * StackMapFrame structures from the method bytecode. If method code is changed
 * or generated from scratch, then developer is responsible to prepare a correct
 * StackMapFrame structures.</i> <p> The format of the stack map in the class
 * file is given below. In the following, <ul> <li>if the length of the
 * method's byte code1 is 65535 or less, then <tt>uoffset</tt> represents the
 * type u2; otherwise <tt>uoffset</tt> represents the type u4.</li> <li>If
 * the maximum number of local variables for the method is 65535 or less, then
 * <tt>ulocalvar</tt> represents the type u2; otherwise <tt>ulocalvar</tt>
 * represents the type u4.</li> <li>If the maximum size of the operand stack
 * is 65535 or less, then <tt>ustack</tt> represents the type u2; otherwise
 * ustack represents the type u4.</li> </ul>
 * 
 * <pre>
 * stack_map { // attribute StackMap
 *   u2 attribute_name_index;
 *   u4 attribute_length
 *   uoffset number_of_entries;
 *   stack_map_frame entries[number_of_entries];
 * }
 * </pre>
 * 
 * Each stack map frame has the following format:
 * 
 * <pre>
 * stack_map_frame {
 *   uoffset offset;
 *   ulocalvar number_of_locals;
 *   verification_type_info locals[number_of_locals];
 *   ustack number_of_stack_items;
 *   verification_type_info stack[number_of_stack_items];
 * }
 * </pre>
 * 
 * The <tt>verification_type_info</tt> structure consists of a one-byte tag
 * followed by zero or more bytes, giving more information about the tag. Each
 * <tt>verification_type_info</tt> structure specifies the verification type
 * of one or two locations.
 * 
 * <pre>
 * union verification_type_info {
 *   Top_variable_info;
 *   Integer_variable_info;
 *   Float_variable_info;
 *   Long_variable_info;
 *   Double_variable_info;
 *   Null_variable_info;
 *   UninitializedThis_variable_info;
 *   Object_variable_info;
 *   Uninitialized_variable_info;
 * }
 *      
 * Top_variable_info {
 *   u1 tag = ITEM_Top; // 0
 * }
 *      
 * Integer_variable_info {
 *   u1 tag = ITEM_Integer; // 1
 * }
 *      
 * Float_variable_info {
 *   u1 tag = ITEM_Float; // 2
 * }
 *      
 * Long_variable_info {
 *   u1 tag = ITEM_Long; // 4
 * }
 *      
 * Double_variable_info {
 *   u1 tag = ITEM_Double; // 3
 * }
 *      
 * Null_variable_info {
 *  u1 tag = ITEM_Null; // 5
 * }
 *      
 * UninitializedThis_variable_info {
 *   u1 tag = ITEM_UninitializedThis; // 6
 * }
 *      
 * Object_variable_info {
 *   u1 tag = ITEM_Object; // 7
 *   u2 cpool_index;
 * }
 *      
 * Uninitialized_variable_info {
 *   u1 tag = ITEM_Uninitialized // 8
 *   uoffset offset;
 * }
 * </pre>
 * 
 * @see <a href="http://www.jcp.org/en/jsr/detail?id=139">JSR 139 : Connected
 *      Limited Device Configuration 1.1</a>
 * 
 * @author Eugene Kuleshov
 */
public class StackMapAttribute extends Attribute {

    static final int MAX_SIZE = 65535;

    /**
     * A List of <code>StackMapFrame</code> instances.
     */
    public List      frames   = new ArrayList();

    public StackMapAttribute() {
        super( "StackMap" );
    }

    public StackMapAttribute(final List frames) {
        this();
        this.frames = frames;
    }

    public List getFrames() {
        return this.frames;
    }

    public StackMapFrame getFrame(final Label label) {
        for ( int i = 0; i < this.frames.size(); i++ ) {
            final StackMapFrame frame = (StackMapFrame) this.frames.get( i );
            if ( frame.label == label ) {
                return frame;
            }
        }
        return null;
    }

    public boolean isUnknown() {
        return false;
    }

    public boolean isCodeAttribute() {
        return true;
    }

    protected Attribute read(final ClassReader cr,
                             int off,
                             final int len,
                             final char[] buf,
                             final int codeOff,
                             final Label[] labels) {
        final StackMapAttribute attr = new StackMapAttribute();
        // note that this is not the size of Code attribute
        final boolean isExtCodeSize = cr.readInt( codeOff + 4 ) > StackMapAttribute.MAX_SIZE;
        final boolean isExtLocals = cr.readUnsignedShort( codeOff + 2 ) > StackMapAttribute.MAX_SIZE;
        final boolean isExtStack = cr.readUnsignedShort( codeOff ) > StackMapAttribute.MAX_SIZE;

        int size = 0;
        if ( isExtCodeSize ) {
            size = cr.readInt( off );
            off += 4;
        } else {
            size = cr.readUnsignedShort( off );
            off += 2;
        }
        for ( int i = 0; i < size; i++ ) {
            int offset;
            if ( isExtCodeSize ) {
                offset = cr.readInt( off );
                off += 4;
            } else {
                offset = cr.readUnsignedShort( off );
                off += 2;
            }

            final Label label = getLabel( offset,
                                          labels );
            final List locals = new ArrayList();
            final List stack = new ArrayList();

            off = readTypeInfo( cr,
                                off,
                                locals,
                                labels,
                                buf,
                                isExtLocals,
                                isExtCodeSize );
            off = readTypeInfo( cr,
                                off,
                                stack,
                                labels,
                                buf,
                                isExtStack,
                                isExtCodeSize );

            attr.frames.add( new StackMapFrame( label,
                                                locals,
                                                stack ) );
        }
        return attr;
    }

    private int readTypeInfo(final ClassReader cr,
                             int off,
                             final List info,
                             final Label[] labels,
                             final char[] buf,
                             final boolean isExt,
                             final boolean isExtCode) {
        int n = 0;
        if ( isExt ) {
            n = cr.readInt( off );
            off += 4;
        } else {
            n = cr.readUnsignedShort( off );
            off += 2;
        }
        for ( int j = 0; j < n; j++ ) {
            final int itemType = cr.readByte( off++ );
            final StackMapType typeInfo = StackMapType.getTypeInfo( itemType );
            info.add( typeInfo );
            switch ( itemType ) {
                case StackMapType.ITEM_Object : //
                    typeInfo.setObject( cr.readClass( off,
                                                      buf ) );
                    off += 2;
                    break;
                case StackMapType.ITEM_Uninitialized : //
                    int offset;
                    if ( isExtCode ) {
                        offset = cr.readInt( off );
                        off += 4;
                    } else {
                        offset = cr.readUnsignedShort( off );
                        off += 2;
                    }
                    typeInfo.setLabel( getLabel( offset,
                                                 labels ) );
                    break;
            }
        }
        return off;
    }

    private void writeTypeInfo(final ByteVector bv,
                               final ClassWriter cw,
                               final List info,
                               final int max) {
        if ( max > StackMapAttribute.MAX_SIZE ) {
            bv.putInt( info.size() );
        } else {
            bv.putShort( info.size() );
        }
        for ( int j = 0; j < info.size(); j++ ) {
            final StackMapType typeInfo = (StackMapType) info.get( j );
            bv.putByte( typeInfo.getType() );
            switch ( typeInfo.getType() ) {
                case StackMapType.ITEM_Object : //
                    bv.putShort( cw.newClass( typeInfo.getObject() ) );
                    break;

                case StackMapType.ITEM_Uninitialized : //
                    bv.putShort( typeInfo.getLabel().getOffset() );
                    break;

            }
        }
    }

    private Label getLabel(final int offset,
                           final Label[] labels) {
        final Label l = labels[offset];
        if ( l != null ) {
            return l;
        }
        return labels[offset] = new Label();
    }

    protected ByteVector write(final ClassWriter cw,
                               final byte[] code,
                               final int len,
                               final int maxStack,
                               final int maxLocals) {
        final ByteVector bv = new ByteVector();
        if ( code != null && code.length > StackMapAttribute.MAX_SIZE ) { // TODO verify value
            bv.putInt( this.frames.size() );
        } else {
            bv.putShort( this.frames.size() );
        }
        for ( int i = 0; i < this.frames.size(); i++ ) {
            writeFrame( (StackMapFrame) this.frames.get( i ),
                        cw,
                        maxStack,
                        maxLocals,
                        bv );
        }
        return bv;
    }

    protected Label[] getLabels() {
        final HashSet labels = new HashSet();
        for ( int i = 0; i < this.frames.size(); i++ ) {
            getFrameLabels( (StackMapFrame) this.frames.get( i ),
                            labels );
        }
        return (Label[]) labels.toArray( new Label[labels.size()] );
    }

    private void writeFrame(final StackMapFrame frame,
                            final ClassWriter cw,
                            final int maxStack,
                            final int maxLocals,
                            final ByteVector bv) {
        bv.putShort( frame.label.getOffset() );
        writeTypeInfo( bv,
                       cw,
                       frame.locals,
                       maxLocals );
        writeTypeInfo( bv,
                       cw,
                       frame.stack,
                       maxStack );
    }

    private void getFrameLabels(final StackMapFrame frame,
                                final Set labels) {
        labels.add( frame.label );
        getTypeInfoLabels( labels,
                           frame.locals );
        getTypeInfoLabels( labels,
                           frame.stack );
    }

    private void getTypeInfoLabels(final Set labels,
                                   final List info) {
        for ( final Iterator it = info.iterator(); it.hasNext(); ) {
            final StackMapType typeInfo = (StackMapType) it.next();
            if ( typeInfo.getType() == StackMapType.ITEM_Uninitialized ) {
                labels.add( typeInfo.getLabel() );
            }
        }
    }

    public String toString() {
        final StringBuffer sb = new StringBuffer( "StackMap[" );
        for ( int i = 0; i < this.frames.size(); i++ ) {
            sb.append( '\n' ).append( '[' ).append( this.frames.get( i ) ).append( ']' );
        }
        sb.append( "\n]" );
        return sb.toString();
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -