Report error on state in multi-file class with -Xmultifile-parts-inherit
Simplify MultifileClassPartCodegen, remove related tests and change some tests to use const val instead of val because backing fields for const properties are stored in the facade, not parts #KT-23701 Fixed
This commit is contained in:
@@ -659,8 +659,6 @@ public class FunctionCodegen {
|
||||
genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap);
|
||||
}
|
||||
|
||||
parentCodegen.beforeMethodBody(mv);
|
||||
|
||||
methodEnd = new Label();
|
||||
context.setMethodEndLabel(methodEnd);
|
||||
strategy.generateBody(mv, frameMap, signature, context, parentCodegen);
|
||||
|
||||
@@ -455,17 +455,13 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
if (clInit == null) {
|
||||
DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
|
||||
SimpleFunctionDescriptorImpl clInitDescriptor = createClInitFunctionDescriptor(contextDescriptor);
|
||||
MethodVisitor mv = createClInitMethodVisitor(contextDescriptor);
|
||||
MethodVisitor mv =
|
||||
v.newMethod(JvmDeclarationOriginKt.OtherOrigin(contextDescriptor), ACC_STATIC, "<clinit>", "()V", null, null);
|
||||
clInit = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInitDescriptor), state, this);
|
||||
}
|
||||
return clInit;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodVisitor createClInitMethodVisitor(@NotNull DeclarationDescriptor contextDescriptor) {
|
||||
return v.newMethod(JvmDeclarationOriginKt.OtherOrigin(contextDescriptor), ACC_STATIC, "<clinit>", "()V", null, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private SimpleFunctionDescriptorImpl createClInitFunctionDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
SimpleFunctionDescriptorImpl clInit = SimpleFunctionDescriptorImpl.create(descriptor, Annotations.Companion.getEMPTY(),
|
||||
@@ -496,9 +492,6 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
}
|
||||
}
|
||||
|
||||
public void beforeMethodBody(@NotNull MethodVisitor mv) {
|
||||
}
|
||||
|
||||
// Requires public access, because it is used by serialization plugin to generate initializer in synthetic constructor
|
||||
public void initializeProperty(@NotNull ExpressionCodegen codegen, @NotNull KtProperty property) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(VARIABLE, property);
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.context.MultifileClassPartContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
@@ -28,13 +27,8 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtTypeAlias
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
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.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
|
||||
class MultifileClassPartCodegen(
|
||||
v: ClassBuilder,
|
||||
@@ -47,31 +41,13 @@ class MultifileClassPartCodegen(
|
||||
) : MemberCodegen<KtFile>(state, null, partContext, file, v) {
|
||||
private val partType = partContext.filePartType
|
||||
private val facadeClassType = partContext.multifileClassType
|
||||
private val staticInitClassType = Type.getObjectType(partType.internalName + STATIC_INIT_CLASS_SUFFIX)
|
||||
|
||||
private val partClassAttributes =
|
||||
if (shouldGeneratePartHierarchy)
|
||||
OPEN_PART_CLASS_ATTRIBUTES
|
||||
else
|
||||
FINAL_PART_CLASS_ATTRIBUTES
|
||||
|
||||
private fun ClassBuilder.newSpecialMethod(originDescriptor: DeclarationDescriptor, name: String) =
|
||||
newMethod(OtherOrigin(originDescriptor), Opcodes.ACC_STATIC, name, "()V", null, null)
|
||||
|
||||
private val staticInitClassBuilder = ClassBuilderOnDemand {
|
||||
state.factory.newVisitor(MultifileClass(file, packageFragment), staticInitClassType, file).apply {
|
||||
defineClass(file, state.classFileVersion, STATE_INITIALIZER_CLASS_ATTRIBUTES,
|
||||
staticInitClassType.internalName, null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY)
|
||||
|
||||
visitSource(file.name, null)
|
||||
init {
|
||||
if (shouldGeneratePartHierarchy && file.declarations.any { it is KtProperty && shouldInitializeProperty(it) }) {
|
||||
throw AssertionError("State is not allowed in multi-file classes with -Xmultifile-parts-inherit")
|
||||
}
|
||||
}
|
||||
|
||||
private val requiresDeferredStaticInitialization =
|
||||
shouldGeneratePartHierarchy && file.declarations.any {
|
||||
it is KtProperty && shouldInitializeProperty(it)
|
||||
}
|
||||
|
||||
override fun generate() {
|
||||
if (!state.classBuilderMode.generateMultiFileFacadePartClasses) return
|
||||
|
||||
@@ -91,41 +67,15 @@ class MultifileClassPartCodegen(
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresDeferredStaticInitialization) {
|
||||
staticInitClassBuilder.apply {
|
||||
newField(OtherOrigin(packageFragment), Opcodes.ACC_STATIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_VOLATILE,
|
||||
CLINIT_SYNC_NAME, "I", null, null)
|
||||
|
||||
newSpecialMethod(packageFragment, CLINIT_TRIGGER_NAME).apply {
|
||||
if (generateBodies) {
|
||||
visitCode()
|
||||
visitFieldInsn(Opcodes.GETSTATIC, staticInitClassType.internalName, CLINIT_SYNC_NAME, "I")
|
||||
visitInsn(Opcodes.RETURN)
|
||||
visitMaxs(1, 0)
|
||||
}
|
||||
visitEnd()
|
||||
}
|
||||
|
||||
newSpecialMethod(packageFragment, "<clinit>").apply {
|
||||
if (generateBodies) {
|
||||
visitCode()
|
||||
visitMethodInsn(Opcodes.INVOKESTATIC, partType.internalName, DEFERRED_PART_CLINIT_NAME, "()V", false)
|
||||
visitInsn(Opcodes.ICONST_0)
|
||||
visitFieldInsn(Opcodes.PUTSTATIC, staticInitClassType.internalName, CLINIT_SYNC_NAME, "I")
|
||||
visitInsn(Opcodes.RETURN)
|
||||
visitMaxs(1, 0)
|
||||
}
|
||||
visitEnd()
|
||||
}
|
||||
|
||||
writeSyntheticClassMetadata(this, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateDeclaration() {
|
||||
v.defineClass(element, state.classFileVersion, partClassAttributes, partType.internalName, null, superClassInternalName, ArrayUtil.EMPTY_STRING_ARRAY)
|
||||
val access = if (shouldGeneratePartHierarchy) 0 else Opcodes.ACC_SYNTHETIC or Opcodes.ACC_FINAL
|
||||
|
||||
v.defineClass(
|
||||
element, state.classFileVersion, access or Opcodes.ACC_SUPER, partType.internalName, null, superClassInternalName,
|
||||
ArrayUtil.EMPTY_STRING_ARRAY
|
||||
)
|
||||
v.visitSource(element.name, null)
|
||||
|
||||
generatePropertyMetadataArrayFieldIfNeeded(partType)
|
||||
@@ -143,20 +93,6 @@ class MultifileClassPartCodegen(
|
||||
}
|
||||
}
|
||||
|
||||
override fun createClInitMethodVisitor(contextDescriptor: DeclarationDescriptor): MethodVisitor =
|
||||
if (requiresDeferredStaticInitialization)
|
||||
v.newSpecialMethod(contextDescriptor, DEFERRED_PART_CLINIT_NAME)
|
||||
else
|
||||
super.createClInitMethodVisitor(contextDescriptor)
|
||||
|
||||
override fun done() {
|
||||
super.done()
|
||||
|
||||
if (staticInitClassBuilder.isComputed) {
|
||||
staticInitClassBuilder.done()
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateKotlinMetadataAnnotation() {
|
||||
val (serializer, packageProto) = PackagePartCodegen.serializePackagePartMembers(this, partType)
|
||||
|
||||
@@ -171,28 +107,4 @@ class MultifileClassPartCodegen(
|
||||
override fun generateSyntheticPartsAfterBody() {
|
||||
generateSyntheticAccessors()
|
||||
}
|
||||
|
||||
override fun beforeMethodBody(mv: MethodVisitor) {
|
||||
if (requiresDeferredStaticInitialization) {
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, staticInitClassType.internalName, CLINIT_TRIGGER_NAME, "()V", false)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val OPEN_PART_CLASS_ATTRIBUTES = Opcodes.ACC_SUPER
|
||||
private val FINAL_PART_CLASS_ATTRIBUTES = Opcodes.ACC_SYNTHETIC or Opcodes.ACC_SUPER or Opcodes.ACC_FINAL
|
||||
private val STATE_INITIALIZER_CLASS_ATTRIBUTES = Opcodes.ACC_SYNTHETIC or Opcodes.ACC_SUPER or Opcodes.ACC_FINAL
|
||||
|
||||
private val STATIC_INIT_CLASS_SUFFIX = "__Clinit"
|
||||
private val CLINIT_TRIGGER_NAME = "\$\$clinitTrigger"
|
||||
private val CLINIT_SYNC_NAME = "\$\$clinitSync"
|
||||
private val DEFERRED_PART_CLINIT_NAME = "\$\$clinit"
|
||||
|
||||
@JvmStatic fun isStaticInitTrigger(insn: AbstractInsnNode) =
|
||||
insn.opcode == Opcodes.INVOKESTATIC
|
||||
&& insn is MethodInsnNode
|
||||
&& insn.owner.endsWith(STATIC_INIT_CLASS_SUFFIX)
|
||||
&& insn.name == CLINIT_TRIGGER_NAME
|
||||
&& insn.desc == "()V"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
sourceCompiler.generateAndInsertFinallyBlocks(
|
||||
adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index
|
||||
)
|
||||
removeStaticInitializationTrigger(adapter)
|
||||
if (!sourceCompiler.isFinallyMarkerRequired()) {
|
||||
removeFinallyMarkers(adapter)
|
||||
}
|
||||
@@ -588,21 +587,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
return (name == "arrayOf" || name == "emptyArray") && callableDescriptor.containingDeclaration is BuiltInsPackageFragment
|
||||
}
|
||||
|
||||
private fun removeStaticInitializationTrigger(methodNode: MethodNode) {
|
||||
val insnList = methodNode.instructions
|
||||
var insn: AbstractInsnNode? = insnList.first
|
||||
while (insn != null) {
|
||||
if (MultifileClassPartCodegen.isStaticInitTrigger(insn)) {
|
||||
val clinitTriggerCall = insn
|
||||
insn = insn.next
|
||||
insnList.remove(clinitTriggerCall)
|
||||
} else {
|
||||
insn = insn.next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*descriptor is null for captured vars*/
|
||||
private fun shouldPutGeneralValue(type: Type, kotlinType: KotlinType?, stackValue: StackValue): Boolean {
|
||||
//remap only inline functions (and maybe non primitives)
|
||||
|
||||
Reference in New Issue
Block a user