Simplify generated code for rangeTo/concat intrinsics

The main reason is avoiding complicated operations like
dup + dup_x2 + pop2 for instances obtained by NEW instruction.

Otherwise it leads to problems in performRefinedTypeAnalysis
because code there has a sensible assumption that NEW instances
can be only dupped or stored into a local (rare cases)

 #KT-17457 Fixed
This commit is contained in:
Denis Zharkov
2017-05-19 16:16:08 +03:00
parent 419f12f1b7
commit 52b2e632df
12 changed files with 134 additions and 25 deletions
@@ -45,7 +45,7 @@ interface Callable {
}
}
fun afterReceiverGeneration(v: InstructionAdapter) {
fun afterReceiverGeneration(v: InstructionAdapter, frameMap: FrameMap) {
}
}
@@ -2262,7 +2262,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
myFrameMap.leaveTemp(firstReceiverType);
}
callableMethod.afterReceiverGeneration(v);
callableMethod.afterReceiverGeneration(v, myFrameMap);
}
}
@@ -377,3 +377,22 @@ fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodege
}
fun <D : CallableDescriptor> D.unwrapFrontendVersion() = unwrapInitialDescriptorForSuspendFunction()
inline fun FrameMap.useTmpVar(type: Type, block: (index: Int) -> Unit) {
val index = enterTemp(type)
block(index)
leaveTemp(type)
}
fun InstructionAdapter.generateNewInstanceDupAndPlaceBeforeStackTop(
frameMap: FrameMap,
topStackType: Type,
newInstanceInternalName: String
) {
frameMap.useTmpVar(topStackType) { index ->
store(index, topStackType)
anew(Type.getObjectType(newInstanceInternalName))
dup()
load(index, topStackType)
}
}
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -83,10 +82,8 @@ class Concat : IntrinsicMethod() {
}
}
override fun afterReceiverGeneration(v: InstructionAdapter) {
v.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder")
v.dupX1()
v.swap()
override fun afterReceiverGeneration(v: InstructionAdapter, frameMap: FrameMap) {
v.generateNewInstanceDupAndPlaceBeforeStackTop(frameMap, AsmTypes.JAVA_STRING_TYPE, "java/lang/StringBuilder")
v.invokespecial("java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false)
}
@@ -18,7 +18,8 @@ package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.FrameMap
import org.jetbrains.kotlin.codegen.generateNewInstanceDupAndPlaceBeforeStackTop
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.Type.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -47,19 +48,8 @@ class RangeTo : IntrinsicMethod() {
nullOr(method.dispatchReceiverType, argType),
nullOr(method.extensionReceiverType, argType)
) {
override fun afterReceiverGeneration(v: InstructionAdapter) {
v.anew(returnType)
when (argType.size) {
1 -> {
v.dupX1()
v.swap()
}
2 -> {
v.dup()
v.dup2X2()
v.pop2()
}
}
override fun afterReceiverGeneration(v: InstructionAdapter, frameMap: FrameMap) {
v.generateNewInstanceDupAndPlaceBeforeStackTop(frameMap, argType, returnType.internalName)
}
override fun invokeIntrinsic(v: InstructionAdapter) {
@@ -116,10 +116,8 @@ class Concat : IntrinsicMethod() {
}
}
override fun afterReceiverGeneration(v: InstructionAdapter) {
v.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder")
v.dupX1()
v.swap()
override fun afterReceiverGeneration(v: InstructionAdapter, frameMap: FrameMap) {
v.generateNewInstanceDupAndPlaceBeforeStackTop(frameMap, AsmTypes.JAVA_STRING_TYPE, "java/lang/StringBuilder")
v.invokespecial("java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false)
}
@@ -0,0 +1,31 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
suspend fun getLong(): Long = suspendCoroutineOrReturn { x ->
x.resume(1234567890123L)
COROUTINE_SUSPENDED
}
suspend fun suspendHere(r: LongRange): Long = suspendCoroutineOrReturn { x ->
x.resume(r.start + r.endInclusive)
COROUTINE_SUSPENDED
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = 0L
builder {
result = suspendHere(1L..getLong())
}
if (result != 1234567890124L) return "fail 1: $result"
return "OK"
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
suspend fun suspendHere(r: LongRange): Long = suspendCoroutineOrReturn { x ->
x.resume(r.start + r.endInclusive)
COROUTINE_SUSPENDED
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = 0L
builder {
result = suspendHere(1L..1234567890123L)
}
if (result != 1234567890124L) return "fail 1: $result"
return "OK"
}
@@ -5168,6 +5168,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("longRangeInSuspendCall.kt")
public void testLongRangeInSuspendCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendCall.kt");
doTest(fileName);
}
@TestMetadata("longRangeInSuspendFun.kt")
public void testLongRangeInSuspendFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendFun.kt");
doTest(fileName);
}
@TestMetadata("mergeNullAndString.kt")
public void testMergeNullAndString() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt");
@@ -5168,6 +5168,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("longRangeInSuspendCall.kt")
public void testLongRangeInSuspendCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendCall.kt");
doTest(fileName);
}
@TestMetadata("longRangeInSuspendFun.kt")
public void testLongRangeInSuspendFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendFun.kt");
doTest(fileName);
}
@TestMetadata("mergeNullAndString.kt")
public void testMergeNullAndString() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt");
@@ -5168,6 +5168,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("longRangeInSuspendCall.kt")
public void testLongRangeInSuspendCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendCall.kt");
doTest(fileName);
}
@TestMetadata("longRangeInSuspendFun.kt")
public void testLongRangeInSuspendFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendFun.kt");
doTest(fileName);
}
@TestMetadata("mergeNullAndString.kt")
public void testMergeNullAndString() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt");
@@ -5876,6 +5876,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("longRangeInSuspendCall.kt")
public void testLongRangeInSuspendCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendCall.kt");
doTest(fileName);
}
@TestMetadata("longRangeInSuspendFun.kt")
public void testLongRangeInSuspendFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/longRangeInSuspendFun.kt");
doTest(fileName);
}
@TestMetadata("mergeNullAndString.kt")
public void testMergeNullAndString() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/mergeNullAndString.kt");