Parcelable: Migrate to canonical NEW-DUP-INVOKESPECIAL form (KT-20545)

This commit is contained in:
Yan Zhulanow
2017-11-15 14:36:11 +09:00
parent 37543deefa
commit 2819fc718a
7 changed files with 87 additions and 73 deletions
@@ -18,36 +18,34 @@ package org.jetbrains.kotlin.android.parcel
import kotlinx.android.parcel.TypeParceler
import org.jetbrains.kotlin.android.parcel.ParcelableResolveExtension.Companion.createMethod
import org.jetbrains.kotlin.android.parcel.serializers.*
import org.jetbrains.kotlin.android.parcel.ParcelableSyntheticComponent.ComponentKind.*
import org.jetbrains.kotlin.android.parcel.serializers.PARCEL_TYPE
import org.jetbrains.kotlin.android.parcel.serializers.ParcelSerializer
import org.jetbrains.kotlin.android.parcel.serializers.TypeParcelerMapping
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy.CodegenBased
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.coroutines.UninitializedStoresProcessor
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.codegen.writeSyntheticClassMetadata
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -104,8 +102,6 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
val containerAsmType = codegen.typeMapper.mapType(this.defaultType)
return findFunction(WRITE_TO_PARCEL)?.write(codegen) {
v.visitAnnotation(UninitializedStoresProcessor.AVOID_UNINITIALIZED_OBJECT_COPYING_CHECK_ANNOTATION_DESCRIPTOR, false)
if (parcelerObject != null) {
val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject)
@@ -117,7 +113,13 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
"(${containerAsmType.descriptor}${PARCEL_TYPE.descriptor}I)V", false)
}
else {
val globalContext = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType, emptyList())
val frameMap = FrameMap().apply {
enterTemp(containerAsmType)
enterTemp(PARCEL_TYPE)
enterTemp(Type.INT_TYPE)
}
val globalContext = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType, emptyList(), frameMap)
for ((fieldName, type, parcelers) in properties) {
val asmType = codegen.typeMapper.mapType(type)
@@ -188,10 +190,9 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
properties: List<PropertyToSerialize>
) {
val containerAsmType = codegen.typeMapper.mapType(parcelableClass)
val creatorAsmType = codegen.typeMapper.mapType(creatorClass)
createMethod(creatorClass, CREATE_FROM_PARCEL, parcelableClass.builtIns.anyType, "in" to parcelClassType).write(codegen) {
v.visitAnnotation(UninitializedStoresProcessor.AVOID_UNINITIALIZED_OBJECT_COPYING_CHECK_ANNOTATION_DESCRIPTOR, false)
if (parcelerObject != null) {
val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject)
@@ -204,7 +205,12 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
v.dup()
val asmConstructorParameters = StringBuilder()
val globalContext = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType, emptyList())
val frameMap = FrameMap().apply {
enterTemp(creatorAsmType)
enterTemp(PARCEL_TYPE)
}
val globalContext = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType, emptyList(), frameMap)
for ((_, type, parcelers) in properties) {
val asmType = codegen.typeMapper.mapType(type)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.android.parcel.serializers.isParcelable
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.FrameMap
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -214,7 +215,12 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
try {
val parcelers = getTypeParcelers(descriptor.annotations) + getTypeParcelers(containerClass.annotations)
val context = ParcelSerializer.ParcelSerializerContext(typeMapper, typeMapper.mapType(containerClass.defaultType), parcelers)
val context = ParcelSerializer.ParcelSerializerContext(
typeMapper,
typeMapper.mapType(containerClass.defaultType),
parcelers,
FrameMap())
ParcelSerializer.get(type, asmType, context, strict = true)
}
catch (e: IllegalArgumentException) {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.android.parcel.serializers
import kotlinx.android.parcel.WriteWith
import org.jetbrains.kotlin.android.parcel.isParcelize
import org.jetbrains.kotlin.codegen.FrameMap
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -54,7 +55,8 @@ interface ParcelSerializer {
data class ParcelSerializerContext(
val typeMapper: KotlinTypeMapper,
val containerClassType: Type,
val typeParcelers: List<TypeParcelerMapping>
val typeParcelers: List<TypeParcelerMapping>,
val frameMap: FrameMap
) {
fun findParcelerClass(type: KotlinType): KotlinType? {
return typeParcelers.firstOrNull { it.first == type }?.second
@@ -152,7 +154,7 @@ interface ParcelSerializer {
}
val elementSerializer = get(elementType, elementAsmType, context, forceBoxed = true, strict = strict())
wrapToNullAwareIfNeeded(type, ListSetParcelSerializer(asmType, elementSerializer))
wrapToNullAwareIfNeeded(type, ListSetParcelSerializer(asmType, elementSerializer, context.frameMap))
}
className == Map::class.java.canonicalName
@@ -168,7 +170,7 @@ interface ParcelSerializer {
keyType.type, typeMapper.mapTypeSafe(keyType.type, forceBoxed = true), context, forceBoxed = true, strict = strict())
val valueSerializer = get(
valueType.type, typeMapper.mapTypeSafe(valueType.type, forceBoxed = true), context, forceBoxed = true, strict = strict())
wrapToNullAwareIfNeeded(type, MapParcelSerializer(asmType, keySerializer, valueSerializer))
wrapToNullAwareIfNeeded(type, MapParcelSerializer(asmType, keySerializer, valueSerializer, context.frameMap))
}
asmType.isBoxedPrimitive() -> wrapToNullAwareIfNeeded(type, BoxedPrimitiveTypeParcelSerializer.forBoxedType(asmType))
@@ -206,16 +208,16 @@ interface ParcelSerializer {
Method("readSparseBooleanArray"))
asmType.isSparseIntArray() -> wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(
asmType, PrimitiveTypeParcelSerializer.getInstance(Type.INT_TYPE)))
asmType, PrimitiveTypeParcelSerializer.getInstance(Type.INT_TYPE), context.frameMap))
asmType.isSparseLongArray() -> wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(
asmType, PrimitiveTypeParcelSerializer.getInstance(Type.LONG_TYPE)))
asmType, PrimitiveTypeParcelSerializer.getInstance(Type.LONG_TYPE), context.frameMap))
asmType.isSparseArray() -> {
val elementType = type.arguments.single().type
val elementSerializer = get(
elementType, typeMapper.mapTypeSafe(elementType, forceBoxed = true), context, forceBoxed = true, strict = strict())
wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(asmType, elementSerializer))
wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(asmType, elementSerializer, context.frameMap))
}
type.isCharSequence() -> CharSequenceParcelSerializer(asmType)
@@ -19,9 +19,10 @@ package org.jetbrains.kotlin.android.parcel.serializers
import kotlinx.android.parcel.Parceler
import org.jetbrains.kotlin.android.parcel.serializers.BoxedPrimitiveTypeParcelSerializer.Companion.BOXED_VALUE_METHOD_NAMES
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.FrameMap
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.useTmpVar
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
@@ -186,8 +187,9 @@ internal fun InstructionAdapter.castIfNeeded(targetType: Type) {
internal class ListSetParcelSerializer(
asmType: Type,
elementSerializer: ParcelSerializer
) : AbstractCollectionParcelSerializer(asmType, elementSerializer) {
elementSerializer: ParcelSerializer,
frameMap: FrameMap
) : AbstractCollectionParcelSerializer(asmType, elementSerializer, frameMap) {
override fun getSize(v: InstructionAdapter) {
v.invokeinterface("java/util/Collection", "size", "()I")
}
@@ -216,8 +218,9 @@ internal class ListSetParcelSerializer(
internal class MapParcelSerializer(
asmType: Type,
private val keySerializer: ParcelSerializer,
elementSerializer: ParcelSerializer
) : AbstractCollectionParcelSerializer(asmType, elementSerializer) {
elementSerializer: ParcelSerializer,
frameMap: FrameMap
) : AbstractCollectionParcelSerializer(asmType, elementSerializer, frameMap) {
override fun getSize(v: InstructionAdapter) {
v.invokeinterface("java/util/Map", "size", "()I")
}
@@ -260,7 +263,8 @@ internal class MapParcelSerializer(
abstract internal class AbstractCollectionParcelSerializer(
final override val asmType: Type,
protected val elementSerializer: ParcelSerializer
protected val elementSerializer: ParcelSerializer,
private val frameMap: FrameMap
) : ParcelSerializer {
protected val collectionType: Type = Type.getObjectType(when (asmType.internalName) {
"java/util/List" -> "java/util/ArrayList"
@@ -331,27 +335,27 @@ abstract internal class AbstractCollectionParcelSerializer(
}
override fun readValue(v: InstructionAdapter) {
frameMap.useTmpVar(Type.INT_TYPE) { sizeVarIndex ->
v.invokevirtual(PARCEL_TYPE.internalName, "readInt", "()I", false) // -> size
v.store(sizeVarIndex, Type.INT_TYPE)
v.anew(collectionType) // -> list
v.dup() // -> list, list
if (hasConstructorWithCapacity) {
v.load(sizeVarIndex, Type.INT_TYPE)
v.invokespecial(collectionType.internalName, "<init>", "(I)V", false) // -> list
} else {
v.invokespecial(collectionType.internalName, "<init>", "()V", false) // -> list
}
v.load(sizeVarIndex, Type.INT_TYPE) // -> list, size
}
val nextLoopIteration = Label()
val loopIsOver = Label()
// Read list size
v.invokevirtual(PARCEL_TYPE.internalName, "readInt", "()I", false) // -> size
v.dup() // -> size, size
v.anew(collectionType) // -> size, size, list
v.dupX1() // -> size, list, size, list
v.swap() // -> size, list, list, size
if (hasConstructorWithCapacity) {
v.invokespecial(collectionType.internalName, "<init>", "(I)V", false) // -> size, list
}
else {
v.pop() // -> size, list, list
v.invokespecial(collectionType.internalName, "<init>", "()V", false) // -> size, list
}
v.visitLabel(nextLoopIteration)
v.swap() // -> list, size
v.dupX1() // -> size, list, size
v.ifeq(loopIsOver) // -> size, list
v.dup() // -> size, list, list
@@ -362,16 +366,19 @@ abstract internal class AbstractCollectionParcelSerializer(
v.aconst(-1) // -> list, size, (-1)
v.add(Type.INT_TYPE) // -> list, (size - 1)
v.swap() // -> size, list
v.goTo(nextLoopIteration)
v.visitLabel(loopIsOver)
v.swap()
v.swap() // -> list, size
v.pop()
}
}
internal class SparseArrayParcelSerializer(override val asmType: Type, private val valueSerializer: ParcelSerializer) : ParcelSerializer {
internal class SparseArrayParcelSerializer(
override val asmType: Type,
private val valueSerializer: ParcelSerializer,
private val frameMap: FrameMap
) : ParcelSerializer {
private val valueType = (valueSerializer as? PrimitiveTypeParcelSerializer)?.asmType ?: Type.getObjectType("java/lang/Object")
override fun writeValue(v: InstructionAdapter) {
@@ -421,12 +428,17 @@ internal class SparseArrayParcelSerializer(override val asmType: Type, private v
}
override fun readValue(v: InstructionAdapter) {
v.invokevirtual(PARCEL_TYPE.internalName, "readInt", "()I", false) // -> size
v.dup() // -> size, size
v.anew(asmType) // -> size, size, arr
v.dupX2() // -> arr, size, size, arr
v.swap() // -> arr, size, arr, size
v.invokespecial(asmType.internalName, "<init>", "(I)V", false) // -> arr, size
frameMap.useTmpVar(Type.INT_TYPE) { sizeVarIndex ->
v.invokevirtual(PARCEL_TYPE.internalName, "readInt", "()I", false) // -> size
v.store(sizeVarIndex, Type.INT_TYPE) // -> (empty)
v.anew(asmType) // -> arr
v.dup() // -> arr, arr
v.load(sizeVarIndex, Type.INT_TYPE) // -> arr, arr, size
v.invokespecial(asmType.internalName, "<init>", "(I)V", false) // -> arr
v.load(sizeVarIndex, Type.INT_TYPE) // -> arr, size
}
val nextLoopIteration = Label()
val loopIsOver = Label()