KotlinToJVMBytecodeCompiler: J2K
This commit is contained in:
+248
-326
@@ -14,418 +14,343 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.cli.jvm.compiler;
|
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Joiner
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.collect.Collections2
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Lists
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Maps
|
||||||
import com.google.common.collect.Maps;
|
import com.intellij.util.ArrayUtil
|
||||||
import com.intellij.util.ArrayUtil;
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
import kotlin.Unit;
|
import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics
|
||||||
import kotlin.jvm.functions.Function0;
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import kotlin.jvm.functions.Function1;
|
import org.jetbrains.kotlin.cli.common.CompilerPluginContext
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
|
||||||
import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics;
|
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||||
import org.jetbrains.kotlin.cli.common.CompilerPlugin;
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.cli.common.CompilerPluginContext;
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport;
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
import org.jetbrains.kotlin.config.addKotlinSourceRoots
|
||||||
import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
|
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.JVMConfigurationKeys;
|
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
|
import org.jetbrains.kotlin.modules.Module
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.ModuleNameKt;
|
import org.jetbrains.kotlin.modules.TargetId
|
||||||
import org.jetbrains.kotlin.codegen.*;
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.config.ContentRootsKt;
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
import org.jetbrains.kotlin.context.ModuleContext;
|
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||||
import org.jetbrains.kotlin.idea.MainFunctionDetector;
|
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager;
|
import org.jetbrains.kotlin.utils.rethrow
|
||||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
|
import java.io.File
|
||||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents;
|
import java.lang.reflect.Constructor
|
||||||
import org.jetbrains.kotlin.modules.JavaRootPath;
|
import java.lang.reflect.InvocationTargetException
|
||||||
import org.jetbrains.kotlin.modules.Module;
|
import java.net.URL
|
||||||
import org.jetbrains.kotlin.modules.TargetId;
|
import java.net.URLClassLoader
|
||||||
import org.jetbrains.kotlin.modules.TargetIdKt;
|
import java.util.concurrent.TimeUnit
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
|
||||||
import org.jetbrains.kotlin.psi.KtScript;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM;
|
|
||||||
import org.jetbrains.kotlin.util.PerformanceCounter;
|
|
||||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
|
||||||
import org.jetbrains.kotlin.utils.KotlinPaths;
|
|
||||||
|
|
||||||
import java.io.File;
|
object KotlinToJVMBytecodeCompiler {
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class KotlinToJVMBytecodeCompiler {
|
private fun getAbsolutePaths(directory: File, module: Module): List<String> {
|
||||||
|
val result = Lists.newArrayList<String>()
|
||||||
|
|
||||||
private KotlinToJVMBytecodeCompiler() {
|
for (sourceFile in module.getSourceFiles()) {
|
||||||
}
|
var source = File(sourceFile)
|
||||||
|
if (!source.isAbsolute) {
|
||||||
@NotNull
|
source = File(directory, sourceFile)
|
||||||
private static List<String> getAbsolutePaths(@NotNull File directory, @NotNull Module module) {
|
|
||||||
List<String> result = Lists.newArrayList();
|
|
||||||
|
|
||||||
for (String sourceFile : module.getSourceFiles()) {
|
|
||||||
File source = new File(sourceFile);
|
|
||||||
if (!source.isAbsolute()) {
|
|
||||||
source = new File(directory, sourceFile);
|
|
||||||
}
|
}
|
||||||
result.add(source.getAbsolutePath());
|
result.add(source.absolutePath)
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeOutput(
|
private fun writeOutput(
|
||||||
@NotNull CompilerConfiguration configuration,
|
configuration: CompilerConfiguration,
|
||||||
@NotNull ClassFileFactory outputFiles,
|
outputFiles: ClassFileFactory,
|
||||||
@Nullable File outputDir,
|
outputDir: File?,
|
||||||
@Nullable File jarPath,
|
jarPath: File?,
|
||||||
boolean jarRuntime,
|
jarRuntime: Boolean,
|
||||||
@Nullable FqName mainClass
|
mainClass: FqName?) {
|
||||||
) {
|
|
||||||
if (jarPath != null) {
|
if (jarPath != null) {
|
||||||
CompileEnvironmentUtil.writeToJar(jarPath, jarRuntime, mainClass, outputFiles);
|
CompileEnvironmentUtil.writeToJar(jarPath, jarRuntime, mainClass, outputFiles)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MessageCollector messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE);
|
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
||||||
OutputUtilsKt.writeAll(outputFiles, outputDir == null ? new File(".") : outputDir, messageCollector);
|
outputFiles.writeAll(outputDir ?: File("."), messageCollector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean compileModules(
|
fun compileModules(
|
||||||
@NotNull KotlinCoreEnvironment environment,
|
environment: KotlinCoreEnvironment,
|
||||||
@NotNull CompilerConfiguration configuration,
|
configuration: CompilerConfiguration,
|
||||||
@NotNull List<Module> chunk,
|
chunk: List<Module>,
|
||||||
@NotNull File directory,
|
directory: File,
|
||||||
@Nullable File jarPath,
|
jarPath: File?,
|
||||||
@NotNull List<String> friendPaths,
|
friendPaths: List<String>,
|
||||||
boolean jarRuntime
|
jarRuntime: Boolean): Boolean {
|
||||||
) {
|
val outputFiles = Maps.newHashMap<Module, ClassFileFactory>()
|
||||||
Map<Module, ClassFileFactory> outputFiles = Maps.newHashMap();
|
|
||||||
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
ModuleVisibilityManager moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.getProject());
|
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project)
|
||||||
|
|
||||||
for (Module module: chunk) {
|
for (module in chunk) {
|
||||||
moduleVisibilityManager.addModule(module);
|
moduleVisibilityManager.addModule(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String path : friendPaths) {
|
for (path in friendPaths) {
|
||||||
moduleVisibilityManager.addFriendPath(path);
|
moduleVisibilityManager.addFriendPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
String targetDescription = "in targets [" + Joiner.on(", ").join(Collections2.transform(chunk, new Function<Module, String>() {
|
val targetDescription = "in targets [" + Joiner.on(", ").join(Collections2.transform(chunk) { input -> if (input != null) input.getModuleName() + "-" + input.getModuleType() else "<null>" }) + "] "
|
||||||
@Override
|
val result = analyze(environment, targetDescription) ?: return false
|
||||||
public String apply(@Nullable Module input) {
|
|
||||||
return input != null ? input.getModuleName() + "-" + input.getModuleType() : "<null>";
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
}
|
|
||||||
})) + "] ";
|
result.throwIfError()
|
||||||
AnalysisResult result = analyze(environment, targetDescription);
|
|
||||||
if (result == null) {
|
for (module in chunk) {
|
||||||
return false;
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
val jetFiles = CompileEnvironmentUtil.getKtFiles(
|
||||||
|
environment.project, getAbsolutePaths(directory, module)) { s -> throw IllegalStateException("Should have been checked before: " + s) }
|
||||||
|
val moduleOutputDirectory = File(module.getOutputDirectory())
|
||||||
|
val generationState = generate(environment, result, jetFiles, module, moduleOutputDirectory,
|
||||||
|
module.getModuleName())
|
||||||
|
outputFiles.put(module, generationState.factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
for (module in chunk) {
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
result.throwIfError();
|
writeOutput(configuration, outputFiles[module]!!, File(module.getOutputDirectory()), jarPath, jarRuntime, null)
|
||||||
|
|
||||||
for (Module module : chunk) {
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
List<KtFile> jetFiles = CompileEnvironmentUtil.getKtFiles(
|
|
||||||
environment.getProject(), getAbsolutePaths(directory, module), new Function1<String, Unit>() {
|
|
||||||
@Override
|
|
||||||
public Unit invoke(String s) {
|
|
||||||
throw new IllegalStateException("Should have been checked before: " + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
File moduleOutputDirectory = new File(module.getOutputDirectory());
|
|
||||||
GenerationState generationState =
|
|
||||||
generate(environment, result, jetFiles, module, moduleOutputDirectory,
|
|
||||||
module.getModuleName());
|
|
||||||
outputFiles.put(module, generationState.getFactory());
|
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
for (Module module : chunk) {
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
writeOutput(configuration, outputFiles.get(module), new File(module.getOutputDirectory()), jarPath, jarRuntime, null);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun createCompilerConfiguration(
|
||||||
public static CompilerConfiguration createCompilerConfiguration(
|
base: CompilerConfiguration,
|
||||||
@NotNull CompilerConfiguration base,
|
chunk: List<Module>,
|
||||||
@NotNull List<Module> chunk,
|
directory: File): CompilerConfiguration {
|
||||||
@NotNull File directory
|
val configuration = base.copy()
|
||||||
) {
|
|
||||||
CompilerConfiguration configuration = base.copy();
|
|
||||||
|
|
||||||
for (Module module : chunk) {
|
for (module in chunk) {
|
||||||
ContentRootsKt.addKotlinSourceRoots(configuration, getAbsolutePaths(directory, module));
|
configuration.addKotlinSourceRoots(getAbsolutePaths(directory, module))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Module module : chunk) {
|
for (module in chunk) {
|
||||||
for (JavaRootPath javaRootPath : module.getJavaSourceRoots()) {
|
for (javaRootPath in module.getJavaSourceRoots()) {
|
||||||
JvmContentRootsKt.addJavaSourceRoot(configuration, new File(javaRootPath.getPath()), javaRootPath.getPackagePrefix());
|
configuration.addJavaSourceRoot(File(javaRootPath.path), javaRootPath.packagePrefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Module module : chunk) {
|
for (module in chunk) {
|
||||||
for (String classpathRoot : module.getClasspathRoots()) {
|
for (classpathRoot in module.getClasspathRoots()) {
|
||||||
JvmContentRootsKt.addJvmClasspathRoot(configuration, new File(classpathRoot));
|
configuration.addJvmClasspathRoot(File(classpathRoot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Module module : chunk) {
|
for (module in chunk) {
|
||||||
configuration.add(JVMConfigurationKeys.MODULES, module);
|
configuration.add(JVMConfigurationKeys.MODULES, module)
|
||||||
}
|
}
|
||||||
|
|
||||||
return configuration;
|
return configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun findMainClass(generationState: GenerationState, files: List<KtFile>): FqName? {
|
||||||
private static FqName findMainClass(@NotNull GenerationState generationState, @NotNull List<KtFile> files) {
|
val mainFunctionDetector = MainFunctionDetector(generationState.bindingContext)
|
||||||
MainFunctionDetector mainFunctionDetector = new MainFunctionDetector(generationState.getBindingContext());
|
var mainClass: FqName? = null
|
||||||
FqName mainClass = null;
|
for (file in files) {
|
||||||
for (KtFile file : files) {
|
if (mainFunctionDetector.hasMain(file.declarations)) {
|
||||||
if (mainFunctionDetector.hasMain(file.getDeclarations())) {
|
|
||||||
if (mainClass != null) {
|
if (mainClass != null) {
|
||||||
// more than one main
|
// more than one main
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
FqName fqName = file.getPackageFqName();
|
val fqName = file.packageFqName
|
||||||
mainClass = JvmFileClassUtil.getFileClassInfoNoResolve(file).getFacadeClassFqName();
|
mainClass = JvmFileClassUtil.getFileClassInfoNoResolve(file).facadeClassFqName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mainClass;
|
return mainClass
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean compileBunchOfSources(
|
fun compileBunchOfSources(
|
||||||
@NotNull KotlinCoreEnvironment environment,
|
environment: KotlinCoreEnvironment,
|
||||||
@Nullable File jar,
|
jar: File?,
|
||||||
@Nullable File outputDir,
|
outputDir: File?,
|
||||||
@NotNull List<String> friendPaths,
|
friendPaths: List<String>,
|
||||||
boolean includeRuntime
|
includeRuntime: Boolean): Boolean {
|
||||||
) {
|
|
||||||
|
|
||||||
ModuleVisibilityManager moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.getProject());
|
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project)
|
||||||
|
|
||||||
for (String path : friendPaths) {
|
for (path in friendPaths) {
|
||||||
moduleVisibilityManager.addFriendPath(path);
|
moduleVisibilityManager.addFriendPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerationState generationState = analyzeAndGenerate(environment);
|
val generationState = analyzeAndGenerate(environment) ?: return false
|
||||||
if (generationState == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FqName mainClass = findMainClass(generationState, environment.getSourceFiles());
|
val mainClass = findMainClass(generationState, environment.getSourceFiles())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writeOutput(environment.getConfiguration(), generationState.getFactory(), outputDir, jar, includeRuntime, mainClass);
|
writeOutput(environment.configuration, generationState.factory, outputDir, jar, includeRuntime, mainClass)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
generationState.destroy();
|
generationState.destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void compileAndExecuteScript(
|
fun compileAndExecuteScript(
|
||||||
@NotNull CompilerConfiguration configuration,
|
configuration: CompilerConfiguration,
|
||||||
@NotNull KotlinPaths paths,
|
paths: KotlinPaths,
|
||||||
@NotNull KotlinCoreEnvironment environment,
|
environment: KotlinCoreEnvironment,
|
||||||
@NotNull List<String> scriptArgs
|
scriptArgs: List<String>) {
|
||||||
) {
|
val scriptClass = compileScript(configuration, paths, environment) ?: return
|
||||||
Class<?> scriptClass = compileScript(configuration, paths, environment);
|
val scriptConstructor = getScriptConstructor(scriptClass)
|
||||||
if (scriptClass == null) return;
|
|
||||||
Constructor<?> scriptConstructor = getScriptConstructor(scriptClass);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
scriptConstructor.newInstance(new Object[] {ArrayUtil.toStringArray(scriptArgs)});
|
scriptConstructor.newInstance(*arrayOf<Any>(ArrayUtil.toStringArray(scriptArgs)))
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (e: Throwable) {
|
||||||
reportExceptionFromScript(e);
|
reportExceptionFromScript(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void reportExceptionFromScript(@NotNull Throwable exception) {
|
private fun reportExceptionFromScript(exception: Throwable) {
|
||||||
// expecting InvocationTargetException from constructor invocation with cause that describes the actual cause
|
// expecting InvocationTargetException from constructor invocation with cause that describes the actual cause
|
||||||
PrintStream stream = System.err;
|
val stream = System.err
|
||||||
Throwable cause = exception.getCause();
|
val cause = exception.cause
|
||||||
if (!(exception instanceof InvocationTargetException) || cause == null) {
|
if (exception !is InvocationTargetException || cause == null) {
|
||||||
exception.printStackTrace(stream);
|
exception.printStackTrace(stream)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
stream.println(cause);
|
stream.println(cause)
|
||||||
StackTraceElement[] fullTrace = cause.getStackTrace();
|
val fullTrace = cause.getStackTrace()
|
||||||
int relevantEntries = fullTrace.length - exception.getStackTrace().length;
|
val relevantEntries = fullTrace.size - exception.getStackTrace().size
|
||||||
for (int i = 0; i < relevantEntries; i++) {
|
for (i in 0..relevantEntries - 1) {
|
||||||
stream.println("\tat " + fullTrace[i]);
|
stream.println("\tat " + fullTrace[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun getScriptConstructor(scriptClass: Class<*>): Constructor<*> {
|
||||||
private static Constructor<?> getScriptConstructor(Class<?> scriptClass) {
|
|
||||||
try {
|
try {
|
||||||
return scriptClass.getConstructor(String[].class);
|
return scriptClass.getConstructor(Array<String>::class.java)
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (e: NoSuchMethodException) {
|
||||||
throw ExceptionUtilsKt.rethrow(e);
|
throw rethrow(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
fun compileScript(
|
||||||
public static Class<?> compileScript(
|
configuration: CompilerConfiguration,
|
||||||
@NotNull CompilerConfiguration configuration,
|
paths: KotlinPaths,
|
||||||
@NotNull KotlinPaths paths,
|
environment: KotlinCoreEnvironment): Class<*>? {
|
||||||
@NotNull KotlinCoreEnvironment environment
|
val state = analyzeAndGenerate(environment) ?: return null
|
||||||
) {
|
|
||||||
GenerationState state = analyzeAndGenerate(environment);
|
|
||||||
if (state == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneratedClassLoader classLoader;
|
val classLoader: GeneratedClassLoader
|
||||||
try {
|
try {
|
||||||
List<URL> classPaths = Lists.newArrayList(paths.getRuntimePath().toURI().toURL());
|
val classPaths = Lists.newArrayList(paths.runtimePath.toURI().toURL())
|
||||||
for (File file : JvmContentRootsKt.getJvmClasspathRoots(configuration)) {
|
for (file in configuration.jvmClasspathRoots) {
|
||||||
classPaths.add(file.toURI().toURL());
|
classPaths.add(file.toURI().toURL())
|
||||||
}
|
}
|
||||||
//noinspection UnnecessaryFullyQualifiedName
|
//noinspection UnnecessaryFullyQualifiedName
|
||||||
classLoader = new GeneratedClassLoader(state.getFactory(),
|
classLoader = GeneratedClassLoader(state.factory,
|
||||||
new URLClassLoader(classPaths.toArray(new URL[classPaths.size()]), null)
|
URLClassLoader(classPaths.toArray<URL>(arrayOfNulls<URL>(classPaths.size)), null))
|
||||||
);
|
|
||||||
|
|
||||||
KtScript script = environment.getSourceFiles().get(0).getScript();
|
val script = environment.getSourceFiles()[0].script
|
||||||
assert script != null : "Script must be parsed";
|
assert(script != null) { "Script must be parsed" }
|
||||||
FqName nameForScript = script.getFqName();
|
val nameForScript = script!!.fqName
|
||||||
return classLoader.loadClass(nameForScript.asString());
|
return classLoader.loadClass(nameForScript.asString())
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (e: Exception) {
|
||||||
throw new RuntimeException("Failed to evaluate script: " + e, e);
|
throw RuntimeException("Failed to evaluate script: " + e, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
|
||||||
public static GenerationState analyzeAndGenerate(@NotNull KotlinCoreEnvironment environment) {
|
val result = analyze(environment, null) ?: return null
|
||||||
AnalysisResult result = analyze(environment, null);
|
|
||||||
|
|
||||||
if (result == null) {
|
if (!result.shouldGenerateCode) return null
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.getShouldGenerateCode()) return null;
|
result.throwIfError()
|
||||||
|
|
||||||
result.throwIfError();
|
return generate(environment, result, environment.getSourceFiles(), null, null, null)
|
||||||
|
|
||||||
return generate(environment, result, environment.getSourceFiles(), null, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private fun analyze(environment: KotlinCoreEnvironment, targetDescription: String?): AnalysisResult? {
|
||||||
private static AnalysisResult analyze(@NotNull final KotlinCoreEnvironment environment, @Nullable String targetDescription) {
|
val collector = environment.configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)!!
|
||||||
MessageCollector collector = environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY);
|
|
||||||
assert collector != null;
|
|
||||||
|
|
||||||
long analysisStart = PerformanceCounter.Companion.currentTime();
|
val analysisStart = PerformanceCounter.currentTime()
|
||||||
AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(collector);
|
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector)
|
||||||
analyzerWithCompilerReport.analyzeAndReport(
|
analyzerWithCompilerReport.analyzeAndReport(
|
||||||
environment.getSourceFiles(), new Function0<AnalysisResult>() {
|
environment.getSourceFiles(), {
|
||||||
@NotNull
|
val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
|
||||||
@Override
|
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project,
|
||||||
public AnalysisResult invoke() {
|
environment.getModuleName())
|
||||||
BindingTrace sharedTrace = new CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace();
|
|
||||||
ModuleContext moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.getProject(),
|
|
||||||
ModuleNameKt
|
|
||||||
.getModuleName(environment));
|
|
||||||
|
|
||||||
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
|
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
|
||||||
moduleContext,
|
moduleContext,
|
||||||
environment.getSourceFiles(),
|
environment.getSourceFiles(),
|
||||||
sharedTrace,
|
sharedTrace,
|
||||||
environment.getConfiguration().get(JVMConfigurationKeys.MODULES),
|
environment.configuration.get(JVMConfigurationKeys.MODULES),
|
||||||
environment.getConfiguration().get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS),
|
environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS),
|
||||||
new JvmPackagePartProvider(environment)
|
JvmPackagePartProvider(environment))
|
||||||
);
|
})
|
||||||
}
|
val analysisNanos = PerformanceCounter.currentTime() - analysisStart
|
||||||
}
|
val message = "ANALYZE: " + environment.getSourceFiles().size + " files (" +
|
||||||
);
|
environment.sourceLinesOfCode + " lines) " +
|
||||||
long analysisNanos = PerformanceCounter.Companion.currentTime() - analysisStart;
|
(targetDescription ?: "") +
|
||||||
String message = "ANALYZE: " + environment.getSourceFiles().size() + " files (" +
|
"in " + TimeUnit.NANOSECONDS.toMillis(analysisNanos) + " ms"
|
||||||
environment.getSourceLinesOfCode() + " lines) " +
|
K2JVMCompiler.reportPerf(environment.configuration, message)
|
||||||
(targetDescription != null ? targetDescription : "") +
|
|
||||||
"in " + TimeUnit.NANOSECONDS.toMillis(analysisNanos) + " ms";
|
|
||||||
K2JVMCompiler.Companion.reportPerf(environment.getConfiguration(), message);
|
|
||||||
|
|
||||||
AnalysisResult result = analyzerWithCompilerReport.getAnalysisResult();
|
val result = analyzerWithCompilerReport.getAnalysisResult()
|
||||||
assert result != null : "AnalysisResult should be non-null, compiling: " + environment.getSourceFiles();
|
assert(result != null) { "AnalysisResult should be non-null, compiling: " + environment.getSourceFiles() }
|
||||||
|
|
||||||
CompilerPluginContext context = new CompilerPluginContext(environment.getProject(), result.getBindingContext(),
|
val context = CompilerPluginContext(environment.project, result!!.bindingContext,
|
||||||
environment.getSourceFiles());
|
environment.getSourceFiles())
|
||||||
for (CompilerPlugin plugin : environment.getConfiguration().getList(CLIConfigurationKeys.COMPILER_PLUGINS)) {
|
for (plugin in environment.configuration.getList(CLIConfigurationKeys.COMPILER_PLUGINS)) {
|
||||||
plugin.processFiles(context);
|
plugin.processFiles(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
return analyzerWithCompilerReport.hasErrors() ? null : result;
|
return if (analyzerWithCompilerReport.hasErrors()) null else result
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun generate(
|
||||||
private static GenerationState generate(
|
environment: KotlinCoreEnvironment,
|
||||||
@NotNull KotlinCoreEnvironment environment,
|
result: AnalysisResult,
|
||||||
@NotNull AnalysisResult result,
|
sourceFiles: List<KtFile>,
|
||||||
@NotNull List<KtFile> sourceFiles,
|
module: Module?,
|
||||||
@Nullable Module module,
|
outputDirectory: File?,
|
||||||
File outputDirectory,
|
moduleName: String?): GenerationState {
|
||||||
String moduleName
|
val configuration = environment.configuration
|
||||||
) {
|
val incrementalCompilationComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||||
CompilerConfiguration configuration = environment.getConfiguration();
|
|
||||||
IncrementalCompilationComponents incrementalCompilationComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS);
|
|
||||||
|
|
||||||
Collection<FqName> packagesWithObsoleteParts;
|
val packagesWithObsoleteParts = hashSetOf<FqName>()
|
||||||
List<FqName> obsoleteMultifileClasses;
|
val obsoleteMultifileClasses = arrayListOf<FqName>()
|
||||||
TargetId targetId = null;
|
var targetId: TargetId? = null
|
||||||
|
|
||||||
if (module == null || incrementalCompilationComponents == null) {
|
if (module != null && incrementalCompilationComponents != null) {
|
||||||
packagesWithObsoleteParts = Collections.emptySet();
|
targetId = TargetId(module)
|
||||||
obsoleteMultifileClasses = Collections.emptyList();
|
val incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId)
|
||||||
}
|
|
||||||
else {
|
|
||||||
targetId = TargetIdKt.TargetId(module);
|
|
||||||
IncrementalCache incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId);
|
|
||||||
|
|
||||||
packagesWithObsoleteParts = new HashSet<FqName>();
|
for (internalName in incrementalCache.getObsoletePackageParts()) {
|
||||||
for (String internalName : incrementalCache.getObsoletePackageParts()) {
|
packagesWithObsoleteParts.add(JvmClassName.byInternalName(internalName).packageFqName)
|
||||||
packagesWithObsoleteParts.add(JvmClassName.byInternalName(internalName).getPackageFqName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obsoleteMultifileClasses = new ArrayList<FqName>();
|
for (obsoleteFacadeInternalName in incrementalCache.getObsoleteMultifileClasses()) {
|
||||||
for (String obsoleteFacadeInternalName : incrementalCache.getObsoleteMultifileClasses()) {
|
obsoleteMultifileClasses.add(JvmClassName.byInternalName(obsoleteFacadeInternalName).fqNameForClassNameWithoutDollars)
|
||||||
obsoleteMultifileClasses.add(JvmClassName.byInternalName(obsoleteFacadeInternalName).getFqNameForClassNameWithoutDollars());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenerationState generationState = new GenerationState(
|
val generationState = GenerationState(
|
||||||
environment.getProject(),
|
environment.project,
|
||||||
ClassBuilderFactories.BINARIES,
|
ClassBuilderFactories.BINARIES,
|
||||||
result.getModuleDescriptor(),
|
result.moduleDescriptor,
|
||||||
result.getBindingContext(),
|
result.bindingContext,
|
||||||
sourceFiles,
|
sourceFiles,
|
||||||
configuration.get(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, false),
|
configuration.get(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, false),
|
||||||
configuration.get(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, false),
|
configuration.get(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, false),
|
||||||
@@ -439,29 +364,26 @@ public class KotlinToJVMBytecodeCompiler {
|
|||||||
moduleName,
|
moduleName,
|
||||||
outputDirectory,
|
outputDirectory,
|
||||||
incrementalCompilationComponents,
|
incrementalCompilationComponents,
|
||||||
configuration.get(JVMConfigurationKeys.MULTIFILE_FACADES_OPEN, false)
|
configuration.get(JVMConfigurationKeys.MULTIFILE_FACADES_OPEN, false))
|
||||||
);
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
|
|
||||||
long generationStart = PerformanceCounter.Companion.currentTime();
|
val generationStart = PerformanceCounter.currentTime()
|
||||||
|
|
||||||
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION);
|
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
|
||||||
|
|
||||||
long generationNanos = PerformanceCounter.Companion.currentTime() - generationStart;
|
val generationNanos = PerformanceCounter.currentTime() - generationStart
|
||||||
String desc = module != null ? "target " + module.getModuleName() + "-" + module.getModuleType() + " " : "";
|
val desc = if (module != null) "target " + module.getModuleName() + "-" + module.getModuleType() + " " else ""
|
||||||
String message = "GENERATE: " + sourceFiles.size() + " files (" +
|
val message = "GENERATE: " + sourceFiles.size + " files (" +
|
||||||
environment.countLinesOfCode(sourceFiles) + " lines) " + desc + "in " + TimeUnit.NANOSECONDS.toMillis(generationNanos) + " ms";
|
environment.countLinesOfCode(sourceFiles) + " lines) " + desc + "in " + TimeUnit.NANOSECONDS.toMillis(generationNanos) + " ms"
|
||||||
K2JVMCompiler.Companion.reportPerf(environment.getConfiguration(), message);
|
K2JVMCompiler.reportPerf(environment.configuration, message)
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
AnalyzerWithCompilerReport.reportDiagnostics(
|
AnalyzerWithCompilerReport.reportDiagnostics(
|
||||||
new FilteredJvmDiagnostics(
|
FilteredJvmDiagnostics(
|
||||||
generationState.getCollectedExtraJvmDiagnostics(),
|
generationState.collectedExtraJvmDiagnostics,
|
||||||
result.getBindingContext().getDiagnostics()
|
result.bindingContext.diagnostics),
|
||||||
),
|
environment.configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)!!)
|
||||||
environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
);
|
return generationState
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
return generationState;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class StdlibTest extends KotlinTestWithEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testStdlib() throws ClassNotFoundException {
|
public void testStdlib() throws ClassNotFoundException {
|
||||||
GenerationState state = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(getEnvironment());
|
GenerationState state = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(getEnvironment());
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
fail("There were compilation errors");
|
fail("There were compilation errors");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.config.ContentRootsKt;
|
|||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform;
|
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform;
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition;
|
import org.jetbrains.kotlin.script.KotlinScriptDefinition;
|
||||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider;
|
|
||||||
import org.jetbrains.kotlin.script.ScriptParameter;
|
import org.jetbrains.kotlin.script.ScriptParameter;
|
||||||
import org.jetbrains.kotlin.test.ConfigurationKind;
|
import org.jetbrains.kotlin.test.ConfigurationKind;
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
@@ -87,7 +86,7 @@ public class ScriptTest {
|
|||||||
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return KotlinToJVMBytecodeCompiler.compileScript(configuration, paths, environment);
|
return KotlinToJVMBytecodeCompiler.INSTANCE.compileScript(configuration, paths, environment);
|
||||||
}
|
}
|
||||||
catch (CompilationException e) {
|
catch (CompilationException e) {
|
||||||
messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
|
messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
|
||||||
|
|||||||
Reference in New Issue
Block a user