Initial internal member mangling

This commit is contained in:
Michael Bogdanov
2015-10-05 11:54:06 +03:00
parent 306ac73eb7
commit 882f6113dc
28 changed files with 364 additions and 30 deletions
@@ -47,7 +47,7 @@ public class AccessorForConstructorDescriptor(
copyValueParameters(calleeDescriptor),
calleeDescriptor.returnType,
Modality.FINAL,
Visibilities.INTERNAL,
Visibilities.LOCAL,
false,
false
)
@@ -47,7 +47,7 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
copyValueParameters(descriptor),
descriptor.getReturnType(),
Modality.FINAL,
Visibilities.INTERNAL,
Visibilities.LOCAL,
descriptor.isOperator(),
descriptor.isInfix());
}
@@ -2234,14 +2234,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
fieldName = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty);
}
else {
Name name;
if (propertyDescriptor instanceof AccessorForPropertyDescriptor) {
name = ((AccessorForPropertyDescriptor) propertyDescriptor).getCalleeDescriptor().getName();
}
else {
name = propertyDescriptor.getName();
}
fieldName = JvmAbi.getDefaultFieldNameForProperty(name, isDelegatedProperty);
fieldName = JetTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty);
}
return StackValue.property(propertyDescriptor, backingFieldOwner,
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.kotlin.ModuleMapping;
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetFunction;
@@ -233,4 +234,9 @@ public class JvmCodegenUtil {
// TODO: drop after some time
av.visit(JvmAnnotationNames.OLD_ABI_VERSION_FIELD_NAME, JvmAbi.VERSION.getMinor());
}
@NotNull
public static String sanitizeAsJavaIdentifier(@NotNull String str) {
return PackagePartClassUtils.sanitizeAsJavaIdentifier(str);
}
}
@@ -18,12 +18,13 @@ package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.AccessorForPropertyDescriptor;
import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.load.java.JvmAbi;
import java.util.HashMap;
import java.util.Map;
@@ -45,10 +46,14 @@ public abstract class FieldOwnerContext<T extends DeclarationDescriptor> extends
@NotNull
public String getFieldName(@NotNull PropertyDescriptor possiblySubstitutedDescriptor, boolean isDelegated) {
if (possiblySubstitutedDescriptor instanceof AccessorForPropertyDescriptor) {
possiblySubstitutedDescriptor = ((AccessorForPropertyDescriptor) possiblySubstitutedDescriptor).getCalleeDescriptor();
}
PropertyDescriptor descriptor = possiblySubstitutedDescriptor.getOriginal();
assert descriptor.getKind().isReal() : "Only declared properties can have backing fields: " + descriptor;
String defaultPropertyName = JvmAbi.getDefaultFieldNameForProperty(descriptor.getName(), isDelegated);
String defaultPropertyName = JetTypeMapper.mapDefaultFieldName(descriptor, isDelegated);
Map<PropertyDescriptor, String> descriptor2Name = fieldNames.get(defaultPropertyName);
if (descriptor2Name == null) {
@@ -20,13 +20,13 @@ import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper
public class KotlinToJvmSignatureMapperImpl : KotlinToJvmSignatureMapper {
// We use empty BindingContext, because it is only used by JetTypeMapper for purposes irrelevant to the needs of this class
private val typeMapper: JetTypeMapper = JetTypeMapper(
BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider, null)
private val typeMapper: JetTypeMapper = JetTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider, null, JvmAbi.DEFAULT_MODULE_NAME)
override fun mapToJvmMethodSignature(function: FunctionDescriptor) = typeMapper.mapSignature(function)
}
@@ -44,11 +44,12 @@ class BuilderFactoryForDuplicateSignatureDiagnostics(
bindingContext: BindingContext,
private val diagnostics: DiagnosticSink,
fileClassesProvider: JvmFileClassesProvider,
incrementalCache: IncrementalCache?
incrementalCache: IncrementalCache?,
moduleName: String
) : SignatureCollectingClassBuilderFactory(builderFactory) {
// Avoid errors when some classes are not loaded for some reason
private val typeMapper = JetTypeMapper(bindingContext, ClassBuilderMode.LIGHT_CLASSES, fileClassesProvider, incrementalCache)
private val typeMapper = JetTypeMapper(bindingContext, ClassBuilderMode.LIGHT_CLASSES, fileClassesProvider, incrementalCache, moduleName)
override fun handleClashingSignatures(data: ConflictingJvmDeclarationsData) {
val noOwnImplementations = data.signatureOrigins.all { it.originKind in EXTERNAL_SOURCES_KINDS }
@@ -92,11 +92,11 @@ public class GenerationState @JvmOverloads constructor(
incrementalCompilationComponents.getIncrementalCache(targetId)
else null
public val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
public val classBuilderMode: ClassBuilderMode = builderFactory.getClassBuilderMode()
public val bindingTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "trace in GenerationState")
public val bindingContext: BindingContext = bindingTrace.getBindingContext()
public val typeMapper: JetTypeMapper = JetTypeMapper(this.bindingContext, classBuilderMode, fileClassesProvider,
getIncrementalCacheForThisTarget())
public val typeMapper: JetTypeMapper = JetTypeMapper(this.bindingContext, classBuilderMode, fileClassesProvider, getIncrementalCacheForThisTarget(), this.moduleName)
public val intrinsics: IntrinsicMethods = IntrinsicMethods()
public val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
public val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics)
@@ -117,7 +117,6 @@ public class GenerationState @JvmOverloads constructor(
public val isInlineEnabled: Boolean = !disableInline
@JvmName("isInlineEnabled") get
public val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
public val rootContext: CodegenContext<*> = RootContext(this)
@@ -125,7 +124,8 @@ public class GenerationState @JvmOverloads constructor(
val optimizationClassBuilderFactory = OptimizationClassBuilderFactory(builderFactory, disableOptimization)
var interceptedBuilderFactory: ClassBuilderFactory = BuilderFactoryForDuplicateSignatureDiagnostics(
optimizationClassBuilderFactory, this.bindingContext, diagnostics, fileClassesProvider,
getIncrementalCacheForThisTarget())
getIncrementalCacheForThisTarget(),
this.moduleName)
interceptedBuilderFactory = BuilderFactoryForDuplicateClassNameDiagnostics(interceptedBuilderFactory, diagnostics);
@@ -87,17 +87,20 @@ public class JetTypeMapper {
private final ClassBuilderMode classBuilderMode;
private final JvmFileClassesProvider fileClassesProvider;
private final IncrementalCache incrementalCache;
private final String moduleName;
public JetTypeMapper(
@NotNull BindingContext bindingContext,
@NotNull ClassBuilderMode classBuilderMode,
@NotNull JvmFileClassesProvider fileClassesProvider,
@Nullable IncrementalCache incrementalCache
@Nullable IncrementalCache incrementalCache,
@NotNull String moduleName
) {
this.bindingContext = bindingContext;
this.classBuilderMode = classBuilderMode;
this.fileClassesProvider = fileClassesProvider;
this.incrementalCache = incrementalCache;
this.moduleName = moduleName;
}
@NotNull
@@ -828,7 +831,7 @@ public class JetTypeMapper {
? JvmAbi.getterName(propertyName)
: JvmAbi.setterName(propertyName);
return isAccessor ? "access$" + accessorName : accessorName;
return updateMemberNameIfInternal(isAccessor ? "access$" + accessorName : accessorName, descriptor);
}
else if (isFunctionLiteral(descriptor)) {
PsiElement element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor);
@@ -848,10 +851,40 @@ public class JetTypeMapper {
return OperatorConventions.INVOKE.asString();
}
else {
return descriptor.getName().asString();
return updateMemberNameIfInternal(descriptor.getName().asString(), descriptor);
}
}
@NotNull
public static String mapDefaultFieldName(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegated) {
String name;
if (propertyDescriptor instanceof AccessorForPropertyDescriptor) {
name = ((AccessorForPropertyDescriptor) propertyDescriptor).getCalleeDescriptor().getName().asString();
}
else {
name = propertyDescriptor.getName().asString();
}
return isDelegated ? name + JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX : name;
}
@NotNull
private String updateMemberNameIfInternal(@NotNull String name, @NotNull CallableMemberDescriptor descriptor) {
if (descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
//script properties should be public
return name;
}
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
return name;
}
if (!(descriptor instanceof ConstructorDescriptor) && descriptor.getVisibility() == Visibilities.INTERNAL) {
return name + "$" + JvmCodegenUtil.sanitizeAsJavaIdentifier(moduleName);
}
return name;
}
@NotNull
public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor descriptor) {
return mapSignature(descriptor, OwnerKind.IMPLEMENTATION);
@@ -40,7 +40,7 @@ public object PackagePartClassUtils {
else
capitalizeAsJavaClassName(sanitizeAsJavaIdentifier(str)) + PART_CLASS_NAME_SUFFIX
private @JvmStatic fun sanitizeAsJavaIdentifier(str: String): String =
public @JvmStatic fun sanitizeAsJavaIdentifier(str: String): String =
str.replace("[^\\p{L}\\p{Digit}]".toRegex(), "_")
private @JvmStatic fun capitalizeAsJavaClassName(str: String): String =
@@ -0,0 +1,29 @@
open class A {
internal open val field = "AF"
internal open fun test(): String = "AM"
}
fun invokeOnA(a: A) = a.test() + a.field
class Z : A() {
override val field: String = "ZF"
override fun test(): String = "ZM"
}
fun box() : String {
var invokeOnA = invokeOnA(A())
if (invokeOnA != "AMAF") return "fail 1: $invokeOnA"
invokeOnA = invokeOnA(Z())
if (invokeOnA != "ZMZF") return "fail 2: $invokeOnA"
val z = Z().test()
if (z != "ZM") return "fail 3: $z"
val f = Z().field
if (f != "ZF") return "fail 4: $f"
return "OK"
}
@@ -0,0 +1,21 @@
open class A {
internal open val field = "F"
internal open fun test(): String = "A"
}
class Z : A() {
override fun test(): String = super.test()
override val field = super.field
}
fun box() : String {
val z = Z().test()
if (z != "A") return "fail 1: $z"
val f = Z().field
if (f != "F") return "fail 2: $f"
return "OK"
}
@@ -0,0 +1,29 @@
open class A {
internal open val field = "AF"
internal open fun test(): String = "AM"
}
fun invokeOnA(a: A) = a.test() + a.field
class Z : A() {
public override val field: String = "ZF"
public override fun test(): String = "ZM"
}
fun box() : String {
var invokeOnA = invokeOnA(A())
if (invokeOnA != "AMAF") return "fail 1: $invokeOnA"
invokeOnA = invokeOnA(Z())
if (invokeOnA != "ZMZF") return "fail 2: $invokeOnA"
val z = Z().test()
if (z != "ZM") return "fail 3: $z"
val f = Z().field
if (f != "ZF") return "fail 4: $f"
return "OK"
}
@@ -0,0 +1,21 @@
open class A {
internal open val field = "F"
internal open fun test(): String = "A"
}
class Z : A() {
public override fun test(): String = super.test()
public override val field = super.field
}
fun box() : String {
val z = Z().test()
if (z != "A") return "fail 1: $z"
val f = Z().field
if (f != "F") return "fail 2: $f"
return "OK"
}
@@ -1,6 +1,6 @@
//NO_CHECK_LAMBDA_INLINING
import test.*
internal fun box(): String {
fun box(): String {
return bar { "OK" }.run()
}
@@ -0,0 +1,5 @@
public class JavaClass extends A {
public String test() {
return "Java";
}
}
@@ -0,0 +1,11 @@
open class A {
internal open fun test(): String = "Kotlin"
}
fun box(): String {
if (A().test() != "Kotlin") return "fail 1: ${A().test()}"
if (JavaClass().test() != "Java") return "fail 2: ${JavaClass().test()}"
return "OK"
}
@@ -0,0 +1,20 @@
package test
internal val noMangling = 1;
class Z {
internal var noMangling = 1;
}
fun box(): String {
val clazz = Z::class.java
val classField = clazz.getDeclaredField("noMangling")
if (classField == null) return "Class internal backing field should exist"
if (!classField.isSynthetic) return "Class internal backing field should be synthetic"
val topLevel = Class.forName("test.FieldKt").getDeclaredField("noMangling")
if (topLevel == null) return "Top level internal backing field should exist"
if (!topLevel.isSynthetic) return "Top level internal backing field should be synthetic"
return "OK"
}
+24
View File
@@ -0,0 +1,24 @@
package test
internal fun noMangling() = 1;
class Z {
internal fun mangled() = 1;
}
fun box(): String {
val clazz = Z::class.java
val declaredMethods = clazz.declaredMethods
val mangled = declaredMethods.firstOrNull {
it.name.startsWith("mangled$")
}
if (mangled == null) return "Class internal function should exist"
if (!mangled.isSynthetic) return "Class internal function should be synthetic"
val topLevel = Class.forName("test.FunKt").getMethod("noMangling")
if (topLevel == null) return "Top level internal function should exist"
if (!topLevel.isSynthetic) return "Top level internal function should be synthetic"
return "OK"
}
@@ -0,0 +1,14 @@
OUT:
Buildfile: [TestData]/build.xml
build:
[kotlinc] Compiling [[TestData]/module1.kt] => [[Temp]/module1.jar]
[kotlinc] Compiling [[TestData]/module2.kt] => [[Temp]/module2.jar]
[java] A_OA_K
[java] B_OB_K
[java] C_OC_K
BUILD SUCCESSFUL
Total time: [time]
Return code: 0
@@ -0,0 +1,21 @@
<project name="Ant Task Test" default="build">
<taskdef resource="org/jetbrains/kotlin/ant/antlib.xml" classpath="${kotlin.lib}/kotlin-ant.jar"/>
<target name="build">
<kotlinc src="${test.data}/module1.kt" output="${temp}/module1.jar" modulename="module1"/>
<kotlinc src="${test.data}/module2.kt" output="${temp}/module2.jar" modulename="module2">
<classpath>
<pathelement path="${temp}/module1.jar"/>
</classpath>
</kotlinc>
<java classname="hello.Module2Kt" fork="true">
<classpath>
<pathelement path="${temp}/module1.jar"/>
<pathelement path="${temp}/module2.jar"/>
<pathelement location="${kotlin.runtime.jar}"/>
</classpath>
</java>
</target>
</project>
@@ -0,0 +1,11 @@
package hello
open class A {
internal val z: String = "A_O"
internal fun test() = "A_K"
}
public fun invokeOnA(a: A) = a.z + a.test()
@@ -0,0 +1,29 @@
package hello
open class B : A() {
internal val z: String = "B_O"
internal fun test() = "B_K"
}
class C : A() {
public val z: String = "C_O"
public fun test() = "C_K"
}
public fun invokeOnB(b: B) = b.z + b.test()
public fun invokeOnC(c: C) = c.z + c.test()
fun main(args: Array<String>) {
val b = B()
println(invokeOnA(b))
println(invokeOnB(b))
println(invokeOnC(C()))
}
@@ -5018,6 +5018,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@TestMetadata("compiler/testData/codegen/box/mangling")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Mangling extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInMangling() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/mangling"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("internalOverride.kt")
public void testInternalOverride() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internalOverride.kt");
doTest(fileName);
}
@TestMetadata("internalOverrideSuperCall.kt")
public void testInternalOverrideSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internalOverrideSuperCall.kt");
doTest(fileName);
}
@TestMetadata("publicOverride.kt")
public void testPublicOverride() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/publicOverride.kt");
doTest(fileName);
}
@TestMetadata("publicOverrideSuperCall.kt")
public void testPublicOverrideSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/publicOverrideSuperCall.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/multiDecl")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -65,6 +65,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("mangling")
public void testMangling() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/mangling/");
doTestWithJava(fileName);
}
@TestMetadata("platformName")
public void testPlatformName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/platformName/");
@@ -2228,6 +2228,27 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/mangling")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Mangling extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInMangling() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/mangling"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("field.kt")
public void testField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/mangling/field.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("fun.kt")
public void testFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/mangling/fun.kt");
doTestWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/multiDeclForArray")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -59,6 +59,12 @@ public class AntTaskTestGenerated extends AbstractAntTaskTest {
doTest(fileName);
}
@TestMetadata("internalMembers")
public void testInternalMembers() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/integration/ant/jvm/internalMembers/");
doTest(fileName);
}
@TestMetadata("jvmClasspath")
public void testJvmClasspath() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/integration/ant/jvm/jvmClasspath/");
@@ -62,11 +62,6 @@ public final class JvmAbi {
return propertyName.asString() + ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX;
}
@NotNull
public static String getDefaultFieldNameForProperty(@NotNull Name propertyName, boolean isDelegated) {
return isDelegated ? propertyName.asString() + DELEGATED_PROPERTY_NAME_SUFFIX : propertyName.asString();
}
public static boolean isGetterName(@NotNull String name) {
return name.startsWith(GET_PREFIX) || name.startsWith(IS_PREFIX);
}