Add support for script classfiles caching
This commit is contained in:
committed by
Pavel V. Talanov
parent
3157421189
commit
8dac72f465
@@ -166,6 +166,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
|||||||
}
|
}
|
||||||
else if (arguments.script) {
|
else if (arguments.script) {
|
||||||
val scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size)
|
val scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size)
|
||||||
|
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||||
val environment = createCoreEnvironment(rootDisposable, configuration)
|
val environment = createCoreEnvironment(rootDisposable, configuration)
|
||||||
if (messageCollector.hasErrors()) return COMPILATION_ERROR
|
if (messageCollector.hasErrors()) return COMPILATION_ERROR
|
||||||
|
|
||||||
|
|||||||
+4
-8
@@ -22,7 +22,6 @@ 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.backend.common.output.SimpleOutputFileCollection
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
import org.jetbrains.kotlin.cli.common.messages.*
|
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.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
||||||
import org.jetbrains.kotlin.script.getScriptDefinition
|
|
||||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||||
import org.jetbrains.kotlin.utils.PathUtil
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
|
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.reflect.Constructor
|
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.jar.Attributes
|
import java.util.jar.Attributes
|
||||||
import kotlin.reflect.KClass
|
|
||||||
import kotlin.reflect.KParameter
|
import kotlin.reflect.KParameter
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
import kotlin.reflect.defaultType
|
import kotlin.reflect.defaultType
|
||||||
import kotlin.reflect.jvm.javaMethod
|
|
||||||
import kotlin.reflect.jvm.javaType
|
import kotlin.reflect.jvm.javaType
|
||||||
|
|
||||||
object KotlinToJVMBytecodeCompiler {
|
object KotlinToJVMBytecodeCompiler {
|
||||||
@@ -106,7 +101,9 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
return GenerationStateEventCallback { state ->
|
return GenerationStateEventCallback { state ->
|
||||||
val currentOutput = SimpleOutputFileCollection(state.factory.currentOutput)
|
val currentOutput = SimpleOutputFileCollection(state.factory.currentOutput)
|
||||||
writeOutput(configuration, currentOutput, mainClass = null)
|
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<*>? {
|
makeParentClassLoader: () -> ClassLoader): Class<*>? {
|
||||||
val state = analyzeAndGenerate(environment) ?: return null
|
val state = analyzeAndGenerate(environment) ?: return null
|
||||||
|
|
||||||
val classLoader: GeneratedClassLoader
|
|
||||||
try {
|
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")
|
val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed")
|
||||||
return classLoader.loadClass(script.fqName.asString())
|
return classLoader.loadClass(script.fqName.asString())
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ public class JVMConfigurationKeys {
|
|||||||
public static final CompilerConfigurationKey<List<KotlinScriptDefinition>> SCRIPT_DEFINITIONS =
|
public static final CompilerConfigurationKey<List<KotlinScriptDefinition>> SCRIPT_DEFINITIONS =
|
||||||
CompilerConfigurationKey.create("script definitions");
|
CompilerConfigurationKey.create("script definitions");
|
||||||
|
|
||||||
|
public static final CompilerConfigurationKey<Boolean> RETAIN_OUTPUT_IN_MEMORY =
|
||||||
|
CompilerConfigurationKey.create("retain compiled classes in memory for further use, e.g. when running scripts");
|
||||||
|
|
||||||
public static final CompilerConfigurationKey<Boolean> DISABLE_CALL_ASSERTIONS =
|
public static final CompilerConfigurationKey<Boolean> DISABLE_CALL_ASSERTIONS =
|
||||||
CompilerConfigurationKey.create("disable not-null call assertions");
|
CompilerConfigurationKey.create("disable not-null call assertions");
|
||||||
public static final CompilerConfigurationKey<Boolean> DISABLE_PARAM_ASSERTIONS =
|
public static final CompilerConfigurationKey<Boolean> DISABLE_PARAM_ASSERTIONS =
|
||||||
|
|||||||
@@ -17,13 +17,13 @@
|
|||||||
package org.jetbrains.kotlin.scripts
|
package org.jetbrains.kotlin.scripts
|
||||||
|
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.messages.*
|
import org.jetbrains.kotlin.cli.common.messages.*
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
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.codegen.CompilationException
|
||||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.addKotlinSourceRoot
|
import org.jetbrains.kotlin.config.addKotlinSourceRoot
|
||||||
@@ -39,8 +39,9 @@ import org.junit.Assert
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
|
||||||
class ScriptTest {
|
class ScriptTest: TestCase() {
|
||||||
@Test
|
@Test
|
||||||
fun testScriptWithParam() {
|
fun testScriptWithParam() {
|
||||||
val aClass = compileScript("fib.kts", SimpleParamsTestScriptDefinition(".kts", numIntParam()))
|
val aClass = compileScript("fib.kts", SimpleParamsTestScriptDefinition(".kts", numIntParam()))
|
||||||
@@ -64,6 +65,21 @@ class ScriptTest {
|
|||||||
Assert.assertNotNull(anObj)
|
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
|
@Test
|
||||||
fun testScriptWithParamConversion() {
|
fun testScriptWithParamConversion() {
|
||||||
val aClass = compileScript("fib.kts", SimpleParamsTestScriptDefinition(".kts", numIntParam()))
|
val aClass = compileScript("fib.kts", SimpleParamsTestScriptDefinition(".kts", numIntParam()))
|
||||||
@@ -163,21 +179,24 @@ class ScriptTest {
|
|||||||
scriptPath: String,
|
scriptPath: String,
|
||||||
scriptDefinition: KotlinScriptDefinition,
|
scriptDefinition: KotlinScriptDefinition,
|
||||||
runIsolated: Boolean = true,
|
runIsolated: Boolean = true,
|
||||||
suppressOutput: Boolean = false): Class<*>? =
|
suppressOutput: Boolean = false,
|
||||||
compileScriptImpl("compiler/testData/script/" + scriptPath, scriptDefinition, runIsolated, suppressOutput)
|
saveClassesDir: File? = null): Class<*>? =
|
||||||
|
compileScriptImpl("compiler/testData/script/" + scriptPath, scriptDefinition, runIsolated, suppressOutput, saveClassesDir)
|
||||||
|
|
||||||
private fun compileSmokeTestScript(
|
private fun compileSmokeTestScript(
|
||||||
scriptPath: String,
|
scriptPath: String,
|
||||||
scriptDefinition: KotlinScriptDefinition,
|
scriptDefinition: KotlinScriptDefinition,
|
||||||
runIsolated: Boolean = true,
|
runIsolated: Boolean = true,
|
||||||
suppressOutput: Boolean = false): Class<*>? =
|
suppressOutput: Boolean = false,
|
||||||
compileScriptImpl("compiler/testData/integration/smoke/" + scriptPath, scriptDefinition, runIsolated, suppressOutput)
|
saveClassesDir: File? = null): Class<*>? =
|
||||||
|
compileScriptImpl("compiler/testData/integration/smoke/" + scriptPath, scriptDefinition, runIsolated, suppressOutput, saveClassesDir)
|
||||||
|
|
||||||
private fun compileScriptImpl(
|
private fun compileScriptImpl(
|
||||||
scriptPath: String,
|
scriptPath: String,
|
||||||
scriptDefinition: KotlinScriptDefinition,
|
scriptDefinition: KotlinScriptDefinition,
|
||||||
runIsolated: Boolean,
|
runIsolated: Boolean,
|
||||||
suppressOutput: Boolean): Class<*>?
|
suppressOutput: Boolean,
|
||||||
|
saveClassesDir: File? = null): Class<*>?
|
||||||
{
|
{
|
||||||
val paths = PathUtil.getKotlinPathsForDistDirectory()
|
val paths = PathUtil.getKotlinPathsForDistDirectory()
|
||||||
val messageCollector =
|
val messageCollector =
|
||||||
@@ -190,6 +209,10 @@ class ScriptTest {
|
|||||||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||||
configuration.addKotlinSourceRoot(scriptPath)
|
configuration.addKotlinSourceRoot(scriptPath)
|
||||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
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)
|
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ class ScriptTest2 {
|
|||||||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||||
configuration.addKotlinSourceRoot(scriptPath)
|
configuration.addKotlinSourceRoot(scriptPath)
|
||||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
|
||||||
|
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||||
|
|
||||||
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user