8000 WiP Separate the scalalib from the Scala.js library. by sjrd · Pull Request #4787 · scala-js/scala-js · GitHub
[go: up one dir, main page]

Skip to content

WiP Separate the scalalib from the Scala.js library. #4787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -5504,7 +5504,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
* the extension to `false`.
*/
for ((arg, wasRepeated) <- args.zipAll(wereRepeated, EmptyTree, false)) yield {
if (wasRepeated) {
if (wasRepeated && !scalaJSOpts.avoidOptimizingScalaVarargsAsJSArray) {
tryGenRepeatedParamAsJSArray(arg, handleNil = false).fold {
genExpr(arg)
} { genArgs =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ trait ScalaJSOptions {
* If false, bad calls to classOf will cause an error. */
def fixClassOf: Boolean

/** Should we avoid optimizing Scala varargs as js.Array-based seqs?
*
* This is normally only used when compiling the scalalib.
*/
def avoidOptimizingScalaVarargsAsJSArray: Boolean

/** Should static forwarders be emitted for non-top-level objects.
*
* Scala/JVM does not do that. Since Scala.js 1.2.0, we do not do it by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class ScalaJSPlugin(val global: Global) extends NscPlugin {
object scalaJSOpts extends ScalaJSOptions {
import ScalaJSOptions.URIMap
var fixClassOf: Boolean = false
var avoidOptimizingScalaVarargsAsJSArray: Boolean = false
var genStaticForwardersForNonTopLevelObjects: Boolean = false
lazy val sourceURIMaps: List[URIMap] = {
if (_sourceURIMaps.nonEmpty)
Expand Down Expand Up @@ -109,6 +110,8 @@ class ScalaJSPlugin(val global: Global) extends NscPlugin {
for (option <- options) {
if (option == "fixClassOf") {
fixClassOf = true
} else if (option == "avoidOptimizingScalaVarargsAsJSArray") {
avoidOptimizingScalaVarargsAsJSArray = true
} else if (option == "genStaticForwardersForNonTopLevelObjects") {
genStaticForwardersForNonTopLevelObjects = true
} else if (option == "nowarnGlobalExecutionContext") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5906,6 +5906,8 @@ private[optimizer] object OptimizerCore {
),
ClassName("scala.collection.mutable.ArrayBuilder$") -> List(
m("scala$collection$mutable$ArrayBuilder$$zeroOf", List(ClassClassRef), O) -> ArrayBuilderZeroOf,
m("scala$collection$mutable$ArrayBuilder$$genericArrayBuilderResult", List(ClassClassRef, O), O) -> GenericArrayBuilderResult,
// and its legacy signature (< v1.13.0)
m("scala$collection$mutable$ArrayBuilder$$genericArrayBuilderResult", List(ClassClassRef, JSArrayClassRef), O) -> GenericArrayBuilderResult
),
ClassName("java.lang.Class") -> List(
Expand Down
26 changes: 16 additions & 10 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -673,9 +673,9 @@ object Build {
}
)

val cleanIRSettings = Def.settings(
def cleanIRSettings(forScalalib: Boolean): Seq[Setting[_]] = Def.settings(
// In order to rewrite anonymous functions and tuples, the code must not be specialized
scalacOptions += "-no-specialization",
scalacOptions ++= (if (forScalalib) Nil else Seq("-no-specialization")),

products in Compile := {
val s = streams.value
Expand All @@ -684,7 +684,7 @@ object Build {

val outputDir = crossTarget.value / "cleaned-classes"

val irCleaner = new JavalibIRCleaner((LocalRootProject / baseDirectory).value.toURI())
val irCleaner = new JavalibIRCleaner((LocalRootProject / baseDirectory).value.toURI(), forScalalib)

val libFileMappings = (PathFinder(prevProducts) ** "*.sjsir")
.pair(Path.rebase(prevProducts, outputDir))
Expand Down Expand Up @@ -1141,7 +1141,7 @@ object Build {
name := "Scala.js linker private library",
publishArtifact in Compile := false,
delambdafySetting,
cleanIRSettings
cleanIRSettings(forScalalib = false),
).withScalaJSCompiler2_12.withScalaJSJUnitPlugin2_12.dependsOnLibrary2_12.dependsOn(
jUnitRuntime.v2_12 % "test", testBridge.v2_12 % "test",
)
Expand Down Expand Up @@ -1457,7 +1457,7 @@ object Build {
Seq(output)
}.taskValue,

cleanIRSettings,
cleanIRSettings(forScalalib = false),

Compile / doc := {
val dir = (Compile / doc / target).value
Expand Down Expand Up @@ -1539,6 +1539,8 @@ object Build {

// Tell the plugin to hack-fix bad classOf trees
scalacOptions ++= scalaJSCompilerOption("fixClassOf"),
// And not to optimize Scala varargs as js.Array-based seqs
scalacOptions ++= scalaJSCompilerOption("avoidOptimizingScalaVarargsAsJSArray"),

libraryDependencies +=
"org.scala-lang" % "scala-library" % scalaVersion.value classifier "sources",
Expand Down Expand Up @@ -1652,6 +1654,8 @@ object Build {

headerSources in Compile := Nil,
headerSources in Test := Nil,

cleanIRSettings(forScalalib = true),
).withScalaJSCompiler.dependsOnLibraryNoJar

lazy val libraryAux: MultiScalaProject = MultiScalaProject(
Expand All @@ -1667,6 +1671,8 @@ object Build {
delambdafySetting,

recompileAllOrNothingSettings,

cleanIRSettings(forScalalib = true),
).withScalaJSCompiler.dependsOnLibraryNoJar

lazy val library: MultiScalaProject = MultiScalaProject(
Expand Down Expand Up @@ -1923,16 +1929,16 @@ object Build {
scalaVersion.value match {
case `default212Version` =>
Some(ExpectedSizes(
fastLink = 772000 to 773000,
fullLink = 145000 to 146000,
fastLinkGz = 91000 to 92000,
fastLink = 767000 to 768000,
fullLink = 144000 to 145000,
fastLinkGz = 90000 to 91000,
fullLinkGz = 35000 to 36000,
))

case `default213Version` =>
Some(ExpectedSizes(
fastLink = 480000 to 481000,
fullLink = 102000 to 103000,
fastLink = 483000 to 484000,
fullLink = 103000 to 104000,
fastLinkGz = 62000 to 63000,
fullLinkGz = 27000 to 28000,
))
Expand Down
70 changes: 52 additions & 18 deletions project/JavalibIRCleaner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ import sbt.{Logger, MessageOnlyException}
* Afterwards, we check that the IR does not contain any reference to classes
* under the `scala.*` package.
*/
final class JavalibIRCleaner(baseDirectoryURI: URI) {
final class JavalibIRCleaner(baseDirectoryURI: URI, forScalalib: Boolean) {
import JavalibIRCleaner._

private val classNameSubstitutions: Map[ClassName, ClassName] =
if (forScalalib) ClassNameSubstitutionsForScalalib
else ClassNameSubstitutionsForJavalib

def cleanIR(dependencyFiles: Seq[File], libFileMappings: Seq[(File, File)],
logger: Logger): Set[File] = {

Expand Down Expand Up @@ -80,11 +84,19 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
}

if (errorManager.hasErrors) {
throw new MessageOnlyException(
s"There were ${errorManager.errorCount} errors while " +
"postprocessing the IR of the javalanglib. " +
"The javalanglib must be written in a style that does not leak any " +
"reference to the Scala library.")
if (forScalalib) {
throw new MessageOnlyException(
s"There were ${errorManager.errorCount} errors while " +
"postprocessing the IR of the scalalib. " +
"The scalalib must be written in a style that does not leak any " +
"reference to the Scala.js standard library.")
} else {
throw new MessageOnlyException(
s"There were ${errorManager.errorCount} errors while " +
"postprocessing the IR of the javalib. " +
"The javalib must be written in a style that does not leak any " +
"reference to the Scala library.")
}
}

resultBuilder.result()
Expand Down Expand Up @@ -146,10 +158,12 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
// Preprocess the super interface list
val newInterfaces = transformInterfaceList(interfaces)

/* Remove the `private def writeReplace__O` generated by scalac 2.13+
* in the companion of serializable classes.
/* javalib only: Remove the `private def writeReplace__O` generated by
* scalac 2.13+ in the companion of serializable classes.
*/
val newMethods = methods.filter(_.name.name != writeReplaceMethodName)
val newMethods =
if (forScalalib) methods
else methods.filter(_.name.name != writeReplaceMethodName)

val preprocessedTree = ClassDef(name, originalName, kind, jsClassCaptures,
superClass, newInterfaces, jsSuperClass, jsNativeLoadSpec, fields,
Expand Down Expand Up @@ -177,9 +191,13 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
/* Replace references to scala.Serializable by java.io.Serializable.
* This works around the fact that scalac adds scala.Serializable to the
* companion object of any class that extends java.io.Serializable.
*
* Don't do it for the scalalib.
*/

if ( 10000 !interfaces.exists(_.name == ScalaSerializable)) {
if (forScalalib) {
interfaces
} else if (!interfaces.exists(_.name == ScalaSerializable)) {
interfaces
} else if (interfaces.exists(_.name == JavaIOSerializable)) {
interfaces.filter(_.name != ScalaSerializable)
Expand Down Expand Up @@ -321,13 +339,13 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
implicit val pos = tree.pos

tree match {
// new AnonFunctionN(closure) --> closure
case New(AnonFunctionNClass(n), _, List(closure)) =>
// javalib only: new AnonFunctionN(closure) --> closure
case New(AnonFunctionNClass(n), _, List(closure)) if !forScalalib =>
closure

// someFunctionN.apply(args) --> someFunctionN(args)
// javalib only: someFunctionN.apply(args) --> someFunctionN(args)
case Apply(ApplyFlags.empty, fun, MethodIdent(FunctionApplyMethodName(n)), args)
if isFunctionNType(n, fun.tpe) =>
if !forScalalib && isFunctionNType(n, fun.tpe) =>
JSFunctionApply(fun, args)

// <= 2.12 : toJSVarArgs(jsArrayOps(jsArray).toSeq) -> jsArray
Expand Down Expand Up @@ -582,7 +600,7 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
}

private def transformClassName(cls: ClassName)(implicit pos: Position): ClassName = {
ClassNameSubstitutions.getOrElse(cls, {
classNameSubstitutions.getOrElse(cls, {
validateClassName(cls)
cls
})
Expand All @@ -600,8 +618,13 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) {
def isAnException: Boolean =
isJavaScriptExceptionWithinItself || isTypedArrayBufferBridgeWithinItself

if (cls.nameString.startsWith("scala.") && !isAnException)
reportError(s"Illegal reference to Scala class ${cls.nameString}")
if (forScalalib) {
if (cls.nameString.startsWith("scala.scalajs."))
reportError(s"Illegal reference to Scala.js class ${cls.nameString}")
} else {
if (cls.nameString.startsWith("scala.") && !isAnException)
reportError(s"Illegal reference to Scala class ${cls.nameString}")
}
}

private def transformNonJSClassName(cls: ClassName)(implicit pos: Position): ClassName = {
Expand Down Expand Up @@ -729,7 +752,7 @@ object JavalibIRCleaner {
false
}

private val ClassNameSubstitutions: Map[ClassName, ClassName] = {
private val ClassNameSubstitutionsForJavalib: Map[ClassName, ClassName] = {
val functionTypePairs = for {
funClass <- FunctionNClasses ++ AnonFunctionNClasses
} yield {
Expand Down Expand Up @@ -762,4 +785,15 @@ object JavalibIRCleaner {
val allPairs = functionTypePairs ++ refPairs ++ tuplePairs ++ otherPairs
allPairs.toMap
}

private val ClassNameSubstitutionsForScalalib: Map[ClassName, ClassName] = {
val anonFunctionPairs = for {
n <- (0 to 22).toList
} yield {
ClassName(s"scala.scalajs.runtime.AnonFunction$n") -> ClassName(s"scala.runtime.AnonFunction$n")
}

val allPairs = anonFunctionPairs
allPairs.toMap
}
}
51 changes: 0 additions & 51 deletions scalalib/overrides-2.12/scala/collection/mutable/Buffer.scala

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ trait ExecutionContext {
/** Prepares for the execution of a task. Returns the prepared
* execution context. The recommended implementation of
* `prepare` is to return `this`.
*
*
* This method should no longer be overridden or called. It was
* originally expected that `prepare` would be called by
* all libraries that consume ExecutionContexts, in order to
Expand Down Expand Up @@ -130,7 +130,7 @@ object ExecutionContext {
* [[https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors-- available processors]].
*/
implicit lazy val global: ExecutionContext =
scala.scalajs.concurrent.JSExecutionContext.queue
JSGlobalExecutionContext()
}

/** Creates an `ExecutionContext` from the given `ExecutorService`.
Expand Down Expand Up @@ -179,5 +179,3 @@ object ExecutionContext {
*/
def defaultReporter: Throwable => Unit = _.printStackTrace()
}


Loading
0