Release generated bytecode after each processed part
Part here means separate '.kt' file or multi-file facade Now this memory optimization doesn't work with jar's, because there is no simple way to write them incrementally.
This commit is contained in:
@@ -36,8 +36,12 @@ public class ClassBuilderOnDemand extends DelegatingClassBuilder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void done() {
|
public void done() {
|
||||||
if (classBuilder.isComputed()) {
|
if (isComputed()) {
|
||||||
classBuilder.invoke().done();
|
classBuilder.invoke().done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isComputed() {
|
||||||
|
return classBuilder.isComputed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ public class ClassFileFactory implements OutputFileCollection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void releaseGeneratedOutput() {
|
||||||
|
generators.clear();
|
||||||
|
}
|
||||||
|
|
||||||
private void writeModuleMappings() {
|
private void writeModuleMappings() {
|
||||||
final JvmPackageTable.PackageTable.Builder builder = JvmPackageTable.PackageTable.newBuilder();
|
final JvmPackageTable.PackageTable.Builder builder = JvmPackageTable.PackageTable.newBuilder();
|
||||||
String outputFilePath = getMappingFileName(state.getModuleName());
|
String outputFilePath = getMappingFileName(state.getModuleName());
|
||||||
@@ -144,6 +148,11 @@ public class ClassFileFactory implements OutputFileCollection {
|
|||||||
@Override
|
@Override
|
||||||
public List<OutputFile> asList() {
|
public List<OutputFile> asList() {
|
||||||
done();
|
done();
|
||||||
|
return getCurrentOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public List<OutputFile> getCurrentOutput() {
|
||||||
return ContainerUtil.map(generators.keySet(), new Function<String, OutputFile>() {
|
return ContainerUtil.map(generators.keySet(), new Function<String, OutputFile>() {
|
||||||
@Override
|
@Override
|
||||||
public OutputFile fun(String relativeClassFilePath) {
|
public OutputFile fun(String relativeClassFilePath) {
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ class MultifileClassCodegen(
|
|||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
try {
|
try {
|
||||||
generatePart(file, generateCallableMemberTasks, partFqNames)
|
generatePart(file, generateCallableMemberTasks, partFqNames)
|
||||||
|
state.afterIndependentPart()
|
||||||
}
|
}
|
||||||
catch (e: ProcessCanceledException) {
|
catch (e: ProcessCanceledException) {
|
||||||
throw e
|
throw e
|
||||||
@@ -292,6 +293,9 @@ class MultifileClassCodegen(
|
|||||||
|
|
||||||
private fun done() {
|
private fun done() {
|
||||||
classBuilder.done()
|
classBuilder.done()
|
||||||
|
if (classBuilder.isComputed) {
|
||||||
|
state.afterIndependentPart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
|||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackageParts;
|
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
@@ -60,6 +59,7 @@ public class PackageCodegen {
|
|||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
try {
|
try {
|
||||||
generateFile(file);
|
generateFile(file);
|
||||||
|
state.afterIndependentPart();
|
||||||
}
|
}
|
||||||
catch (ProcessCanceledException e) {
|
catch (ProcessCanceledException e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ class GenerationState @JvmOverloads constructor(
|
|||||||
val outDirectory: File? = null,
|
val outDirectory: File? = null,
|
||||||
val incrementalCompilationComponents: IncrementalCompilationComponents? = null,
|
val incrementalCompilationComponents: IncrementalCompilationComponents? = null,
|
||||||
val generateOpenMultifileClasses: Boolean = false,
|
val generateOpenMultifileClasses: Boolean = false,
|
||||||
val progress: Progress = Progress.DEAF
|
val progress: Progress = Progress.DEAF,
|
||||||
|
private val onIndependentPartCompilationEnd: GenerationStateEventCallback = GenerationStateEventCallback.DO_NOTHING
|
||||||
) {
|
) {
|
||||||
abstract class GenerateClassFilter {
|
abstract class GenerateClassFilter {
|
||||||
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
|
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
|
||||||
@@ -170,6 +171,10 @@ class GenerationState @JvmOverloads constructor(
|
|||||||
CodegenBinding.initTrace(this)
|
CodegenBinding.initTrace(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun afterIndependentPart() {
|
||||||
|
onIndependentPartCompilationEnd(this)
|
||||||
|
}
|
||||||
|
|
||||||
private fun markUsed() {
|
private fun markUsed() {
|
||||||
if (used) throw IllegalStateException("${GenerationState::class.java} cannot be used more than once")
|
if (used) throw IllegalStateException("${GenerationState::class.java} cannot be used more than once")
|
||||||
|
|
||||||
@@ -197,3 +202,14 @@ private class LazyJvmDiagnostics(compute: () -> Diagnostics): Diagnostics {
|
|||||||
|
|
||||||
override fun iterator() = delegate.iterator()
|
override fun iterator() = delegate.iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GenerationStateEventCallback : (GenerationState) -> Unit {
|
||||||
|
companion object {
|
||||||
|
val DO_NOTHING = GenerationStateEventCallback { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GenerationStateEventCallback(block: (GenerationState) -> Unit): GenerationStateEventCallback =
|
||||||
|
object : GenerationStateEventCallback {
|
||||||
|
override fun invoke(s: GenerationState) = block(s)
|
||||||
|
}
|
||||||
|
|||||||
+36
-7
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.io.JarUtil
|
|||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics
|
import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics
|
||||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||||
|
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.CompilerPluginContext
|
import org.jetbrains.kotlin.cli.common.CompilerPluginContext
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
|||||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.addKotlinSourceRoots
|
import org.jetbrains.kotlin.config.addKotlinSourceRoots
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
@@ -82,6 +84,20 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createOutputFilesFlushingCallbackIfPossible(
|
||||||
|
configuration: CompilerConfiguration,
|
||||||
|
outputDir: File?,
|
||||||
|
jarPath: File?
|
||||||
|
): GenerationStateEventCallback {
|
||||||
|
if (jarPath != null) return GenerationStateEventCallback.DO_NOTHING
|
||||||
|
|
||||||
|
return GenerationStateEventCallback { state ->
|
||||||
|
val currentOutput = SimpleOutputFileCollection(state.factory.currentOutput)
|
||||||
|
writeOutput(configuration, currentOutput, outputDir, jarPath = null, jarRuntime = false, mainClass = null)
|
||||||
|
state.factory.releaseGeneratedOutput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun compileModules(
|
fun compileModules(
|
||||||
environment: KotlinCoreEnvironment,
|
environment: KotlinCoreEnvironment,
|
||||||
configuration: CompilerConfiguration,
|
configuration: CompilerConfiguration,
|
||||||
@@ -119,8 +135,13 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
environment.project, getAbsolutePaths(directory, module), configuration) { s -> throw IllegalStateException("Should have been checked before: " + s) }
|
environment.project, getAbsolutePaths(directory, module), configuration) { s -> throw IllegalStateException("Should have been checked before: " + s) }
|
||||||
if (!checkKotlinPackageUsage(environment, ktFiles)) return false
|
if (!checkKotlinPackageUsage(environment, ktFiles)) return false
|
||||||
val moduleOutputDirectory = File(module.getOutputDirectory())
|
val moduleOutputDirectory = File(module.getOutputDirectory())
|
||||||
|
|
||||||
|
val onIndependentPartCompilationEnd =
|
||||||
|
createOutputFilesFlushingCallbackIfPossible(configuration, File(module.getOutputDirectory()), jarPath)
|
||||||
|
|
||||||
val generationState = generate(environment, result, ktFiles, module, moduleOutputDirectory,
|
val generationState = generate(environment, result, ktFiles, module, moduleOutputDirectory,
|
||||||
module.getModuleName())
|
module.getModuleName(), onIndependentPartCompilationEnd)
|
||||||
|
|
||||||
outputFiles.put(module, generationState.factory)
|
outputFiles.put(module, generationState.factory)
|
||||||
generationStates.add(generationState);
|
generationStates.add(generationState);
|
||||||
}
|
}
|
||||||
@@ -192,7 +213,9 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!checkKotlinPackageUsage(environment, environment.getSourceFiles())) return false
|
if (!checkKotlinPackageUsage(environment, environment.getSourceFiles())) return false
|
||||||
val generationState = analyzeAndGenerate(environment) ?: return false
|
|
||||||
|
val onIndependentPartCompilationEnd = createOutputFilesFlushingCallbackIfPossible(environment.configuration, outputDir, jar)
|
||||||
|
val generationState = analyzeAndGenerate(environment, onIndependentPartCompilationEnd) ?: return false
|
||||||
|
|
||||||
val mainClass = findMainClass(generationState, environment.getSourceFiles())
|
val mainClass = findMainClass(generationState, environment.getSourceFiles())
|
||||||
|
|
||||||
@@ -247,7 +270,7 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
configuration: CompilerConfiguration,
|
configuration: CompilerConfiguration,
|
||||||
paths: KotlinPaths,
|
paths: KotlinPaths,
|
||||||
environment: KotlinCoreEnvironment): Class<*>? {
|
environment: KotlinCoreEnvironment): Class<*>? {
|
||||||
val state = analyzeAndGenerate(environment) ?: return null
|
val state = analyzeAndGenerate(environment, GenerationStateEventCallback.DO_NOTHING) ?: return null
|
||||||
|
|
||||||
val classLoader: GeneratedClassLoader
|
val classLoader: GeneratedClassLoader
|
||||||
try {
|
try {
|
||||||
@@ -266,14 +289,17 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
|
fun analyzeAndGenerate(
|
||||||
|
environment: KotlinCoreEnvironment,
|
||||||
|
onIndependentPartCompilationEnd: GenerationStateEventCallback
|
||||||
|
): GenerationState? {
|
||||||
val result = analyze(environment, null) ?: return null
|
val result = analyze(environment, null) ?: return null
|
||||||
|
|
||||||
if (!result.shouldGenerateCode) return null
|
if (!result.shouldGenerateCode) return null
|
||||||
|
|
||||||
result.throwIfError()
|
result.throwIfError()
|
||||||
|
|
||||||
return generate(environment, result, environment.getSourceFiles(), null, null, null)
|
return generate(environment, result, environment.getSourceFiles(), null, null, null, onIndependentPartCompilationEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyze(environment: KotlinCoreEnvironment, targetDescription: String?): AnalysisResult? {
|
private fun analyze(environment: KotlinCoreEnvironment, targetDescription: String?): AnalysisResult? {
|
||||||
@@ -331,7 +357,9 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
sourceFiles: List<KtFile>,
|
sourceFiles: List<KtFile>,
|
||||||
module: Module?,
|
module: Module?,
|
||||||
outputDirectory: File?,
|
outputDirectory: File?,
|
||||||
moduleName: String?): GenerationState {
|
moduleName: String?,
|
||||||
|
onIndependentPartCompilationEnd: GenerationStateEventCallback
|
||||||
|
): GenerationState {
|
||||||
val configuration = environment.configuration
|
val configuration = environment.configuration
|
||||||
val incrementalCompilationComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
val incrementalCompilationComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||||
|
|
||||||
@@ -369,7 +397,8 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
moduleName,
|
moduleName,
|
||||||
outputDirectory,
|
outputDirectory,
|
||||||
incrementalCompilationComponents,
|
incrementalCompilationComponents,
|
||||||
configuration.get(JVMConfigurationKeys.MULTIFILE_FACADES_OPEN, false))
|
configuration.get(JVMConfigurationKeys.MULTIFILE_FACADES_OPEN, false),
|
||||||
|
onIndependentPartCompilationEnd = onIndependentPartCompilationEnd)
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
val generationStart = PerformanceCounter.currentTime()
|
val generationStart = PerformanceCounter.currentTime()
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler;
|
|||||||
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
|
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
|
||||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
|
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback;
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
||||||
import org.jetbrains.kotlin.config.ContentRootsKt;
|
import org.jetbrains.kotlin.config.ContentRootsKt;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||||
@@ -61,7 +62,8 @@ public class StdlibTest extends KotlinTestWithEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testStdlib() throws ClassNotFoundException {
|
public void testStdlib() throws ClassNotFoundException {
|
||||||
GenerationState state = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(getEnvironment());
|
GenerationState state = KotlinToJVMBytecodeCompiler.INSTANCE.analyzeAndGenerate(
|
||||||
|
getEnvironment(), GenerationStateEventCallback.Companion.getDO_NOTHING());
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
fail("There were compilation errors");
|
fail("There were compilation errors");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user