
com.sun.jdo.api.persistence.enhancer.classfile.CodeAttribute Maven / Gradle / Ivy
/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.jdo.api.persistence.enhancer.classfile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintStream;
/**
* Subtype of ClassAttribute which describes the "Code" attribute
* associated with a method.
*/
public class CodeAttribute extends ClassAttribute {
public final static String expectedAttrName = "Code";//NOI18N
/* The java class file contents defining this code attribute.
If non-null, this must be disassembled before the remaining
fields of this instance may be accessed. */
private byte theDataBytes[];
/* The maximum number of stack entries used by this method */
private int maxStack;
/* The maximum number of local variables used by this method */
private int maxLocals;
/* The java VM byte code sequence for this method - null for native
and abstract methods */
private byte theCodeBytes[];
/* The instruction sequence for this method - initially derived from
the byte code array, but may later be modified */
private Insn theCode;
/* The exception ranges and handlers which apply to the code in this
method */
private ExceptionTable exceptionTable;
/* The attributes which apply to this method */
private AttributeVector codeAttributes;
/* The method environment used for decompiling this code attribute */
CodeEnv codeEnv;
/* public accessors */
/**
* Return the maximum number of stack entries used by this method
*/
public int stackUsed() {
makeValid();
return maxStack;
}
/**
* Set the maximum number of stack entries used by this method
*/
public void setStackUsed(int used) {
makeValid();
maxStack = used;
}
/**
* Return the maximum number of local variables used by this method
*/
public int localsUsed() {
makeValid();
return maxLocals;
}
/**
* Set the maximum number of local variables used by this method
*/
public void setLocalsUsed(int used) {
makeValid();
maxLocals = used;
}
/**
* Return the java VM byte code sequence for this method - null for
* native and abstract methods
*/
public byte[] byteCodes() {
makeValid();
return theCodeBytes;
}
/**
* Return the instruction sequence for this method - initially derived
* from the byte code array, but may later be modified
*/
public Insn theCode() {
makeValid();
if (theCode == null && codeEnv != null) {
buildInstructions(codeEnv);
}
return theCode;
}
/**
* Install the instruction sequence for this method - the byte code array
* is later updated.
*/
public void setTheCode(Insn insn) {
makeValid();
if (insn != null && insn.opcode() != Insn.opc_target)
throw new InsnError(
"The initial instruction in all methods must be a target");//NOI18N
theCode = insn;
}
/**
* Return the exception ranges and handlers which apply to the code in
* this method.
*/
public ExceptionTable exceptionHandlers() {
makeValid();
return exceptionTable;
}
/**
* Return the attributes which apply to this code
*/
public AttributeVector attributes() {
makeValid();
return codeAttributes;
}
/**
* Constructs a CodeAttribute object for construction from scratch
*/
public CodeAttribute(ConstUtf8 attrName,
int maxStack, int maxLocals,
Insn code,
ExceptionTable excTable,
AttributeVector codeAttrs) {
this(attrName, maxStack, maxLocals, code, null, /* byteCodes */
excTable, codeAttrs, null /* CodeEnv */ );
}
/**
* Constructs a CodeAttribute object
*/
public CodeAttribute(ConstUtf8 attrName,
int maxStack, int maxLocals,
Insn code, byte[] codeBytes,
ExceptionTable excTable,
AttributeVector codeAttrs,
CodeEnv codeEnv) {
super(attrName);
this.maxStack = maxStack;
this.maxLocals = maxLocals;
theCode = code;
theCodeBytes = codeBytes;
exceptionTable = excTable;
codeAttributes = codeAttrs;
this.codeEnv = codeEnv;
}
/**
* Constructs a CodeAttribute object for later disassembly
*/
public CodeAttribute(ConstUtf8 attrName, byte[] dataBytes, CodeEnv codeEnv) {
super(attrName);
this.theDataBytes = dataBytes;
this.codeEnv = codeEnv;
}
/* package local methods */
static CodeAttribute read(ConstUtf8 attrName,
DataInputStream data, ConstantPool pool)
throws IOException {
int maxStack = data.readUnsignedShort();
int maxLocals = data.readUnsignedShort();
int codeLength = data.readInt();
byte codeBytes[] = new byte[codeLength];
data.readFully(codeBytes);
Insn code = null;
CodeEnv codeEnv = new CodeEnv(pool);
ExceptionTable excTable = ExceptionTable.read(data, codeEnv);
AttributeVector codeAttrs =
AttributeVector.readAttributes(data, codeEnv);
return new CodeAttribute(attrName, maxStack, maxLocals, code, codeBytes,
excTable, codeAttrs, codeEnv);
}
/* This version reads the attribute into a byte array for later
consumption */
static CodeAttribute read(ConstUtf8 attrName, int attrLength,
DataInputStream data, ConstantPool pool)
throws IOException {
byte dataBytes[] = new byte[attrLength];
data.readFully(dataBytes);
return new CodeAttribute(attrName, dataBytes, new CodeEnv(pool));
}
void write(DataOutputStream out) throws IOException {
out.writeShort(attrName().getIndex());
if (theDataBytes == null) {
buildInstructionBytes();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream tmpOut = new DataOutputStream(baos);
tmpOut.writeShort(maxStack);
tmpOut.writeShort(maxLocals);
tmpOut.writeInt(theCodeBytes.length);
tmpOut.write(theCodeBytes, 0, theCodeBytes.length);
exceptionTable.write(tmpOut);
codeAttributes.write(tmpOut);
tmpOut.flush();
byte tmpBytes[] = baos.toByteArray();
out.writeInt(tmpBytes.length);
out.write(tmpBytes, 0, tmpBytes.length);
} else {
out.writeInt(theDataBytes.length);
out.write(theDataBytes, 0, theDataBytes.length);
}
}
void print(PrintStream out, int indent) {
makeValid();
ClassPrint.spaces(out, indent);
out.print("Code:");//NOI18N
out.print(" max_stack = " + Integer.toString(maxStack));//NOI18N
out.print(" max_locals = " + Integer.toString(maxLocals));//NOI18N
out.println(" Exceptions:");//NOI18N
exceptionTable.print(out, indent+2);
ClassPrint.spaces(out, indent);
out.println("Code Attributes:");//NOI18N
codeAttributes.print(out, indent+2);
Insn insn = theCode();
if (insn != null) {
ClassPrint.spaces(out, indent);
out.println("Instructions:");//NOI18N
while (insn != null) {
insn.print(out, indent+2);
insn = insn.next();
}
}
}
/**
* Assign offsets to instructions and return the number of bytes.
* theCode must be non-null.
*/
private int resolveOffsets() {
Insn insn = theCode;
int currPC = 0;
while (insn != null) {
currPC = insn.resolveOffset(currPC);
insn = insn.next();
}
return currPC;
}
int codeSize() {
makeValid();
return theCodeBytes.length;
}
/**
* Derive the instruction list from the instruction byte codes
*/
private void buildInstructions(CodeEnv codeEnv) {
if (theCodeBytes != null) {
InsnReadEnv insnEnv = new InsnReadEnv(theCodeBytes, codeEnv);
theCode = insnEnv.getTarget(0);
Insn currInsn = theCode;
/* First, create instructions */
while (insnEnv.more()) {
Insn newInsn = Insn.read(insnEnv);
currInsn.setNext(newInsn);
currInsn = newInsn;
}
/* Now, insert targets */
InsnTarget targ;
currInsn = theCode;
Insn prevInsn = null;
while (currInsn != null) {
int off = currInsn.offset();
/* We always insert a target a 0 to start so ignore that one */
if (off > 0) {
targ = codeEnv.findTarget(off);
if (targ != null)
prevInsn.setNext(targ);
}
prevInsn = currInsn;
currInsn = currInsn.next();
}
/* And follow up with a final target if needed */
targ = codeEnv.findTarget(insnEnv.currentPC());
if (targ != null)
prevInsn.setNext(targ);
}
}
/**
* Derive the instruction byte codes from the instruction list
* This should also recompute stack and variables but for now we
* assume that this isn't needed
*/
private void buildInstructionBytes() {
if (theCode != null) {
/* Make sure instructions have correct offsets */
int size = resolveOffsets();
theCodeBytes = new byte[size];
Insn insn = theCode;
int index = 0;
while (insn != null) {
index = insn.store(theCodeBytes, index);
insn = insn.next();
}
}
}
/** If theDataBytes is non-null, disassemble this code attribute
* from the data bytes. */
private void makeValid() {
if (theDataBytes != null) {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(theDataBytes));
try {
maxStack = dis.readUnsignedShort();
maxLocals = dis.readUnsignedShort();
int codeLength = dis.readInt();
theCodeBytes = new byte[codeLength];
dis.readFully(theCodeBytes);
exceptionTable = ExceptionTable.read(dis, codeEnv);
codeAttributes = AttributeVector.readAttributes(dis, codeEnv);
} catch (java.io.IOException ioe) {
ClassFormatError cfe = new ClassFormatError(
"IOException while reading code attribute");//NOI18N
cfe.initCause(ioe);
throw cfe;
}
theDataBytes = null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy