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
@@ -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
}