diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index fb87133abaf..057c0fca1f5 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -166,6 +166,7 @@ class K2JVMCompiler : CLICompiler() { } else if (arguments.script) { val scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) val environment = createCoreEnvironment(rootDisposable, configuration) if (messageCollector.hasErrors()) return COMPILATION_ERROR diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index 9414cbc8e8e..77f632804c4 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics import org.jetbrains.kotlin.backend.common.output.OutputFileCollection import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.messages.* @@ -51,23 +50,19 @@ import org.jetbrains.kotlin.name.isSubpackageOf import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM -import org.jetbrains.kotlin.script.getScriptDefinition import org.jetbrains.kotlin.util.PerformanceCounter import org.jetbrains.kotlin.utils.KotlinPaths import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize import java.io.File import java.io.IOException -import java.lang.reflect.Constructor import java.lang.reflect.InvocationTargetException import java.net.URLClassLoader import java.util.concurrent.TimeUnit import java.util.jar.Attributes -import kotlin.reflect.KClass import kotlin.reflect.KParameter import kotlin.reflect.KType import kotlin.reflect.defaultType -import kotlin.reflect.jvm.javaMethod import kotlin.reflect.jvm.javaType object KotlinToJVMBytecodeCompiler { @@ -106,7 +101,9 @@ object KotlinToJVMBytecodeCompiler { return GenerationStateEventCallback { state -> val currentOutput = SimpleOutputFileCollection(state.factory.currentOutput) writeOutput(configuration, currentOutput, mainClass = null) - state.factory.releaseGeneratedOutput() + if (!configuration.get(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false)) { + state.factory.releaseGeneratedOutput() + } } } @@ -346,9 +343,8 @@ object KotlinToJVMBytecodeCompiler { makeParentClassLoader: () -> ClassLoader): Class<*>? { val state = analyzeAndGenerate(environment) ?: return null - val classLoader: GeneratedClassLoader try { - classLoader = GeneratedClassLoader(state.factory, makeParentClassLoader(), null) + val classLoader = GeneratedClassLoader(state.factory, makeParentClassLoader(), null) val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed") return classLoader.loadClass(script.fqName.asString()) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 69ca952a5eb..d4f145ede8a 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -41,6 +41,9 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey> SCRIPT_DEFINITIONS = CompilerConfigurationKey.create("script definitions"); + public static final CompilerConfigurationKey RETAIN_OUTPUT_IN_MEMORY = + CompilerConfigurationKey.create("retain compiled classes in memory for further use, e.g. when running scripts"); + public static final CompilerConfigurationKey DISABLE_CALL_ASSERTIONS = CompilerConfigurationKey.create("disable not-null call assertions"); public static final CompilerConfigurationKey DISABLE_PARAM_ASSERTIONS = diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt index adb35fa87c7..d36c4e46060 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt @@ -17,13 +17,13 @@ package org.jetbrains.kotlin.scripts import com.intellij.openapi.util.Disposer +import junit.framework.TestCase import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler -import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot import org.jetbrains.kotlin.codegen.CompilationException import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.addKotlinSourceRoot @@ -39,8 +39,9 @@ import org.junit.Assert import org.junit.Test import java.io.File import java.lang.reflect.InvocationTargetException +import java.net.URLClassLoader -class ScriptTest { +class ScriptTest: TestCase() { @Test fun testScriptWithParam() { val aClass = compileScript("fib.kts", SimpleParamsTestScriptDefinition(".kts", numIntParam())) @@ -64,6 +65,21 @@ class ScriptTest { Assert.assertNotNull(anObj) } + @Test + fun testStandardScriptWithSaving() { + val tmpdir = File(KotlinTestUtils.tmpDirForTest(this), "withSaving") + tmpdir.mkdirs() + val aClass = compileScript("fib_std.kts", StandardScriptDefinition, saveClassesDir = tmpdir) + Assert.assertNotNull(aClass) + val anObj = KotlinToJVMBytecodeCompiler.tryConstructClassPub(aClass!!, emptyList()) + Assert.assertNotNull(anObj) + val savedClassLoader = URLClassLoader(arrayOf(tmpdir.toURI().toURL())) + val aClassSaved = savedClassLoader.loadClass(aClass.name) + Assert.assertNotNull(aClassSaved) + val anObjSaved = KotlinToJVMBytecodeCompiler.tryConstructClassPub(aClassSaved!!, emptyList()) + Assert.assertNotNull(anObjSaved) + } + @Test fun testScriptWithParamConversion() { val aClass = compileScript("fib.kts", SimpleParamsTestScriptDefinition(".kts", numIntParam())) @@ -163,21 +179,24 @@ class ScriptTest { scriptPath: String, scriptDefinition: KotlinScriptDefinition, runIsolated: Boolean = true, - suppressOutput: Boolean = false): Class<*>? = - compileScriptImpl("compiler/testData/script/" + scriptPath, scriptDefinition, runIsolated, suppressOutput) + suppressOutput: Boolean = false, + saveClassesDir: File? = null): Class<*>? = + compileScriptImpl("compiler/testData/script/" + scriptPath, scriptDefinition, runIsolated, suppressOutput, saveClassesDir) private fun compileSmokeTestScript( scriptPath: String, scriptDefinition: KotlinScriptDefinition, runIsolated: Boolean = true, - suppressOutput: Boolean = false): Class<*>? = - compileScriptImpl("compiler/testData/integration/smoke/" + scriptPath, scriptDefinition, runIsolated, suppressOutput) + suppressOutput: Boolean = false, + saveClassesDir: File? = null): Class<*>? = + compileScriptImpl("compiler/testData/integration/smoke/" + scriptPath, scriptDefinition, runIsolated, suppressOutput, saveClassesDir) private fun compileScriptImpl( scriptPath: String, scriptDefinition: KotlinScriptDefinition, runIsolated: Boolean, - suppressOutput: Boolean): Class<*>? + suppressOutput: Boolean, + saveClassesDir: File? = null): Class<*>? { val paths = PathUtil.getKotlinPathsForDistDirectory() val messageCollector = @@ -190,6 +209,10 @@ class ScriptTest { configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) configuration.addKotlinSourceRoot(scriptPath) configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + if (saveClassesDir != null) { + configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, saveClassesDir) + } val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt index b727162c209..f8b139ac1d6 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt @@ -91,6 +91,7 @@ class ScriptTest2 { configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) configuration.addKotlinSourceRoot(scriptPath) configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)