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.ReifiedTypeParametersUsages
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
interface BaseExpressionCodegen {
@@ -32,8 +31,6 @@ interface BaseExpressionCodegen {
val lastLineNumber: Int
fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor)
fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages)
fun pushClosureOnStack(
@@ -92,6 +92,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
@@ -1031,7 +1032,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
public StackValue putClosureInstanceOnStack(
private StackValue putClosureInstanceOnStack(
@NotNull ClosureCodegen closureCodegen,
@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);
}
public static void putReifiedOperationMarkerIfTypeIsReifiedParameter(
private static void putReifiedOperationMarkerIfTypeIsReifiedParameter(
@NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v,
@NotNull BaseExpressionCodegen codegen
@NotNull ExpressionCodegen codegen
) {
putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(type, operationKind, v, codegen);
}
private static void putReifiedOperationMarkerIfTypeIsReifiedParameterImpl(
@NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v,
@Nullable BaseExpressionCodegen codegen
@Nullable ExpressionCodegen codegen
) {
Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type);
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
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
@@ -5079,8 +5084,7 @@ The "returned" value of try expression with no finally is either the last expres
return v;
}
@Override
public void consumeReifiedOperationMarker(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
private void consumeReifiedOperationMarker(@NotNull TypeParameterDescriptor typeParameterDescriptor) {
if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) {
parentCodegen.getReifiedTypeParametersUsages().
addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.generateAsCast
import org.jetbrains.kotlin.codegen.generateIsCheck
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
@@ -349,18 +348,14 @@ class ReifiedTypeParametersUsages {
usedTypeParameters.add(name)
}
fun propagateChildUsagesWithinContext(child: ReifiedTypeParametersUsages, context: MethodContext) {
fun propagateChildUsagesWithinContext(child: ReifiedTypeParametersUsages, reifiedTypeParameterNamesInContext: () -> Set<String>) {
if (!child.wereUsedReifiedParameters()) return
// used for propagating reified TP usages from children member codegen to parent's
// mark enclosing object-literal/lambda as needed reification iff
// 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
// i.e. from outer scope
child.usedTypeParameters.filterNot { name ->
context.contextDescriptor.typeParameters.any { typeParameter ->
typeParameter.isReified && typeParameter.name.asString() == name
}
}.forEach { usedTypeParameters.add(it) }
usedTypeParameters.addAll(child.usedTypeParameters - reifiedTypeParameterNamesInContext())
}
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.binding.CodegenBinding
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.serialization.JvmSerializationBindings
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
@@ -54,6 +55,8 @@ open class ClassCodegen protected constructor(
val visitor: ClassBuilder = createClassBuilder()
val reifiedTypeParametersUsages = ReifiedTypeParametersUsages()
open fun createClassBuilder() = state.factory.newVisitor(
OtherOrigin(descriptor.psiElement, descriptor),
type,
@@ -70,7 +73,7 @@ open class ClassCodegen protected constructor(
else -> null
}
fun generate() {
fun generate(): ReifiedTypeParametersUsages {
val superClassInfo = irClass.getSuperClassInfo(typeMapper)
val signature = getSignature(irClass, type, superClassInfo, typeMapper)
@@ -121,6 +124,7 @@ open class ClassCodegen protected constructor(
} else {
done()
}
return reifiedTypeParametersUsages
}
private fun generateKotlinMetadataAnnotation() {
@@ -228,8 +232,8 @@ open class ClassCodegen protected constructor(
}
}
fun generateLocalClass(klass: IrClass) {
ClassCodegen(klass, context, this).generate()
fun generateLocalClass(klass: IrClass): ReifiedTypeParametersUsages {
return ClassCodegen(klass, context, this).generate()
}
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.coroutines.INVOKE_SUSPEND_METHOD_NAME
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.SAFE_AS
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.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
@@ -120,6 +120,8 @@ class ExpressionCodegen(
override var lastLineNumber: Int = -1
private val closureReifiedMarkers = hashMapOf<IrClass, ReifiedTypeParametersUsages>()
private val IrType.asmType: Type
get() = typeMapper.mapType(this)
@@ -322,6 +324,13 @@ class ExpressionCodegen(
when {
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
// instance methods named <init>.
mv.anew(asmType)
@@ -562,7 +571,9 @@ class ExpressionCodegen(
// TODO maybe remove?
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
classCodegen.generateLocalClass(declaration)
classCodegen.generateLocalClass(declaration).also {
closureReifiedMarkers[declaration] = it
}
return immaterialUnitValue
}
@@ -1128,12 +1139,16 @@ class ExpressionCodegen(
return IrInlineCodegen(this, state, original.descriptor, mappings, IrSourceCompilerForInline(state, element, this, data))
}
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) {
//TODO
private fun consumeReifiedOperationMarker(typeParameter: IrTypeParameter) {
if (typeParameter.parent != irFunction) {
classCodegen.reifiedTypeParametersUsages.addUsedReifiedParameter(typeParameter.name.asString())
}
}
override fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) {
//TODO
classCodegen.reifiedTypeParametersUsages.propagateChildUsagesWithinContext(reifiedTypeParametersUsages) {
irFunction.typeParameters.filter { it.isReified }.map { it.name.asString() }.toSet()
}
}
override fun pushClosureOnStack(
@@ -1208,12 +1223,12 @@ class ExpressionCodegen(
/* From ExpressionCodegen.java */
private fun putReifiedOperationMarkerIfTypeIsReifiedParameter(
type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter,
codegen: BaseExpressionCodegen?
codegen: ExpressionCodegen?
) {
val typeParameterAndReificationArgument = extractReificationArgumentWithParameter(type)
if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.first.isReified) {
val irTypeParameter = typeParameterAndReificationArgument.first
codegen?.consumeReifiedOperationMarker(irTypeParameter.descriptor)
codegen?.consumeReifiedOperationMarker(irTypeParameter)
ReifiedTypeInliner.putReifiedOperationMarker(
operationKind, typeParameterAndReificationArgument.second.toReificationArgument(), v
)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun box(): String {
defineFunc<String>()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt
// WITH_RUNTIME
package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt
// WITH_RUNTIME
package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// WITH_REFLECT
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// WITH_REFLECT
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt
package test
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: 1.kt
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: 1.kt
package test