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

scala.scalanative.interflow.Visit.scala Maven / Gradle / Ivy

There is a newer version: 0.5.5
Show newest version
package scala.scalanative
package interflow

import scalanative.nir._
import scalanative.linker._
import scalanative.compat.CompatParColls.Converters._

trait Visit { self: Interflow =>
  def shallVisit(name: Global): Boolean = {
    val orig = originalName(name)

    if (!hasOriginal(orig)) {
      false
    } else {
      val defn = getOriginal(orig)
      val hasInsts = defn.insts.size > 0
      val hasSema = linked.infos.contains(defn.name)

      hasInsts && hasSema
    }
  }

  def shallDuplicate(name: Global, argtys: Seq[Type]): Boolean =
    mode match {
      case build.Mode.Debug | build.Mode.ReleaseFast =>
        false

      case build.Mode.ReleaseFull =>
        if (!shallVisit(name)) {
          false
        } else {
          val defn =
            getOriginal(name)
          val nonExtern =
            !defn.attrs.isExtern
          val canOptimize =
            defn.attrs.opt != Attr.NoOpt
          val canSpecialize =
            defn.attrs.specialize != Attr.NoSpecialize
          val differentArgumentTypes =
            argumentTypes(name) != argtys

          canOptimize && canSpecialize && nonExtern && differentArgumentTypes
        }
    }

  def visitEntries(): Unit =
    mode match {
      case build.Mode.Debug =>
        linked.defns.foreach(defn => visitEntry(defn.name))
      case _: build.Mode.Release =>
        linked.entries.foreach(visitEntry)
    }

  def visitEntry(name: Global): Unit = {
    if (!name.isTop) {
      visitEntry(name.top)
    }
    linked.infos(name) match {
      case meth: Method =>
        visitRoot(name)
      case cls: Class if cls.isModule =>
        val init = cls.name member Sig.Ctor(Seq.empty)
        if (hasOriginal(init)) {
          visitRoot(init)
        }
      case _ =>
        ()
    }
  }

  def visitRoot(name: Global): Unit =
    if (shallVisit(name)) {
      pushTodo(name)
    }

  def visitDuplicate(name: Global, argtys: Seq[Type]): Option[Defn.Define] = {
    mode match {
      case build.Mode.Debug =>
        None
      case _: build.Mode.Release =>
        val dup = duplicateName(name, argtys)
        if (shallVisit(dup)) {
          if (!isDone(dup)) {
            visitMethod(dup)
          }
          maybeDone(dup)
        } else {
          None
        }
    }
  }

  def visitLoop(): Unit = {
    def visit(name: Global): Unit = {
      if (!isDone(name)) {
        visitMethod(name)
      }
    }

    def loop(): Unit = {
      var name = popTodo()
      while (name ne Global.None) {
        visit(name)
        name = popTodo()
      }
    }

    mode match {
      case build.Mode.Debug =>
        allTodo().par.foreach(visit)
      case _: build.Mode.Release =>
        loop()
    }
  }

  def visitMethod(name: Global): Unit =
    if (!hasStarted(name)) {
      markStarted(name)
      val origname = originalName(name)
      val origdefn = getOriginal(origname)
      try {
        if (shallOpt(name)) {
          setDone(name, opt(name))
        } else {
          noOpt(origdefn)
          setDone(name, origdefn)
          setDone(origname, origdefn)
        }
      } catch {
        case BailOut(msg) =>
          log(s"failed to expand ${name.show}: $msg")
          val baildefn =
            origdefn.copy(attrs = origdefn.attrs.copy(opt = Attr.BailOpt(msg)))(
              origdefn.pos
            )
          noOpt(origdefn)
          setDone(name, baildefn)
          setDone(origname, baildefn)
          markBlacklisted(name)
          markBlacklisted(origname)
      }
    }

  def originalName(name: Global): Global = name match {
    case Global.Member(owner, sig) if sig.isDuplicate =>
      val Sig.Duplicate(origSig, argtys) = sig.unmangled
      originalName(Global.Member(owner, origSig))
    case _ =>
      name
  }

  def duplicateName(name: Global, argtys: Seq[Type]): Global = {
    val orig = originalName(name)
    if (!shallDuplicate(orig, argtys)) {
      orig
    } else {
      val origargtys = argumentTypes(name)
      val dupargtys = argtys.zip(origargtys).map {
        case (argty, origty) =>
          // Duplicate argument type should not be
          // less specific than the original declare type.
          if (!Sub.is(argty, origty)) origty else argty
      }
      val Global.Member(top, sig) = orig
      Global.Member(top, Sig.Duplicate(sig, dupargtys))
    }
  }

  def argumentTypes(name: Global): Seq[Type] = name match {
    case Global.Member(_, sig) if sig.isDuplicate =>
      val Sig.Duplicate(_, argtys) = sig.unmangled
      argtys
    case _ =>
      val Type.Function(argtys, _) = linked.infos(name).asInstanceOf[Method].ty
      argtys
  }

  def originalFunctionType(name: Global): Type = name match {
    case Global.Member(owner, sig) if sig.isDuplicate =>
      val Sig.Duplicate(base, _) = sig.unmangled
      originalFunctionType(Global.Member(owner, base))
    case _ =>
      linked.infos(name).asInstanceOf[Method].ty
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy