📄 stackmapattribute.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 + -