From 488418d9609e100f434e15603e25fea87c820957 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Wed, 9 Jan 2019 21:48:39 +0300 Subject: [PATCH] Change mangling for local functions --- .../kotlin/codegen/ExpressionCodegen.java | 18 +++- .../receiverMangling/localFunctions.kt | 9 ++ .../receiverMangling/localFunctions.txt | 86 +++++++++++++++++++ ...smLikeInstructionListingTestGenerated.java | 5 ++ .../idea/debugger/evaluate/VariableFinder.kt | 8 +- 5 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/asmLike/receiverMangling/localFunctions.kt create mode 100644 compiler/testData/codegen/asmLike/receiverMangling/localFunctions.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index aa0ae1ac7cd..4db53c6a9b8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -16,6 +16,7 @@ import com.intellij.util.containers.Stack; import kotlin.Pair; import kotlin.Unit; import kotlin.collections.CollectionsKt; +import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.CodegenUtil; @@ -1412,11 +1413,11 @@ public class ExpressionCodegen extends KtVisitor impleme } private void addLeaveTaskToRemoveNamedFunctionFromFrameMap( - @NotNull KtNamedFunction statement, + @NotNull KtNamedFunction localFunction, Label blockEnd, @NotNull List> leaveTasks ) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement); + FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, localFunction); assert functionDescriptor != null; Type type = asmTypeForAnonymousClass(bindingContext, functionDescriptor); @@ -1427,8 +1428,17 @@ public class ExpressionCodegen extends KtVisitor impleme leaveTasks.add(answer -> { int index = myFrameMap.leave(functionDescriptor); - assert !functionDescriptor.getName().isSpecial() : "Local variable should be generated only for function with name: " + statement.getText(); - v.visitLocalVariable(functionDescriptor.getName().asString() + "$", type.getDescriptor(), null, scopeStart, blockEnd, index); + assert !functionDescriptor.getName().isSpecial() + : "Local variable should be generated only for function with name: " + localFunction.getText(); + + String functionIndex = StringsKt.substringAfterLast(type.getInternalName(), '$', ""); + assert !functionIndex.isEmpty(); + + String localVariableName = "$fun$" + + VariableAsmNameManglingUtils.mangleNameIfNeeded(functionDescriptor.getName().asString()) + + "$" + functionIndex; + + v.visitLocalVariable(localVariableName, type.getDescriptor(), null, scopeStart, blockEnd, index); return null; }); } diff --git a/compiler/testData/codegen/asmLike/receiverMangling/localFunctions.kt b/compiler/testData/codegen/asmLike/receiverMangling/localFunctions.kt new file mode 100644 index 00000000000..4417cd6e4b5 --- /dev/null +++ b/compiler/testData/codegen/asmLike/receiverMangling/localFunctions.kt @@ -0,0 +1,9 @@ +// LOCAL_VARIABLE_TABLE + +fun foo() { + fun a() {} + fun a2() {} + fun a2(a: Int) {} + fun `b c`() {} + fun `c$d`() {} +} \ No newline at end of file diff --git a/compiler/testData/codegen/asmLike/receiverMangling/localFunctions.txt b/compiler/testData/codegen/asmLike/receiverMangling/localFunctions.txt new file mode 100644 index 00000000000..13bbe2b1941 --- /dev/null +++ b/compiler/testData/codegen/asmLike/receiverMangling/localFunctions.txt @@ -0,0 +1,86 @@ +final class LocalFunctionsKt$foo$1 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 { + public final static LocalFunctionsKt$foo$1 INSTANCE + + static void () + + void () + + public java.lang.Object invoke() + + public final void invoke() { + Local variables: + 0 this: LLocalFunctionsKt$foo$1; + } +} + +final class LocalFunctionsKt$foo$2 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 { + public final static LocalFunctionsKt$foo$2 INSTANCE + + static void () + + void () + + public java.lang.Object invoke() + + public final void invoke() { + Local variables: + 0 this: LLocalFunctionsKt$foo$2; + } +} + +final class LocalFunctionsKt$foo$3 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function1 { + public final static LocalFunctionsKt$foo$3 INSTANCE + + static void () + + void () + + public java.lang.Object invoke(java.lang.Object p0) + + public final void invoke(int a) { + Local variables: + 0 this: LLocalFunctionsKt$foo$3; + 1 a: I + } +} + +final class LocalFunctionsKt$foo$4 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 { + public final static LocalFunctionsKt$foo$4 INSTANCE + + static void () + + void () + + public java.lang.Object invoke() + + public final void invoke() { + Local variables: + 0 this: LLocalFunctionsKt$foo$4; + } +} + +final class LocalFunctionsKt$foo$5 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 { + public final static LocalFunctionsKt$foo$5 INSTANCE + + static void () + + void () + + public java.lang.Object invoke() + + public final void invoke() { + Local variables: + 0 this: LLocalFunctionsKt$foo$5; + } +} + +public final class LocalFunctionsKt : java/lang/Object { + public final static void foo() { + Local variables: + 4 $fun$c-0024d$5: LLocalFunctionsKt$foo$5; + 3 $fun$b-0020c$4: LLocalFunctionsKt$foo$4; + 2 $fun$a2$3: LLocalFunctionsKt$foo$3; + 1 $fun$a2$2: LLocalFunctionsKt$foo$2; + 0 $fun$a$1: LLocalFunctionsKt$foo$1; + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java index 0289c3f45e3..53c15daeea6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java @@ -86,6 +86,11 @@ public class AsmLikeInstructionListingTestGenerated extends AbstractAsmLikeInstr runTest("compiler/testData/codegen/asmLike/receiverMangling/innerClass.kt"); } + @TestMetadata("localFunctions.kt") + public void testLocalFunctions() throws Exception { + runTest("compiler/testData/codegen/asmLike/receiverMangling/localFunctions.kt"); + } + @TestMetadata("mangledNames.kt") public void testMangledNames() throws Exception { runTest("compiler/testData/codegen/asmLike/receiverMangling/mangledNames.kt"); diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/VariableFinder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/VariableFinder.kt index 6b0c5a06fb7..f0b6fc36d85 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/VariableFinder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/VariableFinder.kt @@ -265,9 +265,8 @@ class VariableFinder private constructor(private val context: EvaluationContextI val canBeLocalFunction = kind is VariableKind.Ordinary if (canBeLocalFunction && kind.type?.isFunctionType() == true) { - @Suppress("ConvertToStringTemplate") variables.namedEntitySequence() - .filter { it.name == name + "$" && kind.typeMatches(it.type) } + .filter { isLocalFunctionName(it.name, name) && kind.typeMatches(it.type) } .firstOrNull() ?.let { return Result(it.value()) } } @@ -291,6 +290,11 @@ class VariableFinder private constructor(private val context: EvaluationContextI return null } + private fun isLocalFunctionName(name: String, functionName: String): Boolean { + @Suppress("ConvertToStringTemplate") + return name == functionName + "$" || name.startsWith(AsmUtil.LOCAL_FUNCTION_VARIABLE_PREFIX + name + "$") + } + private fun findCoroutineContext(): ObjectReference? { val method = frameProxy.location().safeMethod() ?: return null return findCoroutineContextForLambda(method) ?: findCoroutineContextForMethod(method)