blob: 618d55c45a77677e070fb878be0aeab51169e01e [file] [log] [blame]
/*
* 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 org.netbeans.modules.classfile;
import java.io.DataInputStream;
import java.io.IOException;
/**
* A stack map frame, as defined by a StackMapTable attribute. A stack map
* frame is defined by the Java Virtual Machine Specification, section 4.8.4,
* as a C-like union of stack frame descriptions. To map this union to Java
* classes, this class is abstract and has a separate public subclass for each
* union member. The stack map frame type can be determined either by the
* its <code>frame_type</code> or using an instanceof test.
*
* @author tball
*/
public abstract class StackMapFrame {
int frameType;
static StackMapFrame[] loadStackMapTable(DataInputStream in, ConstantPool pool)
throws IOException {
int n = in.readUnsignedShort();
StackMapFrame[] entries = new StackMapFrame[n];
for (int i = 0; i < n; i++) {
int tag = in.readUnsignedByte();
StackMapFrame frame;
if (tag >= 0 && tag <= 63)
frame = new SameFrame(tag);
else if (tag >= 64 && tag <= 127) {
VerificationTypeInfo typeInfo =
VerificationTypeInfo.loadVerificationTypeInfo(in, pool);
frame = new SameLocals1StackItemFrame(tag, typeInfo);
}
else if (tag >= 128 && tag <= 246)
throw new InvalidClassFormatException("reserved stack map frame tag used: " + tag);
else if (tag == 247) {
int offset = in.readUnsignedShort();
VerificationTypeInfo typeInfo =
VerificationTypeInfo.loadVerificationTypeInfo(in, pool);
frame = new SameLocals1StackItemFrameExtended(tag, offset, typeInfo);
}
else if (tag >= 248 && tag <= 250) {
int offset = in.readUnsignedShort();
frame = new ChopFrame(tag, offset);
}
else if (tag == 251) {
int offset = in.readUnsignedShort();
frame = new SameFrameExtended(tag, offset);
}
else if (tag >= 252 && tag <= 254)
frame = makeAppendFrame(tag, in, pool);
else /* tag == 255 */
frame = makeFullFrame(in, pool);
entries[i] = frame;
}
return entries;
}
private static AppendFrame makeAppendFrame(int tag, DataInputStream in, ConstantPool pool)
throws IOException {
int offset = in.readUnsignedShort();
VerificationTypeInfo[] locals = new VerificationTypeInfo[tag - 251];
for (int i = 0; i < locals.length; i++)
locals[i] = VerificationTypeInfo.loadVerificationTypeInfo(in, pool);
return new AppendFrame(tag, offset, locals);
}
private static FullFrame makeFullFrame(DataInputStream in, ConstantPool pool)
throws IOException {
int offset = in.readUnsignedShort();
int n = in.readUnsignedShort();
VerificationTypeInfo[] locals = new VerificationTypeInfo[n];
for (int i = 0; i < locals.length; i++)
locals[i] = VerificationTypeInfo.loadVerificationTypeInfo(in, pool);
n = in.readUnsignedShort();
VerificationTypeInfo[] stackItems = new VerificationTypeInfo[n];
for (int i = 0; i < stackItems.length; i++)
stackItems[i] = VerificationTypeInfo.loadVerificationTypeInfo(in, pool);
return new FullFrame(255, offset, locals, stackItems);
}
/** Creates new StackMapFrame */
StackMapFrame(int tag) {
frameType = tag;
}
/**
* Returns the frame_type for this frame. As documented in the JVM specification,
* different tag ranges define different frame_type values.
*/
public final int getFrameType() {
return frameType;
}
/**
* Returns the <code>offset_delta</code> for this frame type. From the
* Java Virtual Machine Specification, section 4.8.4:
* <br/><br/>
* "Each stack_map_frame structure specifies the type state at a particular
* byte code offset. Each frame type specifies (explicitly or implicitly) a
* value, <code>offset_delta</code>, that is used to calulate the actual byte
* code offset at which it applies. The byte code offset at which the frame
* applies is given by adding <code>1 + offset_delta</code> to the offset of
* the previous frame, unless the previous frame is the initial frame of
* the method, in which case the byte code offset is <code>offset_delta</code>."
*/
public abstract int getOffsetDelta();
/**
* A frame type of <code>same_frame</code>, which means that the frame
* has exactly the same locals as the previous stack map frame and that
* the number of stack items is zero.
*/
public static final class SameFrame extends StackMapFrame {
SameFrame(int tag) {
super(tag);
}
/**
* The <code>offset_delta</code> value for the frame is the value
* of the tag item, frame_type.
*/
public int getOffsetDelta() {
return frameType;
}
}
/**
* A frame type of <code>same_locals_1_stack_item_frame</code>, which means
* that the frame has exactly the same locals as the previous stack map
* frame and that the number of stack items is 1.
*/
public static final class SameLocals1StackItemFrame extends StackMapFrame {
VerificationTypeInfo typeInfo;
SameLocals1StackItemFrame(int tag, VerificationTypeInfo typeInfo) {
super(tag);
this.typeInfo = typeInfo;
}
/**
* The <code>offset_delta</code> value for the frame is the value
* <code>(frame_type - 64)</code>.
*/
public int getOffsetDelta() {
return frameType - 64;
}
/**
* Returns the verification type info for the single stack item
* referenced by this frame.
*/
public VerificationTypeInfo getVerificationTypeInfo() {
return typeInfo;
}
}
/**
* A frame type of <code>same_locals_1_stack_item_frame_extended</code>,
* which means that the frame has exactly the same locals as the previous
* stack map frame and that the number of stack items is 1.
*/
public static final class SameLocals1StackItemFrameExtended extends StackMapFrame {
int offset;
VerificationTypeInfo typeInfo;
SameLocals1StackItemFrameExtended(int tag, int offset, VerificationTypeInfo typeInfo) {
super(tag);
this.offset = offset;
this.typeInfo = typeInfo;
}
/**
* Returns the <code>offset_delta</code> for this frame type.
*/
public int getOffsetDelta() {
return offset;
}
/**
* Returns the verification type info for the single stack item for
* this frame.
*/
public VerificationTypeInfo getVerificationTypeInfo() {
return typeInfo;
}
}
/**
* A frame type of <code>chop_frame</code>, which means that the operand
* stack is empty and the current locals are the same as the locals in
* the previous frame, except that the <i>k</i> last locals are absent.
* The value of <i>k</i> is given by the formula <code>251-frame_type</code>.
*/
public static final class ChopFrame extends StackMapFrame {
int offset;
ChopFrame(int tag, int offset) {
super(tag);
this.offset = offset;
}
/**
* Returns the <code>offset_delta</code> for this frame type.
*/
public int getOffsetDelta() {
return offset;
}
}
/**
* A frame type of <code>same_frame_extended</code>, which means the frame
* has exactly the same locals as the previous stack map frame and that the
* number of stack items is zero.
*/
public static final class SameFrameExtended extends StackMapFrame {
int offset;
SameFrameExtended(int tag, int offset) {
super(tag);
this.offset = offset;
}
/**
* Returns the <code>offset_delta</code> for this frame type.
*/
public int getOffsetDelta() {
return offset;
}
}
/**
* A frame type of <code>append_frame</code>, which means that the operand
* stack is empty and the current locals are the same as the locals in the
* previous frame, except that <i>k</i> additional locals are defined. The
* value of <i>k</i> is given by the formula <code>frame_type-251</code>.
*/
public static final class AppendFrame extends StackMapFrame {
int offset;
VerificationTypeInfo[] locals;
AppendFrame(int tag, int offset, VerificationTypeInfo[] locals) {
super(tag);
this.offset = offset;
this.locals = locals;
}
/**
* Returns the <code>offset_delta</code> for this frame type.
*/
public int getOffsetDelta() {
return offset;
}
/**
* Returns the verification type info for this frame's set of
* locals.
*/
public VerificationTypeInfo[] getLocals() {
return locals.clone();
}
}
/**
* A frame type of <code>full_frame</code>, which declares all of its
* locals and stack items.
*/
public static final class FullFrame extends StackMapFrame {
int offset;
VerificationTypeInfo[] locals;
VerificationTypeInfo[] stackItems;
FullFrame(int tag, int offset, VerificationTypeInfo[] locals,
VerificationTypeInfo[] stackItems) {
super(tag);
this.offset = offset;
this.locals = locals;
this.stackItems = stackItems;
}
/**
* Returns the <code>offset_delta</code> for this frame type.
*/
public int getOffsetDelta() {
return offset;
}
/**
* Returns the verification type info for this frame's set of
* locals.
*/
public VerificationTypeInfo[] getLocals() {
return locals.clone();
}
/**
* Returns the verification type info for this frame's set of
* stack items.
*/
public VerificationTypeInfo[] getStackItems() {
return stackItems.clone();
}
}
}