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

scala.scalanative.optimizer.analysis.ClassHierarchy.scala Maven / Gradle / Ivy

The newest version!
package scala.scalanative
package optimizer
package analysis

import scala.collection.mutable
import util.unreachable
import nir._

object ClassHierarchy {
  sealed abstract class Node {
    var id: Int   = -1
    var in: Scope = _

    def inTop: Boolean   = in.isInstanceOf[Top]
    def inClass: Boolean = in.isInstanceOf[Class]
    def inTrait: Boolean = in.isInstanceOf[Trait]
    def attrs: Attrs
    def name: Global
  }

  sealed abstract class Scope extends Node {
    var rtti: RuntimeTypeInformation = _

    val members = mutable.UnrolledBuffer.empty[Node]
    val methods = mutable.UnrolledBuffer.empty[Method]
    val fields  = mutable.UnrolledBuffer.empty[Field]
  }

  final class Struct(val attrs: Attrs,
                     val name: Global,
                     val tys: Seq[nir.Type])
      extends Scope

  final class Trait(val attrs: Attrs,
                    val name: Global,
                    val traitNames: Seq[Global])
      extends Scope {
    val traits = mutable.UnrolledBuffer.empty[Trait]
  }

  final class Class(val attrs: Attrs,
                    val name: Global,
                    val parentName: Option[Global],
                    val traitNames: Seq[Global],
                    val isModule: Boolean)
      extends Scope {
    val ty         = Type.Class(name)
    val subclasses = mutable.UnrolledBuffer.empty[Class]
    val traits     = mutable.UnrolledBuffer.empty[Trait]

    var parent: Option[Class]  = _
    var range: Range           = _
    var vtable: VirtualTable   = _
    var layout: FieldLayout    = _
    var dynmap: DynamicHashMap = _
  }

  final class Method(val attrs: Attrs,
                     val name: Global,
                     val ty: nir.Type,
                     val isConcrete: Boolean)
      extends Node {
    val overrides = mutable.UnrolledBuffer.empty[Method]
    val overriden = mutable.UnrolledBuffer.empty[Method]
    val value =
      if (isConcrete) Val.Global(name, Type.Ptr)
      else Val.Null
    def isVirtual =
      !isConcrete || overriden.nonEmpty
    def isStatic =
      !isVirtual
  }

  final class Field(val attrs: Attrs, val name: Global, val ty: nir.Type)
      extends Node

  final class Top(val nodes: mutable.Map[Global, Node],
                  val structs: Seq[Struct],
                  val classes: Seq[Class],
                  val traits: Seq[Trait],
                  val dyns: Seq[String],
                  override val methods: mutable.UnrolledBuffer[Method],
                  override val fields: mutable.UnrolledBuffer[Field])
      extends Scope {
    val fresh                       = nir.Fresh("tx")
    def name                        = Global.None
    def attrs                       = Attrs.None
    var tables: TraitDispatchTables = _
    var moduleArray: ModuleArray    = _
  }

  def apply(defns: Seq[Defn], dyns: Seq[String]): Top = {
    val nodes   = mutable.Map.empty[Global, Node]
    val structs = mutable.UnrolledBuffer.empty[Struct]
    val classes = mutable.UnrolledBuffer.empty[Class]
    val traits  = mutable.UnrolledBuffer.empty[Trait]
    val methods = mutable.UnrolledBuffer.empty[Method]
    val fields  = mutable.UnrolledBuffer.empty[Field]

    def enter[T <: Node](name: Global, node: T): T = {
      nodes += name -> node
      node match {
        case defn: Class  => classes += defn // id given in assignClassIds
        case defn: Trait  => node.id = traits.length; traits += defn
        case defn: Method => methods += defn // id given in assignMethodIds
        case defn: Field  => node.id = fields.length; fields += defn
        case defn: Struct => node.id = structs.length; structs += defn
      }
      node
    }

    def enterDefn(defn: Defn): Unit = defn match {
      case defn: Defn.Trait =>
        enter(defn.name, new Trait(defn.attrs, defn.name, defn.traits))

      case defn: Defn.Class =>
        enter(defn.name,
              new Class(defn.attrs,
                        defn.name,
                        defn.parent,
                        defn.traits,
                        isModule = false))

      case defn: Defn.Module =>
        enter(defn.name,
              new Class(defn.attrs,
                        defn.name,
                        defn.parent,
                        defn.traits,
                        isModule = true))

      case defn: Defn.Var =>
        enter(defn.name, new Field(defn.attrs, defn.name, defn.ty))

      case defn: Defn.Declare =>
        enter(defn.name,
              new Method(defn.attrs, defn.name, defn.ty, isConcrete = false))

      case defn: Defn.Define =>
        enter(defn.name,
              new Method(defn.attrs, defn.name, defn.ty, isConcrete = true))

      case defn: Defn.Struct =>
        enter(defn.name, new Struct(defn.attrs, defn.name, defn.tys))

      case _ =>
        ()
    }

    def sortTraits(traits: Seq[Trait]): Seq[Trait] = {
      var res     = mutable.UnrolledBuffer.empty[Trait]
      val todo    = mutable.Stack.empty[Trait]
      val visited = mutable.Set.empty[Trait]
      todo.pushAll(traits)

      def visit(trt: Trait): Unit = {
        if (!visited.contains(trt)) {
          trt.traitNames.foreach { n =>
            visit(nodes(n).asInstanceOf[Trait])
          }
          visited += trt
          res += trt
        }
      }

      while (todo.nonEmpty) {
        visit(todo.pop())
      }

      res
    }

    def sortClasses(classes: Seq[Class]): Seq[Class] = {
      var res     = mutable.UnrolledBuffer.empty[Class]
      val todo    = mutable.Stack.empty[Class]
      val visited = mutable.Set.empty[Class]
      todo.pushAll(classes)

      def visit(cls: Class): Unit = {
        if (!visited.contains(cls)) {
          cls.parentName.foreach { n =>
            visit(nodes(n).asInstanceOf[Class])
          }
          visited += cls
          res += cls
        }
      }

      while (todo.nonEmpty) {
        visit(todo.pop())
      }

      res
    }

    defns.foreach(enterDefn)
    val top = new Top(nodes = nodes,
                      structs = structs,
                      classes = sortClasses(classes),
                      traits = sortTraits(traits),
                      methods = methods,
                      fields = fields,
                      dyns = dyns)
    top.members ++= nodes.values

    def assignMethodIds(): Unit = {
      var id = 0
      traits.foreach { trt =>
        trt.methods.foreach { meth =>
          meth.id = id
          id += 1
        }
      }
      classes.foreach { cls =>
        cls.methods.foreach { meth =>
          meth.id = id
          id += 1
        }
      }
    }

    def completeMethods(): Unit = methods.foreach { meth =>
      if (meth.name.isTop) {
        meth.in = top
      } else {
        val owner = nodes(meth.name.top).asInstanceOf[Scope]
        meth.in = owner
        owner.members += meth
        owner.methods += meth
        meth.attrs.overrides.foreach { name =>
          val ovmeth = nodes(name).asInstanceOf[Method]
          meth.overrides += ovmeth
          ovmeth.overriden += meth
        }
      }
    }

    def completeFields(): Unit = fields.foreach { node =>
      val owner = nodes(node.name.top).asInstanceOf[Class]
      node.in = owner
      owner.members += node
      owner.fields += node
    }

    def completeTraits(): Unit =
      top.traits.foreach { node =>
        node.in = top
        node.traitNames.foreach { name =>
          node.traits += nodes(name).asInstanceOf[Trait]
        }
        node.rtti = new RuntimeTypeInformation(node)
      }

    def completeStructs(): Unit =
      top.structs.foreach { node =>
        node.in = top
        node.rtti = new RuntimeTypeInformation(node)
      }

    def completeClasses(): Unit = top.classes.foreach { cls =>
      cls.in = top
      cls.parent = cls.parentName.map { name =>
        val parent = nodes(name).asInstanceOf[Class]
        parent.subclasses += cls
        parent
      }
      cls.traitNames.foreach { name =>
        cls.traits += nodes(name).asInstanceOf[Trait]
      }
    }

    def assignClassIds(): Unit = {
      var id = 0

      def loop(node: Class): Unit = {
        val start = id
        id += 1
        node.subclasses.foreach(loop)
        val end = id - 1
        node.id = start
        node.range = start to end
      }

      loop(nodes(Rt.Object.name).asInstanceOf[Class])
    }

    def completeClassMembers(): Unit = top.classes.foreach { cls =>
      cls.vtable = new VirtualTable(cls)
      cls.layout = new FieldLayout(cls)
      cls.dynmap = new DynamicHashMap(cls, dyns)
      cls.rtti = new RuntimeTypeInformation(cls)
    }

    def completeTop(): Unit = {
      top.tables = new TraitDispatchTables(top)
      top.moduleArray = new ModuleArray(top)
    }

    completeFields()
    completeMethods()
    completeTraits()
    completeStructs()
    completeClasses()
    assignClassIds()
    assignMethodIds()
    completeClassMembers()
    completeTop()

    top
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy