alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (JavaUniverse.scala)

This example Scala source code file (JavaUniverse.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Scala source code examples by using tags.

All credit for the original source code belongs to scala-lang.org; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Scala tags/keywords

any, classtag, javauniverse, manifest, reflection, runtime, somephase, treecopier, type, typetag, unit, universe

The JavaUniverse.scala Scala example source code

package scala
package reflect
package runtime

import scala.reflect.internal.{TreeInfo, SomePhase}
import scala.reflect.internal.{SymbolTable => InternalSymbolTable}
import scala.reflect.runtime.{SymbolTable => RuntimeSymbolTable}
import scala.reflect.api.{TreeCreator, TypeCreator, Universe}

/** An implementation of [[scala.reflect.api.Universe]] for runtime reflection using JVM classloaders.
 *
 *  Should not be instantiated directly, use [[scala.reflect.runtime.universe]] instead.
 *
 *  @contentDiagram hideNodes "*Api" "*Extractor"
 */
class JavaUniverse extends InternalSymbolTable with JavaUniverseForce with ReflectSetup with RuntimeSymbolTable { self =>

  override def inform(msg: String): Unit = log(msg)
  def picklerPhase = SomePhase
  def erasurePhase = SomePhase
  lazy val settings = new Settings
  private val isLogging = sys.props contains "scala.debug.reflect"

  def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg)

  type TreeCopier = InternalTreeCopierOps
  implicit val TreeCopierTag: ClassTag[TreeCopier] = ClassTag[TreeCopier](classOf[TreeCopier])
  def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
  def newLazyTreeCopier: TreeCopier = new LazyTreeCopier

  def currentFreshNameCreator = globalFreshNameCreator

  override lazy val internal: Internal = new SymbolTableInternal {
    override def typeTagToManifest[T: ClassTag](mirror0: Any, tag: Universe # TypeTag[T]): Manifest[T] = {
      // SI-6239: make this conversion more precise
      val mirror = mirror0.asInstanceOf[Mirror]
      val runtimeClass = mirror.runtimeClass(tag.in(mirror).tpe)
      Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]]
    }
    override def manifestToTypeTag[T](mirror0: Any, manifest: Manifest[T]): Universe # TypeTag[T] =
      TypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator {
        def apply[U <: Universe with Singleton](mirror: scala.reflect.api.Mirror[U]): U # Type = {
          mirror.universe match {
            case ju: JavaUniverse =>
              val jm = mirror.asInstanceOf[ju.Mirror]
              val sym = jm.classSymbol(manifest.runtimeClass)
              val tpe =
                if (manifest.typeArguments.isEmpty) sym.toType
                else {
                  val tags = manifest.typeArguments map (targ => ju.internal.manifestToTypeTag(jm, targ))
                  ju.appliedType(sym.toTypeConstructor, tags map (_.in(jm).tpe))
                }
              tpe.asInstanceOf[U # Type]
            case u =>
              u.internal.manifestToTypeTag(mirror.asInstanceOf[u.Mirror], manifest).in(mirror).tpe
          }
        }
      })
  }

  // can't put this in runtime.Trees since that's mixed with Global in ReflectGlobal, which has the definition from internal.Trees
  object treeInfo extends {
    val global: JavaUniverse.this.type = JavaUniverse.this
  } with TreeInfo

  init()

  // ======= Initialization of runtime reflection =======
  //
  // This doc describes the carefully laid out sequence of actions used to initialize reflective universes.
  //
  // Before reading the text below, read up the section Mirrors in the reflection pre-SIP
  // https://docs.google.com/document/d/1nAwSw4TmMplsIlzh2shYLUJ5mVh3wndDa1Zm1H6an9A/edit.
  // Take an especially good look at Figure 2, because it illustrates fundamental principles underlying runtime reflection:
  //   1) For each universe we have one mirror per classloader
  //   2) Package symbols are per-mirror
  //   3) Other symbols are per-universe, which means that a symbol (e.g. Seq on the picture) might be shared between multiple owners
  //
  // Main challenges that runtime reflection presents wrt initialization are:
  //   1) Extravagant completion scheme that enters package members on-demand rather than a result of scanning a directory with class files.
  //      (That's a direct consequence of the fact that in general case we can't enumerate all classes in a classloader.
  //      As Paul rightfully mentioned, we could specialcase classloaders that point to filesystems, but that is left for future work).
  //   2) Presence of synthetic symbols that aren't loaded by normal means (from classfiles) but are synthesized on-the-fly,
  //      and the necessity to propagate these synthetic symbols from rootMirror to other mirrors,
  //      complicated by the fact that such symbols depend on normal symbols (e.g. AnyRef depends on Object).
  //   3) Necessity to remain thread-safe, which limits our options related to lazy initialization
  //      (E.g. we cannot use missingHook to enter synthetic symbols, because that's thread-unsafe).
  //
  // Directly addressing the challenge #3, we create all synthetic symbols fully in advance during init().
  // However, it's not that simple as just calling definitions.symbolsNotPresentInBytecode.
  // Before doing that, we need to first initialize ObjectClass, then ScalaPackageClass, and only then deal with synthetics.
  // Below you can find a detailed explanation for that.
  //
  // ### Why ScalaPackageClass? ###
  //
  // Forcing ScalaPackageClass first thing during startup is important, because syntheticCoreClasses such as AnyRefClass
  // need to be entered into ScalaPackageClass, which entails calling ScalaPackageClass.info.decls.enter.
  // If ScalaPackageClass isn't initialized by that moment, the following will happen for runtime reflection:
  //   1) Initialization of ScalaPackageClass will trigger unpickling.
  //   2) Unpickling will need to load some auxiliary types such as, for example, String.
  //   3) To load String, runtime reflection will call mirrorDefining(classOf[String]).
  //   4) This, in turn, will call runtimeMirror(classOf[String].getClassLoader).
  //   5) For some classloader configurations, the resulting mirror will be different from rootMirror.
  //   6) In that case, initialization of the resulting mirror will try to import definitions.syntheticCoreClasses into the mirror.
  //   7) This will force all the lazy vals corresponding to syntheticCoreClasses.
  //   8) By that time, the completer of ScalaPackageClass will have already called setInfo on ScalaPackageClass, so there won't be any stack overflow.
  //
  // So far so good, no crashes, no problems, right? Not quite.
  // If forcing of ScalaPackageClass was called by a syntheticCoreClasses lazy val,
  // then this lazy val will be entered twice: once during step 7 and once when returning from the original call.
  // To avoid this we need to initialize ScalaPackageClass prior to other synthetics.
  //
  // ### Why ObjectClass? ###
  //
  // 1) As explained in JavaMirrors.missingHook, initialization of ScalaPackageClass critically depends on AnyRefClass.
  // 2) AnyRefClass is defined as "lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe)",
  //    which means that initialization of AnyRefClass depends on ObjectClass.
  // 3) ObjectClass is defined as "lazy val ObjectClass = getRequiredClass(sn.Object.toString)",
  //    which means that under some classloader configurations (see JavaMirrors.missingHook for more details)
  //    dereferencing ObjectClass might trigger an avalanche of initializations calling back into AnyRefClass
  //    while another AnyRefClass initializer is still on stack.
  // 4) That will lead to AnyRefClass being entered two times (once when the recursive call returns and once when the original one returns)
  // 5) That will crash PackageScope.enter that helpfully detects double-enters.
  //
  // Therefore, before initializing ScalaPackageClass, we must pre-initialize ObjectClass
  def init() {
    definitions.init()

    // workaround for http://groups.google.com/group/scala-internals/browse_thread/thread/97840ba4fd37b52e
    // constructors are by definition single-threaded, so we initialize all lazy vals (and local object) in advance
    // in order to avoid deadlocks later (e.g. one thread holds a global reflection lock and waits for definitions.Something to initialize,
    // whereas another thread holds a definitions.Something initialization lock and needs a global reflection lock to complete the initialization)

    // TODO Convert this into a macro
    force()
  }
}

Other Scala source code examples

Here is a short list of links related to this Scala JavaUniverse.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.