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

miksilo.modularLanguages.deltas.bytecode.PrintByteCode.scala Maven / Gradle / Ivy

The newest version!
package miksilo.modularLanguages.deltas.bytecode

import java.math.BigInteger

import miksilo.languageServer.core.language.Compilation
import miksilo.modularLanguages.core.node.Node
import miksilo.modularLanguages.deltas.bytecode.ByteCodeSkeleton._
import miksilo.modularLanguages.deltas.javac.classes.skeleton.QualifiedClassName

object PrintByteCode {
  def longToBytes(long: Long): LazyList[Byte] = LazyList.from(toByteArray(long))

  def toByteArray(value: Long): Array[Byte] = {
    // bugs when narrowing byte casts of long values occur.
    val result = new Array[Byte](8)
    var newValue = value
    for (i <- 7 to 0 by -1) {
      result(i) = (value & 0xffL).toByte
      newValue >>= 8
    }
    result
  }
  
  //TODO code uit deze classe naar byte code particles verplaatsen.
  val classAccessFlags = Map("super" -> 0x0020)

  val cafeBabeBytes: Seq[Byte] = intToBytes(0xCAFEBABE)

  val versionNumber: Seq[Byte] = intToBytes(0x00000033)

  def getBytes(compilation: Compilation, byteCode: Node): LazyList[Byte] = {

    val classFile = new ClassFile(byteCode)
    def getBytes(byteCode: Node): LazyList[Byte] = {
      var result = LazyList[Byte]()

      result ++= cafeBabeBytes
      result ++= versionNumber
      val constantPool = classFile.constantPool.constants
      val constantPoolItemCountPlusOne = shortToBytes(constantPool.length + 1)
      result ++= constantPoolItemCountPlusOne
      for (constantPoolEntry <- constantPool) {
        result ++= getConstantEntryByteCode(constantPoolEntry)
      }
      result ++= getAccessFlagsByteCode(classFile)
      result ++= shortToBytes(classFile.classInfoIndex)
      result ++= shortToBytes(classFile.parentIndex)
      result ++= getInterfacesByteCode(classFile)
      result ++= getFieldsByteCode(classFile)
      result ++= getMethodsByteCode(classFile)
      result ++= getAttributesByteCode(compilation, classFile.attributes)
      result
    }

    def getMethodsByteCode(classFile: ClassFile[Node]): Seq[Byte] = {
      val methods = classFile.methods
      shortToBytes(methods.length) ++ methods.flatMap(method => {
        ByteCodeSkeleton.getBytes(compilation, method)
      })
    }

    def getFieldsByteCode(classFile: ClassFile[Node]): Seq[Byte] = {
      val fields = classFile.fields
      PrintByteCode.shortToBytes(fields.length) ++ fields.flatMap(field => {
        ByteCodeSkeleton.getBytes(compilation, field)
      })
    }

    def getConstantEntryByteCode(entry: Any): Seq[Byte] = {
      entry match {
        case metaEntry: Node => ByteCodeSkeleton.getBytes(compilation, metaEntry)
        case qualifiedName: QualifiedClassName => toUTF8ConstantEntry(qualifiedName.parts.mkString("/")) //TODO is this still used?
        case utf8: String => toUTF8ConstantEntry(utf8)
      }
    }

    getBytes(byteCode)
  }

  def prefixWithIntLength(_bytes: () => Seq[Byte]): LazyList[Byte] = {
    val bytes = _bytes()
    LazyList.from(toByteArray(bytes.length)) ++ bytes
  }

  def toByteArray(value: Int) = Array[Byte]((value >> 24).toByte, (value >> 16).toByte, (value >> 8).toByte, value.toByte)
  
  def getInterfacesByteCode(shape: Node) = {
    val interfaces = shape.interfaceIndices
    shortToBytes(interfaces.length) ++ interfaces.flatMap(interface => shortToBytes(interface))
  }

  def getAccessFlagsByteCode(shape: Node): LazyList[Byte] = {
    shortToBytes(classAccessFlags("super"))
  }

  def hexToBytes(hex: String): LazyList[Byte] = LazyList.from(new BigInteger(hex, 16).toByteArray).takeRight(hex.length / 2)

  def toUTF8ConstantEntry(utf8: String): LazyList[Byte] = {
    val bytes = utf8.toString.getBytes("UTF-8")
    byteToBytes(1) ++ shortToBytes(bytes.length) ++ bytes
  }

  def getExceptionByteCode(exception: Node): LazyList[Byte] = ???

  def getAttributesByteCode(compilation: Compilation, attributes: Seq[Node]): Seq[Byte] = {

    def getAttributeByteCode(attribute: Node): Seq[Byte] = {
      shortToBytes(ByteCodeSkeleton.getAttributeNameIndex(attribute)) ++
        prefixWithIntLength(() => ByteCodeSkeleton.getBytes(compilation, attribute))
    }

    shortToBytes(attributes.length) ++ attributes.flatMap(attribute => getAttributeByteCode(attribute))
  }

  def hexToInt(hex: String): Int = new BigInteger(hex, 16).intValue()

  def byteToBytes(value: Int): LazyList[Byte] = {
    LazyList.from(toByteArray(value)).drop(3)
  }

  def shortToBytes(short: Int): LazyList[Byte] = {
    LazyList.from(toByteArray(short)).takeRight(2)
  }

  def intToBytes(int: Int): LazyList[Byte] = {
    LazyList.from(toByteArray(int))
  }

  def printBytes(bytes: LazyList[Byte]): String = {
    formatHexLikeClassFile(valueOf(bytes)).toLowerCase
  }

  def formatHexLikeClassFile(hex: String): String = {
    hex.grouped(4).grouped(8).map(g => g.mkString(" ")).mkString("\n")
  }

  def valueOf(buf: Iterable[Byte]): String = buf.map("%02X" format _).mkString
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy