
com.tangosol.dev.assembler.AbstractLocalVariableTableAttribute Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.dev.assembler;
import java.io.IOException;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeSet;
import java.util.Iterator;
/**
* Represents a Java Virtual Machine byte-code "LocalVariableTable" or
* "LocalVariableTypeTable attribute which cross-references between
* byte-code variable references by index and source file variable
* references by name; also includes scope information of which portion
* of the code the variable "exists" in.
*
* @version 0.50, 05/15/98, assembler/dis-assembler
* @author Cameron Purdy
*/
public abstract class AbstractLocalVariableTableAttribute
extends Attribute
implements Constants
{
// ----- constructors ---------------------------------------------------
/**
* Construct a LocalVariableTable attribute.
*
* @param context the JVM structure containing the attribute
*/
protected AbstractLocalVariableTableAttribute(VMStructure context,
String sAttr)
{
super(context, sAttr);
}
// ----- VMStructure operations -----------------------------------------
/**
* The disassembly process reads the structure from the passed input
* stream and uses the constant pool to dereference any constant
* references.
*
* @param stream the stream implementing java.io.DataInput from which
* to read the assembled VM structure
* @param pool the constant pool for the class which contains any
* constants referenced by this VM structure
*/
protected void disassemble(DataInput stream, ConstantPool pool)
throws IOException
{
clear();
stream.readInt();
int count = stream.readUnsignedShort();
for (int i = 0; i < count; ++i)
{
Range range = new Range();
range.disassemble(stream, pool);
add(range);
}
resetModified();
}
/**
* The pre-assembly step collects the necessary entries for the constant
* pool. During this step, all constants used by this VM structure and
* any sub-structures are registered with (but not yet bound by position
* in) the constant pool.
*
* @param pool the constant pool for the class which needs to be
* populated with the constants required to build this
* VM structure
*/
protected void preassemble(ConstantPool pool)
{
super.preassemble(pool);
for (Range range = m_first; range != null; range = range.getNext())
{
range.preassemble(pool);
}
}
/**
* The assembly process assembles and writes the structure to the passed
* output stream, resolving any dependencies using the passed constant
* pool.
*
* @param stream the stream implementing java.io.DataOutput to which to
* write the assembled VM structure
* @param pool the constant pool for the class which by this point
* contains the entire set of constants required to build
* this VM structure
*/
protected void assemble(DataOutput stream, ConstantPool pool)
throws IOException
{
stream.writeShort(pool.findConstant(super.getNameConstant()));
stream.writeInt(2 + 10 * m_count);
stream.writeShort(m_count);
if (m_count > 0)
{
Set set = new TreeSet();
for (Range range = m_first; range != null; range = range.getNext())
{
set.add(range);
}
for (Iterator iter = set.iterator(); iter.hasNext(); )
{
Range range = (Range) iter.next();
range.assemble(stream, pool);
}
}
}
/**
* Determine if the attribute has been modified.
*
* @return true if the attribute has been modified
*/
public boolean isModified()
{
return m_fModified;
}
/**
* Reset the modified state of the VM structure.
*/
protected void resetModified()
{
m_fModified = false;
}
// ----- accessors ------------------------------------------------------
/**
* Discard any range information.
*/
public void clear()
{
m_first = null;
m_last = null;
m_fModified = true;
}
/**
* Determine if there is no variable range information.
*
* @return true if there is no range information, false otherwise
*/
public boolean isEmpty()
{
return m_first == null;
}
/**
* Add the specified variable definite assignment range.
*
* @param decl
* @param opInit
* @param opStop
*/
protected void add(OpDeclare decl, Op opInit, Op opStop)
{
add(new Range(decl, opInit, opStop));
}
/**
* Add the specified range information.
*/
protected void add(Range range)
{
if (m_first == null)
{
m_first = range;
m_last = range;
}
else
{
m_last.setNext(range);
m_last = range;
}
++m_count;
m_fModified = true;
}
/**
* Enumerate the range information.
*
* @return an enumeration of Range objects
*/
public Enumeration ranges()
{
return new Enumeration()
{
public boolean hasMoreElements()
{
return cur != null;
}
public Object nextElement()
{
if (cur == null)
{
throw new NoSuchElementException();
}
Range range = cur;
cur = range.getNext();
return range;
}
private Range cur = m_first;
};
}
// ----- Object methods -------------------------------------------------
/**
* Provide a debug output of this attribute.
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append(getName() + " for method ")
.append(((Method) ((CodeAttribute) getContext()).getContext()).getIdentity());
for (Enumeration enmr = ranges(); enmr.hasMoreElements(); )
{
sb.append("\n ")
.append(enmr.nextElement());
}
return sb.toString();
}
// ----- data members ---------------------------------------------------
/**
* Tracks modification to this object.
*/
private boolean m_fModified;
/**
* The first range.
*/
private Range m_first;
/**
* The last range.
*/
private Range m_last;
/**
* The count of variable definite assignment range objects.
*/
private int m_count;
// ----- inner classes --------------------------------------------------
/**
* Represents a piece of debugging information that cross-references a
* range of Java Virtual Machine byte-code with a variable which has a
* value within that range.
*
* @version 0.50, 07/20/98, assembler/dis-assembler
* @author Cameron Purdy
*/
public static class Range extends VMStructure implements Constants, Comparable
{
// ----- constructors -----------------------------------------------
/**
* Construct a Range object. Used during disassembly.
*/
protected Range()
{
}
/**
* Construct a Range object. Used during assembly.
*
* @param decl the variable with a definite value in the range
* @param opInit the first op in the range
* @param opStop the first op past the range
*/
protected Range(OpDeclare decl, Op opInit, Op opStop)
{
if (decl == null || opInit == null || opStop == null)
{
String sClass =
"AbstractLocalVariableTableAttribute" + ".Range";
throw new IllegalArgumentException(sClass +
": All parameters required!");
}
m_decl = decl;
m_opInit = opInit;
m_opStop = opStop;
m_utfName = new UtfConstant(decl.getVariableName());
m_utfType = new UtfConstant(decl.getSignature());
// only variables with debugging information can be registered
// in the local variable table
if (m_utfName == null || m_utfType == null)
{
String sClass =
"AbstractLocalVariableTableAttribute" + ".Range";
throw new IllegalArgumentException(sClass +
": Variable is missing debug information!");
}
}
// ----- VMStructure operations -------------------------------------
/**
* The disassembly process reads the structure from the passed input
* stream and uses the constant pool to dereference any constant
* references.
*
* @param stream the stream implementing java.io.DataInput from which
* to read the assembled VM structure
* @param pool the constant pool for the class which contains any
* constants referenced by this VM structure
*/
protected void disassemble(DataInput stream, ConstantPool pool)
throws IOException
{
m_of = stream.readUnsignedShort();
m_cb = stream.readUnsignedShort();
m_utfName = (UtfConstant) pool.getConstant(stream.readUnsignedShort());
m_utfType = (UtfConstant) pool.getConstant(stream.readUnsignedShort());
m_iVar = stream.readUnsignedShort();
}
/**
* The pre-assembly step collects the necessary entries for the constant
* pool. During this step, all constants used by this VM structure and
* any sub-structures are registered with (but not yet bound by position
* in) the constant pool.
*
* @param pool the constant pool for the class which needs to be
* populated with the constants required to build this
* VM structure
*/
protected void preassemble(ConstantPool pool)
{
pool.registerConstant(m_utfName);
pool.registerConstant(m_utfType);
}
/**
* The assembly process assembles and writes the structure to the passed
* output stream, resolving any dependencies using the passed constant
* pool.
*
* @param stream the stream implementing java.io.DataOutput to which to
* write the assembled VM structure
* @param pool the constant pool for the class which by this point
* contains the entire set of constants required to build
* this VM structure
*/
protected void assemble(DataOutput stream, ConstantPool pool)
throws IOException
{
stream.writeShort(getOffset());
stream.writeShort(getLength());
stream.writeShort(pool.findConstant(m_utfName));
stream.writeShort(pool.findConstant(m_utfType));
stream.writeShort(getSlot());
}
// ----- accessors --------------------------------------------------
/**
* Get the byte code offset ("pc") of the range.
*
* @return the byte code offset of the range which the variable has a
* definite value
*/
protected int getOffset()
{
return (m_opInit == null ? m_of : m_opInit.getOffset());
}
/**
* Get the byte code length ("pc") of the range.
*
* @return the length in bytes of the range which the variable has a
* definite value
*/
protected int getLength()
{
return (m_opStop == null ? m_cb : m_opStop.getOffset() - m_opInit.getOffset());
}
/**
* Get the op which starts the range.
*
* @return the op which starts the range
*/
protected Op getInit()
{
return m_opInit;
}
/**
* Set the op which starts the range. Used during disassembly.
*
* @param op the op which starts the range
*/
protected void setInit(Op op)
{
m_opInit = op;
}
/**
* Get the op which stops the range.
*
* @return the op which stops the range
*/
protected Op getStop()
{
return m_opStop;
}
/**
* Set the op which stops the range. Used during disassembly.
*
* @param op the op which stops the range
*/
protected void setStop(Op op)
{
m_opStop = op;
}
/**
* Get the variable declaration.
*
* @return the OpDeclare instance for the range or null if this was
* disassembled
*/
public OpDeclare getVariable()
{
return m_decl;
}
/**
* Determine the variable name declared for the range.
*
* @return the variable name or null if unavailable
*/
public String getVariableName()
{
return m_utfName.getValue();
}
/**
* Determine the variable JVM signature for the range.
*
* @return the variable signature
*/
public String getSignature()
{
return m_utfType.getValue();
}
/**
* Determine the variable slot for the variable declared by this op.
*
* @return the variable slot for this variable declaration
*/
public int getSlot()
{
return (m_decl == null ? m_iVar : m_decl.getSlot());
}
/**
* Get the next Range object in the linked list.
*
* @return the next Range object
*/
protected Range getNext()
{
return m_next;
}
/**
* Set the next Range object in the linked list.
*
* @param next the next Range object
*/
protected void setNext(Range next)
{
m_next = next;
}
// ----- Comparable interface ---------------------------------------
/**
* Compares this object with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
*
* @param o the Object to be compared.
*
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
*/
public int compareTo(Object o)
{
Range that = (Range) o;
// first range goes first
int nResult = this.getOffset() - that.getOffset();
if (nResult == 0)
{
// shorter range goes first
nResult = that.getLength() - this.getLength();
if (nResult == 0)
{
// otherwise order by name
nResult = this.m_utfName.compareTo(that.m_utfName);
}
}
return nResult;
}
// ----- Object methods ---------------------------------------------
/**
* Provide a debug output for this Range.
*/
public String toString()
{
Op opInit = getInit();
Op opStop = getStop();
StringBuffer sb = new StringBuffer();
sb.append("offset=")
.append(getOffset())
.append(", length=")
.append(getLength())
.append(", slot=")
.append(getSlot());
if (opInit != null)
{
String sClass = opInit.getClass().getName();
sb.append(", init=")
.append(opInit)
.append(" (")
.append(sClass.substring(sClass.lastIndexOf('.') + 1))
.append(") @")
.append(opInit.getOffset());
}
if (opStop != null)
{
String sClass = opStop.getClass().getName();
sb.append(", stop=")
.append(opStop)
.append(" (")
.append(sClass.substring(sClass.lastIndexOf('.') + 1))
.append(") @")
.append(opStop.getOffset());
}
sb.append(", var=")
.append(getVariable());
return sb.toString();
}
// ----- data members -----------------------------------------------
/**
* The Variable.
*/
private OpDeclare m_decl;
/**
* The first op in the range.
*/
private Op m_opInit;
/**
* The first op which is not in the range.
*/
private Op m_opStop;
/**
* The byte code offset (for a disassembled range).
*/
private int m_of;
/**
* The byte code length (for a disassembled range).
*/
private int m_cb;
/**
* The variable name (for a disassembled range).
*/
private UtfConstant m_utfName;
/**
* The variable descriptor (for a disassembled range).
*/
private UtfConstant m_utfType;
/**
* The variable slot (for a disassembled range).
*/
private int m_iVar;
/**
* The next range in the linked list.
*/
private Range m_next;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy