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

org.opalj.br.reader.CachedBytecodeReaderAndBinding.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package reader

import org.opalj.control.fillArraySeq
import org.opalj.control.fillIntArray
import org.opalj.bytecode.BytecodeProcessingFailedException
import org.opalj.br.instructions._
import org.opalj.collection.immutable.IntIntPair

/**
 * Defines a method to parse an array of bytes (containing Java bytecode instructions) and
 * to return an array of [[org.opalj.br.instructions.Instruction]]`s.
 *
 * The target array has the same size as the source array to make sure that branch offsets
 * etc. point to the correct instruction.
 *
 * This reader caches the instructions – primarily – to save memory once all class
 * files are loaded.
 *
 * @author Michael Eichberg
 */
trait CachedBytecodeReaderAndBinding extends InstructionsDeserializer {

    def cache: BytecodeInstructionsCache

    /**
     * Transforms an array of bytes into an array of
     * [[org.opalj.br.instructions.Instruction]]s.
     */
    def Instructions(
        cp:                  Constant_Pool,
        ap_name_index:       Constant_Pool_Index,
        ap_descriptor_index: Constant_Pool_Index,
        source:              Array[Byte]
    ): Instructions = {
        import java.io.DataInputStream
        import java.io.ByteArrayInputStream

        val bas = new ByteArrayInputStream(source)
        val in = new DataInputStream(bas)
        val codeLength = source.size
        val instructions = new Array[Instruction](codeLength)

        var wide: Boolean = false

        def lvIndex(): Int =
            if (wide) {
                wide = false
                in.readUnsignedShort
            } else {
                in.readUnsignedByte
            }

        while (in.available > 0) {
            val index = codeLength - in.available

            instructions(index) = (in.readUnsignedByte: @scala.annotation.switch) match {
                case 50 => AALOAD
                case 83 => AASTORE
                case 1  => ACONST_NULL
                case 25 => cache.ALOAD(lvIndex())
                case 42 => ALOAD_0
                case 43 => ALOAD_1
                case 44 => ALOAD_2
                case 45 => ALOAD_3
                case 189 =>
                    val rt = cp(in.readUnsignedShort).asConstantValue(cp).toReferenceType
                    cache.ANEWARRAY(rt)
                case 176 => ARETURN
                case 190 => ARRAYLENGTH
                case 58  => cache.ASTORE(lvIndex())
                case 75  => ASTORE_0
                case 76  => ASTORE_1
                case 77  => ASTORE_2
                case 78  => ASTORE_3
                case 191 => ATHROW
                case 51  => BALOAD
                case 84  => BASTORE
                case 16  => BIPUSH(in.readByte.toInt /* value */ ) // internally cached
                case 52  => CALOAD
                case 85  => CASTORE
                case 192 =>
                    val rt = cp(in.readUnsignedShort).asConstantValue(cp).toReferenceType
                    cache.CHECKCAST(rt)
                case 144 => D2F
                case 142 => D2I
                case 143 => D2L
                case 99  => DADD
                case 49  => DALOAD
                case 82  => DASTORE
                case 152 => DCMPG
                case 151 => DCMPL
                case 14  => DCONST_0
                case 15  => DCONST_1
                case 111 => DDIV
                case 24  => cache.DLOAD(lvIndex())
                case 38  => DLOAD_0
                case 39  => DLOAD_1
                case 40  => DLOAD_2
                case 41  => DLOAD_3
                case 107 => DMUL
                case 119 => DNEG
                case 115 => DREM
                case 175 => DRETURN
                case 57  => cache.DSTORE(lvIndex())
                case 71  => DSTORE_0
                case 72  => DSTORE_1
                case 73  => DSTORE_2
                case 74  => DSTORE_3
                case 103 => DSUB
                case 89  => DUP
                case 90  => DUP_X1
                case 91  => DUP_X2
                case 92  => DUP2
                case 93  => DUP2_X1
                case 94  => DUP2_X2
                case 141 => F2D
                case 139 => F2I
                case 140 => F2L
                case 98  => FADD
                case 48  => FALOAD
                case 81  => FASTORE
                case 150 => FCMPG
                case 149 => FCMPL
                case 11  => FCONST_0
                case 12  => FCONST_1
                case 13  => FCONST_2
                case 110 => FDIV
                case 23  => cache.FLOAD(lvIndex())
                case 34  => FLOAD_0
                case 35  => FLOAD_1
                case 36  => FLOAD_2
                case 37  => FLOAD_3
                case 106 => FMUL
                case 118 => FNEG
                case 114 => FREM
                case 174 => FRETURN
                case 56  => cache.FSTORE(lvIndex())
                case 67  => FSTORE_0
                case 68  => FSTORE_1
                case 69  => FSTORE_2
                case 70  => FSTORE_3
                case 102 => FSUB
                case 180 =>
                    val (declaringClass, name, fieldType): (ObjectType, String, FieldType) =
                        cp(in.readUnsignedShort).asFieldref(cp)
                    GETFIELD(declaringClass, cache.FieldName(name), fieldType)
                case 178 =>
                    val (declaringClass, name, fieldType): (ObjectType, String, FieldType) =
                        cp(in.readUnsignedShort).asFieldref(cp)
                    GETSTATIC(declaringClass, cache.FieldName(name), fieldType)
                case 167 => cache.GOTO(in.readShort.toInt /* branchoffset */ )
                case 200 => GOTO_W(in.readInt /* branchoffset */ )
                case 145 => I2B
                case 146 => I2C
                case 135 => I2D
                case 134 => I2F
                case 133 => I2L
                case 147 => I2S
                case 96  => IADD
                case 46  => IALOAD
                case 126 => IAND
                case 79  => IASTORE
                case 2   => ICONST_M1
                case 3   => ICONST_0
                case 4   => ICONST_1
                case 5   => ICONST_2
                case 6   => ICONST_3
                case 7   => ICONST_4
                case 8   => ICONST_5
                case 108 => IDIV
                case 165 => cache.IF_ACMPEQ(in.readShort.toInt)
                case 166 => cache.IF_ACMPNE(in.readShort.toInt)
                case 159 => cache.IF_ICMPEQ(in.readShort.toInt)
                case 160 => cache.IF_ICMPNE(in.readShort.toInt)
                case 161 => cache.IF_ICMPLT(in.readShort.toInt)
                case 162 => cache.IF_ICMPGE(in.readShort.toInt)
                case 163 => cache.IF_ICMPGT(in.readShort.toInt)
                case 164 => cache.IF_ICMPLE(in.readShort.toInt)
                case 153 => cache.IFEQ(in.readShort.toInt)
                case 154 => cache.IFNE(in.readShort.toInt)
                case 155 => cache.IFLT(in.readShort.toInt)
                case 156 => cache.IFGE(in.readShort.toInt)
                case 157 => cache.IFGT(in.readShort.toInt)
                case 158 => cache.IFLE(in.readShort.toInt)
                case 199 => cache.IFNONNULL(in.readShort.toInt)
                case 198 => cache.IFNULL(in.readShort.toInt)
                case 132 =>
                    if (wide) {
                        wide = false
                        val lvIndex = in.readUnsignedShort
                        val constValue = in.readShort.toInt
                        IINC(lvIndex, constValue)
                    } else {
                        val lvIndex = in.readUnsignedByte
                        val constValue = in.readByte.toInt
                        IINC(lvIndex, constValue)
                    }
                case 21  => cache.ILOAD(lvIndex())
                case 26  => ILOAD_0
                case 27  => ILOAD_1
                case 28  => ILOAD_2
                case 29  => ILOAD_3
                case 104 => IMUL
                case 116 => INEG
                case 193 =>
                    cache.INSTANCEOF(cp(in.readUnsignedShort).asConstantValue(cp).toReferenceType)
                case 186 => // INVOKEDYNAMIC
                    val cpEntry = cp(in.readUnsignedShort).asInvokeDynamic
                    in.readByte // ignored; fixed value
                    in.readByte // ignored; fixed value
                    registerDeferredAction(cp) { classFile =>
                        deferredInvokedynamicResolution(
                            classFile,
                            cp,
                            ap_name_index,
                            ap_descriptor_index,
                            cpEntry,
                            instructions,
                            index
                        )
                    }
                    //INVOKEDYNAMIC(cpe.bootstrapMethodAttributeIndex, cpe.methodName, cpe.methodDescriptor)
                    INCOMPLETE_INVOKEDYNAMIC
                case 185 =>
                    val methodRef = cp(in.readUnsignedShort).asMethodref(cp)
                    val (declaringClass, _, name, methodDescriptor) = methodRef
                    in.readByte // ignored; fixed value
                    in.readByte // ignored; fixed value
                    INVOKEINTERFACE(
                        declaringClass.asObjectType,
                        cache.MethodName(name),
                        methodDescriptor
                    )
                case 183 =>
                    val methodRef = cp(in.readUnsignedShort).asMethodref(cp)
                    val (declaringClass, isInterface, name, methodDescriptor) = methodRef
                    INVOKESPECIAL(
                        declaringClass.asObjectType, isInterface,
                        cache.MethodName(name), methodDescriptor
                    )
                case 184 =>
                    val methodRef = cp(in.readUnsignedShort).asMethodref(cp)
                    val (declaringClass, isInterface, name, methodDescriptor) = methodRef
                    INVOKESTATIC(
                        declaringClass.asObjectType, isInterface,
                        cache.MethodName(name), methodDescriptor
                    )
                case 182 =>
                    val methodRef = cp(in.readUnsignedShort).asMethodref(cp)
                    val (declaringClass, _, name, methodDescriptor) = methodRef
                    INVOKEVIRTUAL(declaringClass, cache.MethodName(name), methodDescriptor)
                case 128 => IOR
                case 112 => IREM
                case 172 => IRETURN
                case 120 => ISHL
                case 122 => ISHR
                case 54  => cache.ISTORE(lvIndex())
                case 59  => ISTORE_0
                case 60  => ISTORE_1
                case 61  => ISTORE_2
                case 62  => ISTORE_3
                case 100 => ISUB
                case 124 => IUSHR
                case 130 => IXOR
                case 168 => JSR(in.readShort.toInt)
                case 201 => JSR_W(in.readInt)
                case 138 => L2D
                case 137 => L2F
                case 136 => L2I
                case 97  => LADD
                case 47  => LALOAD
                case 127 => LAND
                case 80  => LASTORE
                case 148 => LCMP
                case 9   => LCONST_0
                case 10  => LCONST_1
                case 18 =>
                    val constant = cp(in.readUnsignedByte())
                    if (constant.isDynamic) {
                        registerDeferredAction(cp) { classFile =>
                            deferredDynamicConstantResolution(
                                classFile,
                                cp,
                                ap_name_index,
                                ap_descriptor_index,
                                constant.asDynamic,
                                instructions,
                                index /* <=> pc */
                            )
                        }
                        INCOMPLETE_LDC
                    } else {
                        LDC(constant.asConstantValue(cp))
                    }
                case 19 =>
                    val constant = cp(in.readUnsignedShort())
                    if (constant.isDynamic) {
                        registerDeferredAction(cp) { classFile =>
                            deferredDynamicConstantResolution(
                                classFile,
                                cp,
                                ap_name_index,
                                ap_descriptor_index,
                                constant.asDynamic,
                                instructions,
                                index /* <=> pc */
                            )
                        }
                        INCOMPLETE_LDC_W
                    } else {
                        LDC_W(constant.asConstantValue(cp))
                    }
                case 20 =>
                    val constant = cp(in.readUnsignedShort())
                    if (constant.isDynamic) {
                        registerDeferredAction(cp) { classFile =>
                            deferredDynamicConstantResolution(
                                classFile,
                                cp,
                                ap_name_index,
                                ap_descriptor_index,
                                constant.asDynamic,
                                instructions,
                                index /* <=> pc */
                            )
                        }
                        INCOMPLETE_LDC2_W
                    } else {
                        LDC2_W(constant.asConstantValue(cp))
                    }
                case 109 => LDIV
                case 22  => cache.LLOAD(lvIndex())
                case 30  => LLOAD_0
                case 31  => LLOAD_1
                case 32  => LLOAD_2
                case 33  => LLOAD_3
                case 105 => LMUL
                case 117 => LNEG
                case 171 =>
                    in.skip((3 - (index % 4)).toLong) // skip padding bytes
                    val defaultOffset = in.readInt
                    val npairsCount = in.readInt
                    val npairs = fillArraySeq(npairsCount) { IntIntPair(in.readInt, in.readInt) }
                    LOOKUPSWITCH(defaultOffset, npairs)
                case 129 => LOR
                case 113 => LREM
                case 173 => LRETURN
                case 121 => LSHL
                case 123 => LSHR
                case 55  => cache.LSTORE(lvIndex())
                case 63  => LSTORE_0
                case 64  => LSTORE_1
                case 65  => LSTORE_2
                case 66  => LSTORE_3
                case 101 => LSUB
                case 125 => LUSHR
                case 131 => LXOR
                case 194 => MONITORENTER
                case 195 => MONITOREXIT
                case 197 =>
                    MULTIANEWARRAY(
                        // componentType
                        cp(in.readUnsignedShort).asConstantValue(cp).toReferenceType.asArrayType,
                        //  dimensions
                        in.readUnsignedByte
                    )
                case 187 => cache.NEW(cp(in.readUnsignedShort).asObjectType(cp))
                case 188 => NEWARRAY(in.readByte.toInt) // is internally cached
                case 0   => NOP
                case 87  => POP
                case 88  => POP2
                case 181 =>
                    val (declaringClass, name, fieldType): (ObjectType, String, FieldType) =
                        cp(in.readUnsignedShort).asFieldref(cp)
                    PUTFIELD(declaringClass, cache.FieldName(name), fieldType)
                case 179 =>
                    val (declaringClass, name, fieldType): (ObjectType, String, FieldType) =
                        cp(in.readUnsignedShort).asFieldref(cp)
                    PUTSTATIC(declaringClass, cache.FieldName(name), fieldType)
                case 169 =>
                    cache.RET(
                        if (wide) {
                            wide = false
                            in.readUnsignedShort
                        } else {
                            in.readUnsignedByte
                        }
                    )
                case 177 => RETURN
                case 53  => SALOAD
                case 86  => SASTORE
                case 17  => cache.SIPUSH(in.readShort.toInt /* value */ )
                case 95  => SWAP
                case 170 =>
                    in.skip((3 - (index % 4)).toLong) // skip padding bytes
                    val defaultOffset = in.readInt
                    val low = in.readInt
                    val high = in.readInt
                    val jumpOffsets = fillIntArray(high - low + 1) { in.readInt }
                    TABLESWITCH(defaultOffset, low, high, jumpOffsets)
                case 196 =>
                    wide = true
                    WIDE

                case opcode =>
                    throw new BytecodeProcessingFailedException("unsupported opcode: "+opcode)
            }

        }
        instructions
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy