Skip to content

Commit

Permalink
Merge pull request #47 from eed3si9n/topic/library-loader
Browse files Browse the repository at this point in the history
Layered class loading of library and compiler
  • Loading branch information
eed3si9n authored Mar 5, 2018
2 parents a17567c + d8d79b7 commit 200eeff
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
11 changes: 9 additions & 2 deletions launcher-implementation/src/main/scala/xsbt/boot/Launch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,18 @@ class Launch private[xsbt] (val bootDirectory: File, val lockBoot: Boolean, val
}
def componentProvider(appHome: File) = new ComponentProvider(appHome, lockBoot)

def scalaProvider(scalaVersion: String, module: RetrievedModule, parentLoader: ClassLoader, scalaLibDir: File): xsbti.ScalaProvider = new xsbti.ScalaProvider {
def scalaProvider(scalaVersion: String, module: RetrievedModule, parentLoader: ClassLoader, scalaLibDir: File): xsbti.ScalaProvider = new xsbti.ExtendedScalaProvider {
def launcher = Launch.this
def version = scalaVersion
lazy val loader = module.createLoader(parentLoader)

private object LoaderInit {
val (library, other) = module.fullClasspath.partition(_.getName.startsWith("scala-library"))
val libraryLoader = new LibraryClassLoader(toURLs(library), parentLoader, scalaVersion)
val fullLoader = new URLClassLoader(toURLs(other), libraryLoader)
}

override def loaderLibraryOnly(): ClassLoader = LoaderInit.libraryLoader
override def loader(): ClassLoader = LoaderInit.fullLoader
def compilerJar = new File(scalaLibDir, CompilerModuleName + ".jar")
def libraryJar = new File(scalaLibDir, LibraryModuleName + ".jar")
def jars = module.fullClasspath
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package xsbt.boot

import java.net.{ URL, URLClassLoader }

final class LibraryClassLoader(urls: Array[URL], parent: ClassLoader,
val scalaVersion: String) extends URLClassLoader(urls, parent) with xsbti.LibraryClassLoader {
}
22 changes: 17 additions & 5 deletions launcher-implementation/src/test/scala/ScalaProviderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ object ScalaProviderTest extends Specification {
"provide ClassLoader for Scala 2.8.2" in { checkScalaLoader("2.8.2") }
"provide ClassLoader for Scala 2.9.0" in { checkScalaLoader("2.9.0") }
"provide ClassLoader for Scala 2.9.2" in { checkScalaLoader("2.9.2") }
"provide ClassLoader for Scala 2.10.4" in { checkScalaLoader("2.10.4") }
"provide ClassLoader for Scala 2.11.0" in { checkScalaLoader("2.11.0") }
"provide ClassLoader for Scala 2.10.7" in { checkScalaLoader("2.10.7") }
"provide ClassLoader for Scala 2.11.12" in { checkScalaLoader("2.11.12") }
// This requires the test to run in JDK 8
// "provide ClassLoader for Scala 2.12.4" in { checkScalaLoader("2.12.4") }
}

"Launch" should {
Expand Down Expand Up @@ -68,16 +70,26 @@ object ScalaProviderTest extends Specification {
val provider = launcher.getScala(version)
val loader = provider.loader
// ensure that this loader can load Scala classes by trying scala.ScalaObject.
tryScala(loader)
tryScala(loader, loader.getParent)
getScalaVersion(loader) must beEqualTo(versionValue)

val libraryLoader = provider.loader.getParent
// Test the structural type
libraryLoader match {
case x: ClassLoader with LibraryLoader => x.scalaVersion must be(version)
}
tryScala(libraryLoader, libraryLoader)
}
private def tryScala(loader: ClassLoader) = Class.forName("scala.Product", false, loader).getClassLoader must be(loader)
private def tryScala(loader: ClassLoader, libraryLoader: ClassLoader) =
Class.forName("scala.Product", false, loader).getClassLoader must be(libraryLoader)

type LibraryLoader = { def scalaVersion: String }
}
object LaunchTest {
def testApp(main: String): Application = testApp(main, Array[File]())
def testApp(main: String, extra: Array[File]): Application = Application("org.scala-sbt", "launch-test", new Explicit(AppVersion), main, Nil, CrossValue.Disabled, extra)
import Predefined._
def testRepositories = List(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined(_))
def testRepositories = List(Local, MavenCentral, SonatypeOSSSnapshots).map(Repository.Predefined(_))
def withLauncher[T](f: xsbti.Launcher => T): T =
withTemporaryDirectory { bootDirectory =>
f(Launcher(bootDirectory, testRepositories))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package xsbti;

public interface ExtendedScalaProvider extends ScalaProvider
{
/** A ClassLoader that loads the classes from scala-library.jar. It will be the parent of `loader` .*/
public ClassLoader loaderLibraryOnly();
}
11 changes: 11 additions & 0 deletions launcher-interface/src/main/java/xsbti/LibraryClassLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package xsbti;

import java.io.File;

/**
* Marker interface for classloader with just scala-library.
*/
public interface LibraryClassLoader
{
public String scalaVersion();
}

0 comments on commit 200eeff

Please sign in to comment.