Obtain reification marker on default lambda extraction.

Add reification tests.
This commit is contained in:
Mikhael Bogdanov
2017-05-12 13:37:47 +02:00
parent 47c5e64ba5
commit 309051bd21
11 changed files with 234 additions and 9 deletions
@@ -522,7 +522,7 @@ public class InlineCodegen extends CallGenerator {
private void generateClosuresBodies() {
for (LambdaInfo info : expressionMap.values()) {
info.generateLambdaBody(codegen);
info.generateLambdaBody(codegen, reifiedTypeInliner);
}
}
@@ -50,7 +50,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean, @JvmField val is
lateinit var node: SMAPAndMethodNode
abstract fun generateLambdaBody(codegen: ExpressionCodegen)
abstract fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner)
fun addAllParameters(remapper: FieldRemapper): Parameters {
val builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, invokeMethod.descriptor, this)
@@ -81,7 +81,8 @@ class DefaultLambda(
override val lambdaClassType: Type,
val capturedArgs: Array<Type>,
val parameterDescriptor: ValueParameterDescriptor,
val offset: Int
val offset: Int,
val needReification: Boolean
) : LambdaInfo(parameterDescriptor.isCrossinline, false) {
val parameterOffsetsInDefault: MutableList<Int> = arrayListOf()
@@ -99,7 +100,7 @@ class DefaultLambda(
override fun isMyLabel(name: String): Boolean = false
override fun generateLambdaBody(codegen: ExpressionCodegen) {
override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) {
val classReader = InlineCodegenUtil.buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName)
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
@@ -129,6 +130,11 @@ class DefaultLambda(
invokeMethod.name,
invokeMethod.descriptor,
lambdaClassType.internalName)!!
if (needReification) {
//nested classes could also require reification
reifiedTypeInliner.reifyInstructions(node.node)
}
}
}
@@ -223,7 +229,7 @@ class ExpressionLambda(
val isPropertyReference: Boolean
get() = propertyReferenceInfo != null
override fun generateLambdaBody(codegen: ExpressionCodegen) {
override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) {
val closureContext =
if (isPropertyReference)
codegen.getContext().intoAnonymousClass(classDescriptor, codegen, OwnerKind.IMPLEMENTATION)
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.isNeedClassReificationMarker
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.insnText
@@ -153,7 +154,7 @@ private fun extractDefaultLambdasInfo(
instanceInstuction = instanceInstuction.previous
}
val (owner, argTypes) = when (instanceInstuction) {
val (owner, argTypes, needReification) = when (instanceInstuction) {
is MethodInsnNode -> {
assert(instanceInstuction.name == "<init>") { "Expected constructor call for default lambda, but $instanceInstuction" }
val ownerInternalName = instanceInstuction.owner
@@ -170,20 +171,23 @@ private fun extractDefaultLambdasInfo(
addAll(InsnSequence(instanceInstuction, varAssignmentInstruction.next).toList())
}
Type.getObjectType(instanceInstuction.owner) to Type.getArgumentTypes(instanceInstuction.desc)
val needReification = instanceCreation.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null
Triple(Type.getObjectType(instanceInstuction.owner), Type.getArgumentTypes(instanceInstuction.desc), needReification)
}
is FieldInsnNode -> {
toDelete.addAll(InsnSequence(instanceInstuction, varAssignmentInstruction.next).toList())
Type.getObjectType(instanceInstuction.owner) to emptyArray<Type>()
val needReification = instanceInstuction.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null
Triple(Type.getObjectType(instanceInstuction.owner), emptyArray<Type>(), needReification)
}
else -> throw RuntimeException("Can't extract default lambda info $it.\n Unknown instruction: ${instanceInstuction.insnText}")
}
toInsert.add(varAssignmentInstruction to defaultLambdaFakeCallStub(argTypes, it.varIndex))
DefaultLambda(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex)
DefaultLambda(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification)
}
}
@@ -0,0 +1,26 @@
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
//WITH_RUNTIME
package test
class OK
class FAIL
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
inline fun <reified T> inlineFun(lambda: () -> String = { T::class.java.simpleName }): String {
return lambda()
}
inline fun <reified T> inlineFun2(): String {
return inlineFun<OK>()
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun2<FAIL>()
}
@@ -0,0 +1,19 @@
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
//WITH_RUNTIME
package test
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
inline fun <reified T> inlineFun(p: String, lambda: () -> String = { { p + T::class.java.simpleName } () }): String {
return lambda()
}
// FILE: 2.kt
import test.*
class K
fun box(): String {
return inlineFun<OK>("O")
}
@@ -0,0 +1,21 @@
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
//WITH_RUNTIME
package test
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
inline fun <reified T> inlineFun(p: String, crossinline lambda: () -> String = { { p + T::class.java.simpleName } () }): String {
return {
lambda()
} ()
}
// FILE: 2.kt
import test.*
class OK
fun box(): String {
return inlineFun<OK>()
}
@@ -0,0 +1,21 @@
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
//WITH_RUNTIME
package test
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
inline fun <reified T> inlineFun(crossinline lambda: () -> String = { { T::class.java.simpleName } () }): String {
return {
lambda()
} ()
}
// FILE: 2.kt
import test.*
class OK
fun box(): String {
return inlineFun<OK>()
}
@@ -0,0 +1,19 @@
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
//WITH_RUNTIME
package test
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
inline fun <reified T> inlineFun(lambda: () -> String = { { T::class.java.simpleName } () }): String {
return lambda()
}
// FILE: 2.kt
import test.*
class OK
fun box(): String {
return inlineFun<OK>()
}
@@ -0,0 +1,19 @@
// FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default
//WITH_RUNTIME
package test
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
inline fun <reified T> inlineFun(lambda: () -> String = { T::class.java.simpleName }): String {
return lambda()
}
// FILE: 2.kt
import test.*
class OK
fun box(): String {
return inlineFun<OK>()
}
@@ -2141,6 +2141,51 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
}
}
@TestMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultLambda extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInDefaultLambda() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/defaultLambda"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("chain.kt")
public void testChain() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt");
doTest(fileName);
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt");
doTest(fileName);
}
@TestMetadata("nested2.kt")
public void testNested2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt");
doTest(fileName);
}
@TestMetadata("nested2Static.kt")
public void testNested2Static() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt");
doTest(fileName);
}
@TestMetadata("nestedStatic.kt")
public void testNestedStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/reified/isCheck")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2141,6 +2141,51 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
}
}
@TestMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultLambda extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInDefaultLambda() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/defaultLambda"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("chain.kt")
public void testChain() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt");
doTest(fileName);
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt");
doTest(fileName);
}
@TestMetadata("nested2.kt")
public void testNested2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt");
doTest(fileName);
}
@TestMetadata("nested2Static.kt")
public void testNested2Static() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt");
doTest(fileName);
}
@TestMetadata("nestedStatic.kt")
public void testNestedStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/reified/isCheck")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)