| /* |
| * reserved comment block |
| * DO NOT REMOVE OR ALTER! |
| */ |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 com.sun.org.apache.bcel.internal.classfile; |
| |
| import java.io.DataInput; |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| import com.sun.org.apache.bcel.internal.Const; |
| |
| /** |
| * This class represents a stack map entry recording the types of |
| * local variables and the the of stack items at a given byte code offset. |
| * See CLDC specification 5.3.1.2 |
| * |
| * @see StackMap |
| * @see StackMapType |
| */ |
| public final class StackMapEntry implements Node, Cloneable |
| { |
| |
| private int frame_type; |
| private int byte_code_offset; |
| private StackMapType[] types_of_locals; |
| private StackMapType[] types_of_stack_items; |
| private ConstantPool constant_pool; |
| |
| |
| /** |
| * Construct object from input stream. |
| * |
| * @param input Input stream |
| * @throws IOException |
| */ |
| StackMapEntry(final DataInput input, final ConstantPool constantPool) throws IOException { |
| this(input.readByte() & 0xFF, -1, null, null, constantPool); |
| |
| if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { |
| byte_code_offset = frame_type - Const.SAME_FRAME; |
| } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && |
| frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { |
| byte_code_offset = frame_type - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; |
| types_of_stack_items = new StackMapType[1]; |
| types_of_stack_items[0] = new StackMapType(input, constantPool); |
| } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { |
| byte_code_offset = input.readShort(); |
| types_of_stack_items = new StackMapType[1]; |
| types_of_stack_items[0] = new StackMapType(input, constantPool); |
| } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { |
| byte_code_offset = input.readShort(); |
| } else if (frame_type == Const.SAME_FRAME_EXTENDED) { |
| byte_code_offset = input.readShort(); |
| } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { |
| byte_code_offset = input.readShort(); |
| final int number_of_locals = frame_type - 251; |
| types_of_locals = new StackMapType[number_of_locals]; |
| for (int i = 0; i < number_of_locals; i++) { |
| types_of_locals[i] = new StackMapType(input, constantPool); |
| } |
| } else if (frame_type == Const.FULL_FRAME) { |
| byte_code_offset = input.readShort(); |
| final int number_of_locals = input.readShort(); |
| types_of_locals = new StackMapType[number_of_locals]; |
| for (int i = 0; i < number_of_locals; i++) { |
| types_of_locals[i] = new StackMapType(input, constantPool); |
| } |
| final int number_of_stack_items = input.readShort(); |
| types_of_stack_items = new StackMapType[number_of_stack_items]; |
| for (int i = 0; i < number_of_stack_items; i++) { |
| types_of_stack_items[i] = new StackMapType(input, constantPool); |
| } |
| } else { |
| /* Can't happen */ |
| throw new ClassFormatException ("Invalid frame type found while parsing stack map table: " + frame_type); |
| } |
| } |
| |
| /** |
| * DO NOT USE |
| * |
| * @param byteCodeOffset |
| * @param numberOfLocals NOT USED |
| * @param typesOfLocals array of {@link StackMapType}s of locals |
| * @param numberOfStackItems NOT USED |
| * @param typesOfStackItems array ot {@link StackMapType}s of stack items |
| * @param constantPool the constant pool |
| * @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} |
| * instead |
| */ |
| @java.lang.Deprecated |
| public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, |
| final StackMapType[] typesOfLocals, final int numberOfStackItems, |
| final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { |
| this.byte_code_offset = byteCodeOffset; |
| this.types_of_locals = typesOfLocals != null ? typesOfLocals : new StackMapType[0]; |
| this.types_of_stack_items = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0]; |
| this.constant_pool = constantPool; |
| } |
| |
| /** |
| * Create an instance |
| * |
| * @param tag the frame_type to use |
| * @param byteCodeOffset |
| * @param typesOfLocals array of {@link StackMapType}s of locals |
| * @param typesOfStackItems array ot {@link StackMapType}s of stack items |
| * @param constantPool the constant pool |
| */ |
| public StackMapEntry(final int tag, final int byteCodeOffset, |
| final StackMapType[] typesOfLocals, |
| final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { |
| this.frame_type = tag; |
| this.byte_code_offset = byteCodeOffset; |
| this.types_of_locals = typesOfLocals != null ? typesOfLocals : new StackMapType[0]; |
| this.types_of_stack_items = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0]; |
| this.constant_pool = constantPool; |
| } |
| |
| |
| /** |
| * Dump stack map entry |
| * |
| * @param file Output file stream |
| * @throws IOException |
| */ |
| public void dump( final DataOutputStream file ) throws IOException { |
| file.write(frame_type); |
| if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { |
| // nothing to be done |
| } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && |
| frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { |
| types_of_stack_items[0].dump(file); |
| } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { |
| file.writeShort(byte_code_offset); |
| types_of_stack_items[0].dump(file); |
| } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { |
| file.writeShort(byte_code_offset); |
| } else if (frame_type == Const.SAME_FRAME_EXTENDED) { |
| file.writeShort(byte_code_offset); |
| } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { |
| file.writeShort(byte_code_offset); |
| for (final StackMapType type : types_of_locals) { |
| type.dump(file); |
| } |
| } else if (frame_type == Const.FULL_FRAME) { |
| file.writeShort(byte_code_offset); |
| file.writeShort(types_of_locals.length); |
| for (final StackMapType type : types_of_locals) { |
| type.dump(file); |
| } |
| file.writeShort(types_of_stack_items.length); |
| for (final StackMapType type : types_of_stack_items) { |
| type.dump(file); |
| } |
| } else { |
| /* Can't happen */ |
| throw new ClassFormatException ("Invalid Stack map table tag: " + frame_type); |
| } |
| } |
| |
| |
| /** |
| * @return String representation. |
| */ |
| @Override |
| public String toString() { |
| final StringBuilder buf = new StringBuilder(64); |
| buf.append("("); |
| if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { |
| buf.append("SAME"); |
| } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && |
| frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { |
| buf.append("SAME_LOCALS_1_STACK"); |
| } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { |
| buf.append("SAME_LOCALS_1_STACK_EXTENDED"); |
| } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { |
| buf.append("CHOP ").append(String.valueOf(251-frame_type)); |
| } else if (frame_type == Const.SAME_FRAME_EXTENDED) { |
| buf.append("SAME_EXTENDED"); |
| } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { |
| buf.append("APPEND ").append(String.valueOf(frame_type-251)); |
| } else if (frame_type == Const.FULL_FRAME) { |
| buf.append("FULL"); |
| } else { |
| buf.append("UNKNOWN (").append(frame_type).append(")"); |
| } |
| buf.append(", offset delta=").append(byte_code_offset); |
| if (types_of_locals.length > 0) { |
| buf.append(", locals={"); |
| for (int i = 0; i < types_of_locals.length; i++) { |
| buf.append(types_of_locals[i]); |
| if (i < types_of_locals.length - 1) { |
| buf.append(", "); |
| } |
| } |
| buf.append("}"); |
| } |
| if (types_of_stack_items.length > 0) { |
| buf.append(", stack items={"); |
| for (int i = 0; i < types_of_stack_items.length; i++) { |
| buf.append(types_of_stack_items[i]); |
| if (i < types_of_stack_items.length - 1) { |
| buf.append(", "); |
| } |
| } |
| buf.append("}"); |
| } |
| buf.append(")"); |
| return buf.toString(); |
| } |
| |
| |
| /** |
| * Calculate stack map entry size |
| * |
| */ |
| int getMapEntrySize() { |
| if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { |
| return 1; |
| } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && |
| frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { |
| return 1 + (types_of_stack_items[0].hasIndex() ? 3 : 1); |
| } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { |
| return 3 + (types_of_stack_items[0].hasIndex() ? 3 : 1); |
| } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { |
| return 3; |
| } else if (frame_type == Const.SAME_FRAME_EXTENDED) { |
| return 3; |
| } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { |
| int len = 3; |
| for (final StackMapType types_of_local : types_of_locals) { |
| len += types_of_local.hasIndex() ? 3 : 1; |
| } |
| return len; |
| } else if (frame_type == Const.FULL_FRAME) { |
| int len = 7; |
| for (final StackMapType types_of_local : types_of_locals) { |
| len += types_of_local.hasIndex() ? 3 : 1; |
| } |
| for (final StackMapType types_of_stack_item : types_of_stack_items) { |
| len += types_of_stack_item.hasIndex() ? 3 : 1; |
| } |
| return len; |
| } else { |
| throw new RuntimeException("Invalid StackMap frame_type: " + frame_type); |
| } |
| } |
| |
| |
| public void setFrameType( final int f ) { |
| if (f >= Const.SAME_FRAME && f <= Const.SAME_FRAME_MAX) { |
| byte_code_offset = f - Const.SAME_FRAME; |
| } else if (f >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && |
| f <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { |
| byte_code_offset = f - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; |
| } else if (f == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (f == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (f == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock |
| } else { |
| throw new RuntimeException("Invalid StackMap frame_type"); |
| } |
| frame_type = f; |
| } |
| |
| |
| public int getFrameType() { |
| return frame_type; |
| } |
| |
| |
| public void setByteCodeOffset( final int new_offset ) { |
| if (new_offset < 0 || new_offset > 32767) { |
| throw new RuntimeException("Invalid StackMap offset: " + new_offset); |
| } |
| |
| if (frame_type >= Const.SAME_FRAME && |
| frame_type <= Const.SAME_FRAME_MAX) { |
| if (new_offset > Const.SAME_FRAME_MAX) { |
| frame_type = Const.SAME_FRAME_EXTENDED; |
| } else { |
| frame_type = new_offset; |
| } |
| } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && |
| frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { |
| if (new_offset > Const.SAME_FRAME_MAX) { |
| frame_type = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; |
| } else { |
| frame_type = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + new_offset; |
| } |
| } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (frame_type >= Const.CHOP_FRAME && |
| frame_type <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (frame_type == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (frame_type >= Const.APPEND_FRAME && |
| frame_type <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock |
| } else if (frame_type == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock |
| } else { |
| throw new RuntimeException("Invalid StackMap frame_type: " + frame_type); |
| } |
| byte_code_offset = new_offset; |
| } |
| |
| |
| /** |
| * Update the distance (as an offset delta) from this StackMap |
| * entry to the next. Note that this might cause the the |
| * frame type to change. Note also that delta may be negative. |
| * |
| * @param delta offset delta |
| */ |
| public void updateByteCodeOffset(final int delta) { |
| setByteCodeOffset(byte_code_offset + delta); |
| } |
| |
| |
| public int getByteCodeOffset() { |
| return byte_code_offset; |
| } |
| |
| |
| /** |
| * |
| * @deprecated since 6.0 |
| */ |
| @java.lang.Deprecated |
| public void setNumberOfLocals( final int n ) { // TODO unused |
| } |
| |
| |
| public int getNumberOfLocals() { |
| return types_of_locals.length; |
| } |
| |
| |
| public void setTypesOfLocals( final StackMapType[] types ) { |
| types_of_locals = types != null ? types : new StackMapType[0]; |
| } |
| |
| |
| public StackMapType[] getTypesOfLocals() { |
| return types_of_locals; |
| } |
| |
| |
| /** |
| * |
| * @deprecated since 6.0 |
| */ |
| @java.lang.Deprecated |
| public void setNumberOfStackItems( final int n ) { // TODO unused |
| } |
| |
| |
| public int getNumberOfStackItems() { |
| return types_of_stack_items.length; |
| } |
| |
| |
| public void setTypesOfStackItems( final StackMapType[] types ) { |
| types_of_stack_items = types != null ? types : new StackMapType[0]; |
| } |
| |
| |
| public StackMapType[] getTypesOfStackItems() { |
| return types_of_stack_items; |
| } |
| |
| |
| /** |
| * @return deep copy of this object |
| */ |
| public StackMapEntry copy() { |
| StackMapEntry e; |
| try { |
| e = (StackMapEntry) clone(); |
| } catch (final CloneNotSupportedException ex) { |
| throw new Error("Clone Not Supported"); |
| } |
| |
| e.types_of_locals = new StackMapType[types_of_locals.length]; |
| for (int i = 0; i < types_of_locals.length; i++) { |
| e.types_of_locals[i] = types_of_locals[i].copy(); |
| } |
| e.types_of_stack_items = new StackMapType[types_of_stack_items.length]; |
| for (int i = 0; i < types_of_stack_items.length; i++) { |
| e.types_of_stack_items[i] = types_of_stack_items[i].copy(); |
| } |
| return e; |
| } |
| |
| |
| /** |
| * Called by objects that are traversing the nodes of the tree implicitely |
| * defined by the contents of a Java class. I.e., the hierarchy of methods, |
| * fields, attributes, etc. spawns a tree of objects. |
| * |
| * @param v Visitor object |
| */ |
| @Override |
| public void accept( final Visitor v ) { |
| v.visitStackMapEntry(this); |
| } |
| |
| |
| /** |
| * @return Constant pool used by this object. |
| */ |
| public ConstantPool getConstantPool() { |
| return constant_pool; |
| } |
| |
| |
| /** |
| * @param constant_pool Constant pool to be used for this object. |
| */ |
| public void setConstantPool( final ConstantPool constant_pool ) { |
| this.constant_pool = constant_pool; |
| } |
| } |