
org.opalj.bi.reader.Constant_PoolReader.scala Maven / Gradle / Ivy
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package bi
package reader
import scala.reflect.ClassTag
import java.io.DataInputStream
import java.io.ByteArrayInputStream
import org.opalj.bytecode.BytecodeProcessingFailedException
/**
* Defines a template method to read in a class file's constant pool.
*/
trait Constant_PoolReader extends Constant_PoolAbstractions {
//
// TYPE DEFINITIONS AND FACTORY METHODS
//
type Constant_Pool_Entry <: ConstantPoolEntry
implicit val Constant_Pool_EntryManifest: ClassTag[Constant_Pool_Entry]
type CONSTANT_Class_info <: Constant_Pool_Entry
type CONSTANT_Fieldref_info <: Constant_Pool_Entry
type CONSTANT_Methodref_info <: Constant_Pool_Entry
type CONSTANT_InterfaceMethodref_info <: Constant_Pool_Entry
type CONSTANT_String_info <: Constant_Pool_Entry
type CONSTANT_Integer_info <: Constant_Pool_Entry
type CONSTANT_Float_info <: Constant_Pool_Entry
type CONSTANT_Long_info <: Constant_Pool_Entry
type CONSTANT_Double_info <: Constant_Pool_Entry
type CONSTANT_NameAndType_info <: Constant_Pool_Entry
type CONSTANT_Utf8_info <: Constant_Pool_Entry
type CONSTANT_MethodHandle_info <: Constant_Pool_Entry
type CONSTANT_MethodType_info <: Constant_Pool_Entry
type CONSTANT_InvokeDynamic_info <: Constant_Pool_Entry
type CONSTANT_Module_info <: Constant_Pool_Entry
type CONSTANT_Package_info <: Constant_Pool_Entry
type CONSTANT_Dynamic_info <: Constant_Pool_Entry
//
// FACTORY METHODS
//
protected def CONSTANT_Class_info(i: Int): CONSTANT_Class_info
protected def CONSTANT_Fieldref_info(class_index: Int, name_and_type_index: Int): CONSTANT_Fieldref_info
protected def CONSTANT_Methodref_info(class_index: Int, name_and_type_index: Int): CONSTANT_Methodref_info
protected def CONSTANT_InterfaceMethodref_info(class_index: Int, name_and_type_index: Int): CONSTANT_InterfaceMethodref_info
protected def CONSTANT_String_info(i: Int): CONSTANT_String_info
protected def CONSTANT_Integer_info(i: Int): CONSTANT_Integer_info
protected def CONSTANT_Float_info(f: Float): CONSTANT_Float_info
protected def CONSTANT_Long_info(l: Long): CONSTANT_Long_info
protected def CONSTANT_Double_info(d: Double): CONSTANT_Double_info
protected def CONSTANT_NameAndType_info(name_index: Int, descriptor_index: Int): CONSTANT_NameAndType_info
protected def CONSTANT_Utf8_info(r: Array[Byte], s: String): CONSTANT_Utf8_info
// JAVA 7 Constant Pool Entries
protected def CONSTANT_MethodHandle_info(reference_kind: Int, reference_index: Int): CONSTANT_MethodHandle_info
protected def CONSTANT_MethodType_info(descriptor_index: Int): CONSTANT_MethodType_info
protected def CONSTANT_InvokeDynamic_info(bootstrap_method_attr_index: Int, name_and_type_index: Int): CONSTANT_InvokeDynamic_info
// JAVA 9 Constant Pool Entries
protected def CONSTANT_Module_info(name_index: Int): CONSTANT_Module_info
protected def CONSTANT_Package_info(name_index: Int): CONSTANT_Package_info
// JAVA 11 Constant Pool Entries
protected def CONSTANT_Dynamic_info(bootstrap_method_attr_index: Int, name_and_type_index: Int): CONSTANT_Dynamic_info
/**
* Creates a storage area for functions that will be called after the class file was
* completely loaded. This makes it possible to register functions that are newly
* created for a special class file object to perform actions related to that specific
* class file object. For further information study the resolving process of
* `invokedynamic` instructions.
*/
protected[this] def createDeferredActionsStore(): DeferredActionsStore
//
// IMPLEMENTATION
//
def registerDeferredAction(cp: Constant_Pool)(deferredAction: ClassFile ⇒ ClassFile): Unit = {
val store = cp(0).asInstanceOf[DeferredActionsStore]
store.synchronized { store += deferredAction }
}
override def applyDeferredActions(cp: Constant_Pool, classFile: ClassFile): ClassFile = {
var transformedClassFile = classFile
val das = cp(0).asInstanceOf[DeferredActionsStore]
das.foreach { deferredAction ⇒ transformedClassFile = deferredAction(transformedClassFile) }
das.clear()
transformedClassFile
}
import ConstantPoolTags._
def Constant_Pool(in: DataInputStream): Constant_Pool = {
/*
* The value of the constant_pool_count item is equal to the
* number of entries in the constant_pool table plus one. A
* constant_pool index is considered valid if it is greater than zero
* and less than constant_pool_count.
*
* We use position zero in the constant pool table to store functions that need
* to be performed after the entire class is loaded.
*
* E.g., the references of `invokedynamic` instructions can only be resolved after
* the `BootstrapMethods` attribute was loaded.
*/
val constant_pool_count = in.readUnsignedShort
/*
* The format of each constant_pool table entry is indicated by its first
* “tag” byte.
*
* The constant_pool table is indexed from 1 to constant_pool_count−1.
*/
val constant_pool_entries = new Array[Constant_Pool_Entry](constant_pool_count)
constant_pool_entries(0) = createDeferredActionsStore()
var i = 1
while (i < constant_pool_count) {
val tag = in.readUnsignedByte
constant_pool_entries(i) = (tag: @scala.annotation.switch) match {
case CONSTANT_Class_ID ⇒
i += 1
CONSTANT_Class_info(in.readUnsignedShort)
case CONSTANT_Fieldref_ID ⇒
i += 1
CONSTANT_Fieldref_info(in.readUnsignedShort, in.readUnsignedShort)
case CONSTANT_Methodref_ID ⇒
i += 1
CONSTANT_Methodref_info(in.readUnsignedShort, in.readUnsignedShort)
case CONSTANT_InterfaceMethodref_ID ⇒
i += 1
CONSTANT_InterfaceMethodref_info(in.readUnsignedShort, in.readUnsignedShort)
case CONSTANT_String_ID ⇒
i += 1
CONSTANT_String_info(in.readUnsignedShort)
case CONSTANT_Integer_ID ⇒
i += 1
CONSTANT_Integer_info(in.readInt)
case CONSTANT_Float_ID ⇒
i += 1
CONSTANT_Float_info(in.readFloat)
case CONSTANT_Long_ID ⇒
i += 2
CONSTANT_Long_info(in.readLong)
case CONSTANT_Double_ID ⇒
i += 2
CONSTANT_Double_info(in.readDouble)
case CONSTANT_NameAndType_ID ⇒
i += 1
CONSTANT_NameAndType_info(in.readUnsignedShort, in.readUnsignedShort)
case CONSTANT_Utf8_ID ⇒
i += 1
if (in.markSupported()) {
in.mark(UShort.MaxValue + 2)
val length = in.readUnsignedShort
val raw = new Array[Byte](length)
in.readFully(raw)
in.reset()
val value = in.readUTF()
CONSTANT_Utf8_info(raw, value)
} else {
val size = in.readUnsignedShort
val raw = new Array[Byte](size)
in.readFully(raw)
val data = new Array[Byte](size + 2)
data(0) = (0xff & (size >> 8)).toByte
data(1) = (0xff & size).toByte
System.arraycopy(raw, 0, data, 2, size)
val tin = new DataInputStream(new ByteArrayInputStream(data))
CONSTANT_Utf8_info(raw, tin.readUTF)
}
case CONSTANT_MethodHandle_ID ⇒
i += 1
CONSTANT_MethodHandle_info(in.readUnsignedByte, in.readUnsignedShort)
case CONSTANT_MethodType_ID ⇒
i += 1
CONSTANT_MethodType_info(in.readUnsignedShort)
case CONSTANT_InvokeDynamic_ID ⇒
i += 1
CONSTANT_InvokeDynamic_info(in.readUnsignedShort, in.readUnsignedShort)
case CONSTANT_Module_ID ⇒
i += 1
CONSTANT_Module_info(in.readUnsignedShort)
case CONSTANT_Package_ID ⇒
i += 1
CONSTANT_Package_info(in.readUnsignedShort)
case CONSTANT_Dynamic_ID ⇒
i += 1
CONSTANT_Dynamic_info(in.readUnsignedShort, in.readUnsignedShort)
case _ ⇒
val header = s"wrong constant pool tag: $tag (entry: $i/$constant_pool_count); "
val message =
constant_pool_entries.iterator.zipWithIndex.slice(1, i).map(_.swap).
mkString(header+"previous entries:\n\t", "\n\t", "\n")
throw new BytecodeProcessingFailedException(message)
}
}
constant_pool_entries
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy