JVM_IR indy-SAM conversions, 1st passing tests
KT-44278 KT-26060 KT-42621
This commit is contained in:
@@ -207,6 +207,14 @@ class GenerationState private constructor(
|
||||
configuration.get(JVMConfigurationKeys.STRING_CONCAT) ?: JvmStringConcat.INLINE
|
||||
else JvmStringConcat.INLINE
|
||||
|
||||
val samConversionsScheme = run {
|
||||
val fromConfig = configuration.get(JVMConfigurationKeys.SAM_CONVERSIONS) ?: JvmSamConversions.DEFAULT
|
||||
if (target >= fromConfig.minJvmTarget)
|
||||
fromConfig
|
||||
else
|
||||
JvmSamConversions.DEFAULT
|
||||
}
|
||||
|
||||
val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
|
||||
val classBuilderMode: ClassBuilderMode = builderFactory.classBuilderMode
|
||||
val bindingTrace: BindingTrace = DelegatingBindingTrace(
|
||||
|
||||
+9
@@ -362,6 +362,15 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
var stringConcat: String? by NullableStringFreezableVar(JvmStringConcat.INLINE.description)
|
||||
|
||||
@Argument(
|
||||
value = "-Xsam-conversions",
|
||||
valueDescription = "{class|indy}",
|
||||
description = """Select code generation scheme for SAM conversions.
|
||||
-Xsam-conversions=indy Generate SAM conversions using `invokedynamic` with `LambdaMetafactory.metafactory`. Requires `-jvm-target 8` or greater.
|
||||
-Xsam-conversions=class Generate SAM conversions as explicit classes"""
|
||||
)
|
||||
var samConversions: String? by NullableStringFreezableVar(JvmSamConversions.CLASS.description)
|
||||
|
||||
@Argument(
|
||||
value = "-Xklib",
|
||||
valueDescription = "<path>",
|
||||
|
||||
@@ -59,8 +59,28 @@ fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArgu
|
||||
}
|
||||
} else {
|
||||
messageCollector.report(
|
||||
ERROR, "Unknown -Xstring-concat mode: ${arguments.jvmTarget}\n" +
|
||||
"Supported versions: ${JvmStringConcat.values().joinToString { it.description }}"
|
||||
ERROR, "Unknown `-Xstring-concat` mode: ${arguments.stringConcat}\n" +
|
||||
"Supported modes: ${JvmStringConcat.values().joinToString { it.description }}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (arguments.samConversions != null) {
|
||||
val samConversions = JvmSamConversions.fromString(arguments.samConversions)
|
||||
if (samConversions != null) {
|
||||
put(JVMConfigurationKeys.SAM_CONVERSIONS, samConversions)
|
||||
if (jvmTarget < samConversions.minJvmTarget) {
|
||||
messageCollector.report(
|
||||
WARNING,
|
||||
"`-Xsam-conversions=${arguments.samConversions}` requires JVM target at least " +
|
||||
"${samConversions.minJvmTarget.description} and is ignored."
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messageCollector.report(
|
||||
ERROR,
|
||||
"Unknown `-Xsam-conversions` argument: ${arguments.samConversions}\n" +
|
||||
"Supported arguments: ${JvmSamConversions.values().joinToString { it.description }}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,9 @@ public class JVMConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<JvmStringConcat> STRING_CONCAT =
|
||||
CompilerConfigurationKey.create("Specifies string concatenation scheme");
|
||||
|
||||
public static final CompilerConfigurationKey<JvmSamConversions> SAM_CONVERSIONS =
|
||||
CompilerConfigurationKey.create("SAM conversions code generation scheme");
|
||||
|
||||
public static final CompilerConfigurationKey<List<String>> KLIB_PATHS =
|
||||
CompilerConfigurationKey.create("Paths to .klib libraries");
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.config
|
||||
|
||||
enum class JvmSamConversions(
|
||||
val description: String,
|
||||
val minJvmTarget: JvmTarget
|
||||
) {
|
||||
CLASS("class", JvmTarget.JVM_1_6),
|
||||
INDY("indy", JvmTarget.JVM_1_8),
|
||||
;
|
||||
|
||||
companion object {
|
||||
val DEFAULT = CLASS
|
||||
|
||||
@JvmStatic
|
||||
fun fromString(string: String?) =
|
||||
values().find { it.description == string }
|
||||
}
|
||||
}
|
||||
+68
@@ -18379,6 +18379,74 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Invokedynamic extends AbstractFirBlackBoxCodegenTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Sam extends AbstractFirBlackBoxCodegenTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundReference.kt")
|
||||
public void testBoundReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedDispatchReceiver.kt")
|
||||
public void testCapturedDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedExtensionReceiver.kt")
|
||||
public void testCapturedExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingIndyFunInterface.kt")
|
||||
public void testCapturingIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingIndySam.kt")
|
||||
public void testCapturingIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIndyFunInterface.kt")
|
||||
public void testSimpleIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIndySam.kt")
|
||||
public void testSimpleIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+20
-13
@@ -65,7 +65,11 @@ fun IrClass.addField(fieldName: Name, fieldType: IrType, fieldVisibility: Descri
|
||||
visibility = fieldVisibility
|
||||
}
|
||||
|
||||
fun IrClass.addField(fieldName: String, fieldType: IrType, fieldVisibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE): IrField =
|
||||
fun IrClass.addField(
|
||||
fieldName: String,
|
||||
fieldType: IrType,
|
||||
fieldVisibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE
|
||||
): IrField =
|
||||
addField(Name.identifier(fieldName), fieldType, fieldVisibility)
|
||||
|
||||
@PublishedApi
|
||||
@@ -141,16 +145,16 @@ inline fun IrClass.addFunction(builder: IrFunctionBuilder.() -> Unit): IrSimpleF
|
||||
factory.addFunction(this, builder)
|
||||
|
||||
fun IrClass.addFunction(
|
||||
name: String,
|
||||
returnType: IrType,
|
||||
modality: Modality = Modality.FINAL,
|
||||
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC,
|
||||
isStatic: Boolean = false,
|
||||
isSuspend: Boolean = false,
|
||||
isFakeOverride: Boolean = false,
|
||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
|
||||
startOffset: Int = UNDEFINED_OFFSET,
|
||||
endOffset: Int = UNDEFINED_OFFSET
|
||||
name: String,
|
||||
returnType: IrType,
|
||||
modality: Modality = Modality.FINAL,
|
||||
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC,
|
||||
isStatic: Boolean = false,
|
||||
isSuspend: Boolean = false,
|
||||
isFakeOverride: Boolean = false,
|
||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
|
||||
startOffset: Int = UNDEFINED_OFFSET,
|
||||
endOffset: Int = UNDEFINED_OFFSET
|
||||
): IrSimpleFunction =
|
||||
addFunction {
|
||||
this.startOffset = startOffset
|
||||
@@ -216,7 +220,7 @@ internal fun IrFactory.buildValueParameter(builder: IrValueParameterBuilder, par
|
||||
|
||||
|
||||
inline fun <D> buildValueParameter(declaration: D, builder: IrValueParameterBuilder.() -> Unit): IrValueParameter
|
||||
where D : IrDeclaration, D : IrDeclarationParent =
|
||||
where D : IrDeclaration, D : IrDeclarationParent =
|
||||
IrValueParameterBuilder().run {
|
||||
builder()
|
||||
declaration.factory.buildValueParameter(this, declaration)
|
||||
@@ -234,8 +238,11 @@ inline fun IrFunction.addValueParameter(builder: IrValueParameterBuilder.() -> U
|
||||
}
|
||||
|
||||
fun IrFunction.addValueParameter(name: String, type: IrType, origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED): IrValueParameter =
|
||||
addValueParameter(Name.identifier(name), type, origin)
|
||||
|
||||
fun IrFunction.addValueParameter(name: Name, type: IrType, origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED): IrValueParameter =
|
||||
addValueParameter {
|
||||
this.name = Name.identifier(name)
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.origin = origin
|
||||
}
|
||||
|
||||
+1
@@ -46,4 +46,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object COMPANION_PROPERTY_BACKING_FIELD : IrDeclarationOriginImpl("COMPANION_PROPERTY_BACKING_FIELD")
|
||||
object FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE")
|
||||
object ABSTRACT_BRIDGE_STUB : IrDeclarationOriginImpl("ABSTRACT_BRIDGE_STUB")
|
||||
object INVOVEDYNAMIC_CALL_TARGET : IrDeclarationOriginImpl("INVOVEDYNAMIC_CALL_TARGET")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.common.ir.addChild
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
@@ -51,6 +50,17 @@ class JvmSymbols(
|
||||
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
|
||||
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
|
||||
|
||||
// Special package for functions representing dynamic symbols referenced by 'INVOKEDYNAMIC' instruction - e.g.,
|
||||
// 'get(Ljava/lang/String;)Ljava/util/function/Supplier;'
|
||||
// in
|
||||
// INVOKEDYNAMIC get(Ljava/lang/String;)Ljava/util/function/Supplier; [
|
||||
// H_INVOKESTATIC java/lang/invoke/LambdaMetafactory.metafactory(...)Ljava/lang/invoke/CallSite;
|
||||
// ...
|
||||
// ]
|
||||
// Such functions don't exist as methods in the actual bytecode
|
||||
// (they are expected to be provided at run-time by the corresponding bootstrap method).
|
||||
val kotlinJvmInternalInvokeDynamicPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal.invokeDynamic"))
|
||||
|
||||
private val generateOptimizedCallableReferenceSuperClasses = context.state.generateOptimizedCallableReferenceSuperClasses
|
||||
|
||||
private fun createPackage(fqName: FqName): IrPackageFragment =
|
||||
@@ -535,6 +545,82 @@ class JvmSymbols(
|
||||
returnType = dst.defaultType
|
||||
}.symbol
|
||||
|
||||
val indySamConversionIntrinsic: IrSimpleFunctionSymbol =
|
||||
irFactory.buildFun {
|
||||
name = Name.special("<jvm-indy-sam-conversion>")
|
||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||
}.apply {
|
||||
parent = kotlinJvmInternalPackage
|
||||
val samType = addTypeParameter("SAM_TYPE", irBuiltIns.anyType)
|
||||
addValueParameter("method", irBuiltIns.anyNType)
|
||||
returnType = samType.defaultType
|
||||
}.symbol
|
||||
|
||||
val arrayOfAnyType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType)
|
||||
|
||||
// Intrinsic to represent INVOKEDYNAMIC calls in IR.
|
||||
// fun <T> `<jvm-indy>`(
|
||||
// dynamicCall: T,
|
||||
// bootstrapMethodTag: Int,
|
||||
// bootstrapMethodOwner: String,
|
||||
// bootstrapMethodName: String,
|
||||
// bootstrapMethodDesc: String,
|
||||
// vararg bootstrapMethodArgs: Any
|
||||
// ): T
|
||||
// Bootstrap method handle is encoded as a bunch of constants.
|
||||
// For example,
|
||||
// REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(
|
||||
// Ljava/lang/invoke/MethodHandles$Lookup;
|
||||
// Ljava/lang/String;
|
||||
// Ljava/lang/invoke/MethodType;
|
||||
// Ljava/lang/invoke/MethodType;
|
||||
// Ljava/lang/invoke/MethodHandle;
|
||||
// Ljava/lang/invoke/MethodType;
|
||||
// )Ljava/lang/invoke/CallSite;
|
||||
// is represented as
|
||||
// bootstrapMethodTag: IrConst<Int>(value = H_INVOKESTATIC)
|
||||
// bootstrapMethodOwner: IrConst<String>(value = "java/lang/invoke/LambdaMetafactory")
|
||||
// bootstrapMethodName: IrConst<String>(value = "metafactory")
|
||||
// bootstrapMethodDesc: IrConst<String>(value = "(...)Ljava/lang/invoke/CallSite;")
|
||||
// Bootstrap method owner is assumed to be a class (which is true for both LambdaMetafactory and StringConcatFactory).
|
||||
val jvmIndyIntrinsic: IrSimpleFunctionSymbol =
|
||||
irFactory.buildFun {
|
||||
name = Name.special("<jvm-indy>")
|
||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||
}.apply {
|
||||
parent = kotlinJvmInternalPackage
|
||||
val t = addTypeParameter("T", irBuiltIns.anyNType)
|
||||
addValueParameter("dynamicCall", t.defaultType)
|
||||
addValueParameter("bootstrapMethodTag", irBuiltIns.intType)
|
||||
addValueParameter("bootstrapMethodOwner", irBuiltIns.stringType)
|
||||
addValueParameter("bootstrapMethodName", irBuiltIns.stringType)
|
||||
addValueParameter("bootstrapMethodDesc", irBuiltIns.stringType)
|
||||
addValueParameter {
|
||||
name = Name.identifier("bootstrapMethodArguments")
|
||||
type = arrayOfAnyType
|
||||
varargElementType = irBuiltIns.anyType
|
||||
}
|
||||
returnType = t.defaultType
|
||||
}.symbol
|
||||
|
||||
// Intrinsic used to represent MethodType objects in bootstrap method arguments (see jvmInvokeDynamicIntrinsic above).
|
||||
// Type argument is a possibly substituted method owner type (e.g., 'java.lang.function.Supplier<String>').
|
||||
// Value argument is a raw function reference to a corresponding method (e.g., 'java.lang.function.Supplier#get').
|
||||
val jvmMethodTypeIntrinsic: IrSimpleFunctionSymbol =
|
||||
irFactory.buildFun {
|
||||
name = Name.special("<jvm-method-type>")
|
||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||
}.apply {
|
||||
parent = kotlinJvmInternalPackage
|
||||
addTypeParameter("OwnerT", irBuiltIns.anyType)
|
||||
addValueParameter("method", irBuiltIns.anyType)
|
||||
returnType = irBuiltIns.anyType
|
||||
}.symbol
|
||||
|
||||
val flexibleNullabilityAnnotationFqName = JvmGeneratorExtensions.FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME
|
||||
val enhancedNullabilityAnnotationFqName = JvmGeneratorExtensions.ENHANCED_NULLABILITY_ANNOTATION_FQ_NAME
|
||||
val rawTypeAnnotationFQN = JvmGeneratorExtensions.RAW_TYPE_ANNOTATION_FQ_NAME
|
||||
|
||||
private val collectionToArrayClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.CollectionToArray")) { klass ->
|
||||
klass.origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||
|
||||
|
||||
+1
-1
@@ -418,7 +418,7 @@ class ExpressionCodegen(
|
||||
|
||||
val callee = expression.symbol.owner
|
||||
require(callee.parent is IrClass) { "Unhandled intrinsic in ExpressionCodegen: ${callee.render()}" }
|
||||
val callable = methodSignatureMapper.mapToCallableMethod(irFunction, expression)
|
||||
val callable = methodSignatureMapper.mapToCallableMethod(expression, irFunction)
|
||||
val callGenerator = getOrCreateCallGenerator(expression, data, callable.signature)
|
||||
val isSuspensionPoint = expression.isSuspensionPoint()
|
||||
|
||||
|
||||
+12
-7
@@ -366,7 +366,8 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
if (valueArgumentsCount > 0) (getValueArgument(0) as? IrConst<*>)?.value as? Boolean ?: true else null
|
||||
}
|
||||
|
||||
fun mapToCallableMethod(caller: IrFunction, expression: IrCall): IrCallableMethod {
|
||||
// TODO get rid of 'caller' argument
|
||||
internal fun mapToCallableMethod(expression: IrCall, caller: IrFunction?): IrCallableMethod {
|
||||
val callee = expression.symbol.owner
|
||||
val calleeParent = expression.superQualifierSymbol?.owner
|
||||
?: expression.dispatchReceiver?.type?.classOrNull?.owner
|
||||
@@ -385,17 +386,21 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
}
|
||||
|
||||
val declaration = findSuperDeclaration(callee, isSuperCall)
|
||||
val signature = mapOverriddenSpecialBuiltinIfNeeded(caller, declaration, isSuperCall)
|
||||
?: mapSignatureSkipGeneric(declaration)
|
||||
val signature =
|
||||
if (caller != null && caller.isBridge()) {
|
||||
// Do not remap special builtin methods when called from a bridge. The bridges are there to provide the
|
||||
// remapped name or signature and forward to the actually declared method.
|
||||
mapSignatureSkipGeneric(declaration)
|
||||
} else {
|
||||
mapOverriddenSpecialBuiltinIfNeeded(declaration, isSuperCall)
|
||||
?: mapSignatureSkipGeneric(declaration)
|
||||
}
|
||||
|
||||
return IrCallableMethod(owner, invokeOpcode, signature, isInterface)
|
||||
}
|
||||
|
||||
// TODO: get rid of this (probably via some special lowering)
|
||||
private fun mapOverriddenSpecialBuiltinIfNeeded(caller: IrFunction, callee: IrFunction, superCall: Boolean): JvmMethodSignature? {
|
||||
// Do not remap special builtin methods when called from a bridge. The bridges are there to provide the
|
||||
// remapped name or signature and forward to the actually declared method.
|
||||
if (caller.isBridge()) return null
|
||||
private fun mapOverriddenSpecialBuiltinIfNeeded(callee: IrFunction, superCall: Boolean): JvmMethodSignature? {
|
||||
// Do not remap calls to static replacements of inline class methods, since they have completely different signatures.
|
||||
if (callee.isStaticInlineClassReplacement) return null
|
||||
val overriddenSpecialBuiltinFunction =
|
||||
|
||||
+1
@@ -120,6 +120,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
||||
symbols.throwTypeCastException.toKey()!! to ThrowException(Type.getObjectType("kotlin/TypeCastException")),
|
||||
symbols.throwUnsupportedOperationException.toKey()!! to ThrowException(Type.getObjectType("java/lang/UnsupportedOperationException")),
|
||||
symbols.throwKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException,
|
||||
symbols.jvmIndyIntrinsic.toKey()!! to JvmInvokeDynamic
|
||||
) +
|
||||
numberConversionMethods() +
|
||||
unaryFunForPrimitives("plus", UnaryPlus) +
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.inline.v
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.Handle
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
object JvmInvokeDynamic : IntrinsicMethod() {
|
||||
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue {
|
||||
fun fail(message: String): Nothing =
|
||||
throw AssertionError("$message; expression:\n${expression.dump()}")
|
||||
|
||||
val dynamicCall = expression.getValueArgument(0) as? IrCall
|
||||
?: fail("'dynamicCall' is expected to be a call")
|
||||
val dynamicCallee = dynamicCall.symbol.owner
|
||||
if (dynamicCallee.parent != codegen.context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage ||
|
||||
dynamicCallee.origin != JvmLoweredDeclarationOrigin.INVOVEDYNAMIC_CALL_TARGET
|
||||
)
|
||||
fail("Unexpected dynamicCallee: '${dynamicCallee.render()}'")
|
||||
|
||||
val bootstrapMethodTag = expression.getValueArgument(1)?.getIntConst()
|
||||
?: fail("'bootstrapMethodTag' is expected to be an int const")
|
||||
val bootstrapMethodOwner = expression.getValueArgument(2)?.getStringConst()
|
||||
?: fail("'bootstrapMethodOwner' is expected to be a string const")
|
||||
val bootstrapMethodName = expression.getValueArgument(3)?.getStringConst()
|
||||
?: fail("'bootstrapMethodName' is expected to be a string const")
|
||||
val bootstrapMethodDesc = expression.getValueArgument(4)?.getStringConst()
|
||||
?: fail("'bootstrapMethodDesc' is expected to be a string const")
|
||||
val bootstrapMethodArgs = (expression.getValueArgument(5)?.safeAs<IrVararg>()
|
||||
?: fail("'bootstrapMethodArgs' is expected to be a vararg"))
|
||||
|
||||
val asmBootstrapMethodArgs = bootstrapMethodArgs.elements
|
||||
.map { generateBootstrapMethodArg(it, codegen) }
|
||||
.toTypedArray()
|
||||
|
||||
val dynamicCalleeMethod = codegen.methodSignatureMapper.mapAsmMethod(dynamicCallee)
|
||||
val bootstrapMethodHandle = Handle(bootstrapMethodTag, bootstrapMethodOwner, bootstrapMethodName, bootstrapMethodDesc, false)
|
||||
|
||||
val dynamicCallGenerator = IrCallGenerator.DefaultCallGenerator
|
||||
val dynamicCalleeArgumentTypes = dynamicCalleeMethod.argumentTypes
|
||||
for (i in dynamicCallee.valueParameters.indices) {
|
||||
val dynamicCalleeParameter = dynamicCallee.valueParameters[i]
|
||||
val dynamicCalleeArgument = dynamicCall.getValueArgument(i)
|
||||
?: fail("No argument #$i in 'dynamicCall'")
|
||||
val dynamicCalleeArgumentType = dynamicCalleeArgumentTypes.getOrElse(i) {
|
||||
fail("No argument type #$i in dynamic callee: $dynamicCalleeMethod")
|
||||
}
|
||||
dynamicCallGenerator.genValueAndPut(dynamicCalleeParameter, dynamicCalleeArgument, dynamicCalleeArgumentType, codegen, data)
|
||||
}
|
||||
|
||||
codegen.v.invokedynamic(dynamicCalleeMethod.name, dynamicCalleeMethod.descriptor, bootstrapMethodHandle, asmBootstrapMethodArgs)
|
||||
|
||||
return MaterialValue(codegen, dynamicCalleeMethod.returnType, expression.type)
|
||||
}
|
||||
|
||||
private fun generateBootstrapMethodArg(element: IrVarargElement, codegen: ExpressionCodegen): Any =
|
||||
when (element) {
|
||||
is IrRawFunctionReference ->
|
||||
generateMethodHandle(element, codegen)
|
||||
is IrCall ->
|
||||
when (element.symbol) {
|
||||
codegen.context.ir.symbols.jvmMethodTypeIntrinsic ->
|
||||
generateMethodType(element, codegen)
|
||||
else ->
|
||||
throw AssertionError("Unexpected callee in bootstrap method argument:\n${element.dump()}")
|
||||
}
|
||||
is IrConst<*> ->
|
||||
when (element.kind) {
|
||||
IrConstKind.Byte -> (element.value as Byte).toInt()
|
||||
IrConstKind.Short -> (element.value as Short).toInt()
|
||||
IrConstKind.Int -> element.value as Int
|
||||
IrConstKind.Long -> element.value as Long
|
||||
IrConstKind.Float -> element.value as Float
|
||||
IrConstKind.Double -> element.value as Double
|
||||
IrConstKind.String -> element.value as String
|
||||
else ->
|
||||
throw AssertionError("Unexpected constant expression in bootstrap method argument:\n${element.dump()}")
|
||||
}
|
||||
else ->
|
||||
throw AssertionError("Unexpected bootstrap method argument:\n${element.dump()}")
|
||||
}
|
||||
|
||||
private fun generateMethodHandle(irRawFunctionReference: IrRawFunctionReference, codegen: ExpressionCodegen): Any {
|
||||
val irFun = irRawFunctionReference.symbol.owner
|
||||
val irParentClass = irFun.parentAsClass
|
||||
val owner = codegen.typeMapper.mapOwner(irParentClass)
|
||||
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
|
||||
val handleTag = when {
|
||||
irFun.dispatchReceiverParameter == null ->
|
||||
Opcodes.H_INVOKESTATIC
|
||||
else ->
|
||||
Opcodes.H_INVOKEVIRTUAL
|
||||
}
|
||||
return Handle(handleTag, owner.internalName, asmMethod.name, asmMethod.descriptor, irParentClass.isJvmInterface)
|
||||
}
|
||||
|
||||
private fun generateMethodType(jvmMethodTypeCall: IrCall, codegen: ExpressionCodegen): Any {
|
||||
val irRawFunctionReference = jvmMethodTypeCall.getValueArgument(0) as? IrRawFunctionReference
|
||||
?: throw AssertionError(
|
||||
"Argument in ${jvmMethodTypeCall.symbol.owner.name} call is expected to be a raw function reference:\n" +
|
||||
jvmMethodTypeCall.dump()
|
||||
)
|
||||
val irFun = irRawFunctionReference.symbol.owner
|
||||
// TODO substitute signature
|
||||
val asmMethod = codegen.methodSignatureMapper.mapAsmMethod(irFun)
|
||||
return Type.getMethodType(asmMethod.descriptor)
|
||||
}
|
||||
|
||||
private fun IrExpression.getIntConst() =
|
||||
if (this is IrConst<*> && kind == IrConstKind.Int)
|
||||
this.value as Int
|
||||
else
|
||||
null
|
||||
|
||||
private fun IrExpression.getStringConst() =
|
||||
if (this is IrConst<*> && kind == IrConstKind.String)
|
||||
this.value as String
|
||||
else
|
||||
null
|
||||
|
||||
}
|
||||
+64
-17
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
||||
import org.jetbrains.kotlin.config.JvmSamConversions
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
@@ -21,10 +22,7 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -80,6 +78,9 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
FunctionReferenceBuilder(expression).build()
|
||||
}
|
||||
|
||||
private val shouldUseIndySamConversions =
|
||||
context.state.samConversionsScheme == JvmSamConversions.INDY
|
||||
|
||||
// Handle SAM conversions which wrap a function reference:
|
||||
// class sam$n(private val receiver: R) : Interface { override fun method(...) = receiver.target(...) }
|
||||
//
|
||||
@@ -87,20 +88,66 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
// This is actually very common, as `Interface { something }` is a local function + a SAM-conversion
|
||||
// of a reference to it into an implementation.
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||
if (expression.operator == IrTypeOperator.SAM_CONVERSION) {
|
||||
val invokable = expression.argument
|
||||
val reference = if (invokable is IrFunctionReference) {
|
||||
invokable
|
||||
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
||||
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||
invokable.statements.last() as IrFunctionReference
|
||||
} else {
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
reference.transformChildrenVoid()
|
||||
return FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
||||
if (expression.operator != IrTypeOperator.SAM_CONVERSION) {
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
|
||||
val invokable = expression.argument
|
||||
val reference = if (invokable is IrFunctionReference) {
|
||||
invokable
|
||||
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
||||
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||
invokable.statements.last() as IrFunctionReference
|
||||
} else {
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
reference.transformChildrenVoid()
|
||||
|
||||
return if (shouldUseIndySamConversions) {
|
||||
wrapSamConversionArgumentWithIndySamConversion(expression)
|
||||
} else {
|
||||
FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapSamConversionArgumentWithIndySamConversion(expression: IrTypeOperatorCall): IrExpression {
|
||||
return when (val argument = expression.argument) {
|
||||
is IrFunctionReference ->
|
||||
wrapWithIndySamConversion(expression.typeOperand, argument)
|
||||
is IrBlock -> {
|
||||
val last = argument.statements.last()
|
||||
val functionReference = last as? IrFunctionReference
|
||||
?: throw AssertionError("Function reference expected: ${last.render()}")
|
||||
argument.statements[argument.statements.size - 1] = wrapWithIndySamConversion(expression.typeOperand, functionReference)
|
||||
return argument
|
||||
}
|
||||
else -> throw AssertionError("Block or function reference expected: ${expression.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
private val jvmIndySamConversionIntrinsic = context.ir.symbols.indySamConversionIntrinsic
|
||||
|
||||
private val specialNullabilityAnnotationsFqNames =
|
||||
setOf(
|
||||
context.ir.symbols.flexibleNullabilityAnnotationFqName,
|
||||
context.ir.symbols.enhancedNullabilityAnnotationFqName
|
||||
)
|
||||
|
||||
private fun wrapWithIndySamConversion(samType: IrType, irFunRef: IrFunctionReference): IrCall {
|
||||
val notNullSamType = samType.makeNotNull()
|
||||
.removeAnnotations { it.type.classFqName in specialNullabilityAnnotationsFqNames }
|
||||
return context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
|
||||
// We should produce the following expression:
|
||||
// `<jvm-indy-sam-conversion>`<samType>(method)
|
||||
// where:
|
||||
// - 'samType' is a substituted SAM type;
|
||||
// - 'method' is a function reference to the actual method we are going to call
|
||||
// (note that we need an IrFunctionReference here, so that further transformations would extract closure properly).
|
||||
irCall(jvmIndySamConversionIntrinsic, notNullSamType).apply {
|
||||
putTypeArgument(0, notNullSamType)
|
||||
putValueArgument(0, irFunRef)
|
||||
}
|
||||
}
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
|
||||
private inner class FunctionReferenceBuilder(val irFunctionReference: IrFunctionReference, val samSuperType: IrType? = null) {
|
||||
|
||||
-2
@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.util.isLambda
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
|
||||
internal val removeDeclarationsThatWouldBeInlined = makeIrModulePhase(
|
||||
|
||||
+180
-4
@@ -11,26 +11,33 @@ import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.isInlined
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.Handle
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
// After this pass runs there are only four kinds of IrTypeOperatorCalls left:
|
||||
//
|
||||
@@ -95,6 +102,175 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
|
||||
builder.irAs(argument, type)
|
||||
}
|
||||
|
||||
private val indySamConversionIntrinsic = context.ir.symbols.indySamConversionIntrinsic
|
||||
|
||||
private val indyIntrinsic = context.ir.symbols.jvmIndyIntrinsic
|
||||
|
||||
private fun IrBuilderWithScope.jvmInvokeDynamic(
|
||||
dynamicCall: IrCall,
|
||||
bootstrapMethod: Handle,
|
||||
bootstrapMethodArguments: List<IrExpression>
|
||||
) =
|
||||
irCall(indyIntrinsic, dynamicCall.type).apply {
|
||||
putTypeArgument(0, dynamicCall.type)
|
||||
putValueArgument(0, dynamicCall)
|
||||
putValueArgument(1, irInt(bootstrapMethod.tag))
|
||||
putValueArgument(2, irString(bootstrapMethod.owner))
|
||||
putValueArgument(3, irString(bootstrapMethod.name))
|
||||
putValueArgument(4, irString(bootstrapMethod.desc))
|
||||
putValueArgument(5, irVararg(context.irBuiltIns.anyType, bootstrapMethodArguments))
|
||||
}
|
||||
|
||||
private val methodTypeIntrinsic = context.ir.symbols.jvmMethodTypeIntrinsic
|
||||
|
||||
private fun IrBuilderWithScope.jvmMethodType(ownerType: IrType, methodSymbol: IrFunctionSymbol) =
|
||||
irCall(methodTypeIntrinsic, context.irBuiltIns.anyType).apply {
|
||||
putTypeArgument(0, ownerType)
|
||||
putValueArgument(0, irRawFunctionReferefence(context.irBuiltIns.anyType, methodSymbol))
|
||||
}
|
||||
|
||||
private val lambdaMetafactoryHandle =
|
||||
Handle(
|
||||
Opcodes.H_INVOKESTATIC,
|
||||
"java/lang/invoke/LambdaMetafactory",
|
||||
"metafactory",
|
||||
"(" +
|
||||
"Ljava/lang/invoke/MethodHandles\$Lookup;" +
|
||||
"Ljava/lang/String;" +
|
||||
"Ljava/lang/invoke/MethodType;" +
|
||||
"Ljava/lang/invoke/MethodType;" +
|
||||
"Ljava/lang/invoke/MethodHandle;" +
|
||||
"Ljava/lang/invoke/MethodType;" +
|
||||
")Ljava/lang/invoke/CallSite;",
|
||||
false
|
||||
)
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
return when (expression.symbol) {
|
||||
indySamConversionIntrinsic -> updateIndySamConversionIntrinsicCall(expression)
|
||||
else -> super.visitCall(expression)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see FunctionReferenceLowering.wrapWithIndySamConversion
|
||||
*/
|
||||
private fun updateIndySamConversionIntrinsicCall(call: IrCall): IrCall {
|
||||
fun fail(message: String): Nothing =
|
||||
throw AssertionError("$message, call:\n${call.dump()}")
|
||||
|
||||
// We expect:
|
||||
// `<jvm-indy-sam-conversion>`<samType>(method)
|
||||
// where
|
||||
// - 'samType' is a substituted SAM type;
|
||||
// - 'method' is an IrFunctionReference to an actual method that should be called,
|
||||
// with arguments captured by closure stored as function reference arguments.
|
||||
// We replace it with JVM INVOKEDYNAMIC intrinsic.
|
||||
|
||||
val startOffset = call.startOffset
|
||||
val endOffset = call.endOffset
|
||||
|
||||
val samType = call.getTypeArgument(0) as? IrSimpleType
|
||||
?: fail("'samType' is expected to be a simple type")
|
||||
val samClassSymbol = samType.classOrNull
|
||||
?: fail("'samType' is expected to be a class type: '${samType.render()}'")
|
||||
val samMethod = samClassSymbol.owner.functions.singleOrNull { it.modality == Modality.ABSTRACT }
|
||||
?: fail("'${samType.render()}' is not a SAM-type")
|
||||
|
||||
val irFunRef = call.getValueArgument(0) as? IrFunctionReference
|
||||
?: fail("'method' is expected to be 'IrFunctionReference'")
|
||||
val funSymbol = irFunRef.symbol
|
||||
|
||||
val erasedSamType = samClassSymbol.defaultType as IrSimpleType
|
||||
val dynamicCall = wrapClosureInDynamicCall(erasedSamType, samMethod, irFunRef)
|
||||
|
||||
return context.createJvmIrBuilder(
|
||||
funSymbol, // TODO actual symbol for outer scope
|
||||
startOffset, endOffset
|
||||
).run {
|
||||
val samMethodType = jvmMethodType(erasedSamType, samMethod.symbol)
|
||||
val irRawFunRef = irRawFunctionReferefence(irFunRef.type, funSymbol)
|
||||
val instanceMethodType = jvmMethodType(samType, samMethod.symbol)
|
||||
|
||||
jvmInvokeDynamic(
|
||||
dynamicCall,
|
||||
lambdaMetafactoryHandle,
|
||||
listOf(samMethodType, irRawFunRef, instanceMethodType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapClosureInDynamicCall(
|
||||
erasedSamType: IrSimpleType,
|
||||
samMethod: IrSimpleFunction,
|
||||
irFunRef: IrFunctionReference
|
||||
): IrCall {
|
||||
fun fail(message: String): Nothing =
|
||||
throw AssertionError("$message, irFunRef:\n${irFunRef.dump()}")
|
||||
|
||||
val dynamicCallArguments = ArrayList<IrExpression>()
|
||||
|
||||
val irDynamicCallTarget = context.irFactory.buildFun {
|
||||
origin = JvmLoweredDeclarationOrigin.INVOVEDYNAMIC_CALL_TARGET
|
||||
name = samMethod.name
|
||||
returnType = erasedSamType
|
||||
}.apply {
|
||||
parent = context.ir.symbols.kotlinJvmInternalInvokeDynamicPackage
|
||||
|
||||
var syntheticParameterIndex = 0
|
||||
val targetFun = irFunRef.symbol.owner
|
||||
|
||||
val targetDispatchReceiverParameter = targetFun.dispatchReceiverParameter
|
||||
if (targetDispatchReceiverParameter != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetDispatchReceiverParameter.type)
|
||||
val dispatchReceiver = irFunRef.dispatchReceiver
|
||||
?: fail("Captured dispatch receiver is not provided")
|
||||
dynamicCallArguments.add(dispatchReceiver)
|
||||
}
|
||||
|
||||
val targetExtensionReceiverParameter = targetFun.extensionReceiverParameter
|
||||
if (targetExtensionReceiverParameter != null) {
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetExtensionReceiverParameter.type)
|
||||
val extensionReceiver = irFunRef.extensionReceiver
|
||||
?: fail("Captured extension receiver is not provided")
|
||||
dynamicCallArguments.add(extensionReceiver)
|
||||
}
|
||||
|
||||
val samMethodValueParametersCount = samMethod.valueParameters.size
|
||||
val targetFunValueParametersCount = targetFun.valueParameters.size
|
||||
for (i in 0 until targetFunValueParametersCount - samMethodValueParametersCount) {
|
||||
val targetFunValueParameter = targetFun.valueParameters[i]
|
||||
addValueParameter("p${syntheticParameterIndex++}", targetFunValueParameter.type)
|
||||
val capturedValueArgument = irFunRef.getValueArgument(i)
|
||||
?: fail("Captured value argument #$i (${targetFunValueParameter.name} not provided")
|
||||
dynamicCallArguments.add(capturedValueArgument)
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamicCallArguments.size != irDynamicCallTarget.valueParameters.size) {
|
||||
throw AssertionError(
|
||||
"Dynamic call target value parameters (${irDynamicCallTarget.valueParameters.size}) " +
|
||||
"don't match dynamic call arguments (${dynamicCallArguments.size}):\n" +
|
||||
"irDynamicCallTarget:\n" +
|
||||
irDynamicCallTarget.dump() +
|
||||
"dynamicCallArguments:\n" +
|
||||
dynamicCallArguments
|
||||
.withIndex()
|
||||
.joinToString(separator = "\n ", prefix = "[\n ", postfix = "\n]") { (index, irArg) ->
|
||||
"#$index: ${irArg.dump()}"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return context.createJvmIrBuilder(irDynamicCallTarget.symbol)
|
||||
.irCall(irDynamicCallTarget.symbol)
|
||||
.apply {
|
||||
for (i in dynamicCallArguments.indices) {
|
||||
putValueArgument(i, dynamicCallArguments[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression = with(builder) {
|
||||
at(expression)
|
||||
return when (expression.operator) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.isImmutable
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
@@ -326,6 +327,11 @@ fun IrBuilderWithScope.irString(value: String) =
|
||||
fun IrBuilderWithScope.irConcat() =
|
||||
IrStringConcatenationImpl(startOffset, endOffset, context.irBuiltIns.stringType)
|
||||
|
||||
fun IrBuilderWithScope.irVararg(elementType: IrType, values: List<IrExpression>) =
|
||||
IrVarargImpl(startOffset, endOffset, context.irBuiltIns.arrayClass.typeWith(elementType), elementType, values)
|
||||
|
||||
fun IrBuilderWithScope.irRawFunctionReferefence(type: IrType, symbol: IrFunctionSymbol) =
|
||||
IrRawFunctionReferenceImpl(startOffset, endOffset, type, symbol)
|
||||
|
||||
inline fun IrBuilderWithScope.irBlock(
|
||||
startOffset: Int = this.startOffset,
|
||||
|
||||
@@ -645,6 +645,9 @@ class RenderIrElementVisitor(private val normalizeNames: Boolean = false) : IrEl
|
||||
"type=${expression.type.render()} origin=${expression.origin} " +
|
||||
"reflectionTarget=${renderReflectionTarget(expression)}"
|
||||
|
||||
override fun visitRawFunctionReference(expression: IrRawFunctionReference, data: Nothing?): String =
|
||||
"RAW_FUNCTION_REFERENCE '${expression.symbol.renderReference()}' type=${expression.type.render()}"
|
||||
|
||||
private fun renderReflectionTarget(expression: IrFunctionReference) =
|
||||
if (expression.symbol == expression.reflectionTarget)
|
||||
"<same>"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
|
||||
fun interface KRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun runIt(kr: KRunnable) {
|
||||
kr.run()
|
||||
}
|
||||
|
||||
class C(var value: String) {
|
||||
fun fn() {
|
||||
value = "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = C("xxx")
|
||||
runIt(c::fn)
|
||||
return c.value
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
|
||||
fun interface KRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun runIt(kr: KRunnable) {
|
||||
kr.run()
|
||||
}
|
||||
|
||||
class C(var value: String) {
|
||||
fun test(): String {
|
||||
runIt { value = "OK" }
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
fun box() = C("xxx").test()
|
||||
@@ -0,0 +1,20 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
|
||||
fun interface KRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun runIt(kr: KRunnable) {
|
||||
kr.run()
|
||||
}
|
||||
|
||||
class C(var value: String)
|
||||
|
||||
fun C.test(): String {
|
||||
runIt { value = "OK" }
|
||||
return value
|
||||
}
|
||||
|
||||
fun box() = C("xxx").test()
|
||||
@@ -0,0 +1,20 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
|
||||
fun interface KRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun runIt(r: KRunnable) {
|
||||
r.run()
|
||||
}
|
||||
|
||||
var test = "Failed"
|
||||
|
||||
fun box(): String {
|
||||
val ok = "OK"
|
||||
runIt { test = ok }
|
||||
return test
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: capturingIndySam.kt
|
||||
var test = "Failed"
|
||||
|
||||
fun box(): String {
|
||||
val ok = "OK"
|
||||
J.run { test = ok }
|
||||
return test
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
public class J {
|
||||
public static void run(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: primitiveVsWrapperInSam.kt
|
||||
var test = 0
|
||||
|
||||
fun tf2(k: Int) { test = k * 10 }
|
||||
|
||||
fun tf4() = 5678
|
||||
|
||||
fun box(): String {
|
||||
J.accept42 { k: Int -> test = k }
|
||||
if (test != 42) return "Failed 1: test=$test"
|
||||
|
||||
J.accept42(::tf2)
|
||||
if (test != 420) return "Failed 2: test=$test"
|
||||
|
||||
val t3 = J.get { 1234 }
|
||||
if (t3 != 1234) return "Failed 3: t3=$t3"
|
||||
|
||||
val t4 = J.get(::tf4)
|
||||
if (t4 != 5678) return "Failed 4: t4=$t4"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
public class J {
|
||||
public static void accept42(Sam1 sam) {
|
||||
sam.accept(42);
|
||||
}
|
||||
|
||||
public static int get(Sam2 sam) {
|
||||
return sam.get();
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: Sam1.java
|
||||
public interface Sam1 {
|
||||
void accept(Integer x);
|
||||
}
|
||||
|
||||
// FILE: Sam2.java
|
||||
public interface Sam2 {
|
||||
Integer get();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
|
||||
fun interface KRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun runIt(r: KRunnable) {
|
||||
r.run()
|
||||
}
|
||||
|
||||
var test = "Failed"
|
||||
|
||||
fun box(): String {
|
||||
runIt { test = "OK" }
|
||||
return test
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// JVM_TARGET: 1.8
|
||||
// SAM_CONVERSIONS: INDY
|
||||
// FILE: simpleIndySam.kt
|
||||
var test = "Failed"
|
||||
|
||||
fun box(): String {
|
||||
J.run { test = "OK" }
|
||||
return test
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
public class J {
|
||||
public static void run(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
+68
@@ -18379,6 +18379,74 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Invokedynamic extends AbstractBlackBoxCodegenTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Sam extends AbstractBlackBoxCodegenTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundReference.kt")
|
||||
public void testBoundReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedDispatchReceiver.kt")
|
||||
public void testCapturedDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedExtensionReceiver.kt")
|
||||
public void testCapturedExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingIndyFunInterface.kt")
|
||||
public void testCapturingIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingIndySam.kt")
|
||||
public void testCapturingIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIndyFunInterface.kt")
|
||||
public void testSimpleIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIndySam.kt")
|
||||
public void testSimpleIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+68
@@ -18379,6 +18379,74 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Invokedynamic extends AbstractIrBlackBoxCodegenTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Sam extends AbstractIrBlackBoxCodegenTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("boundReference.kt")
|
||||
public void testBoundReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedDispatchReceiver.kt")
|
||||
public void testCapturedDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedExtensionReceiver.kt")
|
||||
public void testCapturedExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingIndyFunInterface.kt")
|
||||
public void testCapturingIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturingIndySam.kt")
|
||||
public void testCapturingIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIndyFunInterface.kt")
|
||||
public void testSimpleIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleIndySam.kt")
|
||||
public void testSimpleIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+3
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.directives
|
||||
|
||||
import org.jetbrains.kotlin.config.JvmSamConversions
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import org.jetbrains.kotlin.test.backend.handlers.BytecodeTextHandler
|
||||
import org.jetbrains.kotlin.test.backend.handlers.IrPrettyKotlinDumpHandler
|
||||
@@ -90,4 +91,6 @@ object CodegenTestDirectives : SimpleDirectivesContainer() {
|
||||
val TREAT_AS_ONE_FILE by directive(
|
||||
description = "Treat bytecode from all files as one in ${BytecodeTextHandler::class}"
|
||||
)
|
||||
|
||||
val SAM_CONVERSIONS by enumDirective<JvmSamConversions>("SAM conversion code generation scheme")
|
||||
}
|
||||
|
||||
+11
@@ -39,3 +39,14 @@ abstract class AbstractJvmBlackBoxCodegenTestBase<R : ResultingArtifact.Frontend
|
||||
useAfterAnalysisCheckers(::BlackBoxCodegenSuppressor)
|
||||
}
|
||||
}
|
||||
|
||||
// This class configures various JVM-specific codegen minutiae.
|
||||
// Ideally, test directives could take care of such things themselves.
|
||||
class JvmCodegenEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
|
||||
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule, project: MockProject) {
|
||||
val samConversions = module.directives[CodegenTestDirectives.SAM_CONVERSIONS].lastOrNull()
|
||||
if (samConversions != null) {
|
||||
configuration.put(JVMConfigurationKeys.SAM_CONVERSIONS, samConversions)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
|
||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE
|
||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.CONSTRUCTOR_CALL_NORMALIZATION_MODE
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.TestHelperGeneratorKt;
|
||||
import org.jetbrains.kotlin.TestsCompilerError;
|
||||
import org.jetbrains.kotlin.TestsCompiletimeError;
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile;
|
||||
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection;
|
||||
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
@@ -40,19 +39,9 @@ import org.jetbrains.kotlin.test.*;
|
||||
import org.jetbrains.kotlin.test.clientserver.TestProxy;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader;
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.SimpleVerifier;
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
+66
@@ -16109,6 +16109,72 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Invokedynamic extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Sam extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("boundReference.kt")
|
||||
public void testBoundReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/boundReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturedDispatchReceiver.kt")
|
||||
public void testCapturedDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturedExtensionReceiver.kt")
|
||||
public void testCapturedExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturedExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturingIndyFunInterface.kt")
|
||||
public void testCapturingIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturingIndySam.kt")
|
||||
public void testCapturingIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/capturingIndySam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primitiveVsWrapperInSam.kt")
|
||||
public void testPrimitiveVsWrapperInSam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/primitiveVsWrapperInSam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleIndyFunInterface.kt")
|
||||
public void testSimpleIndyFunInterface() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndyFunInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleIndySam.kt")
|
||||
public void testSimpleIndySam() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/invokedynamic/sam/simpleIndySam.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+26
@@ -13879,6 +13879,32 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Invokedynamic extends AbstractIrJsCodegenBoxES6Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Sam extends AbstractIrJsCodegenBoxES6Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+26
@@ -13879,6 +13879,32 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Invokedynamic extends AbstractIrJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Sam extends AbstractIrJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Generated
+26
@@ -13944,6 +13944,32 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Invokedynamic extends AbstractJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Sam extends AbstractJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+26
@@ -8040,6 +8040,32 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Invokedynamic extends AbstractIrCodegenBoxWasmTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInvokedynamic() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/invokedynamic/sam")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Sam extends AbstractIrCodegenBoxWasmTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSam() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/invokedynamic/sam"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user