forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Only the files in the Compile configuration are translated. Tests are kept in Scala.
- Loading branch information
Showing
17 changed files
with
610 additions
and
353 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
compiler/src/dotty/tools/dotc/reporting/AbstractReporter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package dotty.tools | ||
package dotc | ||
package reporting | ||
|
||
/** | ||
* This class mixes in a few standard traits, so that it is easier to extend from Java. | ||
*/ | ||
abstract class AbstractReporter extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* sbt -- Simple Build Tool | ||
* Copyright 2008, 2009 Mark Harrah | ||
*/ | ||
package xsbt; | ||
|
||
import xsbti.AnalysisCallback; | ||
import xsbti.Logger; | ||
import xsbti.Reporter; | ||
import xsbti.Severity; | ||
import xsbti.compile.*; | ||
|
||
import java.io.File; | ||
|
||
import dotty.tools.dotc.core.Contexts.Context; | ||
import dotty.tools.dotc.core.Contexts.ContextBase; | ||
import dotty.tools.dotc.Main; | ||
import dotty.tools.dotc.interfaces.*; | ||
|
||
import java.net.URLClassLoader; | ||
|
||
public class CachedCompilerImpl implements CachedCompiler { | ||
private final String[] args; | ||
private final Output output; | ||
private final String[] outputArgs; | ||
|
||
public CachedCompilerImpl(String[] args, Output output) { | ||
super(); | ||
this.args = args; | ||
this.output = output; | ||
|
||
if (!(output instanceof SingleOutput)) | ||
throw new IllegalArgumentException("output should be a SingleOutput, was a " + output.getClass().getName()); | ||
|
||
this.outputArgs = | ||
new String[] { "-d", ((SingleOutput) output).getOutputDirectory().getAbsolutePath().toString() }; | ||
} | ||
|
||
public String[] commandArguments(File[] sources) { | ||
String[] sortedSourcesAbsolute = new String[sources.length]; | ||
for (int i = 0; i < sources.length; i++) | ||
sortedSourcesAbsolute[i] = sources[i].getAbsolutePath(); | ||
java.util.Arrays.sort(sortedSourcesAbsolute); | ||
|
||
// Concatenate outputArgs, args and sortedSourcesAbsolute | ||
String[] result = new String[outputArgs.length + args.length + sortedSourcesAbsolute.length]; | ||
int j = 0; | ||
for (int i = 0; i < outputArgs.length; i++, j++) | ||
result[j] = outputArgs[i]; | ||
for (int i = 0; i < args.length; i++, j++) | ||
result[j] = args[i]; | ||
for (int i = 0; i < sortedSourcesAbsolute.length; i++, j++) | ||
result[j] = sortedSourcesAbsolute[i]; | ||
|
||
return result; | ||
} | ||
|
||
synchronized public void run(File[] sources, DependencyChanges changes, AnalysisCallback callback, Logger log, Reporter delegate, CompileProgress progress) { | ||
log.debug(() -> { | ||
String msg = "Calling Dotty compiler with arguments (CompilerInterface):"; | ||
for (String arg : args) | ||
msg = msg + "\n\t" + arg; | ||
return msg; | ||
}); | ||
|
||
Context ctx = new ContextBase().initialCtx().fresh() | ||
.setSbtCallback(callback) | ||
.setReporter(new DelegatingReporter(delegate)); | ||
|
||
URLClassLoader cl = (URLClassLoader) this.getClass().getClassLoader(); | ||
|
||
dotty.tools.dotc.reporting.Reporter reporter = Main.process(commandArguments(sources), ctx); | ||
if (reporter.hasErrors()) { | ||
throw new InterfaceCompileFailed(args, new Problem[0]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package xsbt; | ||
|
||
import java.lang.reflect.Field; | ||
|
||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
|
||
import java.util.WeakHashMap; | ||
|
||
/** | ||
* A classloader to run the compiler | ||
* <p> | ||
* A CompilerClassLoader is constructed from a list of `urls` that need to be on | ||
* the classpath to run the compiler and the classloader used by sbt. | ||
* <p> | ||
* To understand why a custom classloader is needed for the compiler, let us | ||
* describe some alternatives that wouldn't work. | ||
* <ul> | ||
* <li>`new URLClassLoader(urls)`: | ||
* The compiler contains sbt phases that callback to sbt using the `xsbti.*` | ||
* interfaces. If `urls` does not contain the sbt interfaces we'll get a | ||
* `ClassNotFoundException` in the compiler when we try to use them, if | ||
* `urls` does contain the interfaces we'll get a `ClassCastException` or a | ||
* `LinkageError` because if the same class is loaded by two different | ||
* classloaders, they are considered distinct by the JVM. | ||
* <li>`new URLClassLoader(urls, sbtLoader)`: | ||
* Because of the JVM delegation model, this means that we will only load | ||
* a class from `urls` if it's not present in the parent `sbtLoader`, but | ||
* sbt uses its own version of the scala compiler and scala library which | ||
* is not the one we need to run the compiler. | ||
* </ul> | ||
* <p> | ||
* Our solution is to implement a subclass of URLClassLoader with no parent, instead | ||
* we override `loadClass` to load the `xsbti.*` interfaces from `sbtLoader`. | ||
*/ | ||
public class CompilerClassLoader extends URLClassLoader { | ||
private final ClassLoader sbtLoader; | ||
|
||
public CompilerClassLoader(URL[] urls, ClassLoader sbtLoader) { | ||
super(urls, null); | ||
this.sbtLoader = sbtLoader; | ||
} | ||
|
||
@Override | ||
public Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { | ||
if (className.startsWith("xsbti.")) { | ||
// We can't use the loadClass overload with two arguments because it's | ||
// protected, but we can do the same by hand (the classloader instance | ||
// from which we call resolveClass does not matter). | ||
Class<?> c = sbtLoader.loadClass(className); | ||
if (resolve) | ||
resolveClass(c); | ||
return c; | ||
} else { | ||
return super.loadClass(className, resolve); | ||
} | ||
} | ||
|
||
/** | ||
* Cache the result of `fixBridgeLoader`. | ||
* <p> | ||
* Reusing ClassLoaders is important for warm performance since otherwise the | ||
* JIT code cache for the compiler will be discarded between every call to | ||
* the sbt `compile` task. | ||
*/ | ||
private static WeakHashMap<ClassLoader, ClassLoader> fixedLoaderCache = new WeakHashMap<>(); | ||
|
||
/** | ||
* Fix the compiler bridge ClassLoader | ||
* <p> | ||
* Soundtrack: https://www.youtube.com/watch?v=imamcajBEJs | ||
* <p> | ||
* The classloader that we get from sbt looks like: | ||
* <p> | ||
* URLClassLoader(bridgeURLs, | ||
* DualLoader(scalaLoader, notXsbtiFilter, sbtLoader, xsbtiFilter)) | ||
* <p> | ||
* DualLoader will load the `xsbti.*` interfaces using `sbtLoader` and | ||
* everything else with `scalaLoader`. Once we have loaded the dotty Main | ||
* class using `scalaLoader`, subsequent classes in the dotty compiler will | ||
* also be loaded by `scalaLoader` and _not_ by the DualLoader. But the sbt | ||
* compiler phases are part of dotty and still need access to the `xsbti.*` | ||
* interfaces in `sbtLoader`, therefore DualLoader does not work for us | ||
* (this issue is not present with scalac because the sbt phases are | ||
* currently defined in the compiler bridge itself, not in scalac). | ||
* <p> | ||
* CompilerClassLoader is a replacement for DualLoader. Until we can fix | ||
* this in sbt proper, we need to use reflection to construct our own | ||
* fixed classloader: | ||
* <p> | ||
* URLClassLoader(bridgeURLs, | ||
* CompilerClassLoader(scalaLoader.getURLs, sbtLoader)) | ||
* | ||
* @param bridgeLoader The classloader that sbt uses to load the compiler bridge | ||
* @return A fixed classloader that works with dotty | ||
*/ | ||
synchronized public static ClassLoader fixBridgeLoader(ClassLoader bridgeLoader) { | ||
return fixedLoaderCache.computeIfAbsent(bridgeLoader, k -> computeFixedLoader(k)); | ||
} | ||
|
||
private static ClassLoader computeFixedLoader(ClassLoader bridgeLoader) { | ||
URLClassLoader urlBridgeLoader = (URLClassLoader) bridgeLoader; | ||
ClassLoader dualLoader = urlBridgeLoader.getParent(); | ||
Class<?> dualLoaderClass = dualLoader.getClass(); | ||
|
||
try { | ||
// DualLoader.parentA and DualLoader.parentB are private | ||
Field parentAField = dualLoaderClass.getDeclaredField("parentA"); | ||
parentAField.setAccessible(true); | ||
Field parentBField = dualLoaderClass.getDeclaredField("parentB"); | ||
parentBField.setAccessible(true); | ||
URLClassLoader scalaLoader = (URLClassLoader) parentAField.get(dualLoader); | ||
URLClassLoader sbtLoader = (URLClassLoader) parentBField.get(dualLoader); | ||
|
||
URL[] bridgeURLs = urlBridgeLoader.getURLs(); | ||
return new URLClassLoader(bridgeURLs, | ||
new CompilerClassLoader(scalaLoader.getURLs(), sbtLoader)); | ||
} catch (NoSuchFieldException | IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* sbt -- Simple Build Tool | ||
* Copyright 2008, 2009 Mark Harrah | ||
*/ | ||
package xsbt; | ||
|
||
import xsbti.AnalysisCallback; | ||
import xsbti.Logger; | ||
import xsbti.Reporter; | ||
import xsbti.Severity; | ||
import xsbti.compile.*; | ||
|
||
import java.io.File; | ||
|
||
import dotty.tools.dotc.core.Contexts.ContextBase; | ||
import dotty.tools.dotc.Main; | ||
import dotty.tools.dotc.interfaces.*; | ||
|
||
import java.lang.reflect.InvocationTargetException; | ||
import java.net.URLClassLoader; | ||
|
||
public final class CompilerInterface { | ||
public CachedCompiler newCompiler(String[] options, Output output, Logger initialLog, Reporter initialDelegate) { | ||
// The classloader that sbt uses to load the compiler bridge is broken | ||
// (see CompilerClassLoader#fixBridgeLoader for details). To workaround | ||
// this we construct our own ClassLoader and then run the following code | ||
// with it: | ||
// new CachedCompilerImpl(options, output) | ||
|
||
try { | ||
ClassLoader bridgeLoader = this.getClass().getClassLoader(); | ||
ClassLoader fixedLoader = CompilerClassLoader.fixBridgeLoader(bridgeLoader); | ||
Class<?> cciClass = fixedLoader.loadClass("xsbt.CachedCompilerImpl"); | ||
return (CachedCompiler) cciClass.getConstructors()[0].newInstance(options, output); | ||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
public void run(File[] sources, DependencyChanges changes, AnalysisCallback callback, Logger log, | ||
Reporter delegate, CompileProgress progress, CachedCompiler cached) { | ||
cached.run(sources, changes, callback, log, delegate, progress); | ||
} | ||
} |
Oops, something went wrong.