Simplify storage of JVM signatures in binary metadata
Store the whole method & field descriptor strings. Moving these strings to separate annotation arguments later will allow to reuse them with the ones in the constant pool, presumably allowing to save lots of space (up to 10%)
This commit is contained in:
@@ -24,8 +24,6 @@ import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.RawTypeCapabilities;
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.serialization.*;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
|
||||
@@ -35,8 +33,6 @@ import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.shortNameByAsmType;
|
||||
import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
|
||||
|
||||
@@ -107,7 +103,8 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
if (callable instanceof DeserializedSimpleFunctionDescriptor) {
|
||||
DeserializedSimpleFunctionDescriptor deserialized = (DeserializedSimpleFunctionDescriptor) callable;
|
||||
signature = signatureSerializer.copyMethodSignature(
|
||||
deserialized.getProto().getExtension(JvmProtoBuf.methodSignature), deserialized.getNameResolver());
|
||||
deserialized.getProto().getExtension(JvmProtoBuf.methodSignature), deserialized.getNameResolver()
|
||||
);
|
||||
}
|
||||
else {
|
||||
Method method = bindings.get(METHOD_FOR_FUNCTION, (FunctionDescriptor) callable);
|
||||
@@ -126,23 +123,22 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
Method setterMethod = setter == null ? null : bindings.get(METHOD_FOR_FUNCTION, setter);
|
||||
|
||||
Pair<Type, String> field = bindings.get(FIELD_FOR_PROPERTY, property);
|
||||
Type fieldType;
|
||||
String fieldName;
|
||||
String fieldDesc;
|
||||
boolean isStaticInOuter;
|
||||
Method syntheticMethod;
|
||||
if (field != null) {
|
||||
fieldType = field.first;
|
||||
fieldName = field.second;
|
||||
fieldDesc = field.first.getDescriptor();
|
||||
isStaticInOuter = bindings.get(STATIC_FIELD_IN_OUTER_CLASS, property);
|
||||
syntheticMethod = bindings.get(SYNTHETIC_METHOD_FOR_PROPERTY, property);
|
||||
}
|
||||
else {
|
||||
fieldType = null;
|
||||
fieldName = null;
|
||||
fieldDesc = null;
|
||||
isStaticInOuter = false;
|
||||
syntheticMethod = bindings.get(SYNTHETIC_METHOD_FOR_PROPERTY, property);
|
||||
}
|
||||
|
||||
Method syntheticMethod = bindings.get(SYNTHETIC_METHOD_FOR_PROPERTY, property);
|
||||
|
||||
JvmProtoBuf.JvmPropertySignature signature;
|
||||
if (callable instanceof DeserializedPropertyDescriptor) {
|
||||
DeserializedPropertyDescriptor deserializedCallable = (DeserializedPropertyDescriptor) callable;
|
||||
@@ -152,8 +148,12 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
);
|
||||
}
|
||||
else {
|
||||
signature = signatureSerializer
|
||||
.propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethod, getterMethod, setterMethod);
|
||||
signature = signatureSerializer.propertySignature(
|
||||
fieldName, fieldDesc, isStaticInOuter,
|
||||
syntheticMethod != null ? signatureSerializer.methodSignature(syntheticMethod) : null,
|
||||
getterMethod != null ? signatureSerializer.methodSignature(getterMethod) : null,
|
||||
setterMethod != null ? signatureSerializer.methodSignature(setterMethod) : null
|
||||
);
|
||||
}
|
||||
proto.setExtension(JvmProtoBuf.propertySignature, signature);
|
||||
}
|
||||
@@ -172,23 +172,18 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
@NotNull JvmProtoBuf.JvmMethodSignature signature,
|
||||
@NotNull NameResolver nameResolver
|
||||
) {
|
||||
String method = new SignatureDeserializer(nameResolver).methodSignatureString(signature);
|
||||
return methodSignature(getAsmMethod(method));
|
||||
return methodSignature(new Method(
|
||||
nameResolver.getString(signature.getName()),
|
||||
nameResolver.getString(signature.getDesc())
|
||||
));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JvmProtoBuf.JvmMethodSignature methodSignature(@NotNull Method method) {
|
||||
JvmProtoBuf.JvmMethodSignature.Builder signature = JvmProtoBuf.JvmMethodSignature.newBuilder();
|
||||
|
||||
signature.setName(stringTable.getStringIndex(method.getName()));
|
||||
|
||||
signature.setReturnType(type(method.getReturnType()));
|
||||
|
||||
for (Type type : method.getArgumentTypes()) {
|
||||
signature.addParameterType(type(type));
|
||||
}
|
||||
|
||||
return signature.build();
|
||||
return JvmProtoBuf.JvmMethodSignature.newBuilder()
|
||||
.setName(stringTable.getStringIndex(method.getName()))
|
||||
.setDesc(stringTable.getStringIndex(method.getDescriptor()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -196,103 +191,68 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
@NotNull JvmProtoBuf.JvmPropertySignature signature,
|
||||
@NotNull NameResolver nameResolver
|
||||
) {
|
||||
Type fieldType;
|
||||
String fieldName;
|
||||
String fieldDesc;
|
||||
boolean isStaticInOuter;
|
||||
SignatureDeserializer signatureDeserializer = new SignatureDeserializer(nameResolver);
|
||||
if (signature.hasField()) {
|
||||
JvmProtoBuf.JvmFieldSignature field = signature.getField();
|
||||
fieldType = Type.getType(signatureDeserializer.typeDescriptor(field.getType()));
|
||||
fieldName = nameResolver.getName(field.getName()).asString();
|
||||
fieldName = nameResolver.getString(field.getName());
|
||||
fieldDesc = nameResolver.getString(field.getDesc());
|
||||
isStaticInOuter = field.getIsStaticInOuter();
|
||||
}
|
||||
else {
|
||||
fieldType = null;
|
||||
fieldName = null;
|
||||
fieldDesc = null;
|
||||
isStaticInOuter = false;
|
||||
}
|
||||
|
||||
Method syntheticMethod = signature.hasSyntheticMethod()
|
||||
? getAsmMethod(signatureDeserializer.methodSignatureString(signature.getSyntheticMethod()))
|
||||
: null;
|
||||
|
||||
Method getter = signature.hasGetter() ? getAsmMethod(signatureDeserializer.methodSignatureString(signature.getGetter())) : null;
|
||||
Method setter = signature.hasSetter() ? getAsmMethod(signatureDeserializer.methodSignatureString(signature.getSetter())) : null;
|
||||
|
||||
return propertySignature(fieldType, fieldName, isStaticInOuter, syntheticMethod, getter, setter);
|
||||
return propertySignature(
|
||||
fieldName, fieldDesc, isStaticInOuter,
|
||||
signature.hasSyntheticMethod() ? copyMethodSignature(signature.getSyntheticMethod(), nameResolver) : null,
|
||||
signature.hasGetter() ? copyMethodSignature(signature.getGetter(), nameResolver) : null,
|
||||
signature.hasSetter() ? copyMethodSignature(signature.getSetter(), nameResolver) : null
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JvmProtoBuf.JvmPropertySignature propertySignature(
|
||||
@Nullable Type fieldType,
|
||||
@Nullable String fieldName,
|
||||
@Nullable String fieldDesc,
|
||||
boolean isStaticInOuter,
|
||||
@Nullable Method syntheticMethod,
|
||||
@Nullable Method getter,
|
||||
@Nullable Method setter
|
||||
@Nullable JvmProtoBuf.JvmMethodSignature syntheticMethod,
|
||||
@Nullable JvmProtoBuf.JvmMethodSignature getter,
|
||||
@Nullable JvmProtoBuf.JvmMethodSignature setter
|
||||
) {
|
||||
JvmProtoBuf.JvmPropertySignature.Builder signature = JvmProtoBuf.JvmPropertySignature.newBuilder();
|
||||
|
||||
if (fieldType != null) {
|
||||
assert fieldName != null : "Field name shouldn't be null when there's a field type: " + fieldType;
|
||||
signature.setField(fieldSignature(fieldType, fieldName, isStaticInOuter));
|
||||
if (fieldDesc != null) {
|
||||
assert fieldName != null : "Field name shouldn't be null when there's a field type: " + fieldDesc;
|
||||
signature.setField(fieldSignature(fieldName, fieldDesc, isStaticInOuter));
|
||||
}
|
||||
|
||||
if (syntheticMethod != null) {
|
||||
signature.setSyntheticMethod(methodSignature(syntheticMethod));
|
||||
signature.setSyntheticMethod(syntheticMethod);
|
||||
}
|
||||
|
||||
if (getter != null) {
|
||||
signature.setGetter(methodSignature(getter));
|
||||
signature.setGetter(getter);
|
||||
}
|
||||
if (setter != null) {
|
||||
signature.setSetter(methodSignature(setter));
|
||||
signature.setSetter(setter);
|
||||
}
|
||||
|
||||
return signature.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JvmProtoBuf.JvmFieldSignature fieldSignature(@NotNull Type type, @NotNull String name, boolean isStaticInOuter) {
|
||||
JvmProtoBuf.JvmFieldSignature.Builder signature = JvmProtoBuf.JvmFieldSignature.newBuilder();
|
||||
signature.setName(stringTable.getStringIndex(name));
|
||||
signature.setType(type(type));
|
||||
public JvmProtoBuf.JvmFieldSignature fieldSignature(@NotNull String name, @NotNull String desc, boolean isStaticInOuter) {
|
||||
JvmProtoBuf.JvmFieldSignature.Builder builder = JvmProtoBuf.JvmFieldSignature.newBuilder()
|
||||
.setName(stringTable.getStringIndex(name))
|
||||
.setDesc(stringTable.getStringIndex(desc));
|
||||
if (isStaticInOuter) {
|
||||
signature.setIsStaticInOuter(true);
|
||||
builder.setIsStaticInOuter(true);
|
||||
}
|
||||
return signature.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JvmProtoBuf.JvmType type(@NotNull Type givenType) {
|
||||
JvmProtoBuf.JvmType.Builder builder = JvmProtoBuf.JvmType.newBuilder();
|
||||
|
||||
Type type = givenType;
|
||||
if (type.getSort() == Type.ARRAY) {
|
||||
builder.setArrayDimension(type.getDimensions());
|
||||
type = type.getElementType();
|
||||
}
|
||||
|
||||
if (type.getSort() == Type.OBJECT) {
|
||||
FqName fqName = internalNameToFqName(type.getInternalName());
|
||||
builder.setClassFqName(stringTable.getFqNameIndex(fqName));
|
||||
}
|
||||
else {
|
||||
builder.setPrimitiveType(JvmProtoBuf.JvmType.PrimitiveType.valueOf(type.getSort()));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private FqName internalNameToFqName(@NotNull String internalName) {
|
||||
return FqName.fromSegments(Arrays.asList(internalName.split("/")));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Method getAsmMethod(@NotNull String nameAndDesc) {
|
||||
int indexOf = nameAndDesc.indexOf('(');
|
||||
return new Method(nameAndDesc.substring(0, indexOf), nameAndDesc.substring(indexOf));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.serialization;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
@@ -27,7 +26,5 @@ public interface StringTable {
|
||||
|
||||
int getFqNameIndex(@NotNull ClassDescriptor descriptor);
|
||||
|
||||
int getFqNameIndex(@NotNull FqName fqName);
|
||||
|
||||
void serializeTo(@NotNull OutputStream output);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class StringTableImpl implements StringTable {
|
||||
shortName = descriptor.getName().asString();
|
||||
FqName packageFqName = ((PackageFragmentDescriptor) containingDeclaration).getFqName();
|
||||
if (!packageFqName.isRoot()) {
|
||||
builder.setParentQualifiedName(getFqNameIndex(packageFqName));
|
||||
builder.setParentQualifiedName(getPackageFqNameIndex(packageFqName));
|
||||
}
|
||||
}
|
||||
else if (containingDeclaration instanceof ClassDescriptor) {
|
||||
@@ -109,8 +109,7 @@ public class StringTableImpl implements StringTable {
|
||||
return qualifiedNames.intern(new FqNameProto(builder));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFqNameIndex(@NotNull FqName fqName) {
|
||||
private int getPackageFqNameIndex(@NotNull FqName fqName) {
|
||||
int result = -1;
|
||||
for (Name segment : fqName.pathSegments()) {
|
||||
QualifiedName.Builder builder = QualifiedName.newBuilder();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,39 +22,18 @@ import "core/deserialization/src/descriptors.proto";
|
||||
option java_outer_classname = "JvmProtoBuf";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
message JvmType {
|
||||
// Either a primitive type, or a class FQ name should be present
|
||||
|
||||
enum PrimitiveType {
|
||||
// These values correspond to ASM Type sorts
|
||||
VOID = 0;
|
||||
BOOLEAN = 1;
|
||||
CHAR = 2;
|
||||
BYTE = 3;
|
||||
SHORT = 4;
|
||||
INT = 5;
|
||||
FLOAT = 6;
|
||||
LONG = 7;
|
||||
DOUBLE = 8;
|
||||
}
|
||||
|
||||
optional PrimitiveType primitive_type = 1;
|
||||
|
||||
// id in QualifiedNameTable of a name in the following format: 'package.Outer$Nested'
|
||||
optional int32 class_fq_name = 2 [(fq_name_id_in_table) = true];
|
||||
|
||||
optional int32 array_dimension = 3 [default = 0];
|
||||
}
|
||||
|
||||
message JvmMethodSignature {
|
||||
required int32 name = 1 [(string_id_in_table) = true];
|
||||
required JvmType return_type = 2;
|
||||
repeated JvmType parameter_type = 3;
|
||||
|
||||
// JVM descriptor of the method, e.g. '(Ljava/util/List;)[Ljava/lang/Object;'
|
||||
required int32 desc = 2 [(string_id_in_table) = true];
|
||||
}
|
||||
|
||||
message JvmFieldSignature {
|
||||
required int32 name = 1 [(string_id_in_table) = true];
|
||||
required JvmType type = 2;
|
||||
|
||||
// JVM descriptor of the field type, e.g. 'Ljava/lang/String;'
|
||||
required int32 desc = 2 [(string_id_in_table) = true];
|
||||
|
||||
// True iff this field is a backing field for a companion object and is really present as a static
|
||||
// field in the outer class, not as an instance field here
|
||||
@@ -62,11 +41,9 @@ message JvmFieldSignature {
|
||||
}
|
||||
|
||||
message JvmPropertySignature {
|
||||
// A property itself is identified either by the field, or by the synthetic method.
|
||||
// If the property is annotated, then either field or synthetic_method should be present
|
||||
optional JvmFieldSignature field = 1;
|
||||
|
||||
// Annotations on properties without backing fields are written on a synthetic method with this signature
|
||||
// Annotations on properties are written on a synthetic method with this signature
|
||||
optional JvmMethodSignature synthetic_method = 2;
|
||||
|
||||
optional JvmMethodSignature getter = 3;
|
||||
|
||||
+14
-17
@@ -243,11 +243,11 @@ public abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C
|
||||
|
||||
kotlinClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
|
||||
override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? {
|
||||
return AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name.asString() + desc))
|
||||
return AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name.asString(), desc))
|
||||
}
|
||||
|
||||
override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? {
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(name, desc)
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(name.asString(), desc)
|
||||
|
||||
if (initializer != null) {
|
||||
val constant = loadConstant(desc, initializer)
|
||||
@@ -299,17 +299,16 @@ public abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C
|
||||
): MemberSignature? {
|
||||
if (!proto.hasExtension(propertySignature)) return null
|
||||
|
||||
val propertySignature = proto.getExtension(propertySignature)
|
||||
val deserializer = SignatureDeserializer(nameResolver)
|
||||
val signature = proto.getExtension(propertySignature)
|
||||
|
||||
if (field && propertySignature.hasField()) {
|
||||
val field = propertySignature.field
|
||||
val type = deserializer.typeDescriptor(field.type)
|
||||
val name = nameResolver.getName(field.name)
|
||||
return MemberSignature.fromFieldNameAndDesc(name, type)
|
||||
if (field && signature.hasField()) {
|
||||
return MemberSignature.fromFieldNameAndDesc(
|
||||
nameResolver.getString(signature.field.name),
|
||||
nameResolver.getString(signature.field.desc)
|
||||
)
|
||||
}
|
||||
else if (synthetic && propertySignature.hasSyntheticMethod()) {
|
||||
return deserializer.methodSignature(propertySignature.syntheticMethod)
|
||||
else if (synthetic && signature.hasSyntheticMethod()) {
|
||||
return MemberSignature.fromMethod(nameResolver, signature.syntheticMethod)
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -320,17 +319,15 @@ public abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C
|
||||
nameResolver: NameResolver,
|
||||
kind: AnnotatedCallableKind
|
||||
): MemberSignature? {
|
||||
val deserializer = SignatureDeserializer(nameResolver)
|
||||
|
||||
when (kind) {
|
||||
AnnotatedCallableKind.FUNCTION -> if (proto.hasExtension(methodSignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(methodSignature))
|
||||
return MemberSignature.fromMethod(nameResolver, proto.getExtension(methodSignature))
|
||||
}
|
||||
AnnotatedCallableKind.PROPERTY_GETTER -> if (proto.hasExtension(propertySignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(propertySignature).getGetter())
|
||||
return MemberSignature.fromMethod(nameResolver, proto.getExtension(propertySignature).getter)
|
||||
}
|
||||
AnnotatedCallableKind.PROPERTY_SETTER -> if (proto.hasExtension(propertySignature)) {
|
||||
return deserializer.methodSignature(proto.getExtension(propertySignature).getSetter())
|
||||
return MemberSignature.fromMethod(nameResolver, proto.getExtension(propertySignature).setter)
|
||||
}
|
||||
AnnotatedCallableKind.PROPERTY -> return getPropertySignature(proto, nameResolver, true, true)
|
||||
}
|
||||
@@ -341,4 +338,4 @@ public abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C
|
||||
public val memberAnnotations: Map<MemberSignature, List<A>>,
|
||||
public val propertyConstants: Map<MemberSignature, C>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -16,20 +16,26 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
|
||||
// The purpose of this class is to hold a unique signature of either a method or a field, so that annotations on a member can be put
|
||||
// into a map indexed by these signatures
|
||||
data class MemberSignature private constructor(private val signature: String) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
public fun fromMethodNameAndDesc(nameAndDesc: String): MemberSignature {
|
||||
return MemberSignature(nameAndDesc)
|
||||
public fun fromMethod(nameResolver: NameResolver, signature: JvmProtoBuf.JvmMethodSignature): MemberSignature {
|
||||
return fromMethodNameAndDesc(nameResolver.getString(signature.name), nameResolver.getString(signature.desc))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
public fun fromFieldNameAndDesc(name: Name, desc: String): MemberSignature {
|
||||
return MemberSignature(name.asString() + "#" + desc)
|
||||
public fun fromMethodNameAndDesc(name: String, desc: String): MemberSignature {
|
||||
return MemberSignature(name + desc)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
public fun fromFieldNameAndDesc(name: String, desc: String): MemberSignature {
|
||||
return MemberSignature(name + "#" + desc)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
|
||||
public class SignatureDeserializer {
|
||||
// These types are ordered according to their sorts, this is significant for deserialization
|
||||
private static final char[] PRIMITIVE_TYPES = new char[] {'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D'};
|
||||
|
||||
private final NameResolver nameResolver;
|
||||
|
||||
public SignatureDeserializer(@NotNull NameResolver nameResolver) {
|
||||
this.nameResolver = nameResolver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String methodSignatureString(@NotNull JvmProtoBuf.JvmMethodSignature signature) {
|
||||
Name name = nameResolver.getName(signature.getName());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
for (int i = 0, length = signature.getParameterTypeCount(); i < length; i++) {
|
||||
typeDescriptor(signature.getParameterType(i), sb);
|
||||
}
|
||||
sb.append(')');
|
||||
typeDescriptor(signature.getReturnType(), sb);
|
||||
|
||||
return name.asString() + sb.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MemberSignature methodSignature(@NotNull JvmProtoBuf.JvmMethodSignature signature) {
|
||||
return MemberSignature.fromMethodNameAndDesc(methodSignatureString(signature));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String typeDescriptor(@NotNull JvmProtoBuf.JvmType type) {
|
||||
return typeDescriptor(type, new StringBuilder()).toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringBuilder typeDescriptor(@NotNull JvmProtoBuf.JvmType type, @NotNull StringBuilder sb) {
|
||||
for (int i = 0; i < type.getArrayDimension(); i++) {
|
||||
sb.append('[');
|
||||
}
|
||||
|
||||
if (type.hasPrimitiveType()) {
|
||||
sb.append(PRIMITIVE_TYPES[type.getPrimitiveType().ordinal()]);
|
||||
}
|
||||
else {
|
||||
sb.append("L");
|
||||
sb.append(fqNameToInternalName(nameResolver.getFqName(type.getClassFqName())));
|
||||
sb.append(";");
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String fqNameToInternalName(@NotNull FqName fqName) {
|
||||
return fqName.asString().replace('.', '/');
|
||||
}
|
||||
}
|
||||
+88
-1091
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmType.PrimitiveType.*
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
@@ -229,9 +228,44 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
|
||||
private fun loadParameterTypes(nameResolver: NameResolver, signature: JvmProtoBuf.JvmMethodSignature): List<Class<*>> {
|
||||
val classLoader = jClass.safeClassLoader
|
||||
return signature.parameterTypeList.map { jvmType ->
|
||||
loadJvmType(jvmType, nameResolver, classLoader)
|
||||
val result = arrayListOf<Class<*>>()
|
||||
val desc = nameResolver.getString(signature.desc)
|
||||
|
||||
var i = 1
|
||||
while (desc[i] != ')') {
|
||||
var arrayDimension = 0
|
||||
while (desc[i] == '[') {
|
||||
arrayDimension++
|
||||
i++
|
||||
}
|
||||
|
||||
var type = when (desc[i++]) {
|
||||
'L' -> {
|
||||
val semicolon = desc.indexOf(';', i)
|
||||
val internalName = desc.substring(i, semicolon)
|
||||
i = semicolon + 1
|
||||
classLoader.loadClass(internalName.replace('/', '.'))
|
||||
}
|
||||
'V' -> Void.TYPE
|
||||
'Z' -> java.lang.Boolean.TYPE
|
||||
'C' -> java.lang.Character.TYPE
|
||||
'B' -> java.lang.Byte.TYPE
|
||||
'S' -> java.lang.Short.TYPE
|
||||
'I' -> java.lang.Integer.TYPE
|
||||
'F' -> java.lang.Float.TYPE
|
||||
'J' -> java.lang.Long.TYPE
|
||||
'D' -> java.lang.Double.TYPE
|
||||
else -> throw KotlinReflectionInternalError("Unknown type prefix in the method signature: $desc")
|
||||
}
|
||||
|
||||
repeat(arrayDimension) {
|
||||
type = type.createArrayType()
|
||||
}
|
||||
|
||||
result.add(type)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO: check resulting field's type
|
||||
@@ -268,42 +302,7 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
return jClass.safeClassLoader.loadClass(classId.asSingleFqName().asString())
|
||||
}
|
||||
|
||||
private fun loadJvmType(
|
||||
type: JvmProtoBuf.JvmType,
|
||||
nameResolver: NameResolver,
|
||||
classLoader: ClassLoader,
|
||||
arrayDimension: Int = type.getArrayDimension()
|
||||
): Class<*> {
|
||||
if (arrayDimension > 0) {
|
||||
return loadJvmType(type, nameResolver, classLoader, arrayDimension - 1).createArrayType()
|
||||
}
|
||||
|
||||
if (type.hasPrimitiveType()) {
|
||||
return PRIMITIVE_TYPES[type.getPrimitiveType()]
|
||||
?: throw KotlinReflectionInternalError("Unknown primitive type: ${type.getPrimitiveType()}")
|
||||
}
|
||||
|
||||
if (type.hasClassFqName()) {
|
||||
val fqName = nameResolver.getFqName(type.getClassFqName())
|
||||
return classLoader.loadClass(fqName.asString())
|
||||
}
|
||||
|
||||
throw KotlinReflectionInternalError("Inconsistent metadata for JVM type")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val PRIMITIVE_TYPES = mapOf(
|
||||
VOID to Void.TYPE,
|
||||
BOOLEAN to java.lang.Boolean.TYPE,
|
||||
CHAR to java.lang.Character.TYPE,
|
||||
BYTE to java.lang.Byte.TYPE,
|
||||
SHORT to java.lang.Short.TYPE,
|
||||
INT to java.lang.Integer.TYPE,
|
||||
FLOAT to java.lang.Float.TYPE,
|
||||
LONG to java.lang.Long.TYPE,
|
||||
DOUBLE to java.lang.Double.TYPE
|
||||
)
|
||||
|
||||
private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.*
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -52,7 +51,7 @@ internal sealed class JvmFunctionSignature {
|
||||
val nameResolver: NameResolver
|
||||
) : JvmFunctionSignature() {
|
||||
override fun asString(): String =
|
||||
SignatureDeserializer(nameResolver).methodSignatureString(signature)
|
||||
nameResolver.getString(signature.name) + nameResolver.getString(signature.desc)
|
||||
}
|
||||
|
||||
class JavaMethod(val method: Method) : JvmFunctionSignature() {
|
||||
@@ -96,12 +95,12 @@ internal sealed class JvmPropertySignature {
|
||||
|
||||
init {
|
||||
if (signature.hasGetter()) {
|
||||
string = SignatureDeserializer(nameResolver).methodSignatureString(signature.getter)
|
||||
string = nameResolver.getString(signature.getter.name) + nameResolver.getString(signature.getter.desc)
|
||||
}
|
||||
else {
|
||||
string = JvmAbi.getterName(nameResolver.getString(signature.field.name)) +
|
||||
"()" +
|
||||
SignatureDeserializer(nameResolver).typeDescriptor(signature.field.type)
|
||||
nameResolver.getString(signature.field.desc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,15 +173,15 @@ internal object RuntimeTypeMapper {
|
||||
when (function.name.asString()) {
|
||||
"equals" -> if (parameters.size() == 1 && KotlinBuiltIns.isNullableAny(parameters.single().type)) {
|
||||
return JvmFunctionSignature.BuiltInFunction.Predefined("equals(Ljava/lang/Object;)Z",
|
||||
javaClass<Any>().getDeclaredMethod("equals", javaClass<Any>()))
|
||||
Any::class.java.getDeclaredMethod("equals", Any::class.java))
|
||||
}
|
||||
"hashCode" -> if (parameters.isEmpty()) {
|
||||
return JvmFunctionSignature.BuiltInFunction.Predefined("hashCode()I",
|
||||
javaClass<Any>().getDeclaredMethod("hashCode"))
|
||||
Any::class.java.getDeclaredMethod("hashCode"))
|
||||
}
|
||||
"toString" -> if (parameters.isEmpty()) {
|
||||
return JvmFunctionSignature.BuiltInFunction.Predefined("toString()Ljava/lang/String;",
|
||||
javaClass<Any>().getDeclaredMethod("toString"))
|
||||
Any::class.java.getDeclaredMethod("toString"))
|
||||
}
|
||||
// TODO: generalize and support other functions from built-ins
|
||||
}
|
||||
|
||||
@@ -299,9 +299,7 @@ open class ProtoCompareGenerated(public val oldNameResolver: NameResolver, publi
|
||||
open fun checkEquals(old: JvmProtoBuf.JvmMethodSignature, new: JvmProtoBuf.JvmMethodSignature): Boolean {
|
||||
if (!checkStringEquals(old.name, new.name)) return false
|
||||
|
||||
if (!checkEquals(old.returnType, new.returnType)) return false
|
||||
|
||||
if (!checkEqualsJvmMethodSignatureParameterType(old, new)) return false
|
||||
if (!checkStringEquals(old.desc, new.desc)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -352,29 +350,10 @@ open class ProtoCompareGenerated(public val oldNameResolver: NameResolver, publi
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: JvmProtoBuf.JvmType, new: JvmProtoBuf.JvmType): Boolean {
|
||||
if (old.hasPrimitiveType() != new.hasPrimitiveType()) return false
|
||||
if (old.hasPrimitiveType()) {
|
||||
if (old.primitiveType != new.primitiveType) return false
|
||||
}
|
||||
|
||||
if (old.hasClassFqName() != new.hasClassFqName()) return false
|
||||
if (old.hasClassFqName()) {
|
||||
if (!checkClassIdEquals(old.classFqName, new.classFqName)) return false
|
||||
}
|
||||
|
||||
if (old.hasArrayDimension() != new.hasArrayDimension()) return false
|
||||
if (old.hasArrayDimension()) {
|
||||
if (old.arrayDimension != new.arrayDimension) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: JvmProtoBuf.JvmFieldSignature, new: JvmProtoBuf.JvmFieldSignature): Boolean {
|
||||
if (!checkStringEquals(old.name, new.name)) return false
|
||||
|
||||
if (!checkEquals(old.type, new.type)) return false
|
||||
if (!checkStringEquals(old.desc, new.desc)) return false
|
||||
|
||||
if (old.hasIsStaticInOuter() != new.hasIsStaticInOuter()) return false
|
||||
if (old.hasIsStaticInOuter()) {
|
||||
@@ -550,16 +529,6 @@ open class ProtoCompareGenerated(public val oldNameResolver: NameResolver, publi
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsJvmMethodSignatureParameterType(old: JvmProtoBuf.JvmMethodSignature, new: JvmProtoBuf.JvmMethodSignature): Boolean {
|
||||
if (old.parameterTypeCount != new.parameterTypeCount) return false
|
||||
|
||||
for(i in 0..old.parameterTypeCount - 1) {
|
||||
if (!checkEquals(old.getParameterType(i), new.getParameterType(i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsAnnotationArgumentValueArrayElement(old: ProtoBuf.Annotation.Argument.Value, new: ProtoBuf.Annotation.Argument.Value): Boolean {
|
||||
if (old.arrayElementCount != new.arrayElementCount) return false
|
||||
|
||||
@@ -814,11 +783,7 @@ public fun JvmProtoBuf.JvmMethodSignature.hashCode(stringIndexes: (Int) -> Int,
|
||||
|
||||
hashCode = 31 * hashCode + stringIndexes(name)
|
||||
|
||||
hashCode = 31 * hashCode + returnType.hashCode(stringIndexes, fqNameIndexes)
|
||||
|
||||
for(i in 0..parameterTypeCount - 1) {
|
||||
hashCode = 31 * hashCode + getParameterType(i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
hashCode = 31 * hashCode + stringIndexes(desc)
|
||||
|
||||
return hashCode
|
||||
}
|
||||
@@ -869,30 +834,12 @@ public fun ProtoBuf.Annotation.Argument.hashCode(stringIndexes: (Int) -> Int, fq
|
||||
return hashCode
|
||||
}
|
||||
|
||||
public fun JvmProtoBuf.JvmType.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
if (hasPrimitiveType()) {
|
||||
hashCode = 31 * hashCode + primitiveType.hashCode()
|
||||
}
|
||||
|
||||
if (hasClassFqName()) {
|
||||
hashCode = 31 * hashCode + fqNameIndexes(classFqName)
|
||||
}
|
||||
|
||||
if (hasArrayDimension()) {
|
||||
hashCode = 31 * hashCode + arrayDimension
|
||||
}
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
public fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
hashCode = 31 * hashCode + stringIndexes(name)
|
||||
|
||||
hashCode = 31 * hashCode + type.hashCode(stringIndexes, fqNameIndexes)
|
||||
hashCode = 31 * hashCode + stringIndexes(desc)
|
||||
|
||||
if (hasIsStaticInOuter()) {
|
||||
hashCode = 31 * hashCode + isStaticInOuter.hashCode()
|
||||
|
||||
Reference in New Issue
Block a user