JVM_IR. Support anonymous object/lambda reification

This commit is contained in:
Mikhael Bogdanov
2019-08-05 14:49:19 +02:00
parent 0571f90762
commit 645736f167
29 changed files with 42 additions and 51 deletions
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.inline.NameGenerator import org.jetbrains.kotlin.codegen.inline.NameGenerator
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
interface BaseExpressionCodegen { interface BaseExpressionCodegen {
@@ -32,8 +31,6 @@ interface BaseExpressionCodegen {
val lastLineNumber: Int val lastLineNumber: Int
fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor)
fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages)
fun pushClosureOnStack( fun pushClosureOnStack(
@@ -92,6 +92,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.*; import java.util.*;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.AsmUtil.*;
@@ -1031,7 +1032,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
} }
@NotNull @NotNull
public StackValue putClosureInstanceOnStack( private StackValue putClosureInstanceOnStack(
@NotNull ClosureCodegen closureCodegen, @NotNull ClosureCodegen closureCodegen,
@Nullable StackValue functionReferenceReceiver @Nullable StackValue functionReferenceReceiver
) { ) {
@@ -4839,16 +4840,16 @@ The "returned" value of try expression with no finally is either the last expres
putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(type, operationKind, v, null); putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(type, operationKind, v, null);
} }
public static void putReifiedOperationMarkerIfTypeIsReifiedParameter( private static void putReifiedOperationMarkerIfTypeIsReifiedParameter(
@NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v, @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v,
@NotNull BaseExpressionCodegen codegen @NotNull ExpressionCodegen codegen
) { ) {
putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(type, operationKind, v, codegen); putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(type, operationKind, v, codegen);
} }
private static void putReifiedOperationMarkerIfTypeIsReifiedParameterImpl( private static void putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(
@NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v, @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v,
@Nullable BaseExpressionCodegen codegen @Nullable ExpressionCodegen codegen
) { ) {
Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type); Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type);
if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.getFirst().isReified()) { if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.getFirst().isReified()) {
@@ -4862,7 +4863,11 @@ The "returned" value of try expression with no finally is either the last expres
@Override @Override
public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) { public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) {
parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(usages, context); parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(
usages,
() -> context.getContextDescriptor().getTypeParameters().stream().filter(TypeParameterDescriptor::isReified).map(
it -> it.getName().asString()).collect(Collectors.toSet())
);
} }
@Override @Override
@@ -5079,8 +5084,7 @@ The "returned" value of try expression with no finally is either the last expres
return v; return v;
} }
@Override private void consumeReifiedOperationMarker(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
public void consumeReifiedOperationMarker(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) { if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) {
parentCodegen.getReifiedTypeParametersUsages(). parentCodegen.getReifiedTypeParametersUsages().
addUsedReifiedParameter(typeParameterDescriptor.getName().asString()); addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.generateAsCast import org.jetbrains.kotlin.codegen.generateAsCast
import org.jetbrains.kotlin.codegen.generateIsCheck import org.jetbrains.kotlin.codegen.generateIsCheck
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
@@ -349,18 +348,14 @@ class ReifiedTypeParametersUsages {
usedTypeParameters.add(name) usedTypeParameters.add(name)
} }
fun propagateChildUsagesWithinContext(child: ReifiedTypeParametersUsages, context: MethodContext) { fun propagateChildUsagesWithinContext(child: ReifiedTypeParametersUsages, reifiedTypeParameterNamesInContext: () -> Set<String>) {
if (!child.wereUsedReifiedParameters()) return if (!child.wereUsedReifiedParameters()) return
// used for propagating reified TP usages from children member codegen to parent's // used for propagating reified TP usages from children member codegen to parent's
// mark enclosing object-literal/lambda as needed reification iff // mark enclosing object-literal/lambda as needed reification iff
// 1. at least one of it's method contains operations to reify // 1. at least one of it's method contains operations to reify
// 2. reified type parameter of these operations is not from current method signature // 2. reified type parameter of these operations is not from current method signature
// i.e. from outer scope // i.e. from outer scope
child.usedTypeParameters.filterNot { name -> usedTypeParameters.addAll(child.usedTypeParameters - reifiedTypeParameterNamesInContext())
context.contextDescriptor.typeParameters.any { typeParameter ->
typeParameter.isReified && typeParameter.name.asString() == name
}
}.forEach { usedTypeParameters.add(it) }
} }
fun mergeAll(other: ReifiedTypeParametersUsages) { fun mergeAll(other: ReifiedTypeParametersUsages) {
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
import org.jetbrains.kotlin.codegen.inline.SourceMapper import org.jetbrains.kotlin.codegen.inline.SourceMapper
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
@@ -54,6 +55,8 @@ open class ClassCodegen protected constructor(
val visitor: ClassBuilder = createClassBuilder() val visitor: ClassBuilder = createClassBuilder()
val reifiedTypeParametersUsages = ReifiedTypeParametersUsages()
open fun createClassBuilder() = state.factory.newVisitor( open fun createClassBuilder() = state.factory.newVisitor(
OtherOrigin(descriptor.psiElement, descriptor), OtherOrigin(descriptor.psiElement, descriptor),
type, type,
@@ -70,7 +73,7 @@ open class ClassCodegen protected constructor(
else -> null else -> null
} }
fun generate() { fun generate(): ReifiedTypeParametersUsages {
val superClassInfo = irClass.getSuperClassInfo(typeMapper) val superClassInfo = irClass.getSuperClassInfo(typeMapper)
val signature = getSignature(irClass, type, superClassInfo, typeMapper) val signature = getSignature(irClass, type, superClassInfo, typeMapper)
@@ -121,6 +124,7 @@ open class ClassCodegen protected constructor(
} else { } else {
done() done()
} }
return reifiedTypeParametersUsages
} }
private fun generateKotlinMetadataAnnotation() { private fun generateKotlinMetadataAnnotation() {
@@ -228,8 +232,8 @@ open class ClassCodegen protected constructor(
} }
} }
fun generateLocalClass(klass: IrClass) { fun generateLocalClass(klass: IrClass): ReifiedTypeParametersUsages {
ClassCodegen(klass, context, this).generate() return ClassCodegen(klass, context, this).generate()
} }
private fun generateField(field: IrField) { private fun generateField(field: IrField) {
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.* import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.putNeedClassReificationMarker
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.AS import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.AS
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE_AS import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE_AS
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
@@ -26,7 +27,6 @@ import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -120,6 +120,8 @@ class ExpressionCodegen(
override var lastLineNumber: Int = -1 override var lastLineNumber: Int = -1
private val closureReifiedMarkers = hashMapOf<IrClass, ReifiedTypeParametersUsages>()
private val IrType.asmType: Type private val IrType.asmType: Type
get() = typeMapper.mapType(this) get() = typeMapper.mapType(this)
@@ -322,6 +324,13 @@ class ExpressionCodegen(
when { when {
expression is IrConstructorCall -> { expression is IrConstructorCall -> {
closureReifiedMarkers[expression.symbol.owner.parentAsClass]?.let {
if (it.wereUsedReifiedParameters()) {
putNeedClassReificationMarker(v)
propagateChildReifiedTypeParametersUsages(it)
}
}
// IR constructors have no receiver and return the new instance, but on JVM they are void-returning // IR constructors have no receiver and return the new instance, but on JVM they are void-returning
// instance methods named <init>. // instance methods named <init>.
mv.anew(asmType) mv.anew(asmType)
@@ -562,7 +571,9 @@ class ExpressionCodegen(
// TODO maybe remove? // TODO maybe remove?
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue { override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
classCodegen.generateLocalClass(declaration) classCodegen.generateLocalClass(declaration).also {
closureReifiedMarkers[declaration] = it
}
return immaterialUnitValue return immaterialUnitValue
} }
@@ -1128,12 +1139,16 @@ class ExpressionCodegen(
return IrInlineCodegen(this, state, original.descriptor, mappings, IrSourceCompilerForInline(state, element, this, data)) return IrInlineCodegen(this, state, original.descriptor, mappings, IrSourceCompilerForInline(state, element, this, data))
} }
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) { private fun consumeReifiedOperationMarker(typeParameter: IrTypeParameter) {
//TODO if (typeParameter.parent != irFunction) {
classCodegen.reifiedTypeParametersUsages.addUsedReifiedParameter(typeParameter.name.asString())
}
} }
override fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) { override fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) {
//TODO classCodegen.reifiedTypeParametersUsages.propagateChildUsagesWithinContext(reifiedTypeParametersUsages) {
irFunction.typeParameters.filter { it.isReified }.map { it.name.asString() }.toSet()
}
} }
override fun pushClosureOnStack( override fun pushClosureOnStack(
@@ -1208,12 +1223,12 @@ class ExpressionCodegen(
/* From ExpressionCodegen.java */ /* From ExpressionCodegen.java */
private fun putReifiedOperationMarkerIfTypeIsReifiedParameter( private fun putReifiedOperationMarkerIfTypeIsReifiedParameter(
type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter, type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter,
codegen: BaseExpressionCodegen? codegen: ExpressionCodegen?
) { ) {
val typeParameterAndReificationArgument = extractReificationArgumentWithParameter(type) val typeParameterAndReificationArgument = extractReificationArgumentWithParameter(type)
if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.first.isReified) { if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.first.isReified) {
val irTypeParameter = typeParameterAndReificationArgument.first val irTypeParameter = typeParameterAndReificationArgument.first
codegen?.consumeReifiedOperationMarker(irTypeParameter.descriptor) codegen?.consumeReifiedOperationMarker(irTypeParameter)
ReifiedTypeInliner.putReifiedOperationMarker( ReifiedTypeInliner.putReifiedOperationMarker(
operationKind, typeParameterAndReificationArgument.second.toReificationArgument(), v operationKind, typeParameterAndReificationArgument.second.toReificationArgument(), v
) )
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun box(): String { fun box(): String {
defineFunc<String>() defineFunc<String>()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// WITH_RUNTIME // WITH_RUNTIME
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// WITH_RUNTIME // WITH_RUNTIME
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// WITH_RUNTIME // WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// WITH_RUNTIME // WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// WITH_REFLECT // WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// WITH_REFLECT // WITH_REFLECT
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// WITH_REFLECT // WITH_REFLECT
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: 1.kt // FILE: 1.kt
// WITH_REFLECT // WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test