All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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