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
|
configuration.get(JVMConfigurationKeys.STRING_CONCAT) ?: JvmStringConcat.INLINE
|
||||||
else 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 moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
|
||||||
val classBuilderMode: ClassBuilderMode = builderFactory.classBuilderMode
|
val classBuilderMode: ClassBuilderMode = builderFactory.classBuilderMode
|
||||||
val bindingTrace: BindingTrace = DelegatingBindingTrace(
|
val bindingTrace: BindingTrace = DelegatingBindingTrace(
|
||||||
|
|||||||
+9
@@ -362,6 +362,15 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
var stringConcat: String? by NullableStringFreezableVar(JvmStringConcat.INLINE.description)
|
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(
|
@Argument(
|
||||||
value = "-Xklib",
|
value = "-Xklib",
|
||||||
valueDescription = "<path>",
|
valueDescription = "<path>",
|
||||||
|
|||||||
@@ -59,8 +59,28 @@ fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArgu
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
messageCollector.report(
|
messageCollector.report(
|
||||||
ERROR, "Unknown -Xstring-concat mode: ${arguments.jvmTarget}\n" +
|
ERROR, "Unknown `-Xstring-concat` mode: ${arguments.stringConcat}\n" +
|
||||||
"Supported versions: ${JvmStringConcat.values().joinToString { it.description }}"
|
"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 =
|
public static final CompilerConfigurationKey<JvmStringConcat> STRING_CONCAT =
|
||||||
CompilerConfigurationKey.create("Specifies string concatenation scheme");
|
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 =
|
public static final CompilerConfigurationKey<List<String>> KLIB_PATHS =
|
||||||
CompilerConfigurationKey.create("Paths to .klib libraries");
|
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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+20
-13
@@ -65,7 +65,11 @@ fun IrClass.addField(fieldName: Name, fieldType: IrType, fieldVisibility: Descri
|
|||||||
visibility = fieldVisibility
|
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)
|
addField(Name.identifier(fieldName), fieldType, fieldVisibility)
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
@@ -141,16 +145,16 @@ inline fun IrClass.addFunction(builder: IrFunctionBuilder.() -> Unit): IrSimpleF
|
|||||||
factory.addFunction(this, builder)
|
factory.addFunction(this, builder)
|
||||||
|
|
||||||
fun IrClass.addFunction(
|
fun IrClass.addFunction(
|
||||||
name: String,
|
name: String,
|
||||||
returnType: IrType,
|
returnType: IrType,
|
||||||
modality: Modality = Modality.FINAL,
|
modality: Modality = Modality.FINAL,
|
||||||
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC,
|
visibility: DescriptorVisibility = DescriptorVisibilities.PUBLIC,
|
||||||
isStatic: Boolean = false,
|
isStatic: Boolean = false,
|
||||||
isSuspend: Boolean = false,
|
isSuspend: Boolean = false,
|
||||||
isFakeOverride: Boolean = false,
|
isFakeOverride: Boolean = false,
|
||||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
|
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED,
|
||||||
startOffset: Int = UNDEFINED_OFFSET,
|
startOffset: Int = UNDEFINED_OFFSET,
|
||||||
endOffset: Int = UNDEFINED_OFFSET
|
endOffset: Int = UNDEFINED_OFFSET
|
||||||
): IrSimpleFunction =
|
): IrSimpleFunction =
|
||||||
addFunction {
|
addFunction {
|
||||||
this.startOffset = startOffset
|
this.startOffset = startOffset
|
||||||
@@ -216,7 +220,7 @@ internal fun IrFactory.buildValueParameter(builder: IrValueParameterBuilder, par
|
|||||||
|
|
||||||
|
|
||||||
inline fun <D> buildValueParameter(declaration: D, builder: IrValueParameterBuilder.() -> Unit): IrValueParameter
|
inline fun <D> buildValueParameter(declaration: D, builder: IrValueParameterBuilder.() -> Unit): IrValueParameter
|
||||||
where D : IrDeclaration, D : IrDeclarationParent =
|
where D : IrDeclaration, D : IrDeclarationParent =
|
||||||
IrValueParameterBuilder().run {
|
IrValueParameterBuilder().run {
|
||||||
builder()
|
builder()
|
||||||
declaration.factory.buildValueParameter(this, declaration)
|
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 =
|
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 {
|
addValueParameter {
|
||||||
this.name = Name.identifier(name)
|
this.name = name
|
||||||
this.type = type
|
this.type = type
|
||||||
this.origin = origin
|
this.origin = origin
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -46,4 +46,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
|||||||
object COMPANION_PROPERTY_BACKING_FIELD : IrDeclarationOriginImpl("COMPANION_PROPERTY_BACKING_FIELD")
|
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 FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE")
|
||||||
object ABSTRACT_BRIDGE_STUB : IrDeclarationOriginImpl("ABSTRACT_BRIDGE_STUB")
|
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
|
package org.jetbrains.kotlin.backend.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
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.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
@@ -51,6 +50,17 @@ class JvmSymbols(
|
|||||||
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
|
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
|
||||||
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
|
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 val generateOptimizedCallableReferenceSuperClasses = context.state.generateOptimizedCallableReferenceSuperClasses
|
||||||
|
|
||||||
private fun createPackage(fqName: FqName): IrPackageFragment =
|
private fun createPackage(fqName: FqName): IrPackageFragment =
|
||||||
@@ -535,6 +545,82 @@ class JvmSymbols(
|
|||||||
returnType = dst.defaultType
|
returnType = dst.defaultType
|
||||||
}.symbol
|
}.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 ->
|
private val collectionToArrayClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.CollectionToArray")) { klass ->
|
||||||
klass.origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
klass.origin = JvmLoweredDeclarationOrigin.TO_ARRAY
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -418,7 +418,7 @@ class ExpressionCodegen(
|
|||||||
|
|
||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
require(callee.parent is IrClass) { "Unhandled intrinsic in ExpressionCodegen: ${callee.render()}" }
|
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 callGenerator = getOrCreateCallGenerator(expression, data, callable.signature)
|
||||||
val isSuspensionPoint = expression.isSuspensionPoint()
|
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
|
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 callee = expression.symbol.owner
|
||||||
val calleeParent = expression.superQualifierSymbol?.owner
|
val calleeParent = expression.superQualifierSymbol?.owner
|
||||||
?: expression.dispatchReceiver?.type?.classOrNull?.owner
|
?: expression.dispatchReceiver?.type?.classOrNull?.owner
|
||||||
@@ -385,17 +386,21 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val declaration = findSuperDeclaration(callee, isSuperCall)
|
val declaration = findSuperDeclaration(callee, isSuperCall)
|
||||||
val signature = mapOverriddenSpecialBuiltinIfNeeded(caller, declaration, isSuperCall)
|
val signature =
|
||||||
?: mapSignatureSkipGeneric(declaration)
|
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)
|
return IrCallableMethod(owner, invokeOpcode, signature, isInterface)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: get rid of this (probably via some special lowering)
|
// TODO: get rid of this (probably via some special lowering)
|
||||||
private fun mapOverriddenSpecialBuiltinIfNeeded(caller: IrFunction, callee: IrFunction, superCall: Boolean): JvmMethodSignature? {
|
private fun mapOverriddenSpecialBuiltinIfNeeded(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
|
|
||||||
// Do not remap calls to static replacements of inline class methods, since they have completely different signatures.
|
// Do not remap calls to static replacements of inline class methods, since they have completely different signatures.
|
||||||
if (callee.isStaticInlineClassReplacement) return null
|
if (callee.isStaticInlineClassReplacement) return null
|
||||||
val overriddenSpecialBuiltinFunction =
|
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.throwTypeCastException.toKey()!! to ThrowException(Type.getObjectType("kotlin/TypeCastException")),
|
||||||
symbols.throwUnsupportedOperationException.toKey()!! to ThrowException(Type.getObjectType("java/lang/UnsupportedOperationException")),
|
symbols.throwUnsupportedOperationException.toKey()!! to ThrowException(Type.getObjectType("java/lang/UnsupportedOperationException")),
|
||||||
symbols.throwKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException,
|
symbols.throwKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException,
|
||||||
|
symbols.jvmIndyIntrinsic.toKey()!! to JvmInvokeDynamic
|
||||||
) +
|
) +
|
||||||
numberConversionMethods() +
|
numberConversionMethods() +
|
||||||
unaryFunForPrimitives("plus", UnaryPlus) +
|
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.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
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.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
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.builders.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
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.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
@@ -80,6 +78,9 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
FunctionReferenceBuilder(expression).build()
|
FunctionReferenceBuilder(expression).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val shouldUseIndySamConversions =
|
||||||
|
context.state.samConversionsScheme == JvmSamConversions.INDY
|
||||||
|
|
||||||
// Handle SAM conversions which wrap a function reference:
|
// Handle SAM conversions which wrap a function reference:
|
||||||
// class sam$n(private val receiver: R) : Interface { override fun method(...) = receiver.target(...) }
|
// 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
|
// This is actually very common, as `Interface { something }` is a local function + a SAM-conversion
|
||||||
// of a reference to it into an implementation.
|
// of a reference to it into an implementation.
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||||
if (expression.operator == IrTypeOperator.SAM_CONVERSION) {
|
if (expression.operator != IrTypeOperator.SAM_CONVERSION) {
|
||||||
val invokable = expression.argument
|
return super.visitTypeOperator(expression)
|
||||||
val reference = if (invokable is IrFunctionReference) {
|
}
|
||||||
invokable
|
|
||||||
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
val invokable = expression.argument
|
||||||
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
val reference = if (invokable is IrFunctionReference) {
|
||||||
invokable.statements.last() as IrFunctionReference
|
invokable
|
||||||
} else {
|
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
||||||
return super.visitTypeOperator(expression)
|
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||||
}
|
invokable.statements.last() as IrFunctionReference
|
||||||
reference.transformChildrenVoid()
|
} else {
|
||||||
return FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
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) {
|
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.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
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.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
|
||||||
internal val removeDeclarationsThatWouldBeInlined = makeIrModulePhase(
|
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.lower.irNot
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
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.codegen.fileParent
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
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.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
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.isInlined
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
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:
|
// 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)
|
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) {
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression = with(builder) {
|
||||||
at(expression)
|
at(expression)
|
||||||
return when (expression.operator) {
|
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.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.isImmutable
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
@@ -326,6 +327,11 @@ fun IrBuilderWithScope.irString(value: String) =
|
|||||||
fun IrBuilderWithScope.irConcat() =
|
fun IrBuilderWithScope.irConcat() =
|
||||||
IrStringConcatenationImpl(startOffset, endOffset, context.irBuiltIns.stringType)
|
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(
|
inline fun IrBuilderWithScope.irBlock(
|
||||||
startOffset: Int = this.startOffset,
|
startOffset: Int = this.startOffset,
|
||||||
|
|||||||
@@ -645,6 +645,9 @@ class RenderIrElementVisitor(private val normalizeNames: Boolean = false) : IrEl
|
|||||||
"type=${expression.type.render()} origin=${expression.origin} " +
|
"type=${expression.type.render()} origin=${expression.origin} " +
|
||||||
"reflectionTarget=${renderReflectionTarget(expression)}"
|
"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) =
|
private fun renderReflectionTarget(expression: IrFunctionReference) =
|
||||||
if (expression.symbol == expression.reflectionTarget)
|
if (expression.symbol == expression.reflectionTarget)
|
||||||
"<same>"
|
"<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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@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
|
@Nested
|
||||||
@TestMetadata("compiler/testData/codegen/box/ir")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+3
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.test.directives
|
package org.jetbrains.kotlin.test.directives
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.JvmSamConversions
|
||||||
import org.jetbrains.kotlin.test.TargetBackend
|
import org.jetbrains.kotlin.test.TargetBackend
|
||||||
import org.jetbrains.kotlin.test.backend.handlers.BytecodeTextHandler
|
import org.jetbrains.kotlin.test.backend.handlers.BytecodeTextHandler
|
||||||
import org.jetbrains.kotlin.test.backend.handlers.IrPrettyKotlinDumpHandler
|
import org.jetbrains.kotlin.test.backend.handlers.IrPrettyKotlinDumpHandler
|
||||||
@@ -90,4 +91,6 @@ object CodegenTestDirectives : SimpleDirectivesContainer() {
|
|||||||
val TREAT_AS_ONE_FILE by directive(
|
val TREAT_AS_ONE_FILE by directive(
|
||||||
description = "Treat bytecode from all files as one in ${BytecodeTextHandler::class}"
|
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)
|
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.platform.jvm.JvmPlatforms
|
||||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
import org.jetbrains.kotlin.test.TestJdkKind
|
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
|
||||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE
|
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE
|
||||||
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.CONSTRUCTOR_CALL_NORMALIZATION_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.TestHelperGeneratorKt;
|
||||||
import org.jetbrains.kotlin.TestsCompilerError;
|
import org.jetbrains.kotlin.TestsCompilerError;
|
||||||
import org.jetbrains.kotlin.TestsCompiletimeError;
|
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.backend.common.output.SimpleOutputFileCollection;
|
||||||
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil;
|
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil;
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
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.clientserver.TestProxy;
|
||||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.MalformedURLException;
|
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")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("compiler/testData/codegen/box/ir")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user