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

miksilo.modularLanguages.deltas.bytecode.simpleBytecode.InferredStackFrames.scala Maven / Gradle / Ivy

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

import miksilo.modularLanguages.core.bigrammar.GrammarReference
import miksilo.modularLanguages.core.deltas._
import miksilo.modularLanguages.core.deltas.grammars.LanguageGrammars
import miksilo.modularLanguages.core.node.Node
import miksilo.languageServer.core.language.{Compilation, Language}
import miksilo.modularLanguages.deltas.bytecode.ByteCodeSkeleton.ClassFile
import miksilo.modularLanguages.deltas.bytecode.attributes.StackMapTableAttributeDelta
import miksilo.modularLanguages.deltas.bytecode.attributes.StackMapTableAttributeDelta.{FullFrameLocals, FullFrameStack}
import miksilo.modularLanguages.deltas.bytecode.types.TypeSkeleton

object InferredStackFrames extends DeltaWithPhase with DeltaWithGrammar {

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

  def label(name: String): Node = LabelDelta.shape.create(LabelDelta.Name -> name)

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

      val stackLayouts = new InstructionTypeAnalysisForMethod(program, compilation, method)
      var previousStack = stackLayouts.initialStack
      var previousLocals = stackLayouts.parameters
      for ((label, index) <- instructions.zipWithIndex.filter(i => i._1.shape == LabelDelta.shape)) {
        val typeState = stackLayouts.typeStatePerInstruction(index)
        val currentStack = typeState.stackTypes
        val locals = getLocalTypesSequenceFromMap(typeState.variableTypes)
        label(LabelDelta.StackFrame) = getStackMap(previousStack, currentStack, previousLocals, locals)
        previousStack = currentStack
        previousLocals = locals
      }
    }

    def getLocalTypesSequenceFromMap(localTypes: Map[Int, Node]): Seq[Node] = {
      val max = (localTypes.keys ++ Seq(-1)).max
      0.to(max).map(index => localTypes.getOrElse(index, throw new NotImplementedError))
    }

    def toStackType(_type: Node): Node = TypeSkeleton.toStackType(_type, compilation)

    def getStackMap(previousStack: Seq[Node], stack: Seq[Node], previousLocals: Seq[Node], locals: Seq[Node]) = {
      getStackMapHelper(previousStack.map(toStackType), stack.map(toStackType), previousLocals.map(toStackType), locals.map(toStackType))
    }

    def getStackMapHelper(previousStack: Seq[Node], stack: Seq[Node], previousLocals: Seq[Node], locals: Seq[Node]) = {
      val sameLocalsPrefix = previousLocals.zip(locals).filter(p => p._1 == p._2)
      val removedLocals = previousLocals.drop(sameLocalsPrefix.length)
      val addedLocals = locals.drop(sameLocalsPrefix.length)
      val unchangedLocals = removedLocals.isEmpty && addedLocals.isEmpty
      if (unchangedLocals && stack.isEmpty) {
        new Node(StackMapTableAttributeDelta.SameFrameKey)
      }
      else if (unchangedLocals && stack.size == 1) {
        new Node(StackMapTableAttributeDelta.SameLocals1StackItem,
          StackMapTableAttributeDelta.SameLocals1StackItemType -> stack.head)
      }
      else if (stack.isEmpty && addedLocals.isEmpty) {
        new Node(StackMapTableAttributeDelta.ChopFrame, StackMapTableAttributeDelta.ChopFrameCount -> removedLocals.length)
      }
      else if (stack.isEmpty && removedLocals.isEmpty) {
        new Node(StackMapTableAttributeDelta.AppendFrame, StackMapTableAttributeDelta.AppendFrameTypes ->
          addedLocals.map(l => toStackType(l)))
      }
      else {
        new Node(StackMapTableAttributeDelta.FullFrame, FullFrameLocals -> locals, FullFrameStack -> stack)
      }
    }
  }

  override def description: String = "Generates a stack frame for each label instruction. " +
    "Stack frames can be used to determine the stack and variable types at a particular instruction."

  override def transformGrammars(grammars: LanguageGrammars, state: Language): Unit = {
    import grammars._
    find(LabelDelta.Shape).
      findAs(LabelDelta.StackFrame).
      asInstanceOf[GrammarReference].removeMe()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy