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:
Alexander Udalov
2015-09-19 03:16:02 +03:00
parent 68051fa3bb
commit 7d5bd3cf50
12 changed files with 347 additions and 2991 deletions
@@ -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;
@@ -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>
)
}
}
@@ -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
@@ -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('.', '/');
}
}