.shouldEncodeElementDefault for JVM
This commit is contained in:
+2
-1
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
|||||||
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
import org.jetbrains.kotlin.js.translate.declaration.DeclarationBodyVisitor
|
||||||
import org.jetbrains.kotlin.js.translate.declaration.DefaultPropertyTranslator
|
import org.jetbrains.kotlin.js.translate.declaration.DefaultPropertyTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||||
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF.KOTLIN_EQUALS
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
@@ -193,7 +194,7 @@ class SerializerJsTranslator(descriptor: ClassDescriptor,
|
|||||||
val defaultValue =
|
val defaultValue =
|
||||||
initializersMap.getValue(property.descriptor)?.let { Translation.translateAsExpression(it, ctx) }
|
initializersMap.getValue(property.descriptor)?.let { Translation.translateAsExpression(it, ctx) }
|
||||||
?: throw IllegalStateException("Optional property does not have an initializer?")
|
?: throw IllegalStateException("Optional property does not have an initializer?")
|
||||||
val partA = JsBinaryOperation(JsBinaryOperator.NEQ, property.jsNameRef(), defaultValue)
|
val partA = JsAstUtils.not(KOTLIN_EQUALS.apply(property.jsNameRef(), listOf(defaultValue), ctx))
|
||||||
val partB =
|
val partB =
|
||||||
JsInvocation(JsNameRef(shouldEncodeFunc, localOutputRef), serialClassDescRef, JsIntLiteral(index))
|
JsInvocation(JsNameRef(shouldEncodeFunc, localOutputRef), serialClassDescRef, JsIntLiteral(index))
|
||||||
val cond = JsBinaryOperation(JsBinaryOperator.OR, partA, partB)
|
val cond = JsBinaryOperation(JsBinaryOperator.OR, partA, partB)
|
||||||
|
|||||||
+10
@@ -361,3 +361,13 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty, ty
|
|||||||
else -> throw AssertionError("Unexpected sort for $type") // should not happen
|
else -> throw AssertionError("Unexpected sort for $type") // should not happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun InstructionAdapter.stackValueDefault(type: Type) {
|
||||||
|
when (type.sort) {
|
||||||
|
BOOLEAN, BYTE, SHORT, CHAR, INT -> iconst(0)
|
||||||
|
LONG -> lconst(0)
|
||||||
|
FLOAT -> fconst(0f)
|
||||||
|
DOUBLE -> dconst(0.0)
|
||||||
|
else -> aconst(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
+82
-20
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.CompilationException
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
|
||||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -51,10 +51,24 @@ class SerializableCodegenImpl(
|
|||||||
|
|
||||||
private val descToProps = classCodegen.myClass.bodyPropertiesDescriptorsMap(classCodegen.bindingContext)
|
private val descToProps = classCodegen.myClass.bodyPropertiesDescriptorsMap(classCodegen.bindingContext)
|
||||||
|
|
||||||
private val paramsToProps: Map<PropertyDescriptor, KtParameter> = classCodegen.myClass.primaryPropertiesDescriptorsMap(classCodegen.bindingContext)
|
private val paramsToProps: Map<PropertyDescriptor, KtParameter> =
|
||||||
|
classCodegen.myClass.primaryPropertiesDescriptorsMap(classCodegen.bindingContext)
|
||||||
|
|
||||||
private fun getProp(prop: SerializableProperty) = descToProps[prop.descriptor]
|
private fun getProp(prop: SerializableProperty) = descToProps[prop.descriptor]
|
||||||
private fun getParam(prop: SerializableProperty) = paramsToProps[prop.descriptor]
|
private fun getParam(prop: SerializableProperty) = paramsToProps[prop.descriptor]
|
||||||
|
|
||||||
|
private fun initializersMapper(prop: SerializableProperty): Pair<KtExpression, Type> {
|
||||||
|
val maybeInit =
|
||||||
|
getProp(prop)?.let { it.delegateExpressionOrInitializer ?: throw AssertionError("${it.name} property must have initializer") }
|
||||||
|
|
||||||
|
val initializer = maybeInit ?: getParam(prop)?.let {
|
||||||
|
it.defaultValue ?: throw AssertionError("${it.name} property must have initializer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (initializer == null) throw AssertionError("Can't find initializer for property ${prop.descriptor}")
|
||||||
|
else initializer to classCodegen.typeMapper.mapType(prop.type)
|
||||||
|
}
|
||||||
|
|
||||||
private val SerializableProperty.asmType get() = classCodegen.typeMapper.mapType(this.type)
|
private val SerializableProperty.asmType get() = classCodegen.typeMapper.mapType(this.type)
|
||||||
|
|
||||||
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) {
|
override fun generateInternalConstructor(constructorDescriptor: ClassConstructorDescriptor) {
|
||||||
@@ -94,13 +108,58 @@ class SerializableCodegenImpl(
|
|||||||
myPropsStart = 0
|
myPropsStart = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in myPropsStart until properties.serializableProperties.size) {
|
fun emitEncoderCall(property: SerializableProperty, index: Int) {
|
||||||
val property = properties[i]
|
|
||||||
// output.writeXxxElementValue (desc, index, value)
|
// output.writeXxxElementValue (desc, index, value)
|
||||||
load(outputI, kOutputType)
|
load(outputI, kOutputType)
|
||||||
load(serialDescI, descType)
|
load(serialDescI, descType)
|
||||||
iconst(i)
|
iconst(index)
|
||||||
genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI, generator = this@SerializableCodegenImpl)
|
genKOutputMethodCall(
|
||||||
|
property,
|
||||||
|
classCodegen,
|
||||||
|
exprCodegen,
|
||||||
|
thisAsmType,
|
||||||
|
thisI,
|
||||||
|
offsetI,
|
||||||
|
generator = this@SerializableCodegenImpl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in myPropsStart until properties.serializableProperties.size) {
|
||||||
|
val property = properties[i]
|
||||||
|
if (!property.optional) {
|
||||||
|
emitEncoderCall(property, i)
|
||||||
|
} else {
|
||||||
|
val writeLabel = Label()
|
||||||
|
val nonWriteLabel = Label()
|
||||||
|
// obj.prop != DEFAULT_VAL
|
||||||
|
ImplementationBodyCodegen.genPropertyOnStack(
|
||||||
|
this,
|
||||||
|
exprCodegen.context,
|
||||||
|
property.descriptor,
|
||||||
|
thisAsmType,
|
||||||
|
thisI,
|
||||||
|
classCodegen.state
|
||||||
|
)
|
||||||
|
val propAsmType = classCodegen.typeMapper.mapType(property.type)
|
||||||
|
val lhs = StackValue.onStack(propAsmType)
|
||||||
|
val (expr, _) = initializersMapper(property)
|
||||||
|
exprCodegen.gen(expr, propAsmType)
|
||||||
|
val rhs = StackValue.onStack(propAsmType)
|
||||||
|
// INVOKESTATIC kotlin/jvm/internal/Intrinsics.areEqual (Ljava/lang/Object;Ljava/lang/Object;)Z
|
||||||
|
AsmUtil.genEqualsForExpressionsOnStack(KtTokens.EXCLEQ, lhs, rhs).put(Type.BOOLEAN_TYPE, null, this)
|
||||||
|
ifne(writeLabel)
|
||||||
|
|
||||||
|
// output.shouldEncodeElementDefault(descriptor, i)
|
||||||
|
load(outputI, kOutputType)
|
||||||
|
load(serialDescI, descType)
|
||||||
|
iconst(i)
|
||||||
|
invokeinterface(kOutputType.internalName, CallingConventions.shouldEncodeDefault, "(${descType.descriptor}I)Z")
|
||||||
|
ifeq(nonWriteLabel)
|
||||||
|
|
||||||
|
visitLabel(writeLabel)
|
||||||
|
emitEncoderCall(property, i)
|
||||||
|
visitLabel(nonWriteLabel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
areturn(Type.VOID_TYPE)
|
areturn(Type.VOID_TYPE)
|
||||||
@@ -201,24 +260,27 @@ class SerializableCodegenImpl(
|
|||||||
private fun needInitProperty(prop: SerializableProperty) = getProp(prop)?.let { classCodegen.shouldInitializeProperty(it) }
|
private fun needInitProperty(prop: SerializableProperty) = getProp(prop)?.let { classCodegen.shouldInitializeProperty(it) }
|
||||||
?: getParam(prop)?.hasDefaultValue() ?: throw IllegalStateException()
|
?: getParam(prop)?.hasDefaultValue() ?: throw IllegalStateException()
|
||||||
|
|
||||||
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty)
|
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
|
||||||
= getProp(prop)?.let {
|
|
||||||
classCodegen.initializeProperty(this, it)
|
classCodegen.initializeProperty(this, it)
|
||||||
}
|
}
|
||||||
?: getParam(prop)?.let {
|
?: getParam(prop)?.let {
|
||||||
this.v.load(0, thisAsmType)
|
this.v.load(0, thisAsmType)
|
||||||
if (!it.hasDefaultValue()) throw CompilationException("Optional field ${it.name} in primary constructor of serializable " +
|
if (!it.hasDefaultValue()) throw CompilationException(
|
||||||
"$serializableDescriptor must have default value", null, it)
|
"Optional field ${it.name} in primary constructor of serializable " +
|
||||||
this.gen(it.defaultValue, prop.asmType)
|
"$serializableDescriptor must have default value", null, it
|
||||||
this.v.putfield(thisAsmType.internalName, prop.descriptor.name.asString(), prop.asmType.descriptor)
|
)
|
||||||
}
|
this.gen(it.defaultValue, prop.asmType)
|
||||||
?: throw IllegalStateException()
|
this.v.putfield(thisAsmType.internalName, prop.descriptor.name.asString(), prop.asmType.descriptor)
|
||||||
|
}
|
||||||
|
?: throw IllegalStateException()
|
||||||
|
|
||||||
private fun ExpressionCodegen.genInitParam(prop: PropertyDescriptor, param: KtParameter) {
|
private fun ExpressionCodegen.genInitParam(prop: PropertyDescriptor, param: KtParameter) {
|
||||||
this.v.load(0, thisAsmType)
|
this.v.load(0, thisAsmType)
|
||||||
val mapType = classCodegen.typeMapper.mapType(prop.type)
|
val mapType = classCodegen.typeMapper.mapType(prop.type)
|
||||||
if (!param.hasDefaultValue()) throw CompilationException("Transient field ${param.name} in primary constructor of serializable " +
|
if (!param.hasDefaultValue()) throw CompilationException(
|
||||||
"$serializableDescriptor must have default value", null, param)
|
"Transient field ${param.name} in primary constructor of serializable " +
|
||||||
|
"$serializableDescriptor must have default value", null, param
|
||||||
|
)
|
||||||
this.gen(param.defaultValue, mapType)
|
this.gen(param.defaultValue, mapType)
|
||||||
this.v.putfield(thisAsmType.internalName, prop.name.asString(), mapType.descriptor)
|
this.v.putfield(thisAsmType.internalName, prop.name.asString(), mapType.descriptor)
|
||||||
}
|
}
|
||||||
|
|||||||
-13
@@ -534,17 +534,4 @@ class SerializerCodegenImpl(
|
|||||||
visitLabel(nextLabel)
|
visitLabel(nextLabel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: move to StackValue?
|
|
||||||
private fun InstructionAdapter.stackValueDefault(type: Type) {
|
|
||||||
when (type.sort) {
|
|
||||||
BOOLEAN, BYTE, SHORT, CHAR, INT -> iconst(0)
|
|
||||||
LONG -> lconst(0)
|
|
||||||
FLOAT -> fconst(0f)
|
|
||||||
DOUBLE -> dconst(0.0)
|
|
||||||
else -> aconst(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user