Use our own primitive boxing methods in coroutines codegen
#KT-26490 Fixed
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.codegen.coroutines
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.boxing.isPrimitiveBoxing
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
|
import org.jetbrains.kotlin.codegen.topLevelClassInternalName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||||
|
import org.jetbrains.kotlin.utils.sure
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
|
|
||||||
|
private val BOXING_CLASS_INTERNAL_NAME =
|
||||||
|
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||||
|
|
||||||
|
object ChangeBoxingMethodTransformer : MethodTransformer() {
|
||||||
|
private val wrapperToInternalBoxing: Map<String, String>
|
||||||
|
|
||||||
|
init {
|
||||||
|
val map = hashMapOf<String, String>()
|
||||||
|
for (primitiveType in JvmPrimitiveType.values()) {
|
||||||
|
val name = primitiveType.wrapperFqName.topLevelClassInternalName()
|
||||||
|
map[name] = "box${primitiveType.javaKeywordName.capitalize()}"
|
||||||
|
}
|
||||||
|
wrapperToInternalBoxing = map
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
|
for (boxing in methodNode.instructions.asSequence().filter { it.isPrimitiveBoxing() }) {
|
||||||
|
assert(boxing.opcode == Opcodes.INVOKESTATIC) {
|
||||||
|
"boxing shall be INVOKESTATIC wrapper.valueOf"
|
||||||
|
}
|
||||||
|
boxing as MethodInsnNode
|
||||||
|
val methodName = wrapperToInternalBoxing[boxing.owner].sure {
|
||||||
|
"expected primitive wrapper, but got ${boxing.owner}"
|
||||||
|
}
|
||||||
|
methodNode.instructions.set(
|
||||||
|
boxing,
|
||||||
|
MethodInsnNode(boxing.opcode, BOXING_CLASS_INTERNAL_NAME, methodName, boxing.desc, false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -83,6 +83,9 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
|
|
||||||
FixStackMethodTransformer().transform(containingClassInternalName, methodNode)
|
FixStackMethodTransformer().transform(containingClassInternalName, methodNode)
|
||||||
RedundantLocalsEliminationMethodTransformer(languageVersionSettings).transform(containingClassInternalName, methodNode)
|
RedundantLocalsEliminationMethodTransformer(languageVersionSettings).transform(containingClassInternalName, methodNode)
|
||||||
|
if (languageVersionSettings.isReleaseCoroutines()) {
|
||||||
|
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||||
|
}
|
||||||
updateMaxStack(methodNode)
|
updateMaxStack(methodNode)
|
||||||
|
|
||||||
val suspensionPoints = collectSuspensionPoints(methodNode)
|
val suspensionPoints = collectSuspensionPoints(methodNode)
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ const val DO_RESUME_METHOD_NAME = "doResume"
|
|||||||
const val INVOKE_SUSPEND_METHOD_NAME = "invokeSuspend"
|
const val INVOKE_SUSPEND_METHOD_NAME = "invokeSuspend"
|
||||||
const val EXCEPTION_FIELD_NAME = "exception"
|
const val EXCEPTION_FIELD_NAME = "exception"
|
||||||
|
|
||||||
private val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
|
val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
|
||||||
|
|
||||||
fun LanguageVersionSettings.isResumeImplMethodName(name: String) =
|
fun LanguageVersionSettings.isResumeImplMethodName(name: String) =
|
||||||
if (isReleaseCoroutines())
|
if (isReleaseCoroutines())
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// !LANGUAGE: +ReleaseCoroutines
|
||||||
|
|
||||||
|
inline fun inlineMe(crossinline c: suspend () -> Int): suspend () -> Int {
|
||||||
|
val i: suspend () -> Int = { c() + c() }
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 valueOf
|
||||||
|
// 0 boxInt
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// !LANGUAGE: +ReleaseCoroutines
|
||||||
|
|
||||||
|
inline suspend fun inlineMe() = 1000
|
||||||
|
|
||||||
|
// inlineMe$$forInline : valueOf
|
||||||
|
// inlineMe : boxInt
|
||||||
|
|
||||||
|
// 1 valueOf
|
||||||
|
// 1 boxInt
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// !LANGUAGE: +ReleaseCoroutines
|
||||||
|
|
||||||
|
suspend fun produce(): Int = 1000
|
||||||
|
|
||||||
|
// 0 valueOf
|
||||||
|
// 1 boxInt
|
||||||
@@ -397,6 +397,34 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/bytecodeText/boxing")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Boxing extends AbstractBytecodeTextTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInBoxing() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/boxing"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossinlineSuspend.kt")
|
||||||
|
public void testCrossinlineSuspend() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/boxing/crossinlineSuspend.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineSuspend.kt")
|
||||||
|
public void testInlineSuspend() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/boxing/inlineSuspend.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("suspend.kt")
|
||||||
|
public void testSuspend() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/boxing/suspend.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/bytecodeText/boxingOptimization")
|
@TestMetadata("compiler/testData/codegen/bytecodeText/boxingOptimization")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user