Do not use non-existing class for suspend markers

As they remain in inline functions now proguard emits
a warning about them, even though inline suspend functions
are effectively inline-only and these markers can't be
executed at runtime

 #KT-18702 Fixed
This commit is contained in:
Denis Zharkov
2017-06-15 15:40:28 +03:00
parent cb95986c36
commit d88d1d6189
4 changed files with 55 additions and 40 deletions
@@ -2238,19 +2238,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
} }
if (isSuspendCall) { if (isSuspendCall) {
v.invokestatic( addSuspendMarker(v, true);
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME,
"()V", false
);
} }
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this); callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
if (isSuspendCall) { if (isSuspendCall) {
v.invokestatic( addSuspendMarker(v, false);
CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
CoroutineCodegenUtilKt.AFTER_SUSPENSION_POINT_MARKER_NAME, "()V", false);
addInlineMarker(v, false); addInlineMarker(v, false);
} }
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
import org.jetbrains.kotlin.codegen.inline.MaxStackFrameSizeAndLocalsCalculator import org.jetbrains.kotlin.codegen.inline.MaxStackFrameSizeAndLocalsCalculator
import org.jetbrains.kotlin.codegen.inline.isAfterSuspendMarker
import org.jetbrains.kotlin.codegen.inline.isBeforeSuspendMarker
import org.jetbrains.kotlin.codegen.inline.isInlineMarker import org.jetbrains.kotlin.codegen.inline.isInlineMarker
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.* import org.jetbrains.kotlin.codegen.optimization.common.*
@@ -302,7 +304,7 @@ class CoroutineTransformerMethodVisitor(
// It doesn't introduce an additional state to the corresponding coroutine's FSM. // It doesn't introduce an additional state to the corresponding coroutine's FSM.
suspensionPoints.forEach { suspensionPoints.forEach {
if (dceResult.isAlive(it.suspensionCallBegin) && dceResult.isRemoved(it.suspensionCallEnd)) { if (dceResult.isAlive(it.suspensionCallBegin) && dceResult.isRemoved(it.suspensionCallEnd)) {
methodNode.instructions.remove(it.suspensionCallBegin) it.removeBeforeSuspendMarker(methodNode)
} }
} }
@@ -311,17 +313,15 @@ class CoroutineTransformerMethodVisitor(
private fun collectSuspensionPoints(methodNode: MethodNode): MutableList<SuspensionPoint> { private fun collectSuspensionPoints(methodNode: MethodNode): MutableList<SuspensionPoint> {
val suspensionPoints = mutableListOf<SuspensionPoint>() val suspensionPoints = mutableListOf<SuspensionPoint>()
val beforeSuspensionPointMarkerStack = Stack<MethodInsnNode>() val beforeSuspensionPointMarkerStack = Stack<AbstractInsnNode>()
for (methodInsn in methodNode.instructions.toArray().filterIsInstance<MethodInsnNode>()) { for (methodInsn in methodNode.instructions.toArray().filterIsInstance<MethodInsnNode>()) {
if (methodInsn.owner != COROUTINE_MARKER_OWNER) continue when {
isBeforeSuspendMarker(methodInsn) -> {
when (methodInsn.name) { beforeSuspensionPointMarkerStack.add(methodInsn.previous)
BEFORE_SUSPENSION_POINT_MARKER_NAME -> {
beforeSuspensionPointMarkerStack.add(methodInsn)
} }
AFTER_SUSPENSION_POINT_MARKER_NAME -> { isAfterSuspendMarker(methodInsn) -> {
suspensionPoints.add(SuspensionPoint(beforeSuspensionPointMarkerStack.pop(), methodInsn)) suspensionPoints.add(SuspensionPoint(beforeSuspensionPointMarkerStack.pop(), methodInsn))
} }
} }
@@ -335,10 +335,8 @@ class CoroutineTransformerMethodVisitor(
private fun dropSuspensionMarkers(methodNode: MethodNode, suspensionPoints: List<SuspensionPoint>) { private fun dropSuspensionMarkers(methodNode: MethodNode, suspensionPoints: List<SuspensionPoint>) {
// Drop markers // Drop markers
suspensionPoints.forEach { suspensionPoints.forEach {
// before-marker it.removeBeforeSuspendMarker(methodNode)
methodNode.instructions.remove(it.suspensionCallBegin) it.removeAfterSuspendMarker(methodNode)
// after-marker
methodNode.instructions.remove(it.suspensionCallEnd)
} }
} }
@@ -615,18 +613,30 @@ private fun Type.normalize() =
/** /**
* Suspension call may consists of several instructions: * Suspension call may consists of several instructions:
* INVOKESTATIC beforeSuspensionMarker * ICONST_0
* INVOKESTATIC InlineMarker.mark()
* INVOKEVIRTUAL suspensionMethod()Ljava/lang/Object; // actually it could be some inline method instead of plain call * INVOKEVIRTUAL suspensionMethod()Ljava/lang/Object; // actually it could be some inline method instead of plain call
* CHECKCAST Type * CHECKCAST Type
* INVOKESTATIC afterSuspensionMarker * ICONST_1
* INVOKESTATIC InlineMarker.mark()
*/ */
private class SuspensionPoint( private class SuspensionPoint(
// INVOKESTATIC beforeSuspensionMarker // ICONST_0
val suspensionCallBegin: AbstractInsnNode, val suspensionCallBegin: AbstractInsnNode,
// INVOKESTATIC afterSuspensionMarker // INVOKESTATIC InlineMarker.mark()
val suspensionCallEnd: AbstractInsnNode val suspensionCallEnd: AbstractInsnNode
) { ) {
lateinit var tryCatchBlocksContinuationLabel: LabelNode lateinit var tryCatchBlocksContinuationLabel: LabelNode
fun removeBeforeSuspendMarker(methodNode: MethodNode) {
methodNode.instructions.remove(suspensionCallBegin.next)
methodNode.instructions.remove(suspensionCallBegin)
}
fun removeAfterSuspendMarker(methodNode: MethodNode) {
methodNode.instructions.remove(suspensionCallEnd.previous)
methodNode.instructions.remove(suspensionCallEnd)
}
} }
private fun getLastParameterIndex(desc: String, access: Int) = private fun getLastParameterIndex(desc: String, access: Int) =
@@ -747,4 +757,4 @@ private fun AbstractInsnNode?.isInvisibleInDebugVarInsn(methodNode: MethodNode):
} }
private val SAFE_OPCODES = private val SAFE_OPCODES =
((Opcodes.DUP..Opcodes.DUP2_X2) + Opcodes.POP + Opcodes.POP2 + (Opcodes.IFEQ..Opcodes.GOTO)).toSet() ((Opcodes.DUP..Opcodes.DUP2_X2) + Opcodes.POP + Opcodes.POP2 + (Opcodes.IFEQ..Opcodes.GOTO)).toSet()
@@ -52,11 +52,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode import org.jetbrains.org.objectweb.asm.tree.MethodNode
// These classes do not actually exist at runtime
const val COROUTINE_MARKER_OWNER = "kotlin/coroutines/Markers"
const val BEFORE_SUSPENSION_POINT_MARKER_NAME = "beforeSuspensionPoint"
const val AFTER_SUSPENSION_POINT_MARKER_NAME = "afterSuspensionPoint"
const val COROUTINE_LABEL_FIELD_NAME = "label" const val COROUTINE_LABEL_FIELD_NAME = "label"
const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create" const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create"
const val DO_RESUME_METHOD_NAME = "doResume" const val DO_RESUME_METHOD_NAME = "doResume"
@@ -22,18 +22,19 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.BaseExpressionCodegen import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.context.CodegenContext import org.jetbrains.kotlin.codegen.context.CodegenContext
import org.jetbrains.kotlin.codegen.context.CodegenContextUtil import org.jetbrains.kotlin.codegen.context.CodegenContextUtil
import org.jetbrains.kotlin.codegen.context.InlineLambdaContext import org.jetbrains.kotlin.codegen.context.InlineLambdaContext
import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.intrinsics.* import org.jetbrains.kotlin.codegen.intrinsics.classId
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fileClasses.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider
import org.jetbrains.kotlin.fileClasses.getFileClassType
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
@@ -44,7 +45,11 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.*
@@ -53,15 +58,9 @@ import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.util.Printer import org.jetbrains.org.objectweb.asm.util.Printer
import org.jetbrains.org.objectweb.asm.util.Textifier import org.jetbrains.org.objectweb.asm.util.Textifier
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
const val GENERATE_SMAP = true const val GENERATE_SMAP = true
const val API = Opcodes.ASM5 const val API = Opcodes.ASM5
@@ -88,6 +87,8 @@ private const val INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"
private const val INLINE_MARKER_FINALLY_START = "finallyStart" private const val INLINE_MARKER_FINALLY_START = "finallyStart"
private const val INLINE_MARKER_FINALLY_END = "finallyEnd" private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0
private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1
internal fun getMethodNode( internal fun getMethodNode(
classData: ByteArray, classData: ByteArray,
@@ -430,6 +431,21 @@ internal fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
) )
} }
internal fun addSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
v.iconst(if (isStartNotEnd) INLINE_MARKER_BEFORE_SUSPEND_ID else INLINE_MARKER_AFTER_SUSPEND_ID)
v.visitMethodInsn(
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
"mark",
"(I)V", false
)
}
internal fun isBeforeSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_BEFORE_SUSPEND_ID)
internal fun isAfterSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_AFTER_SUSPEND_ID)
private fun isSuspendMarker(insn: AbstractInsnNode, id: Int) =
isInlineMarker(insn, "mark") && insn.previous.intConstant == id
internal fun isInlineMarker(insn: AbstractInsnNode): Boolean { internal fun isInlineMarker(insn: AbstractInsnNode): Boolean {
return isInlineMarker(insn, null) return isInlineMarker(insn, null)
} }
@@ -581,4 +597,4 @@ class InlineOnlySmapSkipper(codegen: BaseExpressionCodegen) {
mv.visitLineNumber(callLineNumber, label) mv.visitLineNumber(callLineNumber, label)
} }
} }
} }