Change mangling for local functions

This commit is contained in:
Yan Zhulanow
2019-01-09 21:48:39 +03:00
committed by Yan Zhulanow
parent aca3be12e9
commit 488418d960
5 changed files with 120 additions and 6 deletions
@@ -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<StackValue, StackValue> impleme
}
private void addLeaveTaskToRemoveNamedFunctionFromFrameMap(
@NotNull KtNamedFunction statement,
@NotNull KtNamedFunction localFunction,
Label blockEnd,
@NotNull List<Function<StackValue, Void>> 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<StackValue, StackValue> 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;
});
}
@@ -0,0 +1,9 @@
// LOCAL_VARIABLE_TABLE
fun foo() {
fun a() {}
fun a2() {}
fun a2(a: Int) {}
fun `b c`() {}
fun `c$d`() {}
}
@@ -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 <clinit>()
void <init>()
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 <clinit>()
void <init>()
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 <clinit>()
void <init>()
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 <clinit>()
void <init>()
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 <clinit>()
void <init>()
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;
}
}
@@ -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");
@@ -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)