diff --git a/build.xml b/build.xml index 1bf76646246..3e8a240633d 100644 --- a/build.xml +++ b/build.xml @@ -781,7 +781,7 @@ - + diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt index 89a29034dfb..6c931e151dd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.MemberComparator import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClass import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClassPart import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin @@ -50,6 +51,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import java.util.* public class MultifileClassCodegen( @@ -86,12 +88,18 @@ public class MultifileClassCodegen( val singleSourceFile = if (previouslyCompiledCallables.isNotEmpty()) null else filesWithCallables.singleOrNull() - classBuilder.defineClass(singleSourceFile, Opcodes.V1_6, FACADE_CLASS_ATTRIBUTES, + classBuilder.defineClass(singleSourceFile, Opcodes.V1_6, + if (state.generateOpenMultifileClasses) OPEN_FACADE_CLASS_ATTRIBUTES else FACADE_CLASS_ATTRIBUTES, facadeClassType.internalName, null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY) if (singleSourceFile != null) { classBuilder.visitSource(singleSourceFile.name, null) } + + if (state.generateOpenMultifileClasses) { + generateMultifileFacadeClassConstructor(classBuilder, originFile) + } + classBuilder } @@ -148,6 +156,16 @@ public class MultifileClassCodegen( MemberCodegen.genClassOrObject(packagePartContext, classOrObject, state, null) } + + private fun generateMultifileFacadeClassConstructor(classBuilder: ClassBuilder, originFile: KtFile?) { + val mv = classBuilder.newMethod(JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_PUBLIC, "", "()V", null, null) + val v = InstructionAdapter(mv) + v.load(0, facadeClassType) + v.invokespecial("java/lang/Object", "", "()V", false) + v.visitInsn(Opcodes.RETURN) + FunctionCodegen.endVisit(v, "multifile class constructor", originFile) + } + private fun generatePart( file: KtFile, generateCallableMemberTasks: MutableMap Unit>, @@ -280,6 +298,7 @@ public class MultifileClassCodegen( companion object { private val FACADE_CLASS_ATTRIBUTES = Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL + private val OPEN_FACADE_CLASS_ATTRIBUTES = Opcodes.ACC_PUBLIC private fun getOnlyPackageFragment(packageFqName: FqName, files: Collection, bindingContext: BindingContext): PackageFragmentDescriptor? { val fragments = SmartList() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index 671d8652f16..14f6269efa6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -66,6 +66,7 @@ public class GenerationState @JvmOverloads constructor( // TODO: get rid of it with the proper module infrastructure public val outDirectory: File? = null, public val incrementalCompilationComponents: IncrementalCompilationComponents? = null, + public val generateOpenMultifileClasses: Boolean = false, public val progress: Progress = Progress.DEAF ) { public abstract class GenerateClassFilter { diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java index 74710a50d2e..191df7eec40 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java @@ -64,6 +64,9 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments { @Argument(value = "Xreport-perf", description = "Report detailed performance statistics") public boolean reportPerf; + @Argument(value = "Xmultifile-facades-open", description = "Compile multifile facade classes as open") + public boolean multifileFacadesOpen; + // Paths to output directories for friend modules. public String[] friendPaths; 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 65be6f61d5a..6d584bfcd8e 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -275,6 +275,7 @@ public open class K2JVMCompiler : CLICompiler() { configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions) configuration.put(JVMConfigurationKeys.DISABLE_INLINE, arguments.noInline) configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize) + configuration.put(JVMConfigurationKeys.MULTIFILE_FACADES_OPEN, arguments.multifileFacadesOpen); } private fun getClasspath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): List { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index b3264c7f23b..a92e3c245eb 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -438,7 +438,8 @@ public class KotlinToJVMBytecodeCompiler { targetId, moduleName, outputDirectory, - incrementalCompilationComponents + incrementalCompilationComponents, + configuration.get(JVMConfigurationKeys.MULTIFILE_FACADES_OPEN, false) ); ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JVMConfigurationKeys.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JVMConfigurationKeys.java index fe62938e683..ff86335cb94 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JVMConfigurationKeys.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JVMConfigurationKeys.java @@ -35,6 +35,8 @@ public class JVMConfigurationKeys { CompilerConfigurationKey.create("disable inline"); public static final CompilerConfigurationKey DISABLE_OPTIMIZATION = CompilerConfigurationKey.create("disable optimization"); + public static final CompilerConfigurationKey MULTIFILE_FACADES_OPEN = + CompilerConfigurationKey.create("compile multifile facade classes as open"); public static final CompilerConfigurationKey INCREMENTAL_COMPILATION_COMPONENTS = CompilerConfigurationKey.create("incremental cache provider"); diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 5bc3a7a881d..a39536a38ac 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -4,6 +4,7 @@ where advanced options include: -Xno-param-assertions Don't generate not-null assertions on parameters of methods accessible from Java -Xno-optimize Disable optimizations -Xreport-perf Report detailed performance statistics + -Xmultifile-facades-open Compile multifile facade classes as open -Xno-inline Disable method inlining -Xrepeat Repeat compilation (for performance analysis) -Xplugin Load plugins from the given classpath diff --git a/libraries/stdlib/pom.xml b/libraries/stdlib/pom.xml index 0b03eac4279..39c70b84248 100644 --- a/libraries/stdlib/pom.xml +++ b/libraries/stdlib/pom.xml @@ -31,6 +31,12 @@ kotlin-maven-plugin ${project.version} + + + -Xmultifile-facades-open + + + compile