Introduce new string table optimized for JVM class files
This format of the string table allows to reduce the size of the Kotlin metadata in JVM class files by reusing constants already present in the constant pool. Currently the string table produced by JvmStringTable is not fully optimized in serialization (in particular, the 'substring' operation which will be used to extract type names out of generic signature, is not used at all), but the format and its complete support in the deserialization (JvmNameResolver) allows future improvement without changing the binary version
This commit is contained in:
@@ -46,6 +46,8 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
|||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPackage;
|
import org.jetbrains.kotlin.resolve.jvm.JvmPackage;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||||
|
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
|
||||||
|
import org.jetbrains.kotlin.codegen.serialization.JvmStringTable;
|
||||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
|
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
|
||||||
import org.jetbrains.kotlin.types.JetType;
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
@@ -842,7 +844,7 @@ public class AsmUtil {
|
|||||||
av.visitEnd();
|
av.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeAnnotationData(@NotNull AnnotationVisitor av, @NotNull byte[] bytes) {
|
public static void writeAnnotationData(@NotNull AnnotationVisitor av, @NotNull DescriptorSerializer serializer, @NotNull byte[] bytes) {
|
||||||
JvmCodegenUtil.writeAbiVersion(av);
|
JvmCodegenUtil.writeAbiVersion(av);
|
||||||
AnnotationVisitor data = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
AnnotationVisitor data = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
|
||||||
for (String string : BitEncoding.encodeBytes(bytes)) {
|
for (String string : BitEncoding.encodeBytes(bytes)) {
|
||||||
@@ -850,7 +852,9 @@ public class AsmUtil {
|
|||||||
}
|
}
|
||||||
data.visitEnd();
|
data.visitEnd();
|
||||||
AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.STRINGS_FIELD_NAME);
|
AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.STRINGS_FIELD_NAME);
|
||||||
// TODO: write the actual string table
|
for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
|
||||||
|
strings.visit(null, string);
|
||||||
|
}
|
||||||
strings.visitEnd();
|
strings.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
|||||||
ProtoBuf.Callable callableProto = serializer.callableProto(funDescriptor).build();
|
ProtoBuf.Callable callableProto = serializer.callableProto(funDescriptor).build();
|
||||||
|
|
||||||
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CALLABLE), true);
|
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CALLABLE), true);
|
||||||
writeAnnotationData(av, serializer.serialize(callableProto));
|
writeAnnotationData(av, serializer, serializer.serialize(callableProto));
|
||||||
av.visitEnd();
|
av.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
|
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
|
||||||
|
|
||||||
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true);
|
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true);
|
||||||
writeAnnotationData(av, serializer.serialize(classProto));
|
writeAnnotationData(av, serializer, serializer.serialize(classProto));
|
||||||
if (kind != null) {
|
if (kind != null) {
|
||||||
av.visitEnum(
|
av.visitEnum(
|
||||||
JvmAnnotationNames.KIND_FIELD_NAME,
|
JvmAnnotationNames.KIND_FIELD_NAME,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.kotlin.codegen.serialization.JvmStringTable;
|
||||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||||
@@ -39,7 +40,7 @@ import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
|
|||||||
public class JvmSerializerExtension extends SerializerExtension {
|
public class JvmSerializerExtension extends SerializerExtension {
|
||||||
private final JvmSerializationBindings bindings;
|
private final JvmSerializationBindings bindings;
|
||||||
private final JetTypeMapper typeMapper;
|
private final JetTypeMapper typeMapper;
|
||||||
private final StringTableImpl stringTable = new StringTableImpl(this);
|
private final StringTable stringTable = new JvmStringTable(this);
|
||||||
private final AnnotationSerializer annotationSerializer = new AnnotationSerializer(stringTable);
|
private final AnnotationSerializer annotationSerializer = new AnnotationSerializer(stringTable);
|
||||||
|
|
||||||
public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull JetTypeMapper typeMapper) {
|
public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull JetTypeMapper typeMapper) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class MultifileClassPartCodegen(
|
|||||||
if (packageProto.memberCount == 0) return
|
if (packageProto.memberCount == 0) return
|
||||||
|
|
||||||
val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true)
|
val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true)
|
||||||
AsmUtil.writeAnnotationData(av, serializer.serialize(packageProto))
|
AsmUtil.writeAnnotationData(av, serializer, serializer.serialize(packageProto))
|
||||||
av.visit(JvmAnnotationNames.MULTIFILE_CLASS_NAME_FIELD_NAME, multifileClassFqName.shortName().asString())
|
av.visit(JvmAnnotationNames.MULTIFILE_CLASS_NAME_FIELD_NAME, multifileClassFqName.shortName().asString())
|
||||||
av.visitEnd()
|
av.visitEnd()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ public class PackageCodegen {
|
|||||||
ProtoBuf.Package packageProto = serializer.packageProtoWithoutDescriptors().build();
|
ProtoBuf.Package packageProto = serializer.packageProtoWithoutDescriptors().build();
|
||||||
|
|
||||||
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE), true);
|
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE), true);
|
||||||
AsmUtil.writeAnnotationData(av, serializer.serialize(packageProto));
|
AsmUtil.writeAnnotationData(av, serializer, serializer.serialize(packageProto));
|
||||||
av.visitEnd();
|
av.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public class PackagePartCodegen extends MemberCodegen<JetFile> {
|
|||||||
if (packageProto.getMemberCount() == 0) return;
|
if (packageProto.getMemberCount() == 0) return;
|
||||||
|
|
||||||
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FILE_FACADE), true);
|
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FILE_FACADE), true);
|
||||||
writeAnnotationData(av, serializer.serialize(packageProto));
|
writeAnnotationData(av, serializer, serializer.serialize(packageProto));
|
||||||
av.visitEnd();
|
av.visitEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassOrPackageFragmentDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
|
import org.jetbrains.kotlin.serialization.SerializerExtension
|
||||||
|
import org.jetbrains.kotlin.serialization.StringTable
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class JvmStringTable(private val extension: SerializerExtension) : StringTable {
|
||||||
|
public val strings = ArrayList<String>()
|
||||||
|
private val records = ArrayList<Record>()
|
||||||
|
private val map = HashMap<String, Int>()
|
||||||
|
private val localNames = HashSet<Int>()
|
||||||
|
|
||||||
|
override fun getStringIndex(string: String): Int =
|
||||||
|
map.getOrPut(string) {
|
||||||
|
strings.size().apply {
|
||||||
|
strings.add(string)
|
||||||
|
records.add(Record.newBuilder().apply {
|
||||||
|
// TODO: optimize, don't always store the operation
|
||||||
|
setOperation(Record.Operation.NONE)
|
||||||
|
}.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFqNameIndex(descriptor: ClassDescriptor): Int {
|
||||||
|
if (ErrorUtils.isError(descriptor)) {
|
||||||
|
throw IllegalStateException("Cannot get FQ name of error class: " + descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
val string: String
|
||||||
|
val storeAsLiteral: Boolean
|
||||||
|
|
||||||
|
val parent = sequence(descriptor, DeclarationDescriptor::getContainingDeclaration).first { it !is ClassDescriptor }
|
||||||
|
if (parent is PackageFragmentDescriptor) {
|
||||||
|
val classId = descriptor.classId
|
||||||
|
val packageName = classId.packageFqName
|
||||||
|
val className = classId.relativeClassName.asString()
|
||||||
|
string =
|
||||||
|
if (packageName.isRoot) className
|
||||||
|
else packageName.asString().replace('.', '/') + "/" + className
|
||||||
|
|
||||||
|
// If any of the class names contains '$', we can't simply replace all '$' with '.' upon deserialization.
|
||||||
|
// This case is rather rare, so we're storing a literal string
|
||||||
|
storeAsLiteral = '$' in string && classId.relativeClassName.pathSegments().any { '$' in it.asString() }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
storeAsLiteral = true
|
||||||
|
string = descriptor.localClassName()
|
||||||
|
}
|
||||||
|
|
||||||
|
val isLocal = descriptor.containingDeclaration !is ClassOrPackageFragmentDescriptor
|
||||||
|
|
||||||
|
map[string]?.let { recordedIndex ->
|
||||||
|
if (isLocal == (recordedIndex in localNames)) {
|
||||||
|
return recordedIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val index = strings.size()
|
||||||
|
if (isLocal) {
|
||||||
|
localNames.add(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
val record = Record.newBuilder()
|
||||||
|
|
||||||
|
if (storeAsLiteral) {
|
||||||
|
strings.add(string)
|
||||||
|
// TODO: optimize, don't always store the operation
|
||||||
|
record.setOperation(Record.Operation.NONE)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(string)
|
||||||
|
if (predefinedIndex != null) {
|
||||||
|
record.setPredefinedIndex(predefinedIndex)
|
||||||
|
record.setOperation(Record.Operation.NONE)
|
||||||
|
// TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored)
|
||||||
|
strings.add("")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
record.setOperation(Record.Operation.DESC_TO_CLASS_ID)
|
||||||
|
strings.add("L$string;")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
records.add(record.build())
|
||||||
|
|
||||||
|
map[string] = index
|
||||||
|
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ClassDescriptor.localClassName(): String {
|
||||||
|
val container = containingDeclaration
|
||||||
|
return when (container) {
|
||||||
|
is ClassDescriptor -> container.localClassName() + "." + name.asString()
|
||||||
|
else -> extension.getLocalClassName(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serializeTo(output: OutputStream) {
|
||||||
|
with(JvmProtoBuf.StringTableTypes.newBuilder()) {
|
||||||
|
addAllRecord(records)
|
||||||
|
addAllLocalName(localNames)
|
||||||
|
build().writeDelimitedTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -12,6 +12,6 @@ interface A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 foo
|
// 1 foo\(
|
||||||
// 1 getProp
|
// 1 getProp
|
||||||
// 1 defaultFun\$
|
// 1 defaultFun\$
|
||||||
|
|||||||
@@ -13042,7 +13042,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
boolean hasFlags();
|
boolean hasFlags();
|
||||||
@@ -13059,7 +13061,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
int getFlags();
|
int getFlags();
|
||||||
@@ -14599,7 +14603,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public boolean hasFlags() {
|
public boolean hasFlags() {
|
||||||
@@ -14618,7 +14624,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
@@ -15352,7 +15360,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public boolean hasFlags() {
|
public boolean hasFlags() {
|
||||||
@@ -15371,7 +15381,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
@@ -15390,7 +15402,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Builder setFlags(int value) {
|
public Builder setFlags(int value) {
|
||||||
@@ -15412,7 +15426,9 @@ public final class DebugProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Builder clearFlags() {
|
public Builder clearFlags() {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.serialization.jvm
|
||||||
|
|
||||||
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.DESC_TO_CLASS_ID
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.INTERNAL_TO_CLASS_ID
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.NONE
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class JvmNameResolverTest : UsefulTestCase() {
|
||||||
|
private class Context {
|
||||||
|
val types = JvmProtoBuf.StringTableTypes.newBuilder()
|
||||||
|
val strings = ArrayList<String>()
|
||||||
|
|
||||||
|
fun string(
|
||||||
|
string: String?,
|
||||||
|
range: Int? = null,
|
||||||
|
predefinedIndex: Int? = null,
|
||||||
|
operation: Record.Operation? = null,
|
||||||
|
substringIndex: List<Int>? = null,
|
||||||
|
replaceChar: List<Char>? = null
|
||||||
|
) {
|
||||||
|
types.addRecord(Record.newBuilder().apply {
|
||||||
|
range?.let { setRange(it) }
|
||||||
|
predefinedIndex?.let { setPredefinedIndex(it) }
|
||||||
|
operation?.let { setOperation(it) }
|
||||||
|
substringIndex?.let { addAllSubstringIndex(it) }
|
||||||
|
replaceChar?.let { addAllReplaceChar(it.map(Char::toInt)) }
|
||||||
|
}.build())
|
||||||
|
|
||||||
|
string?.let { strings.add(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun create(init: Context.() -> Unit): JvmNameResolver {
|
||||||
|
return Context().run {
|
||||||
|
init()
|
||||||
|
JvmNameResolver(types.build(), strings.toTypedArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun str(string: String?, predefinedIndex: Int? = null, operation: Record.Operation? = null): String {
|
||||||
|
return create { string(string, null, predefinedIndex, operation, null, null) }.getString(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleString() {
|
||||||
|
assertEquals("abc", str("abc"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSimpleClassId() {
|
||||||
|
assertEquals(
|
||||||
|
ClassId.topLevel(FqName("foo.bar.Baz")),
|
||||||
|
create { string("Lfoo/bar/Baz;", operation = DESC_TO_CLASS_ID) }.getClassId(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testBasicOperations() {
|
||||||
|
assertEquals("java/util/Map.Entry", str("Ljava/util/Map\$Entry;", operation = DESC_TO_CLASS_ID))
|
||||||
|
assertEquals("java/util/Map.Entry", str("java/util/Map\$Entry", operation = INTERNAL_TO_CLASS_ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testPredefined() {
|
||||||
|
for ((index, predefined) in JvmNameResolver.PREDEFINED_STRINGS.withIndex()) {
|
||||||
|
assertEquals(predefined, str("ignored", predefinedIndex = index), "Predefined string failed: $predefined (index $index)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testNotExistingPredefinedString() {
|
||||||
|
assertEquals("not-ignored", str("not-ignored", predefinedIndex = 123456789))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testOperationOnBadString() {
|
||||||
|
assertEquals("X", str("X", operation = DESC_TO_CLASS_ID))
|
||||||
|
assertEquals("", str("", operation = DESC_TO_CLASS_ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSubstring() {
|
||||||
|
val n = create {
|
||||||
|
string("kotlin", substringIndex = listOf(0, 6))
|
||||||
|
string("kotlin", substringIndex = listOf(1, 4))
|
||||||
|
string("kotlin", substringIndex = listOf(6, 6))
|
||||||
|
|
||||||
|
// Invalid operations
|
||||||
|
string("kotlin", substringIndex = listOf(7, 5))
|
||||||
|
string("kotlin", substringIndex = listOf(0, -2))
|
||||||
|
string("kotlin", substringIndex = listOf(3, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("kotlin", n.getString(0))
|
||||||
|
assertEquals("otl", n.getString(1))
|
||||||
|
assertEquals("", n.getString(2))
|
||||||
|
|
||||||
|
// All invalid operations should be ignored
|
||||||
|
(3..5).forEach { assertEquals("kotlin", n.getString(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSubstringHappensAfterOperation() {
|
||||||
|
assertEquals("tl", create {
|
||||||
|
string("kotlin", substringIndex = listOf(1, 5), operation = DESC_TO_CLASS_ID)
|
||||||
|
}.getString(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testReplaceAll() {
|
||||||
|
val n = create {
|
||||||
|
string("kotlin", replaceChar = listOf('k', 'm'))
|
||||||
|
string("java", replaceChar = listOf('a', 'o', 'a', 'b', 'c', 'd')) // All chars after the first two are ignored
|
||||||
|
|
||||||
|
// Invalid operations
|
||||||
|
string("kotlin", replaceChar = listOf())
|
||||||
|
string("kotlin", replaceChar = listOf('k'))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("motlin", n.getString(0))
|
||||||
|
assertEquals("jovo", n.getString(1))
|
||||||
|
|
||||||
|
// All invalid operations should be ignored
|
||||||
|
(2..3).forEach { assertEquals("kotlin", n.getString(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testRange() {
|
||||||
|
val n = create {
|
||||||
|
string("a\$b\$c", operation = INTERNAL_TO_CLASS_ID, range = 2)
|
||||||
|
string("d\$e\$f", operation = NONE, range = 2)
|
||||||
|
string("abc")
|
||||||
|
string("def")
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("d.e.f", n.getString(1))
|
||||||
|
assertEquals("def", n.getString(3))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testRangeWithDifferentOperations() {
|
||||||
|
val n = create {
|
||||||
|
string("a\$b\$c", operation = INTERNAL_TO_CLASS_ID, range = 2)
|
||||||
|
string("d\$e\$f", operation = NONE, substringIndex = listOf(2, 5))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("a.b.c", n.getString(0))
|
||||||
|
assertEquals("d.e.f", n.getString(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,45 @@ import "core/deserialization/src/descriptors.proto";
|
|||||||
option java_outer_classname = "JvmProtoBuf";
|
option java_outer_classname = "JvmProtoBuf";
|
||||||
option optimize_for = LITE_RUNTIME;
|
option optimize_for = LITE_RUNTIME;
|
||||||
|
|
||||||
|
message StringTableTypes {
|
||||||
|
message Record {
|
||||||
|
// The number of times this record should be repeated; this is used to collapse identical subsequent records in the list
|
||||||
|
optional int32 range = 1 [default = 1];
|
||||||
|
|
||||||
|
// Index of the predefined constant. If this field is present, the associated string is ignored
|
||||||
|
optional int32 predefined_index = 2;
|
||||||
|
|
||||||
|
enum Operation {
|
||||||
|
NONE = 0;
|
||||||
|
|
||||||
|
// replaceAll('$', '.')
|
||||||
|
// java/util/Map$Entry -> java/util/Map.Entry;
|
||||||
|
INTERNAL_TO_CLASS_ID = 1;
|
||||||
|
|
||||||
|
// substring(1, length - 1) and then replaceAll('$', '.')
|
||||||
|
// Ljava/util/Map$Entry; -> java/util/Map.Entry
|
||||||
|
DESC_TO_CLASS_ID = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a described operation on the string
|
||||||
|
optional Operation operation = 3 [default = NONE];
|
||||||
|
|
||||||
|
// If this field is present, the "substring" operation must be performed with the first element of this list as the start index,
|
||||||
|
// and the second element as the end index.
|
||||||
|
// If an operation is not NONE, it's applied _after_ this substring operation
|
||||||
|
repeated int32 substring_index = 4 [packed = true];
|
||||||
|
|
||||||
|
// If this field is present, the "replaceAll" operation must be performed with the first element of this list as the code point
|
||||||
|
// of the character to replace, and the second element as the code point of the replacement character
|
||||||
|
repeated int32 replace_char = 5 [packed = true];
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated Record record = 1;
|
||||||
|
|
||||||
|
// Indices of strings which are names of local classes or anonymous objects
|
||||||
|
repeated int32 local_name = 5 [packed = true];
|
||||||
|
}
|
||||||
|
|
||||||
message JvmMethodSignature {
|
message JvmMethodSignature {
|
||||||
required int32 name = 1 [(string_id_in_table) = true];
|
required int32 name = 1 [(string_id_in_table) = true];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.load.kotlin
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.DESC_TO_CLASS_ID
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.INTERNAL_TO_CLASS_ID
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.NONE
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class JvmNameResolver(
|
||||||
|
private val types: JvmProtoBuf.StringTableTypes,
|
||||||
|
private val strings: Array<String>
|
||||||
|
) : NameResolver {
|
||||||
|
private val localNameIndices = types.localNameList.run { if (isEmpty()) emptySet() else toSet() }
|
||||||
|
|
||||||
|
// Here we expand the 'range' field of the Record message for simplicity to a list of records
|
||||||
|
private val records: List<Record> = ArrayList<Record>().apply {
|
||||||
|
val records = types.recordList
|
||||||
|
this.ensureCapacity(records.size())
|
||||||
|
for (record in records) {
|
||||||
|
repeat(record.range) {
|
||||||
|
this.add(record)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.trimToSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getString(index: Int): String {
|
||||||
|
val record = records[index]
|
||||||
|
|
||||||
|
var string =
|
||||||
|
if (record.hasPredefinedIndex() && record.predefinedIndex in PREDEFINED_STRINGS.indices)
|
||||||
|
PREDEFINED_STRINGS[record.predefinedIndex]
|
||||||
|
else strings[index]
|
||||||
|
|
||||||
|
if (record.substringIndexCount >= 2) {
|
||||||
|
val (begin, end) = record.substringIndexList
|
||||||
|
if (0 <= begin && begin <= end && end <= string.length()) {
|
||||||
|
string = string.substring(begin, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.replaceCharCount >= 2) {
|
||||||
|
val (from, to) = record.replaceCharList
|
||||||
|
string = string.replace(from.toChar(), to.toChar())
|
||||||
|
}
|
||||||
|
|
||||||
|
when (record.operation ?: NONE) {
|
||||||
|
NONE -> {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
INTERNAL_TO_CLASS_ID -> {
|
||||||
|
string = string.replace('$', '.')
|
||||||
|
}
|
||||||
|
DESC_TO_CLASS_ID -> {
|
||||||
|
if (string.length() >= 2) {
|
||||||
|
string = string.substring(1, string.length() - 1)
|
||||||
|
}
|
||||||
|
string = string.replace('$', '.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(index: Int) = Name.guess(getString(index))
|
||||||
|
|
||||||
|
override fun getClassId(index: Int): ClassId {
|
||||||
|
val string = getString(index)
|
||||||
|
val lastSlash = string.lastIndexOf('/')
|
||||||
|
val packageName =
|
||||||
|
if (lastSlash < 0) FqName.ROOT
|
||||||
|
else FqName(string.substring(0, lastSlash).replace('/', '.'))
|
||||||
|
val className = FqName(string.substring(lastSlash + 1))
|
||||||
|
return ClassId(packageName, className, index in localNameIndices)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val PREDEFINED_STRINGS = listOf(
|
||||||
|
"kotlin/Any",
|
||||||
|
"kotlin/Nothing",
|
||||||
|
"kotlin/Unit",
|
||||||
|
"kotlin/Throwable",
|
||||||
|
"kotlin/Number",
|
||||||
|
|
||||||
|
"kotlin/Byte", "kotlin/Double", "kotlin/Float", "kotlin/Int",
|
||||||
|
"kotlin/Long", "kotlin/Short", "kotlin/Boolean", "kotlin/Char",
|
||||||
|
|
||||||
|
"kotlin/CharSequence",
|
||||||
|
"kotlin/String",
|
||||||
|
"kotlin/Comparable",
|
||||||
|
"kotlin/Enum",
|
||||||
|
|
||||||
|
"kotlin/Array",
|
||||||
|
"kotlin/ByteArray", "kotlin/DoubleArray", "kotlin/FloatArray", "kotlin/IntArray",
|
||||||
|
"kotlin/LongArray", "kotlin/ShortArray", "kotlin/BooleanArray", "kotlin/CharArray",
|
||||||
|
|
||||||
|
"kotlin/Cloneable",
|
||||||
|
"kotlin/Annotation",
|
||||||
|
|
||||||
|
"kotlin/Iterable", "kotlin/MutableIterable",
|
||||||
|
"kotlin/Collection", "kotlin/MutableCollection",
|
||||||
|
"kotlin/List", "kotlin/MutableList",
|
||||||
|
"kotlin/Set", "kotlin/MutableSet",
|
||||||
|
"kotlin/Map", "kotlin/MutableMap",
|
||||||
|
"kotlin/Map.Entry", "kotlin/MutableMap.MutableEntry",
|
||||||
|
|
||||||
|
"kotlin/Iterator", "kotlin/MutableIterator",
|
||||||
|
"kotlin/ListIterator", "kotlin/MutableListIterator"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val PREDEFINED_STRINGS_MAP = PREDEFINED_STRINGS.withIndex().toMap({ it.value }, { it.index })
|
||||||
|
|
||||||
|
fun getPredefinedStringIndex(string: String): Int? = PREDEFINED_STRINGS_MAP[string]
|
||||||
|
}
|
||||||
|
}
|
||||||
+1904
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -17,10 +17,10 @@
|
|||||||
package org.jetbrains.kotlin.serialization.jvm
|
package org.jetbrains.kotlin.serialization.jvm
|
||||||
|
|
||||||
import com.google.protobuf.ExtensionRegistryLite
|
import com.google.protobuf.ExtensionRegistryLite
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||||
import org.jetbrains.kotlin.serialization.ClassData
|
import org.jetbrains.kotlin.serialization.ClassData
|
||||||
import org.jetbrains.kotlin.serialization.PackageData
|
import org.jetbrains.kotlin.serialization.PackageData
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
public object JvmProtoBufUtil {
|
public object JvmProtoBufUtil {
|
||||||
@@ -37,7 +37,7 @@ public object JvmProtoBufUtil {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
public fun readClassDataFrom(bytes: ByteArray, strings: Array<String>): ClassData {
|
public fun readClassDataFrom(bytes: ByteArray, strings: Array<String>): ClassData {
|
||||||
val input = ByteArrayInputStream(bytes)
|
val input = ByteArrayInputStream(bytes)
|
||||||
val nameResolver = NameResolverImpl.read(input)
|
val nameResolver = JvmNameResolver(JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, EXTENSION_REGISTRY), strings)
|
||||||
val classProto = ProtoBuf.Class.parseFrom(input, EXTENSION_REGISTRY)
|
val classProto = ProtoBuf.Class.parseFrom(input, EXTENSION_REGISTRY)
|
||||||
return ClassData(nameResolver, classProto)
|
return ClassData(nameResolver, classProto)
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ public object JvmProtoBufUtil {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
public fun readPackageDataFrom(bytes: ByteArray, strings: Array<String>): PackageData {
|
public fun readPackageDataFrom(bytes: ByteArray, strings: Array<String>): PackageData {
|
||||||
val input = ByteArrayInputStream(bytes)
|
val input = ByteArrayInputStream(bytes)
|
||||||
val nameResolver = NameResolverImpl.read(input)
|
val nameResolver = JvmNameResolver(JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, EXTENSION_REGISTRY), strings)
|
||||||
val packageProto = ProtoBuf.Package.parseFrom(input, EXTENSION_REGISTRY)
|
val packageProto = ProtoBuf.Package.parseFrom(input, EXTENSION_REGISTRY)
|
||||||
return PackageData(nameResolver, packageProto)
|
return PackageData(nameResolver, packageProto)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10043,7 +10043,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
boolean hasFlags();
|
boolean hasFlags();
|
||||||
@@ -10060,7 +10062,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
int getFlags();
|
int getFlags();
|
||||||
@@ -11277,7 +11281,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public boolean hasFlags() {
|
public boolean hasFlags() {
|
||||||
@@ -11296,7 +11302,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
@@ -11907,7 +11915,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public boolean hasFlags() {
|
public boolean hasFlags() {
|
||||||
@@ -11926,7 +11936,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
@@ -11945,7 +11957,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Builder setFlags(int value) {
|
public Builder setFlags(int value) {
|
||||||
@@ -11967,7 +11981,9 @@ public final class ProtoBuf {
|
|||||||
*hasGetter
|
*hasGetter
|
||||||
*hasSetter
|
*hasSetter
|
||||||
*hasConstant
|
*hasConstant
|
||||||
|
*isConst
|
||||||
*lateinit
|
*lateinit
|
||||||
|
*isOperator
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Builder clearFlags() {
|
public Builder clearFlags() {
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
package kotlin.reflect.jvm
|
package kotlin.reflect.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
|
|
||||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
import kotlin.jvm.internal.KotlinCallable
|
import kotlin.jvm.internal.KotlinCallable
|
||||||
import kotlin.reflect.KFunction
|
import kotlin.reflect.KFunction
|
||||||
@@ -37,7 +38,10 @@ import kotlin.reflect.jvm.internal.getOrCreateModule
|
|||||||
public fun <R> Function<R>.reflect(): KFunction<R>? {
|
public fun <R> Function<R>.reflect(): KFunction<R>? {
|
||||||
val callable = javaClass.getAnnotation(KotlinCallable::class.java) ?: return null
|
val callable = javaClass.getAnnotation(KotlinCallable::class.java) ?: return null
|
||||||
val input = BitEncoding.decodeBytes(callable.data).inputStream()
|
val input = BitEncoding.decodeBytes(callable.data).inputStream()
|
||||||
val nameResolver = NameResolverImpl.read(input)
|
val nameResolver = JvmNameResolver(
|
||||||
|
JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY),
|
||||||
|
callable.strings
|
||||||
|
)
|
||||||
val proto = ProtoBuf.Callable.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
val proto = ProtoBuf.Callable.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
||||||
val moduleData = javaClass.getOrCreateModule()
|
val moduleData = javaClass.getOrCreateModule()
|
||||||
val context = DeserializationContext(moduleData.deserialization, nameResolver, moduleData.module,
|
val context = DeserializationContext(moduleData.deserialization, nameResolver, moduleData.module,
|
||||||
|
|||||||
+17
-18
@@ -16,28 +16,28 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.jps.build.classFilesComparison
|
package org.jetbrains.kotlin.jps.build.classFilesComparison
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import org.junit.Assert.*
|
|
||||||
import org.jetbrains.org.objectweb.asm.util.TraceClassVisitor
|
|
||||||
import java.io.PrintWriter
|
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
|
||||||
import java.io.StringWriter
|
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
import com.google.common.io.Files
|
|
||||||
import com.google.common.hash.Hashing
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
|
||||||
import com.google.common.collect.Sets
|
import com.google.common.collect.Sets
|
||||||
import java.util.HashSet
|
import com.google.common.hash.Hashing
|
||||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
import com.google.common.io.Files
|
||||||
import org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf
|
|
||||||
import com.google.protobuf.ExtensionRegistry
|
import com.google.protobuf.ExtensionRegistry
|
||||||
import java.io.ByteArrayInputStream
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import org.jetbrains.kotlin.serialization.DebugProtoBuf
|
|
||||||
import java.util.Arrays
|
|
||||||
import org.jetbrains.kotlin.jps.incremental.LocalFileKotlinClass
|
import org.jetbrains.kotlin.jps.incremental.LocalFileKotlinClass
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
|
||||||
|
import org.jetbrains.kotlin.serialization.DebugProtoBuf
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||||
|
import org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf
|
||||||
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||||
|
import org.jetbrains.org.objectweb.asm.util.TraceClassVisitor
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNotNull
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.io.StringWriter
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
// Set this to true if you want to dump all bytecode (test will fail in this case)
|
// Set this to true if you want to dump all bytecode (test will fail in this case)
|
||||||
val DUMP_ALL = System.getProperty("comparison.dump.all") == "true"
|
val DUMP_ALL = System.getProperty("comparison.dump.all") == "true"
|
||||||
@@ -139,8 +139,7 @@ fun classFileToString(classFile: File): String {
|
|||||||
ByteArrayInputStream(BitEncoding.decodeBytes(annotationDataEncoded)).use {
|
ByteArrayInputStream(BitEncoding.decodeBytes(annotationDataEncoded)).use {
|
||||||
input ->
|
input ->
|
||||||
|
|
||||||
out.write("\n------ simpleNames proto -----\n${DebugProtoBuf.StringTable.parseDelimitedFrom(input)}")
|
out.write("\n------ string table types proto -----\n${DebugJvmProtoBuf.StringTableTypes.parseDelimitedFrom(input)}")
|
||||||
out.write("\n------ qualifiedNames proto -----\n${DebugProtoBuf.QualifiedNameTable.parseDelimitedFrom(input)}")
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
classHeader!!.isCompatiblePackageFacadeKind() ->
|
classHeader!!.isCompatiblePackageFacadeKind() ->
|
||||||
|
|||||||
Reference in New Issue
Block a user