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

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

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

import scala.collection.mutable
import ClassHierarchy._
import nir._

class TraitDispatchTables(top: Top) {
  val dispatchName                          = Global.Top("__dispatch")
  val dispatchVal                           = Val.Global(dispatchName, Type.Ptr)
  var dispatchTy: Type                      = _
  var dispatchDefn: Defn                    = _
  var dispatchOffset: mutable.Map[Int, Int] = _

  val classHasTraitName       = Global.Top("__class_has_trait")
  val classHasTraitVal        = Val.Global(classHasTraitName, Type.Ptr)
  var classHasTraitTy: Type   = _
  var classHasTraitDefn: Defn = _

  val traitHasTraitName       = Global.Top("__trait_has_trait")
  val traitHasTraitVal        = Val.Global(traitHasTraitName, Type.Ptr)
  var traitHasTraitTy: Type   = _
  var traitHasTraitDefn: Defn = _

  val traitMethods = top.methods.filter(_.inTrait).sortBy(_.id)
  val traitMethodSigs = {
    val sigs = mutable.Map.empty[String, Int]
    var i    = 0
    traitMethods.foreach { meth =>
      val sig = meth.name.id
      if (!sigs.contains(sig)) {
        sigs(sig) = i
        i += 1
      }
    }
    sigs
  }

  def initDispatch(): Unit = {
    val sigs          = traitMethodSigs
    val sigsLength    = traitMethodSigs.size
    val classes       = top.classes.sortBy(_.id)
    val classesLength = classes.length
    val table =
      Array.fill[Val](classesLength * sigsLength)(Val.Null)
    val mins = Array.fill[Int](sigsLength)(Int.MaxValue)
    val maxs = Array.fill[Int](sigsLength)(Int.MinValue)

    def put(cls: Int, meth: Int, value: Val) = {
      table(meth * classesLength + cls) = value
      mins(meth) = mins(meth) min cls
      maxs(meth) = maxs(meth) max cls
    }
    def get(cls: Int, meth: Int) =
      table(meth * classesLength + cls)

    // Visit every class and enter all the trait sigs they support
    classes.foreach { cls =>
      def visit(cur: Class): Unit = {
        cur.methods.foreach { meth =>
          val sig = meth.name.id
          if (sigs.contains(sig)) {
            val id = sigs(sig)
            if (get(cls.id, id) eq Val.Null) {
              put(cls.id, id, meth.value)
            }
          }
        }
        cur.parent.foreach(visit)
      }
      visit(cls)
    }

    // Generate a compressed representation of the dispatch table
    // that displaces method rows one of top of the other to miniminize
    // number of nulls in the table.
    val offsets = mutable.Map.empty[Int, Int]
    val compressed = new Array[Val]({
      var meth = 0
      var size = 0
      while (meth < sigsLength) {
        val min = mins(meth)
        if (min != Int.MaxValue) {
          val max = maxs(meth)
          size += max - min + 1
        }
        meth += 1
      }
      size
    })
    var current = 0
    var meth    = 0
    while (meth < sigsLength) {
      val start = mins(meth)
      val end   = maxs(meth)
      if (start == Int.MaxValue) {
        offsets(meth) = 0
      } else {
        val total = end - start + 1
        java.lang.System.arraycopy(table,
                                   meth * classesLength + start,
                                   compressed,
                                   current,
                                   total)
        offsets(meth) = current - start
        current += total
      }
      meth += 1
    }

    val value = Val.Array(Type.Ptr, compressed)

    dispatchOffset = offsets
    dispatchTy = Type.Ptr
    dispatchDefn = Defn.Const(Attrs.None, dispatchName, value.ty, value)
  }

  def markTraits(row: Array[Boolean], cls: Class): Unit = {
    cls.traits.foreach(markTraits(row, _))
    cls.parent.foreach(markTraits(row, _))
  }

  def markTraits(row: Array[Boolean], trt: Trait): Unit = {
    row(trt.id) = true
    trt.traits.foreach { right =>
      row(right.id) = true
    }
    trt.traits.foreach(markTraits(row, _))
  }

  def initClassHasTrait(): Unit = {
    val columns = top.classes.sortBy(_.id).map { cls =>
      val row = new Array[Boolean](top.traits.length)
      markTraits(row, cls)
      Val.Array(Type.Bool, row.map(Val.Bool))
    }
    val table = Val.Array(Type.Array(Type.Bool, top.traits.length), columns)

    classHasTraitTy = table.ty
    classHasTraitDefn =
      Defn.Const(Attrs.None, classHasTraitName, table.ty, table)
  }

  def initTraitHasTrait(): Unit = {
    val columns = top.traits.sortBy(_.id).map { left =>
      val row = new Array[Boolean](top.traits.length)
      markTraits(row, left)
      row(left.id) = true
      Val.Array(Type.Bool, row.map(Val.Bool))
    }
    val table = Val.Array(Type.Array(Type.Bool, top.traits.length), columns)

    traitHasTraitTy = table.ty
    traitHasTraitDefn =
      Defn.Const(Attrs.None, traitHasTraitName, table.ty, table)
  }

  initDispatch()
  initClassHasTrait()
  initTraitHasTrait()
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy