Replace POP with ARETURN if it pops Unit and ARETURN shall return Unit
#KT-16880: Fixed
This commit is contained in:
@@ -2324,6 +2324,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
|
||||
|
||||
if (isSuspendCall) {
|
||||
addReturnsUnitMarkerIfNecessary(v, resolvedCall);
|
||||
|
||||
addSuspendMarker(v, false);
|
||||
addInlineMarker(v, false);
|
||||
}
|
||||
|
||||
+3
-1
@@ -77,6 +77,8 @@ class CoroutineTransformerMethodVisitor(
|
||||
FixStackMethodTransformer().transform(containingClassInternalName, methodNode)
|
||||
|
||||
if (isForNamedFunction) {
|
||||
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||
|
||||
if (allSuspensionPointsAreTailCalls(containingClassInternalName, methodNode, suspensionPoints)) {
|
||||
dropSuspensionMarkers(methodNode, suspensionPoints)
|
||||
return
|
||||
@@ -701,7 +703,7 @@ private fun allSuspensionPointsAreTailCalls(
|
||||
}
|
||||
}
|
||||
|
||||
private class IgnoringCopyOperationSourceInterpreter : SourceInterpreter() {
|
||||
internal class IgnoringCopyOperationSourceInterpreter : SourceInterpreter() {
|
||||
override fun copyOperation(insn: AbstractInsnNode?, value: SourceValue?) = value
|
||||
}
|
||||
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.codegen.inline.isReturnsUnitMarker
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.isUnitInstance
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.ControlFlowGraph
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeAll
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
/*
|
||||
* Replace POP with ARETURN iff
|
||||
* 1) It is immediately followed by { GETSTATIC Unit.INSTANCE, ARETURN } sequences
|
||||
* 2) It is poping Unit
|
||||
*/
|
||||
object ReturnUnitMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val unitMarks = findReturnsUnitMarks(methodNode)
|
||||
if (unitMarks.isEmpty()) return
|
||||
|
||||
val units = findReturnUnitSequences(methodNode)
|
||||
if (units.isEmpty()) {
|
||||
cleanUpReturnsUnitMarkers(methodNode, unitMarks)
|
||||
return
|
||||
}
|
||||
|
||||
val pops = methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP }.toList()
|
||||
val popSuccessors = findSuccessors(methodNode, pops)
|
||||
val sourceInsns = findSourceInstructions(internalClassName, methodNode, pops)
|
||||
val safePops = filterOutUnsafes(popSuccessors, units, sourceInsns)
|
||||
|
||||
// Replace POP with ARETURN for tail call optimization
|
||||
safePops.forEach { methodNode.instructions.set(it, InsnNode(Opcodes.ARETURN)) }
|
||||
cleanUpReturnsUnitMarkers(methodNode, unitMarks)
|
||||
}
|
||||
|
||||
// Return list of POPs, which can be safely replaced by ARETURNs
|
||||
private fun filterOutUnsafes(
|
||||
popSuccessors: Map<AbstractInsnNode, Collection<AbstractInsnNode>>,
|
||||
units: Collection<AbstractInsnNode>,
|
||||
sourceInsns: Map<AbstractInsnNode, Collection<AbstractInsnNode>>
|
||||
): Collection<AbstractInsnNode> {
|
||||
return popSuccessors.filter { (pop, successors) ->
|
||||
successors.all { it in units } &&
|
||||
sourceInsns[pop].sure { "Sources of $pop cannot be null" }.all(::isSuspendingCallReturningUnit)
|
||||
}.keys
|
||||
}
|
||||
|
||||
// Find instructions which do something on stack, ignoring markers
|
||||
// Return map {insn => list of found instructions}
|
||||
private fun findSuccessors(
|
||||
methodNode: MethodNode,
|
||||
insns: List<AbstractInsnNode>
|
||||
): Map<AbstractInsnNode, Collection<AbstractInsnNode>> {
|
||||
val cfg = ControlFlowGraph.build(methodNode)
|
||||
return insns.keysToMap { findSuccessors(cfg, it, methodNode) }
|
||||
}
|
||||
|
||||
// Find all meaningful successors of [insn]
|
||||
private fun findSuccessors(cfg: ControlFlowGraph, insn: AbstractInsnNode, methodNode: MethodNode): Collection<AbstractInsnNode> {
|
||||
val stack = cfg.getSuccessorsIndices(insn).mapTo(ArrayList()) { methodNode.instructions[it] }
|
||||
val successors = arrayListOf<AbstractInsnNode>()
|
||||
while (stack.isNotEmpty()) {
|
||||
val current = stack.pop()
|
||||
if (current in successors || isReturnsUnitMarker(current)) continue
|
||||
if (!current.isMeaningful || current is JumpInsnNode || current.opcode == Opcodes.NOP) {
|
||||
cfg.getSuccessorsIndices(current).mapTo(stack) { methodNode.instructions[it] }
|
||||
continue
|
||||
}
|
||||
// There can be multiple chains of { UnitInstance, POP } after inlining. Ignore them
|
||||
if (current.isUnitInstance()) {
|
||||
val newSuccessors = findSuccessors(cfg, current, methodNode)
|
||||
if (newSuccessors.all { it.opcode == Opcodes.POP }) {
|
||||
newSuccessors.flatMapTo(stack) { findSuccessors(cfg, it, methodNode) }
|
||||
continue
|
||||
}
|
||||
}
|
||||
successors.add(current)
|
||||
}
|
||||
return successors
|
||||
}
|
||||
|
||||
private fun isSuspendingCallReturningUnit(node: AbstractInsnNode): Boolean =
|
||||
node.safeAs<MethodInsnNode>()?.next?.next?.let(::isReturnsUnitMarker) == true
|
||||
|
||||
private fun findSourceInstructions(
|
||||
internalClassName: String,
|
||||
methodNode: MethodNode,
|
||||
pops: Collection<AbstractInsnNode>
|
||||
): Map<AbstractInsnNode, Collection<AbstractInsnNode>> {
|
||||
val frames = analyze(internalClassName, methodNode, IgnoringCopyOperationSourceInterpreter())
|
||||
return pops.keysToMap {
|
||||
frames[methodNode.instructions.indexOf(it)].getStack(0).insns
|
||||
}
|
||||
}
|
||||
|
||||
// Find { GETSTATIC kotlin/Unit.INSTANCE, ARETURN } sequences
|
||||
// Result is list of GETSTATIC kotlin/Unit.INSTANCE instructions
|
||||
private fun findReturnUnitSequences(methodNode: MethodNode): Collection<AbstractInsnNode> =
|
||||
methodNode.instructions.asSequence().filter { it.isUnitInstance() && it.next?.opcode == Opcodes.ARETURN }.toList()
|
||||
|
||||
private fun findReturnsUnitMarks(methodNode: MethodNode): Collection<AbstractInsnNode> =
|
||||
methodNode.instructions.asSequence().filter(::isReturnsUnitMarker).toList()
|
||||
|
||||
private fun cleanUpReturnsUnitMarkers(methodNode: MethodNode, unitMarks: Collection<AbstractInsnNode>) {
|
||||
unitMarks.forEach { methodNode.instructions.removeAll(listOf(it.previous, it)) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.substitute
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
|
||||
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContextUtil
|
||||
import org.jetbrains.kotlin.codegen.context.InlineLambdaContext
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.classId
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
@@ -43,14 +45,16 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
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.source.PsiSourceElement
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -87,6 +91,7 @@ private const val INLINE_MARKER_FINALLY_START = "finallyStart"
|
||||
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
|
||||
private const val INLINE_MARKET_RETURNS_UNIT = 2
|
||||
private val INTRINSIC_ARRAY_CONSTRUCTOR_TYPE = AsmUtil.asmTypeByClassId(classId)
|
||||
|
||||
internal fun getMethodNode(
|
||||
@@ -386,6 +391,26 @@ internal fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
||||
)
|
||||
}
|
||||
|
||||
internal fun addReturnsUnitMarkerIfNecessary(v: InstructionAdapter, resolvedCall: ResolvedCall<*>) {
|
||||
val wrapperDescriptor = resolvedCall.candidateDescriptor.safeAs<FunctionDescriptor>() ?: return
|
||||
val unsubstitutedDescriptor = wrapperDescriptor.unwrapInitialDescriptorForSuspendFunction()
|
||||
|
||||
val typeSubstitutor = TypeSubstitutor.create(
|
||||
unsubstitutedDescriptor.typeParameters
|
||||
.withIndex()
|
||||
.associateBy({ it.value.typeConstructor }) {
|
||||
TypeProjectionImpl(resolvedCall.typeArguments[wrapperDescriptor.typeParameters[it.index]] ?: return)
|
||||
}
|
||||
)
|
||||
|
||||
val substitutedDescriptor = unsubstitutedDescriptor.substitute(typeSubstitutor) ?: return
|
||||
val returnType = substitutedDescriptor.returnType ?: return
|
||||
|
||||
if (KotlinBuiltIns.isUnit(returnType)) {
|
||||
addReturnsUnitMarker(v)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun addSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
||||
v.iconst(if (isStartNotEnd) INLINE_MARKER_BEFORE_SUSPEND_ID else INLINE_MARKER_AFTER_SUSPEND_ID)
|
||||
v.visitMethodInsn(
|
||||
@@ -395,8 +420,18 @@ internal fun addSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
||||
)
|
||||
}
|
||||
|
||||
private fun addReturnsUnitMarker(v: InstructionAdapter) {
|
||||
v.iconst(INLINE_MARKET_RETURNS_UNIT)
|
||||
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)
|
||||
internal fun isReturnsUnitMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKET_RETURNS_UNIT)
|
||||
|
||||
private fun isSuspendMarker(insn: AbstractInsnNode, id: Int) =
|
||||
isInlineMarker(insn, "mark") && insn.previous.intConstant == id
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
suspend fun empty() {}
|
||||
suspend fun withoutReturn() { empty() }
|
||||
suspend fun withReturn() { return empty() }
|
||||
suspend fun notTailCall() { empty(); empty() }
|
||||
suspend fun lambdaAsParameter(c: suspend ()->Unit) { c() }
|
||||
suspend fun lambdaAsParameterNotTailCall(c: suspend ()->Unit) { c(); c() }
|
||||
suspend fun lambdaAsParameterReturn(c: suspend ()->Unit) { return c() }
|
||||
suspend fun returnsInt() = 42
|
||||
// This should not be tail-call, since the caller should push Unit.INSTANCE on stack
|
||||
suspend fun callsIntNotTailCall() { returnsInt() }
|
||||
suspend fun multipleExitPoints(b: Boolean) { if (b) empty() else withoutReturn() }
|
||||
suspend fun multipleExitPointsNotTailCall(b: Boolean) { if (b) empty() else returnsInt() }
|
||||
|
||||
fun ordinary() = 1
|
||||
inline fun ordinaryInline() { ordinary() }
|
||||
suspend fun multipleExitPointsWithOrdinaryInline(b: Boolean) { if (b) empty() else ordinaryInline() }
|
||||
|
||||
suspend fun multipleExitPointsWhen(i: Int) {
|
||||
when(i) {
|
||||
1 -> empty()
|
||||
2 -> withReturn()
|
||||
3 -> withoutReturn()
|
||||
else -> lambdaAsParameter {}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> generic(): T = TODO()
|
||||
suspend fun useGenericReturningUnit() {
|
||||
generic<Unit>()
|
||||
}
|
||||
|
||||
class Generic<T> {
|
||||
suspend fun foo(): T = TODO()
|
||||
}
|
||||
suspend fun useGenericClass(g: Generic<Unit>) {
|
||||
g.foo()
|
||||
}
|
||||
|
||||
suspend fun <T> genericInferType(c: () -> T): T = TODO()
|
||||
suspend fun useGenericIngerType() {
|
||||
genericInferType {}
|
||||
}
|
||||
|
||||
suspend fun nullableUnit(): Unit? = null
|
||||
suspend fun useNullableUnit() {
|
||||
nullableUnit()
|
||||
}
|
||||
|
||||
suspend fun useRunRunRunRunRun() {
|
||||
run {
|
||||
run {
|
||||
run {
|
||||
run {
|
||||
run {
|
||||
empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
@kotlin.Metadata
|
||||
public final class Generic {
|
||||
public method <init>(): void
|
||||
public final @org.jetbrains.annotations.Nullable method foo(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$callsIntNotTailCall$1 {
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class TailSuspendUnitFunKt$callsIntNotTailCall$1
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
synthetic final method getLabel(): int
|
||||
synthetic final method setLabel(p0: int): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$lambdaAsParameterNotTailCall$1 {
|
||||
field L$0: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class TailSuspendUnitFunKt$lambdaAsParameterNotTailCall$1
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
synthetic final method getLabel(): int
|
||||
synthetic final method setLabel(p0: int): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$multipleExitPointsNotTailCall$1 {
|
||||
field Z$0: boolean
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class TailSuspendUnitFunKt$multipleExitPointsNotTailCall$1
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
synthetic final method getLabel(): int
|
||||
synthetic final method setLabel(p0: int): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$multipleExitPointsWhen$2 {
|
||||
inner class TailSuspendUnitFunKt$multipleExitPointsWhen$2
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method create(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$notTailCall$1 {
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class TailSuspendUnitFunKt$notTailCall$1
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
synthetic final method getLabel(): int
|
||||
synthetic final method setLabel(p0: int): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$useGenericIngerType$2 {
|
||||
public final static field INSTANCE: TailSuspendUnitFunKt$useGenericIngerType$2
|
||||
inner class TailSuspendUnitFunKt$useGenericIngerType$2
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public synthetic method invoke(): java.lang.Object
|
||||
public final method invoke(): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TailSuspendUnitFunKt$useNullableUnit$1 {
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class TailSuspendUnitFunKt$useNullableUnit$1
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
synthetic final method getLabel(): int
|
||||
synthetic final method setLabel(p0: int): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class TailSuspendUnitFunKt {
|
||||
inner class TailSuspendUnitFunKt$callsIntNotTailCall$1
|
||||
inner class TailSuspendUnitFunKt$lambdaAsParameterNotTailCall$1
|
||||
inner class TailSuspendUnitFunKt$multipleExitPointsNotTailCall$1
|
||||
inner class TailSuspendUnitFunKt$multipleExitPointsWhen$2
|
||||
inner class TailSuspendUnitFunKt$notTailCall$1
|
||||
inner class TailSuspendUnitFunKt$useGenericIngerType$2
|
||||
inner class TailSuspendUnitFunKt$useNullableUnit$1
|
||||
public final static @org.jetbrains.annotations.Nullable method callsIntNotTailCall(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method empty(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method genericInferType(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method lambdaAsParameter(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method lambdaAsParameterNotTailCall(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method lambdaAsParameterReturn(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method multipleExitPoints(p0: boolean, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method multipleExitPointsNotTailCall(p0: boolean, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method multipleExitPointsWhen(p0: int, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method multipleExitPointsWithOrdinaryInline(p0: boolean, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method notTailCall(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method nullableUnit(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static method ordinary(): int
|
||||
public final static method ordinaryInline(): void
|
||||
public final static @org.jetbrains.annotations.Nullable method returnsInt(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method useGenericClass(@org.jetbrains.annotations.NotNull p0: Generic, @org.jetbrains.annotations.Nullable p1: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method useGenericIngerType(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method useGenericReturningUnit(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method useNullableUnit(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method useRunRunRunRunRun(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method withReturn(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method withoutReturn(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
@@ -162,6 +162,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("tailSuspendUnitFun.kt")
|
||||
public void testTailSuspendUnitFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/tailSuspendUnitFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/annotations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user