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

miksilo.modularLanguages.deltas.bytecode.additions.PoptimizeDelta.scala Maven / Gradle / Ivy

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

import miksilo.modularLanguages.core.node.Node
import miksilo.modularLanguages.core.deltas.{Contract, DeltaWithPhase}
import miksilo.languageServer.core.language.{Compilation, Language}
import miksilo.modularLanguages.deltas.bytecode.ByteCodeSkeleton.ClassFile
import miksilo.modularLanguages.deltas.bytecode.attributes.CodeAttributeDelta
import miksilo.modularLanguages.deltas.bytecode.coreInstructions._
import miksilo.modularLanguages.deltas.bytecode.simpleBytecode.InstructionTypeAnalysisForMethod
import miksilo.modularLanguages.deltas.bytecode.types.TypeSkeleton

object PoptimizeDelta extends DeltaWithPhase {

  override def dependencies: Set[Contract] = Set(PopDelta)

  private def getSignatureInOutLengths(state: Language, signature: InstructionSignature): (Int, Int) = {
    val inputLength = signature.inputs.map(_type => TypeSkeleton.getTypeSize(_type, state)).sum
    val outputLength = signature.outputs.map(_type => TypeSkeleton.getTypeSize(_type, state)).sum
    (inputLength, outputLength)
  }

  override def transformProgram(program: Node, compilation: Compilation): Unit = {
    val classFile = new ClassFile(program)
    for (method <- classFile.methods) {
      val typeAnalysis =  new InstructionTypeAnalysisForMethod(program, compilation, method)
      val codeAnnotation = method.codeAttribute
      val instructions = codeAnnotation.instructions

      def getInOutSizes(instructionIndex: Int) = {
        val instruction = instructions(instructionIndex)
        val signature = instruction.delta.getSignature(instruction, typeAnalysis.typeStatePerInstruction(instructionIndex), compilation)
        getSignatureInOutLengths(compilation.language, signature)
      }

      var newInstructions = List.empty[Node]
      var consumptions = List.empty[Boolean]

      def processInstruction(instructionIndex: Int): Unit = {
        val instruction = instructions(instructionIndex)
        if (instruction.shape == PopDelta.shape) {
          consumptions ::= true
          return
        }

        if (instruction.shape == Pop2Delta.shape) {
          consumptions = List(true,true) ++ consumptions
          return
        }

        val (in, out) = getInOutSizes(instructionIndex)
        var outLeft = out
        var outPop = 0
        while (outLeft > 0 && consumptions.nonEmpty) {
          val pop = consumptions.head
          outPop += (if (pop) 1 else 0)
          consumptions = consumptions.tail
          outLeft -= 1
        }
        val outConsumption = out - outPop
        val hasSideEffect = guessIfInstructionHasSideEffect(out)
        val keepInstruction = outConsumption != 0 || hasSideEffect
        if (keepInstruction) {
          val pop2Instructions = 0.until(outPop / 2).map(_ => Pop2Delta.pop2).toList
          val pop1Instructions: ((Nothing) => Any) with Iterable[Node] = if (outPop % 2 == 1) Seq(PopDelta.pop) else Set.empty
          newInstructions = pop2Instructions ++ pop1Instructions ++ newInstructions
          consumptions = 0.until(in).map(_ => false).toList ++ consumptions
          newInstructions = instruction :: newInstructions
        }
      }

      for (instructionIndex <- instructions.indices.reverse) {
        processInstruction(instructionIndex)
      }
      codeAnnotation(CodeAttributeDelta.Instructions) = newInstructions.toSeq
    }
  }

  def guessIfInstructionHasSideEffect(out: Int): Boolean = {
    out == 0 //dangerous assumption :D
  }

  override def description: String = "Optimizes a bytecode program by removing instructions in cases where an instructions output will always be consumed by a pop."
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy