This is initial implementation of serializer/deserializer for inline IR bodies.
The deserialization is disabled by default. Use `-enable deserializer` to enable it. Use `-verbose deserializer` to watch it crunch.
This commit is contained in:
committed by
alexander-gorshenev
parent
4a4225fd72
commit
ff8acd21e6
+11
-1
@@ -11,6 +11,11 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
|
||||
fun validateIrFunction(context: BackendContext, irFunction: IrFunction) {
|
||||
val visitor = IrValidator(context)
|
||||
irFunction.acceptVoid(visitor)
|
||||
}
|
||||
|
||||
fun validateIrFile(context: BackendContext, irFile: IrFile) {
|
||||
val visitor = IrValidator(context)
|
||||
irFile.acceptVoid(visitor)
|
||||
@@ -65,7 +70,12 @@ fun validateIrModule(context: BackendContext, irModule: IrModuleFragment) {
|
||||
}
|
||||
|
||||
private fun BackendContext.reportIrValidationError(message: String, irFile: IrFile, irElement: IrElement) {
|
||||
this.reportWarning("[IR VALIDATION] $message", irFile, irElement)
|
||||
try {
|
||||
this.reportWarning("[IR VALIDATION] $message", irFile, irElement)
|
||||
} catch (e: Throwable) {
|
||||
println("an error trying to print a warning message: $e")
|
||||
e.printStackTrace()
|
||||
}
|
||||
// TODO: throw an exception after fixing bugs leading to invalid IR.
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.Llvm
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.functionName
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.verifyModule
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
@@ -202,6 +203,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
ClassVtablesBuilder(classDescriptor, this)
|
||||
}
|
||||
|
||||
// We serialize untouched descriptor tree and inline IR bodies
|
||||
// right after the frontend.
|
||||
// But we have to wait until the code generation phase,
|
||||
// to dump this information into generated file.
|
||||
lateinit var serializedLinkData: String
|
||||
|
||||
// TODO: make lateinit?
|
||||
var irModule: IrModuleFragment? = null
|
||||
set(module: IrModuleFragment?) {
|
||||
|
||||
+10
-1
@@ -3,9 +3,11 @@ package org.jetbrains.kotlin.backend.konan
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.backend.common.messageCollector
|
||||
import org.jetbrains.kotlin.backend.common.validateIrModule
|
||||
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
|
||||
import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializationUtil
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.markBackingFields
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.kotlinSourceRoots
|
||||
@@ -70,6 +72,13 @@ public fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEn
|
||||
|
||||
validateIrModule(context, module)
|
||||
}
|
||||
phaser.phase(KonanPhase.SERIALIZER) {
|
||||
markBackingFields(context)
|
||||
val serializer = KonanSerializationUtil(context)
|
||||
context.serializedLinkData =
|
||||
serializer.serializeModule(context.moduleDescriptor!!)
|
||||
DeserializerDriver(context).dumpAllInlineBodies()
|
||||
}
|
||||
phaser.phase(KonanPhase.BACKEND) {
|
||||
phaser.phase(KonanPhase.LOWER) {
|
||||
KonanLower(context).lower()
|
||||
|
||||
+7
@@ -8,9 +8,11 @@ enum class KonanPhase(val description: String,
|
||||
|
||||
/* */ FRONTEND("Frontend builds AST"),
|
||||
/* */ PSI_TO_IR("Psi to IR conversion"),
|
||||
/* */ SERIALIZER("Serialize descriptor tree and inline IR bodies"),
|
||||
/* */ BACKEND("All backend"),
|
||||
/* ... */ LOWER("IR Lowering"),
|
||||
/* ... ... */ LOWER_INLINE("Functions inlining"),
|
||||
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
|
||||
/* ... ... */ LOWER_INTEROP("Interop lowering"),
|
||||
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
|
||||
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
|
||||
@@ -53,6 +55,11 @@ object KonanPhases {
|
||||
|
||||
fun config(config: KonanConfig) {
|
||||
with (config.configuration) { with (KonanConfigKeys) {
|
||||
|
||||
// We disable inline IR deserialization
|
||||
// until we have enough test passes
|
||||
KonanPhase.DESERIALIZER.enabled = false
|
||||
|
||||
val disabled = get(DISABLED_PHASES)
|
||||
disabled?.forEach { phases[known(it)]!!.enabled = false }
|
||||
|
||||
|
||||
+18
@@ -98,3 +98,21 @@ open class DeepVisitor<D>(val worker: DeclarationDescriptorVisitor<Boolean, D>)
|
||||
}
|
||||
}
|
||||
|
||||
open public class EmptyDescriptorVisitorVoid: DeclarationDescriptorVisitor<Boolean, Unit> {
|
||||
override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: Unit) = true
|
||||
override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor, data: Unit) = true
|
||||
override fun visitVariableDescriptor(descriptor: VariableDescriptor, data: Unit) = true
|
||||
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit) = true
|
||||
override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor, data: Unit) = true
|
||||
override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Unit) = true
|
||||
override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Unit) = true
|
||||
override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: Unit) = true
|
||||
override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit) = true
|
||||
override fun visitScriptDescriptor(descriptor: ScriptDescriptor, data: Unit) = true
|
||||
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit) = true
|
||||
override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor, data: Unit) = true
|
||||
override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor, data: Unit) = true
|
||||
override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor, data: Unit) = true
|
||||
override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor, data: Unit) = true
|
||||
}
|
||||
|
||||
|
||||
+18
-3
@@ -157,9 +157,11 @@ internal val <T : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.contributedMethods: List<FunctionDescriptor>
|
||||
get () = unsubstitutedMemberScope.contributedMethods
|
||||
|
||||
internal val MemberScope.contributedMethods: List<FunctionDescriptor>
|
||||
get () {
|
||||
val contributedDescriptors = unsubstitutedMemberScope.getContributedDescriptors()
|
||||
// (includes declarations from supers)
|
||||
val contributedDescriptors = this.getContributedDescriptors()
|
||||
|
||||
val functions = contributedDescriptors.filterIsInstance<FunctionDescriptor>()
|
||||
|
||||
@@ -174,6 +176,7 @@ internal val ClassDescriptor.contributedMethods: List<FunctionDescriptor>
|
||||
return allMethods
|
||||
}
|
||||
|
||||
|
||||
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|
||||
|| this.kind == ClassKind.ENUM_CLASS
|
||||
|
||||
@@ -264,4 +267,16 @@ internal fun FunctionDescriptor.bridgeDirectionsTo(overriddenDescriptor: Functio
|
||||
}
|
||||
|
||||
return ourDirections
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun DeclarationDescriptor.getMemberScope(): MemberScope {
|
||||
val containingScope = when (this) {
|
||||
is ClassDescriptor -> this.unsubstitutedMemberScope
|
||||
is PackageViewDescriptor -> this.memberScope
|
||||
else -> error("Unexpected member scope: $containingDeclaration")
|
||||
}
|
||||
return containingScope
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan.ir
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
|
||||
// This is what Context collects about IR.
|
||||
|
||||
-6
@@ -108,12 +108,6 @@ internal class MetadatorVisitor(val context: Context) : IrElementVisitorVoid {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitProperty(declaration: IrProperty) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
metadator.property(declaration)
|
||||
|
||||
}
|
||||
|
||||
override fun visitModuleFragment(module: IrModuleFragment) {
|
||||
module.acceptChildrenVoid(this)
|
||||
metadator.endModule(module)
|
||||
|
||||
+28
-20
@@ -2,16 +2,14 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.*
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import java.io.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
|
||||
fun loadMetadata(configuration: CompilerConfiguration, file: File): ModuleDescriptorImpl {
|
||||
|
||||
@@ -86,12 +84,28 @@ class MetadataReader(file: File) : Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
fun namedMetadataNodes(name: String): Array<LLVMValueRef> {
|
||||
val result = mutableListOf<LLVMValueRef>()
|
||||
memScoped {
|
||||
val nodeCount = LLVMGetNamedMetadataNumOperands(llvmModule, name)
|
||||
val nodeArray = allocArray<LLVMValueRefVar>(nodeCount)
|
||||
|
||||
LLVMGetNamedMetadataOperands(llvmModule, name, nodeArray[0].ptr)
|
||||
|
||||
//return Pair(nodeCount, nodeArray[0].value!!)
|
||||
for (index in 0..nodeCount-1) {
|
||||
result.add(nodeArray[index].value!!)
|
||||
}
|
||||
}
|
||||
return result.toTypedArray<LLVMValueRef>()
|
||||
}
|
||||
|
||||
fun namedMetadataNode(name: String): Pair<Int, LLVMValueRef> {
|
||||
memScoped {
|
||||
val nodeCount = LLVMGetNamedMetadataNumOperands(llvmModule, name)
|
||||
val nodeArray = allocArray<LLVMValueRefVar>(nodeCount)
|
||||
|
||||
LLVMGetNamedMetadataOperands(llvmModule, "kmetadata", nodeArray[0].ptr)
|
||||
LLVMGetNamedMetadataOperands(llvmModule, name, nodeArray[0].ptr)
|
||||
|
||||
return Pair(nodeCount, nodeArray[0].value!!)
|
||||
}
|
||||
@@ -126,13 +140,6 @@ internal class MetadataGenerator(override val context: Context): ContextUtils {
|
||||
return md
|
||||
}
|
||||
|
||||
internal fun property(declaration: IrProperty) {
|
||||
if (declaration.backingField == null) return
|
||||
assert(declaration.backingField!!.descriptor == declaration.descriptor || declaration.isDelegated)
|
||||
|
||||
context.ir.propertiesWithBackingFields.add(declaration.descriptor)
|
||||
}
|
||||
|
||||
private fun emitModuleMetadata(name: String, md: LLVMValueRef?) {
|
||||
LLVMAddNamedMetadataOperand(context.llvmModule, name, md)
|
||||
}
|
||||
@@ -141,18 +148,19 @@ internal class MetadataGenerator(override val context: Context): ContextUtils {
|
||||
return LLVMMDString(str, str.length)!!
|
||||
}
|
||||
|
||||
internal fun endModule(module: IrModuleFragment) {
|
||||
private fun addLinkData(module: IrModuleFragment) {
|
||||
val abiVersion = context.config.configuration.get(KonanConfigKeys.ABI_VERSION)
|
||||
val abiNode = metadataString("$abiVersion")
|
||||
|
||||
val moduleName = metadataString(module.descriptor.name.asString())
|
||||
|
||||
val serializer = KonanSerializationUtil(context)
|
||||
val moduleAsString = serializer.serializeModule(module.descriptor)
|
||||
val moduleAsString = context.serializedLinkData
|
||||
val dataNode = metadataString(moduleAsString)
|
||||
|
||||
val kmetadataArg = metadataNode(listOf(abiNode, moduleName, dataNode))
|
||||
emitModuleMetadata("kmetadata", kmetadataArg)
|
||||
}
|
||||
|
||||
internal fun endModule(module: IrModuleFragment) {
|
||||
addLinkData(module)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
|
||||
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
|
||||
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -29,6 +30,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
|
||||
var currentScope : Scope? = null
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
val deserializer = DeserializerDriver(context)
|
||||
|
||||
fun inline(irFile: IrFile) = irFile.accept(this, null)
|
||||
|
||||
@@ -143,15 +145,13 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun inlineFunction(irCall: IrCall): IrExpression {
|
||||
|
||||
val functionDescriptor = irCall.descriptor as FunctionDescriptor
|
||||
val functionDeclaration = context.ir.originalModuleIndex
|
||||
.functions[functionDescriptor.original] // Get FunctionDeclaration by FunctionDescriptor.
|
||||
|
||||
if (functionDeclaration == null) return super.visitCall(irCall) // Function is declared in another module.
|
||||
|
||||
val originalDescriptor = functionDescriptor.original
|
||||
val functionDeclaration =
|
||||
context.ir.originalModuleIndex.functions[originalDescriptor] ?: // Function is declared in the current module.
|
||||
deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module.
|
||||
if (functionDeclaration == null) return super.visitCall(irCall)
|
||||
val copyFuncDeclaration = functionDeclaration.accept(InlineCopyIr(), // Create copy of the function.
|
||||
null) as IrFunction
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid {
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitProperty(declaration: IrProperty) {
|
||||
if (declaration.backingField == null) return
|
||||
assert(declaration.backingField!!.descriptor
|
||||
== declaration.descriptor || declaration.isDelegated)
|
||||
|
||||
context.ir.propertiesWithBackingFields.add(declaration.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun markBackingFields(context: Context) {
|
||||
context.irModule!!.accept(BackingFieldVisitor(context), null)
|
||||
}
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import kotlin.properties.Delegates
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName
|
||||
|
||||
|
||||
// TODO: we currently just assign each encountered
|
||||
// descriptor a new int id.
|
||||
// That;s okay until we have more than one external module.
|
||||
// In that case the descriptors will get different ids.
|
||||
// Need to come up with a stable scheme of ids
|
||||
// dependant on something like FunctionDescriptor.functionName
|
||||
class DescriptorTable(val builtIns: IrBuiltIns) {
|
||||
|
||||
val table = mutableMapOf<DeclarationDescriptor, Int>()
|
||||
var currentIndex = 0
|
||||
|
||||
init {
|
||||
builtIns.irBuiltInDescriptors.forEachIndexed {
|
||||
index, descriptor ->
|
||||
|
||||
table.put(descriptor, index)
|
||||
currentIndex = index + 1
|
||||
}
|
||||
}
|
||||
|
||||
fun indexByValue(value: DeclarationDescriptor): Int {
|
||||
val index = table.getOrPut(value) {
|
||||
currentIndex ++
|
||||
}
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
class IrDeserializationDescriptorIndex(irBuiltIns: IrBuiltIns) {
|
||||
|
||||
val map = mutableMapOf<Int, DeclarationDescriptor>()
|
||||
|
||||
init {
|
||||
irBuiltIns.irBuiltInDescriptors.forEachIndexed {
|
||||
index, descriptor ->
|
||||
map.put(index, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val IrBuiltIns.irBuiltInDescriptors
|
||||
get() = listOf<FunctionDescriptor>(
|
||||
this.eqeqeq,
|
||||
this.eqeq,
|
||||
this.lt0,
|
||||
this.lteq0,
|
||||
this.gt0,
|
||||
this.gteq0,
|
||||
this.throwNpe,
|
||||
this.booleanNot,
|
||||
this.noWhenBranchMatchedException,
|
||||
this.enumValueOf)
|
||||
|
||||
|
||||
+416
@@ -0,0 +1,416 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.contributedMethods
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.base64Decode
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.KonanIr
|
||||
import org.jetbrains.kotlin.serialization.KonanIr.KotlinDescriptor
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
|
||||
internal fun printType(proto: ProtoBuf.Type) {
|
||||
println("debug text: " + proto.getExtension(KonanLinkData.typeText))
|
||||
}
|
||||
|
||||
internal fun printTypeTable(proto: ProtoBuf.TypeTable) {
|
||||
proto.getTypeList().forEach {
|
||||
printType(it)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
|
||||
return if (this is PackageFragmentDescriptor) this
|
||||
else this.containingDeclaration!!.findPackage()
|
||||
}
|
||||
|
||||
internal fun DeserializedSimpleFunctionDescriptor.nameTable(): ProtoBuf.QualifiedNameTable {
|
||||
val pkg = this.findPackage()
|
||||
assert(pkg is KonanPackageFragment)
|
||||
return (pkg as KonanPackageFragment).proto.getNameTable()
|
||||
}
|
||||
|
||||
|
||||
internal fun DeserializedSimpleFunctionDescriptor.nameResolver(): NameResolver {
|
||||
val pkg = this.findPackage() as KonanPackageFragment
|
||||
return NameResolverImpl(pkg.proto.getStringTable(), pkg.proto.getNameTable())
|
||||
}
|
||||
|
||||
|
||||
// This is the class that knowns how to deserialize
|
||||
// Kotlin descriptors and types for IR.
|
||||
|
||||
internal class IrDescriptorDeserializer(val context: Context,
|
||||
val deserializationDescriptorIndex: IrDeserializationDescriptorIndex,
|
||||
val rootFunction: DeserializedSimpleFunctionDescriptor,
|
||||
val localDeserializer: LocalDeclarationDeserializer) {
|
||||
|
||||
val loopIndex = mutableMapOf<Int, IrLoop>()
|
||||
val nameResolver = rootFunction.nameResolver() as NameResolverImpl
|
||||
val nameTable = rootFunction.nameTable()
|
||||
val descriptorIndex = deserializationDescriptorIndex.map
|
||||
|
||||
fun deserializeKotlinType(proto: KonanIr.KotlinType): KotlinType {
|
||||
|
||||
val index = proto.getIndex()
|
||||
val text = proto.getDebugText()
|
||||
val typeProto = localDeserializer.typeTable!![index]
|
||||
val type = localDeserializer.deserializeInlineType(typeProto)
|
||||
context.log("### deserialized Kotlin Type index=$index, text=$text:\t$type")
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
fun deserializeLocalDeclaration(proto: KonanLinkData.Descriptor): DeclarationDescriptor {
|
||||
when {
|
||||
proto.hasFunction() -> {
|
||||
val functionProto = proto.function
|
||||
val index = functionProto.getExtension(KonanLinkData.functionIndex)
|
||||
val descriptor = localDeserializer.deserializeFunction(functionProto)
|
||||
descriptorIndex.put(index, descriptor)
|
||||
return descriptor
|
||||
}
|
||||
|
||||
proto.hasProperty() -> {
|
||||
val propertyProto = proto.property
|
||||
val index = propertyProto.getExtension(KonanLinkData.propertyIndex)
|
||||
val descriptor = localDeserializer.deserializeProperty(propertyProto)
|
||||
descriptorIndex.put(index, descriptor)
|
||||
return descriptor
|
||||
}
|
||||
// TODO
|
||||
// proto.hasClazz() ->
|
||||
else -> error("Unexpected descriptor kind")
|
||||
}
|
||||
}
|
||||
|
||||
// Either (a substitution of) a public descriptor
|
||||
// or an already seen local declaration.
|
||||
fun deserializeKnownDescriptor(proto: KonanIr.KotlinDescriptor): DeclarationDescriptor {
|
||||
|
||||
val index = proto.index
|
||||
val kind = proto.kind
|
||||
|
||||
val descriptor = when (kind) {
|
||||
KonanIr.KotlinDescriptor.Kind.VALUE_PARAMETER,
|
||||
KonanIr.KotlinDescriptor.Kind.TYPE_PARAMETER,
|
||||
KonanIr.KotlinDescriptor.Kind.RECEIVER,
|
||||
KonanIr.KotlinDescriptor.Kind.VARIABLE ->
|
||||
descriptorIndex[index]!!
|
||||
|
||||
KonanIr.KotlinDescriptor.Kind.CONSTRUCTOR,
|
||||
KonanIr.KotlinDescriptor.Kind.FUNCTION,
|
||||
KonanIr.KotlinDescriptor.Kind.ACCESSOR -> {
|
||||
descriptorIndex[index] ?:
|
||||
findInTheDescriptorTree(proto)!!
|
||||
}
|
||||
else -> TODO("Unexpected descriptor kind: $kind")
|
||||
}
|
||||
|
||||
return descriptor
|
||||
}
|
||||
|
||||
|
||||
fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor): DeclarationDescriptor {
|
||||
|
||||
context.log("### deserializeDescriptor ${proto.kind} ${proto.index}")
|
||||
|
||||
val descriptor = if (proto.hasIrLocalDeclaration()) {
|
||||
val realDescriptor = proto.irLocalDeclaration.descriptor
|
||||
deserializeLocalDeclaration(realDescriptor)
|
||||
} else
|
||||
deserializeKnownDescriptor(proto)
|
||||
|
||||
descriptorIndex.put(proto.index, descriptor)
|
||||
|
||||
context.log("### descriptor ${proto.kind} ${proto.index} -> $descriptor")
|
||||
|
||||
// Now there are several descriptors that automatically
|
||||
// recreated in addition to this one. Register them
|
||||
// all too.
|
||||
|
||||
if (descriptor is FunctionDescriptor) {
|
||||
registerParameterDescriptors(proto, descriptor)
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
||||
//
|
||||
// The section below is a poor man's resolve.
|
||||
// Having a 'kind' and a 'name' of a descriptor,
|
||||
// we need to find it's original unsubstituted version
|
||||
// in the descriptor tree. And then apply the substitutions
|
||||
// to get the same substituted descriptor we've obtained
|
||||
// in the original ir.
|
||||
//
|
||||
|
||||
// We don't deserialize value, type and receiver parameters, rather
|
||||
// just obtain them from their function descriptor and match them to the indices
|
||||
// stored in the IR serialization.
|
||||
fun registerParameterDescriptors (
|
||||
proto: KonanIr.KotlinDescriptor,
|
||||
functionDescriptor: FunctionDescriptor) {
|
||||
|
||||
//val functionProto = functionDescriptor.proto
|
||||
functionDescriptor.valueParameters.forEachIndexed { i, parameter ->
|
||||
//val parameterProto = functionProto.getValueParameter(i)
|
||||
// Assume they are in the same order.
|
||||
val index = proto.getValueParameter(i).index
|
||||
descriptorIndex.put(index, parameter)
|
||||
}
|
||||
|
||||
functionDescriptor.typeParameters.forEachIndexed {i, parameter ->
|
||||
//val parameterProto = functionProto.getTypeParameter(i)
|
||||
// Assume they are in the same order too.
|
||||
val index = proto.getTypeParameter(i).index
|
||||
descriptorIndex.put(index, parameter)
|
||||
}
|
||||
|
||||
val dispatchReceiver = functionDescriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiver != null) {
|
||||
assert(proto.hasDispatchReceiverIndex())
|
||||
val dispatchReceiverIndex = proto.dispatchReceiverIndex
|
||||
descriptorIndex.put(dispatchReceiverIndex, dispatchReceiver)
|
||||
}
|
||||
|
||||
|
||||
val extensionReceiver = functionDescriptor.extensionReceiverParameter
|
||||
if (extensionReceiver != null) {
|
||||
assert(proto.hasExtensionReceiverIndex())
|
||||
val extensionReceiverIndex = proto.extensionReceiverIndex
|
||||
descriptorIndex.put(extensionReceiverIndex, extensionReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun substituteFunction(proto: KonanIr.KotlinDescriptor,
|
||||
originalDescriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
|
||||
val newDescriptor =
|
||||
originalDescriptor.newCopyBuilder().apply() {
|
||||
setOriginal(originalDescriptor)
|
||||
setReturnType(deserializeKotlinType(proto.type))
|
||||
if (proto.hasExtensionReceiverType()) {
|
||||
setExtensionReceiverType(deserializeKotlinType(proto.extensionReceiverType))
|
||||
}
|
||||
}.build()!!
|
||||
|
||||
descriptorIndex.put(proto.index, newDescriptor)
|
||||
|
||||
return newDescriptor
|
||||
}
|
||||
|
||||
fun substituteConstructor(proto: KonanIr.KotlinDescriptor,
|
||||
originalDescriptor: ClassConstructorDescriptor): ClassConstructorDescriptor {
|
||||
|
||||
val newDescriptor = originalDescriptor.newCopyBuilder().apply() {
|
||||
setOriginal(originalDescriptor)
|
||||
setReturnType(deserializeKotlinType(proto.type))
|
||||
if (proto.hasExtensionReceiverType()) {
|
||||
setExtensionReceiverType(deserializeKotlinType(proto.extensionReceiverType))
|
||||
}
|
||||
}.build()!!
|
||||
|
||||
descriptorIndex.put(proto.index, newDescriptor)
|
||||
|
||||
// TODO: why?
|
||||
return newDescriptor as ClassConstructorDescriptor
|
||||
}
|
||||
|
||||
// Property accessors are different because the accessors don't have
|
||||
// ProtoBuf serializations. Only their properties do.
|
||||
// And also an accessor can not be copied, only properties can.
|
||||
fun substituteAccessor(proto: KonanIr.KotlinDescriptor,
|
||||
originalDescriptor: PropertyAccessorDescriptor): PropertyAccessorDescriptor {
|
||||
|
||||
val originalPropertyDescriptor = originalDescriptor.correspondingProperty as DeserializedPropertyDescriptor
|
||||
|
||||
|
||||
// TODO: property copy building is a mess.
|
||||
// Plus it is changing in the big Kotlin under my fingers.
|
||||
// What should I do here???
|
||||
// how do I set type and extensionreceiver for a property???
|
||||
val newPropertyDescriptor = originalPropertyDescriptor
|
||||
|
||||
val newDescriptor = when (originalDescriptor) {
|
||||
is PropertyGetterDescriptor ->
|
||||
newPropertyDescriptor.getter
|
||||
is PropertySetterDescriptor ->
|
||||
newPropertyDescriptor.setter
|
||||
else -> error("Unexpected accessor kind")
|
||||
}
|
||||
|
||||
descriptorIndex.put(proto.index, newDescriptor!!)
|
||||
|
||||
newDescriptor.valueParameters.forEachIndexed { i, parameter ->
|
||||
// Assume they are in the same order.
|
||||
val index = proto.getValueParameter(i).index
|
||||
descriptorIndex.put(index, parameter)
|
||||
}
|
||||
|
||||
newPropertyDescriptor.typeParameters.forEachIndexed { i, parameter ->
|
||||
// Assume they are in the same order too.
|
||||
val index = proto.getTypeParameter(i).index
|
||||
descriptorIndex.put(index, parameter)
|
||||
}
|
||||
|
||||
val dispatchReceiver = newPropertyDescriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiver != null) {
|
||||
assert(proto.hasDispatchReceiverIndex())
|
||||
val dispatchReceiverIndex = proto.dispatchReceiverIndex
|
||||
descriptorIndex.put(dispatchReceiverIndex, dispatchReceiver)
|
||||
}
|
||||
|
||||
val extensionReceiver = newPropertyDescriptor.extensionReceiverParameter
|
||||
if (extensionReceiver != null) {
|
||||
assert(proto.hasExtensionReceiverIndex())
|
||||
val extensionReceiverIndex = proto.extensionReceiverIndex
|
||||
descriptorIndex.put(extensionReceiverIndex, extensionReceiver)
|
||||
}
|
||||
|
||||
return newDescriptor
|
||||
}
|
||||
|
||||
fun parentMemberScopeByFqNameIndex(index: Int): MemberScope {
|
||||
val parent = parentByFqNameIndex(index)
|
||||
return when (parent) {
|
||||
is ClassDescriptor -> parent.getUnsubstitutedMemberScope()
|
||||
is PackageFragmentDescriptor -> parent.getMemberScope()
|
||||
is PackageViewDescriptor -> parent.memberScope
|
||||
else -> error("could not get a member scope")
|
||||
}
|
||||
}
|
||||
|
||||
fun parentByFqNameIndex(index: Int): DeclarationDescriptor {
|
||||
val module = context.moduleDescriptor!!
|
||||
val parent = nameResolver.getDescriptorByFqNameIndex(module, nameTable, index)
|
||||
return parent
|
||||
|
||||
}
|
||||
|
||||
fun matchNameInParentScope(proto: KonanIr.KotlinDescriptor): Collection<DeclarationDescriptor> {
|
||||
val classOrPackage = proto.classOrPackage
|
||||
val name = proto.name
|
||||
|
||||
when (proto.kind) {
|
||||
KotlinDescriptor.Kind.CONSTRUCTOR -> {
|
||||
val parent = parentByFqNameIndex(classOrPackage)
|
||||
assert(parent is ClassDescriptor)
|
||||
return (parent as ClassDescriptor).constructors
|
||||
}
|
||||
KotlinDescriptor.Kind.ACCESSOR,
|
||||
KotlinDescriptor.Kind.FUNCTION -> {
|
||||
val parentScope =
|
||||
parentMemberScopeByFqNameIndex(classOrPackage)
|
||||
return parentScope.contributedMethods.filter{
|
||||
it.name == Name.guessByFirstCharacter(name)
|
||||
}
|
||||
}
|
||||
else -> TODO("Can't find matching names for ${proto.kind}")
|
||||
}
|
||||
}
|
||||
|
||||
fun selectFunction(
|
||||
functions: Collection<DeclarationDescriptor>,
|
||||
proto: KonanIr.KotlinDescriptor ):
|
||||
DeserializedSimpleFunctionDescriptor {
|
||||
|
||||
val originalIndex = proto.originalIndex
|
||||
return functions.single() {
|
||||
val proto = (it as DeserializedSimpleFunctionDescriptor).proto
|
||||
proto.getExtension(KonanLinkData.functionIndex) == originalIndex
|
||||
} as DeserializedSimpleFunctionDescriptor
|
||||
}
|
||||
|
||||
fun selectConstructor(
|
||||
constructors: Collection<DeclarationDescriptor>,
|
||||
proto: KonanIr.KotlinDescriptor):
|
||||
DeserializedClassConstructorDescriptor {
|
||||
|
||||
val originalIndex = proto.originalIndex
|
||||
return constructors.single {
|
||||
val proto = (it as DeserializedClassConstructorDescriptor).proto
|
||||
proto.getExtension(KonanLinkData.constructorIndex) == originalIndex
|
||||
} as DeserializedClassConstructorDescriptor
|
||||
}
|
||||
|
||||
|
||||
fun selectAccessor(
|
||||
functions: Collection<DeclarationDescriptor>,
|
||||
proto: KonanIr.KotlinDescriptor):
|
||||
PropertyAccessorDescriptor {
|
||||
|
||||
// TODO: property accessors are not serialized by
|
||||
// descriptor serialization mechanisms, we can't match
|
||||
// the "original" field of the deserialized descriptors.
|
||||
// So KonanIr.KonanDescriptor.original contains
|
||||
// original index of the property rather than accessor's.
|
||||
val originalIndex = proto.originalIndex
|
||||
return functions.single {
|
||||
val property = (it as PropertyAccessorDescriptor).correspondingProperty as DeserializedPropertyDescriptor
|
||||
property.proto.getExtension(KonanLinkData.propertyIndex) == originalIndex
|
||||
} as PropertyAccessorDescriptor
|
||||
}
|
||||
|
||||
fun selectAmongMatchingNames(
|
||||
matching: Collection<DeclarationDescriptor>,
|
||||
proto: KonanIr.KotlinDescriptor):
|
||||
DeclarationDescriptor {
|
||||
|
||||
return when(proto.kind) {
|
||||
KotlinDescriptor.Kind.FUNCTION ->
|
||||
selectFunction(matching, proto)
|
||||
KotlinDescriptor.Kind.ACCESSOR ->
|
||||
selectAccessor(matching, proto)
|
||||
KotlinDescriptor.Kind.CONSTRUCTOR ->
|
||||
selectConstructor(matching, proto)
|
||||
else -> TODO("don't know how to select ${proto.kind}")
|
||||
}
|
||||
}
|
||||
|
||||
fun performSubstitutions(proto: KonanIr.KotlinDescriptor,
|
||||
originalDescriptor: DeclarationDescriptor):
|
||||
DeclarationDescriptor {
|
||||
|
||||
//TODO: We need to properly skip creating substituted
|
||||
// copies for public descriptors if we know the substituted
|
||||
// descriptor is going to be the same.
|
||||
// But that's not a trivial thing to find out.
|
||||
if (originalDescriptor == rootFunction)
|
||||
return rootFunction
|
||||
|
||||
return when (originalDescriptor) {
|
||||
is SimpleFunctionDescriptor ->
|
||||
substituteFunction(proto, originalDescriptor)
|
||||
is PropertyAccessorDescriptor ->
|
||||
substituteAccessor(proto, originalDescriptor)
|
||||
is ClassConstructorDescriptor ->
|
||||
substituteConstructor(proto, originalDescriptor)
|
||||
else -> error("unexpected type of public function")
|
||||
}
|
||||
}
|
||||
|
||||
fun findInTheDescriptorTree(proto: KonanIr.KotlinDescriptor): DeclarationDescriptor? {
|
||||
|
||||
val matchingNames = matchNameInParentScope(proto)
|
||||
if (matchingNames.size == 0) return null
|
||||
|
||||
val originalDescriptor = selectAmongMatchingNames(matchingNames, proto)
|
||||
|
||||
return performSubstitutions(proto, originalDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.serialization.KonanIr
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
val DeclarationDescriptor.classOrPackage: DeclarationDescriptor?
|
||||
get() {
|
||||
return if (this.containingDeclaration!! is ClassOrPackageFragmentDescriptor)
|
||||
containingDeclaration
|
||||
else null
|
||||
}
|
||||
|
||||
internal class IrDescriptorSerializer(
|
||||
val context: Context,
|
||||
val descriptorTable: DescriptorTable,
|
||||
val stringTable: KonanStringTable,
|
||||
var typeSerializer: ((KotlinType)->Int),
|
||||
var rootFunction: FunctionDescriptor) {
|
||||
|
||||
fun serializeKotlinType(type: KotlinType): KonanIr.KotlinType {
|
||||
val index = this.typeSerializer!!(type)
|
||||
val proto = KonanIr.KotlinType.newBuilder()
|
||||
.setIndex(index)
|
||||
.setDebugText(type.toString())
|
||||
.build()
|
||||
return proto
|
||||
}
|
||||
|
||||
fun kotlinDescriptorKind(descriptor: DeclarationDescriptor) =
|
||||
when (descriptor) {
|
||||
is ConstructorDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.CONSTRUCTOR
|
||||
is PropertyAccessorDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.ACCESSOR
|
||||
is FunctionDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.FUNCTION
|
||||
is ClassDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.CLASS
|
||||
is ValueParameterDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.VALUE_PARAMETER
|
||||
is LocalVariableDescriptor,
|
||||
is IrTemporaryVariableDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.VARIABLE
|
||||
is TypeParameterDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.TYPE_PARAMETER
|
||||
is ReceiverParameterDescriptor
|
||||
-> KonanIr.KotlinDescriptor.Kind.RECEIVER
|
||||
else -> TODO("Unexpected local descriptor.")
|
||||
}
|
||||
|
||||
fun functionDescriptorSpecifics(descriptor: FunctionDescriptor, proto: KonanIr.KotlinDescriptor.Builder) {
|
||||
|
||||
descriptor.valueParameters.forEach {
|
||||
proto.addValueParameter(serializeDescriptor(it))
|
||||
}
|
||||
|
||||
descriptor.typeParameters.forEach {
|
||||
proto.addTypeParameter(serializeDescriptor(it))
|
||||
}
|
||||
|
||||
// Allocate two indicies for the receivers.
|
||||
// They are not deserialized from protobuf,
|
||||
// just recreated together with their function.
|
||||
|
||||
val dispatchReceiver = descriptor.dispatchReceiverParameter
|
||||
if (dispatchReceiver != null)
|
||||
proto.setDispatchReceiverIndex(
|
||||
descriptorTable.indexByValue(dispatchReceiver))
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter
|
||||
if (extensionReceiver != null) {
|
||||
proto.setExtensionReceiverIndex(
|
||||
descriptorTable.indexByValue(extensionReceiver))
|
||||
proto.setExtensionReceiverType(
|
||||
serializeKotlinType(extensionReceiver.type!!))
|
||||
}
|
||||
|
||||
proto.setType(serializeKotlinType(
|
||||
descriptor.returnType!!))
|
||||
|
||||
}
|
||||
|
||||
fun variableDescriptorSpecifics(descriptor: VariableDescriptor, proto: KonanIr.KotlinDescriptor.Builder) {
|
||||
proto.setType(serializeKotlinType(descriptor.type))
|
||||
}
|
||||
|
||||
fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor {
|
||||
|
||||
if (descriptor is CallableMemberDescriptor &&
|
||||
descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
// TODO: It seems rather braindead.
|
||||
// Do we need to do anything more than that?
|
||||
return serializeDescriptor(DescriptorUtils.unwrapFakeOverride(descriptor))
|
||||
}
|
||||
|
||||
val classOrPackage = descriptor.classOrPackage
|
||||
val parentFqNameIndex = if (classOrPackage is ClassOrPackageFragmentDescriptor) {
|
||||
stringTable.getClassOrPackageFqNameIndex(classOrPackage)
|
||||
} else { -1 }
|
||||
|
||||
val index = descriptorTable.indexByValue(descriptor)
|
||||
// For getters and setters we use
|
||||
// the *protperty* original index.
|
||||
val originalIndex = if (descriptor is PropertyAccessorDescriptor) {
|
||||
descriptorTable.indexByValue(descriptor.correspondingProperty.original)
|
||||
} else {
|
||||
descriptorTable.indexByValue(descriptor.original)
|
||||
|
||||
}
|
||||
|
||||
context.log("index = $index")
|
||||
context.log("originalIndex = $originalIndex")
|
||||
context.log("")
|
||||
|
||||
val proto = KonanIr.KotlinDescriptor.newBuilder()
|
||||
.setName(descriptor.name.asString())
|
||||
.setKind(kotlinDescriptorKind(descriptor))
|
||||
.setIndex(index)
|
||||
.setOriginalIndex(originalIndex)
|
||||
.setClassOrPackage(parentFqNameIndex)
|
||||
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor ->
|
||||
functionDescriptorSpecifics(descriptor, proto)
|
||||
is VariableDescriptor ->
|
||||
variableDescriptorSpecifics(descriptor, proto)
|
||||
}
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+666
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.serialization
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
import org.jetbrains.kotlin.resolve.constants.NullValue
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfo
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.Interner
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.*
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializerExtension
|
||||
|
||||
// This is an almost exact copy of DescriptorSerializer
|
||||
// from the big Kotlin.
|
||||
// The only difference for now is typeId is public now.
|
||||
// Consider bringing the new functionaity upstream.
|
||||
|
||||
class KonanDescriptorSerializer private constructor(
|
||||
private val containingDeclaration: DeclarationDescriptor?,
|
||||
private val typeParameters: Interner<TypeParameterDescriptor>,
|
||||
private val extension: SerializerExtension,
|
||||
private val typeTable: MutableTypeTable,
|
||||
private val sinceKotlinInfoTable: MutableSinceKotlinInfoTable,
|
||||
private val serializeTypeTableToFunction: Boolean
|
||||
) {
|
||||
fun serialize(message: MessageLite): ByteArray {
|
||||
return ByteArrayOutputStream().apply {
|
||||
stringTable.serializeTo(this)
|
||||
message.writeTo(this)
|
||||
}.toByteArray()
|
||||
}
|
||||
|
||||
private fun createChildSerializer(descriptor: DeclarationDescriptor): KonanDescriptorSerializer =
|
||||
KonanDescriptorSerializer(descriptor, Interner(typeParameters), extension, typeTable, sinceKotlinInfoTable,
|
||||
serializeTypeTableToFunction = false)
|
||||
|
||||
val stringTable: StringTable
|
||||
get() = extension.stringTable
|
||||
|
||||
private fun useTypeTable(): Boolean = extension.shouldUseTypeTable()
|
||||
|
||||
fun classProto(classDescriptor: ClassDescriptor): ProtoBuf.Class.Builder {
|
||||
val builder = ProtoBuf.Class.newBuilder()
|
||||
|
||||
val flags = Flags.getClassFlags(
|
||||
hasAnnotations(classDescriptor), classDescriptor.visibility, classDescriptor.modality, classDescriptor.kind,
|
||||
classDescriptor.isInner, classDescriptor.isCompanionObject, classDescriptor.isData, classDescriptor.isExternal
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
}
|
||||
|
||||
builder.fqName = getClassifierId(classDescriptor)
|
||||
|
||||
for (typeParameterDescriptor in classDescriptor.declaredTypeParameters) {
|
||||
builder.addTypeParameter(typeParameter(typeParameterDescriptor))
|
||||
}
|
||||
|
||||
if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
|
||||
// Special classes (Any, Nothing) have no supertypes
|
||||
for (supertype in classDescriptor.typeConstructor.supertypes) {
|
||||
if (useTypeTable()) {
|
||||
builder.addSupertypeId(typeId(supertype))
|
||||
}
|
||||
else {
|
||||
builder.addSupertype(type(supertype))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (descriptor in classDescriptor.constructors) {
|
||||
builder.addConstructor(constructorProto(descriptor))
|
||||
}
|
||||
|
||||
for (descriptor in sort(DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope))) {
|
||||
if (descriptor is CallableMemberDescriptor) {
|
||||
if (descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue
|
||||
|
||||
when (descriptor) {
|
||||
is PropertyDescriptor -> builder.addProperty(propertyProto(descriptor))
|
||||
is FunctionDescriptor -> builder.addFunction(functionProto(descriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (descriptor in sort(DescriptorUtils.getAllDescriptors(classDescriptor.unsubstitutedInnerClassesScope))) {
|
||||
if (descriptor is TypeAliasDescriptor) {
|
||||
builder.addTypeAlias(typeAliasProto(descriptor))
|
||||
}
|
||||
else {
|
||||
val name = getSimpleNameIndex(descriptor.name)
|
||||
if (isEnumEntry(descriptor)) {
|
||||
builder.addEnumEntry(enumEntryProto(descriptor as ClassDescriptor))
|
||||
}
|
||||
else {
|
||||
builder.addNestedClassName(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sealedSubclass in classDescriptor.sealedSubclasses) {
|
||||
builder.addSealedSubclassFqName(getClassifierId(sealedSubclass))
|
||||
}
|
||||
|
||||
val companionObjectDescriptor = classDescriptor.companionObjectDescriptor
|
||||
if (companionObjectDescriptor != null) {
|
||||
builder.companionObjectName = getSimpleNameIndex(companionObjectDescriptor.name)
|
||||
}
|
||||
|
||||
val typeTableProto = typeTable.serialize()
|
||||
if (typeTableProto != null) {
|
||||
builder.typeTable = typeTableProto
|
||||
}
|
||||
|
||||
val sinceKotlinInfoProto = sinceKotlinInfoTable.serialize()
|
||||
if (sinceKotlinInfoProto != null) {
|
||||
builder.sinceKotlinInfoTable = sinceKotlinInfoProto
|
||||
}
|
||||
|
||||
extension.serializeClass(classDescriptor, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
fun propertyProto(descriptor: PropertyDescriptor): ProtoBuf.Property.Builder {
|
||||
val builder = ProtoBuf.Property.newBuilder()
|
||||
|
||||
val local = createChildSerializer(descriptor)
|
||||
|
||||
var hasGetter = false
|
||||
var hasSetter = false
|
||||
val lateInit = descriptor.isLateInit
|
||||
val isConst = descriptor.isConst
|
||||
|
||||
val compileTimeConstant = descriptor.compileTimeInitializer
|
||||
val hasConstant = compileTimeConstant != null && compileTimeConstant !is NullValue
|
||||
|
||||
val hasAnnotations = descriptor.annotations.getAllAnnotations().isNotEmpty()
|
||||
|
||||
val propertyFlags = Flags.getAccessorFlags(hasAnnotations, descriptor.visibility, descriptor.modality, false, false, false)
|
||||
|
||||
val getter = descriptor.getter
|
||||
if (getter != null) {
|
||||
hasGetter = true
|
||||
val accessorFlags = getAccessorFlags(getter)
|
||||
if (accessorFlags != propertyFlags) {
|
||||
builder.getterFlags = accessorFlags
|
||||
}
|
||||
}
|
||||
|
||||
val setter = descriptor.setter
|
||||
if (setter != null) {
|
||||
hasSetter = true
|
||||
val accessorFlags = getAccessorFlags(setter)
|
||||
if (accessorFlags != propertyFlags) {
|
||||
builder.setterFlags = accessorFlags
|
||||
}
|
||||
|
||||
if (!setter.isDefault) {
|
||||
val setterLocal = local.createChildSerializer(setter)
|
||||
for (valueParameterDescriptor in setter.valueParameters) {
|
||||
builder.setSetterValueParameter(setterLocal.valueParameter(valueParameterDescriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val flags = Flags.getPropertyFlags(
|
||||
hasAnnotations, descriptor.visibility, descriptor.modality, descriptor.kind, descriptor.isVar,
|
||||
hasGetter, hasSetter, hasConstant, isConst, lateInit, descriptor.isExternal,
|
||||
@Suppress("DEPRECATION") descriptor.isDelegated
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
}
|
||||
|
||||
builder.name = getSimpleNameIndex(descriptor.name)
|
||||
|
||||
if (useTypeTable()) {
|
||||
builder.returnTypeId = local.typeId(descriptor.type)
|
||||
}
|
||||
else {
|
||||
builder.setReturnType(local.type(descriptor.type))
|
||||
}
|
||||
|
||||
for (typeParameterDescriptor in descriptor.typeParameters) {
|
||||
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor))
|
||||
}
|
||||
|
||||
val receiverParameter = descriptor.extensionReceiverParameter
|
||||
if (receiverParameter != null) {
|
||||
if (useTypeTable()) {
|
||||
builder.receiverTypeId = local.typeId(receiverParameter.type)
|
||||
}
|
||||
else {
|
||||
builder.setReceiverType(local.type(receiverParameter.type))
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
|
||||
builder.sinceKotlinInfo = writeSinceKotlinInfo(LanguageFeature.Coroutines)
|
||||
}
|
||||
|
||||
extension.serializeProperty(descriptor, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
fun functionProto(descriptor: FunctionDescriptor): ProtoBuf.Function.Builder {
|
||||
val builder = ProtoBuf.Function.newBuilder()
|
||||
|
||||
val local = createChildSerializer(descriptor)
|
||||
|
||||
val flags = Flags.getFunctionFlags(
|
||||
hasAnnotations(descriptor), descriptor.visibility, descriptor.modality, descriptor.kind, descriptor.isOperator,
|
||||
descriptor.isInfix, descriptor.isInline, descriptor.isTailrec, descriptor.isExternal, descriptor.isSuspend
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
}
|
||||
|
||||
builder.name = getSimpleNameIndex(descriptor.name)
|
||||
|
||||
if (useTypeTable()) {
|
||||
builder.returnTypeId = local.typeId(descriptor.returnType!!)
|
||||
}
|
||||
else {
|
||||
builder.setReturnType(local.type(descriptor.returnType!!))
|
||||
}
|
||||
|
||||
for (typeParameterDescriptor in descriptor.typeParameters) {
|
||||
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor))
|
||||
}
|
||||
|
||||
val receiverParameter = descriptor.extensionReceiverParameter
|
||||
if (receiverParameter != null) {
|
||||
if (useTypeTable()) {
|
||||
builder.receiverTypeId = local.typeId(receiverParameter.type)
|
||||
}
|
||||
else {
|
||||
builder.setReceiverType(local.type(receiverParameter.type))
|
||||
}
|
||||
}
|
||||
|
||||
for (valueParameterDescriptor in descriptor.valueParameters) {
|
||||
builder.addValueParameter(local.valueParameter(valueParameterDescriptor))
|
||||
}
|
||||
|
||||
if (serializeTypeTableToFunction) {
|
||||
val typeTableProto = typeTable.serialize()
|
||||
if (typeTableProto != null) {
|
||||
builder.typeTable = typeTableProto
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
|
||||
builder.sinceKotlinInfo = writeSinceKotlinInfo(LanguageFeature.Coroutines)
|
||||
}
|
||||
|
||||
extension.serializeFunction(descriptor, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
fun constructorProto(descriptor: ConstructorDescriptor): ProtoBuf.Constructor.Builder {
|
||||
val builder = ProtoBuf.Constructor.newBuilder()
|
||||
|
||||
val local = createChildSerializer(descriptor)
|
||||
|
||||
val flags = Flags.getConstructorFlags(hasAnnotations(descriptor), descriptor.visibility, !descriptor.isPrimary)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
}
|
||||
|
||||
for (valueParameterDescriptor in descriptor.valueParameters) {
|
||||
builder.addValueParameter(local.valueParameter(valueParameterDescriptor))
|
||||
}
|
||||
|
||||
if (descriptor.isSuspendOrHasSuspendTypesInSignature()) {
|
||||
builder.sinceKotlinInfo = writeSinceKotlinInfo(LanguageFeature.Coroutines)
|
||||
}
|
||||
|
||||
extension.serializeConstructor(descriptor, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun CallableMemberDescriptor.isSuspendOrHasSuspendTypesInSignature(): Boolean {
|
||||
if (this is FunctionDescriptor && isSuspend) return true
|
||||
|
||||
return listOfNotNull(
|
||||
extensionReceiverParameter?.type,
|
||||
returnType,
|
||||
*valueParameters.map(ValueParameterDescriptor::getType).toTypedArray()
|
||||
).any { type -> type.contains(UnwrappedType::isSuspendFunctionType) }
|
||||
}
|
||||
|
||||
fun typeAliasProto(descriptor: TypeAliasDescriptor): ProtoBuf.TypeAlias.Builder {
|
||||
val builder = ProtoBuf.TypeAlias.newBuilder()
|
||||
val local = createChildSerializer(descriptor)
|
||||
|
||||
val flags = Flags.getTypeAliasFlags(hasAnnotations(descriptor), descriptor.visibility)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
}
|
||||
|
||||
builder.name = getSimpleNameIndex(descriptor.name)
|
||||
|
||||
for (typeParameterDescriptor in descriptor.declaredTypeParameters) {
|
||||
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor))
|
||||
}
|
||||
|
||||
val underlyingType = descriptor.underlyingType
|
||||
if (useTypeTable()) {
|
||||
builder.underlyingTypeId = local.typeId(underlyingType)
|
||||
}
|
||||
else {
|
||||
builder.setUnderlyingType(local.type(underlyingType))
|
||||
}
|
||||
|
||||
val expandedType = descriptor.expandedType
|
||||
if (useTypeTable()) {
|
||||
builder.expandedTypeId = local.typeId(expandedType)
|
||||
}
|
||||
else {
|
||||
builder.setExpandedType(local.type(expandedType))
|
||||
}
|
||||
|
||||
builder.addAllAnnotation(descriptor.annotations.map { extension.annotationSerializer.serializeAnnotation(it) })
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
fun enumEntryProto(descriptor: ClassDescriptor): ProtoBuf.EnumEntry.Builder {
|
||||
val builder = ProtoBuf.EnumEntry.newBuilder()
|
||||
builder.name = getSimpleNameIndex(descriptor.name)
|
||||
extension.serializeEnumEntry(descriptor, builder)
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun valueParameter(descriptor: ValueParameterDescriptor): ProtoBuf.ValueParameter.Builder {
|
||||
val builder = ProtoBuf.ValueParameter.newBuilder()
|
||||
|
||||
val flags = Flags.getValueParameterFlags(
|
||||
hasAnnotations(descriptor), descriptor.declaresDefaultValue(),
|
||||
descriptor.isCrossinline, descriptor.isNoinline
|
||||
)
|
||||
if (flags != builder.flags) {
|
||||
builder.flags = flags
|
||||
}
|
||||
|
||||
builder.name = getSimpleNameIndex(descriptor.name)
|
||||
|
||||
if (useTypeTable()) {
|
||||
builder.typeId = typeId(descriptor.type)
|
||||
}
|
||||
else {
|
||||
builder.setType(type(descriptor.type))
|
||||
}
|
||||
|
||||
val varargElementType = descriptor.varargElementType
|
||||
if (varargElementType != null) {
|
||||
if (useTypeTable()) {
|
||||
builder.varargElementTypeId = typeId(varargElementType)
|
||||
}
|
||||
else {
|
||||
builder.setVarargElementType(type(varargElementType))
|
||||
}
|
||||
}
|
||||
|
||||
extension.serializeValueParameter(descriptor, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun typeParameter(typeParameter: TypeParameterDescriptor): ProtoBuf.TypeParameter.Builder {
|
||||
val builder = ProtoBuf.TypeParameter.newBuilder()
|
||||
|
||||
builder.id = getTypeParameterId(typeParameter)
|
||||
|
||||
builder.name = getSimpleNameIndex(typeParameter.name)
|
||||
|
||||
if (typeParameter.isReified != builder.reified) {
|
||||
builder.reified = typeParameter.isReified
|
||||
}
|
||||
|
||||
val variance = variance(typeParameter.variance)
|
||||
if (variance != builder.variance) {
|
||||
builder.variance = variance
|
||||
}
|
||||
extension.serializeTypeParameter(typeParameter, builder)
|
||||
|
||||
val upperBounds = typeParameter.upperBounds
|
||||
if (upperBounds.size == 1 && KotlinBuiltIns.isDefaultBound(upperBounds.single())) return builder
|
||||
|
||||
for (upperBound in upperBounds) {
|
||||
if (useTypeTable()) {
|
||||
builder.addUpperBoundId(typeId(upperBound))
|
||||
}
|
||||
else {
|
||||
builder.addUpperBound(type(upperBound))
|
||||
}
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
public fun typeId(type: KotlinType): Int = typeTable[type(type)]
|
||||
|
||||
private fun type(type: KotlinType): ProtoBuf.Type.Builder {
|
||||
val builder = ProtoBuf.Type.newBuilder()
|
||||
|
||||
if (type.isError) {
|
||||
extension.serializeErrorType(type, builder)
|
||||
return builder
|
||||
}
|
||||
|
||||
if (type.isFlexible()) {
|
||||
val flexibleType = type.asFlexibleType()
|
||||
|
||||
val lowerBound = type(flexibleType.lowerBound)
|
||||
val upperBound = type(flexibleType.upperBound)
|
||||
extension.serializeFlexibleType(flexibleType, lowerBound, upperBound)
|
||||
if (useTypeTable()) {
|
||||
lowerBound.flexibleUpperBoundId = typeTable[upperBound]
|
||||
}
|
||||
else {
|
||||
lowerBound.setFlexibleUpperBound(upperBound)
|
||||
}
|
||||
return lowerBound
|
||||
}
|
||||
|
||||
if (type.isSuspendFunctionType) {
|
||||
val functionType = type(transformSuspendFunctionToRuntimeFunctionType(type))
|
||||
functionType.flags = Flags.getTypeFlags(true)
|
||||
return functionType
|
||||
}
|
||||
|
||||
val descriptor = type.constructor.declarationDescriptor
|
||||
when (descriptor) {
|
||||
is ClassDescriptor, is TypeAliasDescriptor -> {
|
||||
val possiblyInnerType = type.buildPossiblyInnerType() ?: error("possiblyInnerType should not be null: $type")
|
||||
fillFromPossiblyInnerType(builder, possiblyInnerType)
|
||||
}
|
||||
is TypeParameterDescriptor -> {
|
||||
if (descriptor.containingDeclaration === containingDeclaration) {
|
||||
builder.typeParameterName = getSimpleNameIndex(descriptor.name)
|
||||
}
|
||||
else {
|
||||
builder.typeParameter = getTypeParameterId(descriptor)
|
||||
}
|
||||
|
||||
assert(type.arguments.isEmpty()) { "Found arguments for type constructor build on type parameter: $descriptor" }
|
||||
}
|
||||
}
|
||||
|
||||
if (type.isMarkedNullable != builder.nullable) {
|
||||
builder.nullable = type.isMarkedNullable
|
||||
}
|
||||
|
||||
val abbreviation = type.getAbbreviatedType()?.abbreviation
|
||||
if (abbreviation != null) {
|
||||
if (useTypeTable()) {
|
||||
builder.abbreviatedTypeId = typeId(abbreviation)
|
||||
}
|
||||
else {
|
||||
builder.setAbbreviatedType(type(abbreviation))
|
||||
}
|
||||
}
|
||||
|
||||
extension.serializeType(type, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun fillFromPossiblyInnerType(builder: ProtoBuf.Type.Builder, type: PossiblyInnerType) {
|
||||
val classifierDescriptor = type.classifierDescriptor
|
||||
val classifierId = getClassifierId(classifierDescriptor)
|
||||
when (classifierDescriptor) {
|
||||
is ClassDescriptor -> builder.className = classifierId
|
||||
is TypeAliasDescriptor -> builder.typeAliasName = classifierId
|
||||
}
|
||||
|
||||
for (projection in type.arguments) {
|
||||
builder.addArgument(typeArgument(projection))
|
||||
}
|
||||
|
||||
if (type.outerType != null) {
|
||||
val outerBuilder = ProtoBuf.Type.newBuilder()
|
||||
fillFromPossiblyInnerType(outerBuilder, type.outerType!!)
|
||||
if (useTypeTable()) {
|
||||
builder.outerTypeId = typeTable[outerBuilder]
|
||||
}
|
||||
else {
|
||||
builder.setOuterType(outerBuilder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun typeArgument(typeProjection: TypeProjection): ProtoBuf.Type.Argument.Builder {
|
||||
val builder = ProtoBuf.Type.Argument.newBuilder()
|
||||
|
||||
if (typeProjection.isStarProjection) {
|
||||
builder.projection = ProtoBuf.Type.Argument.Projection.STAR
|
||||
}
|
||||
else {
|
||||
val projection = projection(typeProjection.projectionKind)
|
||||
|
||||
if (projection != builder.projection) {
|
||||
builder.projection = projection
|
||||
}
|
||||
|
||||
if (useTypeTable()) {
|
||||
builder.typeId = typeId(typeProjection.type)
|
||||
}
|
||||
else {
|
||||
builder.setType(type(typeProjection.type))
|
||||
}
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
fun packagePartProto(packageFqName: FqName, members: Collection<DeclarationDescriptor>): ProtoBuf.Package.Builder {
|
||||
val builder = ProtoBuf.Package.newBuilder()
|
||||
|
||||
for (declaration in sort(members)) {
|
||||
when (declaration) {
|
||||
is PropertyDescriptor -> builder.addProperty(propertyProto(declaration))
|
||||
is FunctionDescriptor -> builder.addFunction(functionProto(declaration))
|
||||
is TypeAliasDescriptor -> builder.addTypeAlias(typeAliasProto(declaration))
|
||||
}
|
||||
}
|
||||
|
||||
val typeTableProto = typeTable.serialize()
|
||||
if (typeTableProto != null) {
|
||||
builder.typeTable = typeTableProto
|
||||
}
|
||||
|
||||
val sinceKotlinInfoProto = sinceKotlinInfoTable.serialize()
|
||||
if (sinceKotlinInfoProto != null) {
|
||||
builder.sinceKotlinInfoTable = sinceKotlinInfoProto
|
||||
}
|
||||
|
||||
extension.serializePackage(packageFqName, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun writeSinceKotlinInfo(languageFeature: LanguageFeature): Int {
|
||||
val languageVersion = languageFeature.sinceVersion!!
|
||||
val sinceKotlinInfo = ProtoBuf.SinceKotlinInfo.newBuilder().apply {
|
||||
SinceKotlinInfo.Version(languageVersion.major, languageVersion.minor).encode(
|
||||
writeVersion = { version = it },
|
||||
writeVersionFull = { versionFull = it }
|
||||
)
|
||||
}
|
||||
return sinceKotlinInfoTable[sinceKotlinInfo]
|
||||
}
|
||||
|
||||
private fun getClassifierId(descriptor: ClassifierDescriptorWithTypeParameters): Int =
|
||||
stringTable.getFqNameIndex(descriptor)
|
||||
|
||||
private fun getSimpleNameIndex(name: Name): Int =
|
||||
stringTable.getStringIndex(name.asString())
|
||||
|
||||
private fun getTypeParameterId(descriptor: TypeParameterDescriptor): Int =
|
||||
typeParameters.intern(descriptor)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createTopLevel(extension: SerializerExtension): KonanDescriptorSerializer {
|
||||
return KonanDescriptorSerializer(null, Interner(), extension, MutableTypeTable(), MutableSinceKotlinInfoTable(),
|
||||
serializeTypeTableToFunction = false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createForLambda(extension: SerializerExtension): KonanDescriptorSerializer {
|
||||
return KonanDescriptorSerializer(null, Interner(), extension, MutableTypeTable(), MutableSinceKotlinInfoTable(),
|
||||
serializeTypeTableToFunction = true)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun create(descriptor: ClassDescriptor, extension: SerializerExtension): KonanDescriptorSerializer {
|
||||
val container = descriptor.containingDeclaration
|
||||
val parentSerializer = if (container is ClassDescriptor)
|
||||
create(container, extension)
|
||||
else
|
||||
createTopLevel(extension)
|
||||
|
||||
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
|
||||
// serializing outer classes before nested classes.
|
||||
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
|
||||
val serializer = KonanDescriptorSerializer(
|
||||
descriptor,
|
||||
Interner(parentSerializer.typeParameters),
|
||||
parentSerializer.extension,
|
||||
MutableTypeTable(),
|
||||
MutableSinceKotlinInfoTable(),
|
||||
serializeTypeTableToFunction = false
|
||||
)
|
||||
for (typeParameter in descriptor.declaredTypeParameters) {
|
||||
serializer.typeParameters.intern(typeParameter)
|
||||
}
|
||||
return serializer
|
||||
}
|
||||
|
||||
private fun getAccessorFlags(accessor: PropertyAccessorDescriptor): Int {
|
||||
return Flags.getAccessorFlags(
|
||||
hasAnnotations(accessor),
|
||||
accessor.visibility,
|
||||
accessor.modality,
|
||||
!accessor.isDefault,
|
||||
accessor.isExternal,
|
||||
accessor.isInline
|
||||
)
|
||||
}
|
||||
|
||||
private fun variance(variance: Variance): ProtoBuf.TypeParameter.Variance = when (variance) {
|
||||
Variance.INVARIANT -> ProtoBuf.TypeParameter.Variance.INV
|
||||
Variance.IN_VARIANCE -> ProtoBuf.TypeParameter.Variance.IN
|
||||
Variance.OUT_VARIANCE -> ProtoBuf.TypeParameter.Variance.OUT
|
||||
}
|
||||
|
||||
private fun projection(projectionKind: Variance): ProtoBuf.Type.Argument.Projection = when (projectionKind) {
|
||||
Variance.INVARIANT -> ProtoBuf.Type.Argument.Projection.INV
|
||||
Variance.IN_VARIANCE -> ProtoBuf.Type.Argument.Projection.IN
|
||||
Variance.OUT_VARIANCE -> ProtoBuf.Type.Argument.Projection.OUT
|
||||
}
|
||||
|
||||
private fun hasAnnotations(descriptor: Annotated): Boolean = !descriptor.annotations.isEmpty()
|
||||
|
||||
fun <T : DeclarationDescriptor> sort(descriptors: Collection<T>): List<T> =
|
||||
ArrayList(descriptors).apply {
|
||||
//NOTE: the exact comparator does matter here
|
||||
Collections.sort(this, MemberComparator.INSTANCE)
|
||||
}
|
||||
}
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
|
||||
syntax = "proto2";
|
||||
package org.jetbrains.kotlin.serialization;
|
||||
|
||||
import "org/jetbrains/kotlin/backend/konan/serialization/KonanLinkData.proto";
|
||||
option java_outer_classname = "KonanIr";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
// This is subject to change.
|
||||
// One can think of it as a 'descriptor reference'.
|
||||
// The real descriptor data is encoded in KonanLinkdData.
|
||||
message KotlinDescriptor {
|
||||
enum Kind {
|
||||
FUNCTION = 1;
|
||||
VARIABLE = 2;
|
||||
CLASS = 3;
|
||||
VALUE_PARAMETER = 4;
|
||||
CONSTRUCTOR = 5;
|
||||
TYPE_PARAMETER = 6;
|
||||
RECEIVER = 7;
|
||||
ACCESSOR = 8;
|
||||
}
|
||||
// TODO: Use the string table?
|
||||
optional string name = 1;
|
||||
required Kind kind = 2;
|
||||
required int32 index = 3;
|
||||
required int32 original_index = 4;
|
||||
// index in fq name table
|
||||
required int32 class_or_package = 5;
|
||||
// Descriptor kind specific fields.
|
||||
optional KotlinType type = 6;
|
||||
repeated KotlinDescriptor value_parameter = 7;
|
||||
repeated KotlinDescriptor type_parameter = 8;
|
||||
optional int32 dispatch_receiver_index = 9;
|
||||
optional int32 extension_receiver_index = 10;
|
||||
optional KotlinType extension_receiver_type = 11;
|
||||
optional LocalDeclaration ir_local_declaration = 12;
|
||||
}
|
||||
|
||||
message LocalDeclaration {
|
||||
// This is Descriptor message from KonanLinkData
|
||||
required Descriptor descriptor = 1;
|
||||
}
|
||||
|
||||
message KotlinType {
|
||||
required int32 index = 1;
|
||||
optional string debug_text = 2; // TODO: remove me
|
||||
}
|
||||
|
||||
message Coordinates {
|
||||
required int32 start_offset = 1;
|
||||
required int32 end_offset = 2;
|
||||
}
|
||||
|
||||
message TypeMap {
|
||||
message Pair {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
required KotlinType type = 2;
|
||||
}
|
||||
repeated Pair pair = 1;
|
||||
}
|
||||
|
||||
/* ------ IrExpressions --------------------------------------------- */
|
||||
|
||||
message IrBreak {
|
||||
required int32 loop_id = 1;
|
||||
optional string label = 2;
|
||||
}
|
||||
|
||||
message IrBlock {
|
||||
required bool is_transparent_scope = 1;
|
||||
repeated IrStatement statement = 2;
|
||||
}
|
||||
|
||||
message IrCall {
|
||||
enum Primitive {
|
||||
NOT_PRIMITIVE = 1;
|
||||
NULLARY = 2;
|
||||
UNARY = 3;
|
||||
BINARY = 4;
|
||||
}
|
||||
required Primitive kind = 1;
|
||||
required KotlinDescriptor descriptor = 2;
|
||||
required TypeMap type_map = 3;
|
||||
optional KotlinDescriptor super = 4;
|
||||
optional IrExpression dispatch_receiver = 5;
|
||||
optional IrExpression extension_receiver = 6;
|
||||
repeated IrExpression value_argument = 7;
|
||||
}
|
||||
|
||||
message IrCallableReference {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
required TypeMap type_map = 2;
|
||||
//required int32 value_parameters_size = 3;
|
||||
}
|
||||
|
||||
message IrConst {
|
||||
oneof value {
|
||||
bool null = 1;
|
||||
bool boolean = 2;
|
||||
int32 char = 3;
|
||||
int32 byte = 4;
|
||||
int32 short = 5;
|
||||
int32 int = 6;
|
||||
int64 long = 7;
|
||||
float float = 8;
|
||||
double double = 9;
|
||||
string string = 10;
|
||||
}
|
||||
}
|
||||
|
||||
message IrDelegatingConstructorCall {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
required TypeMap type_map = 2;
|
||||
repeated IrExpression value_argument = 3;
|
||||
}
|
||||
|
||||
message IrGetValue {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
}
|
||||
|
||||
message IrGetObject {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
}
|
||||
|
||||
message IrInstanceInitializerCall {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
}
|
||||
|
||||
message IrReturn {
|
||||
required KotlinDescriptor return_target = 1;
|
||||
required IrExpression value = 2;
|
||||
}
|
||||
|
||||
message IrSetVariable {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
required IrExpression value = 2;
|
||||
}
|
||||
|
||||
message IrStringConcat {
|
||||
repeated IrExpression argument = 1;
|
||||
}
|
||||
|
||||
message IrThrow {
|
||||
required IrExpression value = 1;
|
||||
}
|
||||
|
||||
message IrTry {
|
||||
required IrExpression result = 1;
|
||||
repeated IrStatement catch = 2;
|
||||
optional IrExpression finally = 3;
|
||||
}
|
||||
|
||||
message IrTypeOp {
|
||||
required IrTypeOperator operator = 1;
|
||||
required KotlinType operand = 2;
|
||||
required IrExpression argument = 3;
|
||||
}
|
||||
|
||||
message IrVararg {
|
||||
required KotlinType element_type = 1;
|
||||
}
|
||||
|
||||
message IrWhen {
|
||||
repeated IrStatement branch = 1;
|
||||
}
|
||||
|
||||
message IrWhile {
|
||||
required int32 loop_id = 1;
|
||||
required IrExpression condition = 2;
|
||||
optional string label = 3;
|
||||
optional IrExpression body = 4;
|
||||
}
|
||||
|
||||
message IrOperation {
|
||||
oneof operation {
|
||||
IrBlock block = 1;
|
||||
IrBreak break = 2;
|
||||
IrCall call = 3;
|
||||
IrCallableReference callable_reference = 4;
|
||||
IrConst const = 5;
|
||||
IrDelegatingConstructorCall delegating_constructor_call = 6;
|
||||
IrGetValue get_value = 7;
|
||||
IrGetObject get_object = 8;
|
||||
IrInstanceInitializerCall instance_initializer_call = 9;
|
||||
IrReturn return = 10;
|
||||
IrSetVariable set_variable = 11;
|
||||
IrStringConcat string_concat = 12;
|
||||
IrThrow throw = 13;
|
||||
IrTry try = 14;
|
||||
IrTypeOp type_op = 15;
|
||||
IrVararg vararg = 16;
|
||||
IrWhen when = 17;
|
||||
IrWhile while = 18;
|
||||
}
|
||||
}
|
||||
|
||||
enum IrTypeOperator {
|
||||
CAST = 1;
|
||||
IMPLICIT_CAST = 2;
|
||||
IMPLICIT_NOTNULL = 3;
|
||||
IMPLICIT_COERCION_TO_UNIT = 4;
|
||||
SAFE_CAST = 5;
|
||||
INSTANCEOF = 6;
|
||||
NOT_INSTANCEOF = 7;
|
||||
}
|
||||
|
||||
message IrExpression {
|
||||
required IrOperation operation = 1;
|
||||
required KotlinType type = 2;
|
||||
required Coordinates coordinates = 3;
|
||||
}
|
||||
|
||||
|
||||
/* ------ Declarations --------------------------------------------- */
|
||||
|
||||
message IrFunc {
|
||||
optional IrStatement body = 1;
|
||||
}
|
||||
|
||||
message IrVar {
|
||||
optional IrExpression initializer = 1;
|
||||
}
|
||||
|
||||
message IrClass {
|
||||
repeated IrDeclaration member = 1;
|
||||
}
|
||||
|
||||
message IrDeclarator {
|
||||
oneof symbol {
|
||||
IrVar variable = 1;
|
||||
IrFunc function = 2;
|
||||
IrClass ir_class = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message IrDeclaration {
|
||||
required KotlinDescriptor descriptor = 1;
|
||||
required Coordinates coordinates = 2;
|
||||
required IrDeclarator declarator = 3;
|
||||
repeated IrDeclaration nested = 4;
|
||||
}
|
||||
|
||||
/* ------- IrStatements --------------------------------------------- */
|
||||
|
||||
message IrBranch {
|
||||
required IrExpression condition = 1;
|
||||
required IrExpression result = 2;
|
||||
}
|
||||
|
||||
message IrBlockBody {
|
||||
repeated IrStatement statement = 1;
|
||||
}
|
||||
|
||||
message IrCatch {
|
||||
required KotlinDescriptor parameter = 1;
|
||||
required IrExpression result = 2;
|
||||
}
|
||||
|
||||
// Let's try to map IrElement as well as IrStatement to IrStatement.
|
||||
message IrStatement {
|
||||
required Coordinates coordinates = 1;
|
||||
oneof statement {
|
||||
IrDeclaration declaration = 2;
|
||||
IrExpression expression = 3;
|
||||
IrBlockBody block_body = 4;
|
||||
IrBranch branch = 5;
|
||||
IrCatch catch = 6;
|
||||
}
|
||||
}
|
||||
|
||||
+37
-2
@@ -2,7 +2,7 @@
|
||||
syntax = "proto2";
|
||||
package org.jetbrains.kotlin.serialization;
|
||||
|
||||
// This, an all the rest of the included proto files have ".proto1" extension.
|
||||
// This, and all the rest of the included proto files have ".proto1" extension.
|
||||
// That allows us to construct the current file,
|
||||
// but protoc will skip .class files for them.
|
||||
// The issue here is that we need to co-exist with the big Kotlin,
|
||||
@@ -21,35 +21,70 @@ extend Package {
|
||||
|
||||
extend Class {
|
||||
repeated Annotation class_annotation = 170;
|
||||
optional int32 class_index = 171;
|
||||
}
|
||||
|
||||
extend Constructor {
|
||||
repeated Annotation constructor_annotation = 170;
|
||||
optional int32 constructor_index = 171;
|
||||
optional int32 constructor_parent = 172;
|
||||
}
|
||||
|
||||
extend Function {
|
||||
repeated Annotation function_annotation = 170;
|
||||
optional int32 function_index = 171;
|
||||
optional int32 function_parent = 172;
|
||||
optional InlineIrBody inline_ir_body = 174;
|
||||
}
|
||||
|
||||
extend Property {
|
||||
repeated Annotation property_annotation = 170;
|
||||
optional Annotation.Argument.Value compile_time_value = 171;
|
||||
optional int32 property_index = 171;
|
||||
optional int32 property_parent = 172;
|
||||
optional bool used_as_variable = 173;
|
||||
optional Annotation.Argument.Value compile_time_value = 174;
|
||||
}
|
||||
|
||||
extend EnumEntry {
|
||||
repeated Annotation enum_entry_annotation = 170;
|
||||
optional int32 enum_entry_index = 171;
|
||||
}
|
||||
|
||||
extend ValueParameter {
|
||||
repeated Annotation parameter_annotation = 170;
|
||||
optional int32 value_parameter_index = 171;
|
||||
}
|
||||
|
||||
extend Type {
|
||||
repeated Annotation type_annotation = 170;
|
||||
optional int32 type_index = 171;
|
||||
optional string type_text = 172; // TODO: remove me
|
||||
}
|
||||
|
||||
extend TypeParameter {
|
||||
repeated Annotation type_parameter_annotation = 170;
|
||||
//optional int32 type_parameter_index = 171;
|
||||
//optional int32 type_parameter_parent = 172;
|
||||
}
|
||||
|
||||
message InlineIrBody {
|
||||
// We need to refer from descriptors to ir inline body.
|
||||
// And in ir we need to refer local declaration descriptors
|
||||
// That requires mutual import of KonanIr and KonanLinkData.
|
||||
// I break the circle here by storing encoded IR.
|
||||
// May be we need to merge KonanIr into KonanLinkData.
|
||||
// That'd allow mutually recursive messages.
|
||||
required string encoded_ir = 11;
|
||||
}
|
||||
|
||||
// Inner descriptors used for inlining.
|
||||
message Descriptor {
|
||||
oneof descriptor {
|
||||
Function function = 1;
|
||||
Class clazz = 2;
|
||||
Property property = 3;
|
||||
Constructor constructor = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Konan Binary Linkdata structures.
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class KonanPackageFragment( private val proto: KonanLinkData.PackageFragment,
|
||||
class KonanPackageFragment( val proto: KonanLinkData.PackageFragment,
|
||||
storageManager: StorageManager, module: ModuleDescriptor) :
|
||||
DeserializedPackageFragment(FqName(proto.getFqName()),
|
||||
storageManager, module) {
|
||||
|
||||
+78
-6
@@ -6,15 +6,23 @@ import org.jetbrains.kotlin.backend.konan.llvm.base64Decode
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.base64Encode
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||
import org.jetbrains.kotlin.descriptors.Modality.FINAL
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities.INTERNAL
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations.Companion.EMPTY
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
@@ -73,7 +81,6 @@ internal fun deserializeModule(configuration: CompilerConfiguration,
|
||||
builtIns.builtInsModule = moduleDescriptor
|
||||
val deserializationConfiguration = CompilerDeserializationConfiguration(configuration)
|
||||
|
||||
|
||||
val libraryAsByteArray = base64Decode(base64)
|
||||
val libraryProto = KonanLinkData.Library.parseFrom(
|
||||
libraryAsByteArray, KonanSerializerProtocol.extensionRegistry)
|
||||
@@ -92,8 +99,9 @@ internal fun deserializeModule(configuration: CompilerConfiguration,
|
||||
|
||||
internal class KonanSerializationUtil(val context: Context) {
|
||||
|
||||
val serializerExtension = KonanSerializerExtension(context)
|
||||
val serializer = DescriptorSerializer.createTopLevel(serializerExtension)
|
||||
val serializerExtension = KonanSerializerExtension(context, this)
|
||||
val serializer = KonanDescriptorSerializer.createTopLevel(serializerExtension)
|
||||
val typeSerializer: (KotlinType)->Int = { it -> serializer.typeId(it) }
|
||||
|
||||
fun serializeClass(packageName: FqName,
|
||||
builder: KonanLinkData.Classes.Builder,
|
||||
@@ -102,7 +110,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
|
||||
if (skip(classDescriptor)) return
|
||||
|
||||
val classProto = serializer.classProto(classDescriptor).build()
|
||||
val classProto = serializer.classProto(classDescriptor).build()
|
||||
?: error("Class not serialized: $classDescriptor")
|
||||
|
||||
builder.addClasses(classProto)
|
||||
@@ -136,7 +144,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
val skip: (DeclarationDescriptor) -> Boolean =
|
||||
{ DescriptorUtils.getContainingModule(it) != module }
|
||||
|
||||
val classifierDescriptors = DescriptorSerializer.sort(packageView.memberScope.getContributedDescriptors(
|
||||
val classifierDescriptors = KonanDescriptorSerializer.sort(packageView.memberScope.getContributedDescriptors(
|
||||
DescriptorKindFilter.CLASSIFIERS))
|
||||
|
||||
val classesBuilder = KonanLinkData.Classes.newBuilder()
|
||||
@@ -190,6 +198,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): String {
|
||||
val library = KonanLinkData.Library.newBuilder()
|
||||
|
||||
|
||||
getPackagesFqNames(moduleDescriptor).forEach {
|
||||
val packageProto = serializePackage(it, moduleDescriptor)
|
||||
library.addPackageFragment(packageProto)
|
||||
@@ -199,5 +208,68 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
val base64 = base64Encode(libraryAsByteArray)
|
||||
return base64
|
||||
}
|
||||
|
||||
/* The section below is specific for IR serialization */
|
||||
|
||||
// TODO: We utilize DescriptorSerializer's property
|
||||
// serialization to serialize variables for now.
|
||||
// Need to negotiate the ability to deserialize
|
||||
// variables with the big kotlin somehow.
|
||||
fun variableAsProperty(variable: VariableDescriptor): PropertyDescriptor {
|
||||
|
||||
val isDelegated = when (variable) {
|
||||
is LocalVariableDescriptor -> variable.isDelegated
|
||||
is IrTemporaryVariableDescriptor -> false
|
||||
else -> error("Unexpected variable descriptor.")
|
||||
}
|
||||
|
||||
val property = PropertyDescriptorImpl.create(
|
||||
variable.containingDeclaration,
|
||||
EMPTY,
|
||||
FINAL,
|
||||
INTERNAL,
|
||||
variable.isVar(),
|
||||
variable.name,
|
||||
DECLARATION,
|
||||
NO_SOURCE,
|
||||
false, false, false, false, false,
|
||||
isDelegated)
|
||||
|
||||
property.setType(variable.type, listOf(), null, null as KotlinType?)
|
||||
|
||||
// TODO: transform the getter and the setter too.
|
||||
property.initialize(null, null)
|
||||
return property
|
||||
}
|
||||
|
||||
fun serializeLocalDeclaration(descriptor: DeclarationDescriptor): KonanLinkData.Descriptor {
|
||||
|
||||
val proto = KonanLinkData.Descriptor.newBuilder()
|
||||
|
||||
context.log("### serializeLocalDeclaration: $descriptor")
|
||||
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor ->
|
||||
proto.setFunction(serializer.functionProto(descriptor))
|
||||
is PropertyDescriptor ->
|
||||
proto.setProperty(serializer.propertyProto(descriptor))
|
||||
|
||||
is ClassDescriptor ->
|
||||
proto.setClazz(serializer.classProto(descriptor))
|
||||
|
||||
is VariableDescriptor -> {
|
||||
val property = variableAsProperty(descriptor)
|
||||
serializerExtension.originalVariables.put(property, descriptor)
|
||||
proto.setProperty(serializer.propertyProto(property))
|
||||
}
|
||||
|
||||
else -> error("Unexpected descriptor kind: $descriptor")
|
||||
}
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
+113
-22
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
@@ -23,23 +7,130 @@ import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.serialization.*
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData.InlineIrBody
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.StringTableImpl
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||
import org.jetbrains.kotlin.types.FlexibleType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class KonanSerializerExtension(val context: Context) :
|
||||
|
||||
internal class KonanSerializerExtension(val context: Context, val util: KonanSerializationUtil) :
|
||||
KotlinSerializerExtensionBase(KonanSerializerProtocol) {
|
||||
|
||||
val inlineDescriptorTable = DescriptorTable(context.irBuiltIns)
|
||||
val originalVariables = mutableMapOf<PropertyDescriptor, VariableDescriptor>()
|
||||
override val stringTable = KonanStringTable()
|
||||
override fun shouldUseTypeTable(): Boolean = true
|
||||
|
||||
private val backingFieldClass =
|
||||
override fun serializeType(descriptor: KotlinType, proto: ProtoBuf.Type.Builder) {
|
||||
|
||||
proto.setExtension(KonanLinkData.typeText, descriptor.toString())
|
||||
|
||||
super.serializeType(descriptor, proto)
|
||||
}
|
||||
|
||||
override fun serializeTypeParameter(descriptor: TypeParameterDescriptor, proto: ProtoBuf.TypeParameter.Builder) {
|
||||
super.serializeTypeParameter(descriptor, proto)
|
||||
}
|
||||
|
||||
override fun serializeValueParameter(descriptor: ValueParameterDescriptor, proto: ProtoBuf.ValueParameter.Builder) {
|
||||
|
||||
val index = inlineDescriptorTable.indexByValue(descriptor)
|
||||
proto.setExtension(KonanLinkData.valueParameterIndex, index)
|
||||
|
||||
super.serializeValueParameter(descriptor, proto)
|
||||
}
|
||||
|
||||
override fun serializeEnumEntry(descriptor: ClassDescriptor, proto: ProtoBuf.EnumEntry.Builder) {
|
||||
|
||||
super.serializeEnumEntry(descriptor, proto)
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.parentFqNameIndex(): Int {
|
||||
|
||||
if (this.containingDeclaration is ClassOrPackageFragmentDescriptor) {
|
||||
val parentIndex = stringTable.getClassOrPackageFqNameIndex(
|
||||
this.containingDeclaration as ClassOrPackageFragmentDescriptor)
|
||||
return parentIndex
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder) {
|
||||
|
||||
proto.setExtension(KonanLinkData.constructorIndex,
|
||||
inlineDescriptorTable.indexByValue(descriptor))
|
||||
val parentIndex = descriptor.parentFqNameIndex()
|
||||
proto.setExtension(KonanLinkData.constructorParent, parentIndex)
|
||||
|
||||
super.serializeConstructor(descriptor, proto)
|
||||
}
|
||||
|
||||
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
|
||||
|
||||
proto.setExtension(KonanLinkData.classIndex, inlineDescriptorTable.indexByValue(descriptor))
|
||||
super.serializeClass(descriptor, proto)
|
||||
}
|
||||
|
||||
override fun serializeFunction(descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder) {
|
||||
|
||||
proto.setExtension(KonanLinkData.functionIndex,
|
||||
inlineDescriptorTable.indexByValue(descriptor))
|
||||
val parentIndex = descriptor.parentFqNameIndex()
|
||||
proto.setExtension(KonanLinkData.functionParent, parentIndex)
|
||||
|
||||
if (descriptor.isInline()) {
|
||||
|
||||
val encodedIR: String = IrSerializer( context,
|
||||
inlineDescriptorTable, stringTable, util, descriptor)
|
||||
.serializeInlineBody()
|
||||
|
||||
val inlineIrBody = KonanLinkData.InlineIrBody
|
||||
.newBuilder()
|
||||
.setEncodedIr(encodedIR)
|
||||
.build()
|
||||
|
||||
proto.setExtension(KonanLinkData.inlineIrBody, inlineIrBody)
|
||||
|
||||
}
|
||||
super.serializeFunction(descriptor, proto)
|
||||
}
|
||||
|
||||
private val backingFieldClass =
|
||||
context.builtIns.getKonanInternalClass("HasBackingField").getDefaultType()
|
||||
|
||||
private val backingFieldAnnotation = AnnotationDescriptorImpl(
|
||||
backingFieldClass, emptyMap(), SourceElement.NO_SOURCE)
|
||||
|
||||
override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder) {
|
||||
super.serializeProperty(descriptor, proto)
|
||||
|
||||
if (context.ir.propertiesWithBackingFields.contains(descriptor)) {
|
||||
proto.addExtension(KonanLinkData.propertyAnnotation,
|
||||
override fun serializeProperty(property: PropertyDescriptor, proto: ProtoBuf.Property.Builder) {
|
||||
val parentIndex = property.parentFqNameIndex()
|
||||
proto.setExtension(KonanLinkData.propertyParent, parentIndex)
|
||||
val variable = originalVariables[property]
|
||||
if (variable != null) {
|
||||
proto.setExtension(KonanLinkData.usedAsVariable, true)
|
||||
proto.setExtension(KonanLinkData.propertyIndex, inlineDescriptorTable.indexByValue(variable))
|
||||
|
||||
} else {
|
||||
proto.setExtension(KonanLinkData.propertyIndex, inlineDescriptorTable.indexByValue(property))
|
||||
}
|
||||
|
||||
super.serializeProperty(property, proto)
|
||||
|
||||
if (context.ir.propertiesWithBackingFields.contains(property)) {
|
||||
proto.addExtension(KonanLinkData.propertyAnnotation,
|
||||
annotationSerializer.serializeAnnotation(backingFieldAnnotation))
|
||||
|
||||
proto.flags = proto.flags or Flags.HAS_ANNOTATIONS.toFlags(true)
|
||||
|
||||
+12
@@ -7,6 +7,18 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
|
||||
class KonanStringTable : StringTableImpl() {
|
||||
|
||||
fun getClassOrPackageFqNameIndex(descriptor: ClassOrPackageFragmentDescriptor): Int {
|
||||
when (descriptor) {
|
||||
is PackageFragmentDescriptor ->
|
||||
return getPackageFqNameIndex(descriptor.fqName)
|
||||
|
||||
is ClassDescriptor ->
|
||||
return getFqNameIndex(descriptor as ClassifierDescriptorWithTypeParameters)
|
||||
else -> error("Can not get fqNameIndex for $descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFqNameIndexOfLocalAnonymousClass(descriptor: ClassifierDescriptorWithTypeParameters): Int {
|
||||
return if (descriptor.containingDeclaration is CallableMemberDescriptor) {
|
||||
val superClassifiers = descriptor.getAllSuperClassifiers()
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfoTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
// This class knows how to construct contexts for
|
||||
// MemberDeserializer to deserialize descriptors declared in IR.
|
||||
// Consider merging it all to the very MemberDesereializer itself eventually.
|
||||
|
||||
class LocalDeclarationDeserializer(val rootFunction: FunctionDescriptor, val module: ModuleDescriptor) {
|
||||
|
||||
val pkg = rootFunction.getContainingDeclaration() as KonanPackageFragment
|
||||
init {
|
||||
assert(pkg is KonanPackageFragment)
|
||||
}
|
||||
|
||||
val components = pkg.components
|
||||
val nameResolver = NameResolverImpl(pkg.proto.getStringTable(), pkg.proto.getNameTable())
|
||||
val nameTable = pkg.proto.getNameTable()
|
||||
val typeTable = TypeTable(pkg.proto.getPackage().getTypeTable())
|
||||
val context = components.createContext(
|
||||
pkg, nameResolver, typeTable, SinceKotlinInfoTable.EMPTY, null)
|
||||
|
||||
val typeParameters = (rootFunction as DeserializedSimpleFunctionDescriptor).proto.typeParameterList
|
||||
|
||||
val childContext = context.childContext(rootFunction, typeParameters, nameResolver, typeTable)
|
||||
val typeDeserializer = childContext.typeDeserializer
|
||||
val memberDeserializer = MemberDeserializer(childContext)
|
||||
|
||||
fun deserializeInlineType(type: ProtoBuf.Type): KotlinType {
|
||||
val result = typeDeserializer.type(type)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun getDescriptorByFqNameIndex(module: ModuleDescriptor, fqNameIndex: Int): DeclarationDescriptor {
|
||||
|
||||
val packageName = nameResolver.getPackageFqName(fqNameIndex)
|
||||
val shortName = nameResolver.getString(fqNameIndex)
|
||||
// Here we using internals of NameresolverImpl.
|
||||
val proto = nameTable.getQualifiedName(fqNameIndex)
|
||||
when (proto.kind) {
|
||||
QualifiedName.Kind.CLASS,
|
||||
QualifiedName.Kind.LOCAL ->
|
||||
return module.findClassAcrossModuleDependencies(nameResolver.getClassId(fqNameIndex))!!
|
||||
QualifiedName.Kind.PACKAGE ->
|
||||
return module.getPackage(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
fun memberDeserializerByParentFqNameIndex(fqName: Int): MemberDeserializer {
|
||||
|
||||
val parent = getDescriptorByFqNameIndex(module, fqName)
|
||||
val typeParameters = if (parent is DeserializedClassDescriptor) {
|
||||
parent.classProto.typeParameterList
|
||||
} else listOf<ProtoBuf.TypeParameter>()
|
||||
|
||||
val childContext = context.childContext(parent, typeParameters, nameResolver, typeTable)
|
||||
return MemberDeserializer(childContext)
|
||||
|
||||
}
|
||||
|
||||
fun deserializeFunction(proto: ProtoBuf.Function): FunctionDescriptor {
|
||||
val containingFqName = proto.getExtension(KonanLinkData.functionParent)
|
||||
// TODO: learn to take the containing IR declaration
|
||||
val memberDeserializer = if (containingFqName == -1)
|
||||
this.memberDeserializer
|
||||
else
|
||||
memberDeserializerByParentFqNameIndex(containingFqName)
|
||||
|
||||
val function = memberDeserializer.loadFunction(proto)
|
||||
|
||||
return function
|
||||
}
|
||||
|
||||
fun deserializeConstructor(proto: ProtoBuf.Constructor): ConstructorDescriptor {
|
||||
|
||||
val containingFqName = proto.getExtension(KonanLinkData.constructorParent)
|
||||
val memberDeserializer = memberDeserializerByParentFqNameIndex(containingFqName)
|
||||
val isPrimary = !Flags.IS_SECONDARY.get(proto.flags)
|
||||
val constructor = memberDeserializer.loadConstructor(proto, isPrimary)
|
||||
|
||||
return constructor
|
||||
}
|
||||
|
||||
|
||||
fun deserializeProperty(proto: ProtoBuf.Property): VariableDescriptor {
|
||||
val containingFqName = proto.getExtension(KonanLinkData.propertyParent)
|
||||
|
||||
// TODO: learn to take the containing IR declaration
|
||||
val memberDeserializer = if (containingFqName == -1)
|
||||
this.memberDeserializer
|
||||
else
|
||||
memberDeserializerByParentFqNameIndex(containingFqName)
|
||||
|
||||
val property = memberDeserializer.loadProperty(proto)
|
||||
|
||||
return if (proto.getExtension(KonanLinkData.usedAsVariable)) {
|
||||
propertyToVariable(property)
|
||||
} else {
|
||||
property
|
||||
}
|
||||
}
|
||||
|
||||
fun propertyToVariable(property: PropertyDescriptor): LocalVariableDescriptor {
|
||||
val variable = LocalVariableDescriptor(
|
||||
property.containingDeclaration,
|
||||
property.annotations,
|
||||
property.name,
|
||||
property.type,
|
||||
property.isVar,
|
||||
property.isDelegated,
|
||||
SourceElement.NO_SOURCE)
|
||||
|
||||
// TODO: Should we transform the getter and the setter too?
|
||||
return variable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+934
@@ -0,0 +1,934 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getMemberScope
|
||||
import org.jetbrains.kotlin.backend.konan.ir.ir2string
|
||||
import org.jetbrains.kotlin.backend.konan.ir.ir2stringWhole
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.base64Decode
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.base64Encode
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.DEFINED
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.serialization.KonanIr
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class IrSerializer(val context: Context,
|
||||
val descriptorTable: DescriptorTable,
|
||||
val stringTable: KonanStringTable,
|
||||
val util: KonanSerializationUtil,
|
||||
var rootFunction: FunctionDescriptor) {
|
||||
|
||||
val loopIndex = mutableMapOf<IrLoop, Int>()
|
||||
var currentLoopIndex = 0
|
||||
val irDescriptorSerializer = IrDescriptorSerializer(context,
|
||||
descriptorTable, stringTable, util.typeSerializer, rootFunction)
|
||||
|
||||
fun serializeInlineBody(): String {
|
||||
val declaration = context.ir.originalModuleIndex.functions[rootFunction]!!
|
||||
context.log("INLINE: ${ir2stringWhole(declaration)}")
|
||||
return encodeDeclaration(declaration as IrFunction)
|
||||
}
|
||||
|
||||
fun serializeKotlinType(type: KotlinType): KonanIr.KotlinType {
|
||||
context.log("### serializing KotlinType: " + type)
|
||||
return irDescriptorSerializer.serializeKotlinType(type)
|
||||
}
|
||||
|
||||
fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor {
|
||||
context.log("### serializeDescriptor $descriptor")
|
||||
|
||||
// Behind this call starts a large world of
|
||||
// descriptor serialization for IR.
|
||||
return irDescriptorSerializer.serializeDescriptor(descriptor)
|
||||
}
|
||||
|
||||
fun serializeCoordinates(start: Int, end: Int): KonanIr.Coordinates {
|
||||
val proto = KonanIr.Coordinates.newBuilder()
|
||||
.setStartOffset(start)
|
||||
.setEndOffset(end)
|
||||
.build()
|
||||
return proto
|
||||
}
|
||||
|
||||
fun serializeTypeMap(typeArguments: Map<TypeParameterDescriptor, KotlinType>): KonanIr.TypeMap {
|
||||
val proto = KonanIr.TypeMap.newBuilder()
|
||||
typeArguments.forEach { key, value ->
|
||||
val pair = KonanIr.TypeMap.Pair.newBuilder()
|
||||
.setDescriptor(serializeDescriptor(key))
|
||||
.setType(serializeKotlinType(value))
|
||||
.build()
|
||||
proto.addPair(pair)
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
fun serializeBlockBody(expression: IrBlockBody): KonanIr.IrBlockBody {
|
||||
val proto = KonanIr.IrBlockBody.newBuilder()
|
||||
expression.statements.forEach {
|
||||
proto.addStatement(serializeStatement(it))
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeBranch(branch: IrBranch): KonanIr.IrBranch {
|
||||
val proto = KonanIr.IrBranch.newBuilder()
|
||||
|
||||
proto.setCondition(serializeExpression(branch.condition))
|
||||
proto.setResult(serializeExpression(branch.result))
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeBlock(block: IrBlock): KonanIr.IrBlock {
|
||||
val proto = KonanIr.IrBlock.newBuilder()
|
||||
.setIsTransparentScope(block.isTransparentScope)
|
||||
block.statements.forEach {
|
||||
proto.addStatement(serializeStatement(it))
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeCatch(catch: IrCatch): KonanIr.IrCatch {
|
||||
val proto = KonanIr.IrCatch.newBuilder()
|
||||
.setParameter(serializeDescriptor(catch.parameter))
|
||||
.setResult(serializeExpression(catch.result))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeStringConcat(expression: IrStringConcatenation): KonanIr.IrStringConcat {
|
||||
val proto = KonanIr.IrStringConcat.newBuilder()
|
||||
expression.arguments.forEach {
|
||||
proto.addArgument(serializeExpression(it))
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun irCallToPrimitiveKind(call: IrCall): KonanIr.IrCall.Primitive {
|
||||
return when (call) {
|
||||
is IrNullaryPrimitiveImpl
|
||||
-> return KonanIr.IrCall.Primitive.NULLARY
|
||||
is IrUnaryPrimitiveImpl
|
||||
-> return KonanIr.IrCall.Primitive.UNARY
|
||||
is IrBinaryPrimitiveImpl
|
||||
-> return KonanIr.IrCall.Primitive.BINARY
|
||||
else
|
||||
-> return KonanIr.IrCall.Primitive.NOT_PRIMITIVE
|
||||
}
|
||||
}
|
||||
|
||||
fun serializeCall(call: IrCall): KonanIr.IrCall {
|
||||
val proto = KonanIr.IrCall.newBuilder()
|
||||
|
||||
proto.setKind(irCallToPrimitiveKind(call))
|
||||
proto.setDescriptor(serializeDescriptor(call.descriptor))
|
||||
|
||||
if (call.extensionReceiver != null) {
|
||||
proto.setExtensionReceiver(serializeExpression(call.extensionReceiver!!))
|
||||
}
|
||||
|
||||
if (call.dispatchReceiver != null) {
|
||||
proto.setDispatchReceiver(serializeExpression(call.dispatchReceiver!!))
|
||||
}
|
||||
|
||||
if (call.superQualifier != null) {
|
||||
proto.setSuper(serializeDescriptor(call.superQualifier!!))
|
||||
}
|
||||
|
||||
val typeMap = mutableMapOf<TypeParameterDescriptor, KotlinType>()
|
||||
call.descriptor.original.typeParameters.forEach {
|
||||
val type = call.getTypeArgument(it)
|
||||
if (type != null) typeMap.put(it, type)
|
||||
}
|
||||
proto.setTypeMap(serializeTypeMap(typeMap))
|
||||
|
||||
call.descriptor.valueParameters.forEach {
|
||||
val actual = call.getValueArgument(it.index)
|
||||
if (actual == null) {
|
||||
// Am I observing an IR generation regtession?
|
||||
// I see a lack of arg for an empty vararg,
|
||||
// rather than an empty vararg node.
|
||||
assert(it.varargElementType != null)
|
||||
} else {
|
||||
val arg = actual!!
|
||||
val argProto = serializeExpression(arg)
|
||||
proto.addValueArgument(argProto)
|
||||
}
|
||||
}
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeCallableReference(callable: IrCallableReference): KonanIr.IrCallableReference {
|
||||
val proto = KonanIr.IrCallableReference.newBuilder()
|
||||
.setDescriptor(serializeDescriptor(callable.descriptor))
|
||||
|
||||
val typeMap = mutableMapOf<TypeParameterDescriptor, KotlinType>()
|
||||
callable.descriptor.original.typeParameters.forEach {
|
||||
val type = callable.getTypeArgument(it)
|
||||
if (type != null) {
|
||||
typeMap.put(it, type)
|
||||
}
|
||||
}
|
||||
proto.setTypeMap(serializeTypeMap(typeMap))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeConst(value: IrConst<*>): KonanIr.IrConst {
|
||||
val proto = KonanIr.IrConst.newBuilder()
|
||||
when (value.kind) {
|
||||
IrConstKind.Null -> proto.setNull(true)
|
||||
IrConstKind.Boolean -> proto.setBoolean(value.value as Boolean)
|
||||
IrConstKind.Byte -> proto.setByte((value.value as Byte).toInt())
|
||||
IrConstKind.Int -> proto.setInt(value.value as Int)
|
||||
IrConstKind.Long -> proto.setLong(value.value as Long)
|
||||
IrConstKind.String -> proto.setString(value.value as String)
|
||||
IrConstKind.Float -> proto.setFloat(value.value as Float)
|
||||
IrConstKind.Double -> proto.setDouble(value.value as Double)
|
||||
else -> {
|
||||
TODO("Const type serialization not implemented yet: ${ir2string(value)}")
|
||||
}
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeDelegatingConstructorCall(call: IrDelegatingConstructorCall): KonanIr.IrDelegatingConstructorCall {
|
||||
val proto = KonanIr.IrDelegatingConstructorCall.newBuilder()
|
||||
|
||||
proto.setDescriptor(serializeDescriptor(call.descriptor))
|
||||
|
||||
val typeMap = mutableMapOf<TypeParameterDescriptor, KotlinType>()
|
||||
call.descriptor.original.typeParameters.forEach {
|
||||
val type = call.getTypeArgument(it)
|
||||
if (type != null) typeMap.put(it, type)
|
||||
}
|
||||
proto.setTypeMap(serializeTypeMap(typeMap))
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeGetValue(expression: IrGetValue): KonanIr.IrGetValue {
|
||||
val proto = KonanIr.IrGetValue.newBuilder()
|
||||
.setDescriptor(serializeDescriptor(expression.descriptor))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeGetObject(expression: IrGetObjectValue): KonanIr.IrGetObject {
|
||||
val proto = KonanIr.IrGetObject.newBuilder()
|
||||
.setDescriptor(serializeDescriptor(expression.descriptor))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeInstanceInitializerCall(call: IrInstanceInitializerCall): KonanIr.IrInstanceInitializerCall {
|
||||
val proto = KonanIr.IrInstanceInitializerCall.newBuilder()
|
||||
|
||||
proto.setDescriptor(serializeDescriptor(call.classDescriptor))
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeReturn(expression: IrReturn): KonanIr.IrReturn {
|
||||
val proto = KonanIr.IrReturn.newBuilder()
|
||||
.setReturnTarget(serializeDescriptor(expression.returnTarget))
|
||||
.setValue(serializeExpression(expression.value))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeSetVariable(expression: IrSetVariable): KonanIr.IrSetVariable {
|
||||
val proto = KonanIr.IrSetVariable.newBuilder()
|
||||
.setDescriptor(serializeDescriptor(expression.descriptor))
|
||||
.setValue(serializeExpression(expression.value))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeThrow(expression: IrThrow): KonanIr.IrThrow {
|
||||
val proto = KonanIr.IrThrow.newBuilder()
|
||||
.setValue(serializeExpression(expression.value))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeTry(expression: IrTry): KonanIr.IrTry {
|
||||
val proto = KonanIr.IrTry.newBuilder()
|
||||
.setResult(serializeExpression(expression.tryResult))
|
||||
val catchList = expression.catches
|
||||
catchList.forEach {
|
||||
proto.addCatch(serializeStatement(it))
|
||||
}
|
||||
val finallyExpression = expression.finallyExpression
|
||||
if (finallyExpression != null) {
|
||||
proto.setFinally(serializeExpression(finallyExpression))
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeTypeOperator(operator: IrTypeOperator): KonanIr.IrTypeOperator {
|
||||
when (operator) {
|
||||
IrTypeOperator.CAST
|
||||
-> return KonanIr.IrTypeOperator.CAST
|
||||
IrTypeOperator.IMPLICIT_CAST
|
||||
-> return KonanIr.IrTypeOperator.IMPLICIT_CAST
|
||||
IrTypeOperator.IMPLICIT_NOTNULL
|
||||
-> return KonanIr.IrTypeOperator.IMPLICIT_NOTNULL
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
-> return KonanIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
IrTypeOperator.SAFE_CAST
|
||||
-> return KonanIr.IrTypeOperator.SAFE_CAST
|
||||
IrTypeOperator.INSTANCEOF
|
||||
-> return KonanIr.IrTypeOperator.INSTANCEOF
|
||||
IrTypeOperator.NOT_INSTANCEOF
|
||||
-> return KonanIr.IrTypeOperator.NOT_INSTANCEOF
|
||||
else -> error("Unknown type operator")
|
||||
}
|
||||
}
|
||||
|
||||
fun serializeTypeOp(expression: IrTypeOperatorCall): KonanIr.IrTypeOp {
|
||||
val proto = KonanIr.IrTypeOp.newBuilder()
|
||||
.setOperator(serializeTypeOperator(expression.operator))
|
||||
.setOperand(serializeKotlinType(expression.typeOperand))
|
||||
.setArgument(serializeExpression(expression.argument))
|
||||
return proto.build()
|
||||
|
||||
}
|
||||
|
||||
fun serializeVararg(expression: IrVararg): KonanIr.IrVararg {
|
||||
val proto = KonanIr.IrVararg.newBuilder()
|
||||
.setElementType(serializeKotlinType(expression.varargElementType))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeWhen(expression: IrWhen): KonanIr.IrWhen {
|
||||
val proto = KonanIr.IrWhen.newBuilder()
|
||||
|
||||
val branches = expression.branches
|
||||
branches.forEach {
|
||||
proto.addBranch(serializeStatement(it))
|
||||
}
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeWhile(expression: IrWhileLoop): KonanIr.IrWhile {
|
||||
val proto = KonanIr.IrWhile.newBuilder()
|
||||
.setCondition(serializeExpression(expression.condition))
|
||||
val label = expression.label
|
||||
if (label != null) {
|
||||
proto.setLabel(label)
|
||||
}
|
||||
|
||||
proto.setLoopId(currentLoopIndex)
|
||||
loopIndex.put(expression, currentLoopIndex++)
|
||||
|
||||
val body = expression.body
|
||||
if (body != null) {
|
||||
proto.setBody(serializeExpression(body))
|
||||
}
|
||||
return proto.build()
|
||||
|
||||
}
|
||||
|
||||
fun serializeBreak(expression: IrBreak): KonanIr.IrBreak {
|
||||
val proto = KonanIr.IrBreak.newBuilder()
|
||||
val label = expression.label
|
||||
if (label != null) {
|
||||
proto.setLabel(label)
|
||||
}
|
||||
val loopId = loopIndex[expression.loop!!]!!
|
||||
proto.setLoopId(loopId)
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeExpression(expression: IrExpression): KonanIr.IrExpression {
|
||||
context.log("### serializing Expression: ${ir2string(expression)}")
|
||||
|
||||
val coordinates = serializeCoordinates(expression.startOffset, expression.endOffset)
|
||||
val proto = KonanIr.IrExpression.newBuilder()
|
||||
.setType(serializeKotlinType(expression.type))
|
||||
.setCoordinates(coordinates)
|
||||
|
||||
val operationProto = KonanIr.IrOperation.newBuilder()
|
||||
|
||||
when (expression) {
|
||||
is IrBlock -> operationProto.setBlock(serializeBlock(expression))
|
||||
is IrBreak -> operationProto.setBreak(serializeBreak(expression))
|
||||
is IrCall -> operationProto.setCall(serializeCall(expression))
|
||||
is IrCallableReference
|
||||
-> operationProto.setCallableReference(serializeCallableReference(expression))
|
||||
is IrConst<*> -> operationProto.setConst(serializeConst(expression))
|
||||
is IrDelegatingConstructorCall
|
||||
-> operationProto.setDelegatingConstructorCall(serializeDelegatingConstructorCall(expression))
|
||||
is IrGetValue -> operationProto.setGetValue(serializeGetValue(expression))
|
||||
is IrGetObjectValue
|
||||
-> operationProto.setGetObject(serializeGetObject(expression))
|
||||
is IrInstanceInitializerCall
|
||||
-> operationProto.setInstanceInitializerCall(serializeInstanceInitializerCall(expression))
|
||||
is IrReturn -> operationProto.setReturn(serializeReturn(expression))
|
||||
is IrSetVariable -> operationProto.setSetVariable(serializeSetVariable(expression))
|
||||
is IrStringConcatenation
|
||||
-> operationProto.setStringConcat(serializeStringConcat(expression))
|
||||
is IrThrow -> operationProto.setThrow(serializeThrow(expression))
|
||||
is IrTry -> operationProto.setTry(serializeTry(expression))
|
||||
is IrTypeOperatorCall
|
||||
-> operationProto.setTypeOp(serializeTypeOp(expression))
|
||||
is IrVararg -> operationProto.setVararg(serializeVararg(expression))
|
||||
is IrWhen -> operationProto.setWhen(serializeWhen(expression))
|
||||
is IrWhileLoop -> operationProto.setWhile(serializeWhile(expression))
|
||||
else -> {
|
||||
TODO("Expression serialization not implemented yet: ${ir2string(expression)}.")
|
||||
}
|
||||
}
|
||||
proto.setOperation(operationProto)
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeStatement(statement: IrElement): KonanIr.IrStatement {
|
||||
context.log("### serializing Statement: ${ir2string(statement)}")
|
||||
|
||||
val coordinates = serializeCoordinates(statement.startOffset, statement.endOffset)
|
||||
val proto = KonanIr.IrStatement.newBuilder()
|
||||
.setCoordinates(coordinates)
|
||||
|
||||
when (statement) {
|
||||
is IrDeclaration -> proto.setDeclaration(serializeDeclaration(statement))
|
||||
is IrExpression -> proto.setExpression(serializeExpression(statement))
|
||||
is IrBlockBody -> proto.setBlockBody(serializeBlockBody(statement))
|
||||
is IrBranch -> proto.setBranch(serializeBranch(statement))
|
||||
is IrCatch -> proto.setCatch(serializeCatch(statement))
|
||||
else -> {
|
||||
TODO("Statement not implemented yet: ${ir2string(statement)}")
|
||||
}
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeFunction(function: IrFunction): KonanIr.IrFunc {
|
||||
val proto = KonanIr.IrFunc.newBuilder()
|
||||
val body = function.body
|
||||
if (body != null) proto.setBody(serializeStatement(body))
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeVariable(variable: IrVariable): KonanIr.IrVar {
|
||||
val proto = KonanIr.IrVar.newBuilder()
|
||||
val initializer = variable.initializer
|
||||
if (initializer != null) {
|
||||
proto.setInitializer(serializeExpression(initializer))
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeIrClass(clazz: IrClass): KonanIr.IrClass {
|
||||
val proto = KonanIr.IrClass.newBuilder()
|
||||
val declarations = clazz.declarations
|
||||
declarations.forEach {
|
||||
proto.addMember(serializeDeclaration(it))
|
||||
}
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun serializeDeclaration(declaration: IrDeclaration): KonanIr.IrDeclaration {
|
||||
context.log("### serializing Declaration: ${ir2string(declaration)}")
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
var kotlinDescriptor = serializeDescriptor(descriptor)
|
||||
if (descriptor != rootFunction) {
|
||||
val realDescriptor = util.serializeLocalDeclaration(descriptor)
|
||||
val localDeclaration = KonanIr.LocalDeclaration
|
||||
.newBuilder()
|
||||
.setDescriptor(realDescriptor)
|
||||
.build()
|
||||
kotlinDescriptor = kotlinDescriptor
|
||||
.toBuilder()
|
||||
.setIrLocalDeclaration(localDeclaration)
|
||||
.build()
|
||||
} else if (descriptor is ClassDescriptor) {
|
||||
// TODO
|
||||
context.log("Can't serialize local class declarations in inline functions")
|
||||
}
|
||||
|
||||
val coordinates = serializeCoordinates(declaration.startOffset, declaration.endOffset)
|
||||
val proto = KonanIr.IrDeclaration.newBuilder()
|
||||
//.setKind(declaration.irKind())
|
||||
.setDescriptor(kotlinDescriptor)
|
||||
.setCoordinates(coordinates)
|
||||
|
||||
val declarator = KonanIr.IrDeclarator.newBuilder()
|
||||
|
||||
when (declaration) {
|
||||
is IrFunction
|
||||
-> declarator.setFunction(serializeFunction(declaration))
|
||||
is IrVariable
|
||||
-> declarator.setVariable(serializeVariable(declaration))
|
||||
is IrClass
|
||||
-> declarator.setIrClass(serializeIrClass(declaration))
|
||||
else
|
||||
-> {
|
||||
TODO("Declaration serialization not supported yet.")
|
||||
}
|
||||
}
|
||||
|
||||
proto.setDeclarator(declarator)
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
|
||||
fun encodeDeclaration(declaration: IrDeclaration): String {
|
||||
val proto = serializeDeclaration(declaration)
|
||||
val byteArray = proto.toByteArray()
|
||||
val base64 = base64Encode(byteArray)
|
||||
return base64
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// --------- Deserializer part -----------------------------
|
||||
|
||||
internal class IrDeserializer(val context: Context,
|
||||
val descriptorIndex: IrDeserializationDescriptorIndex,
|
||||
val rootFunction: DeserializedSimpleFunctionDescriptor) {
|
||||
|
||||
val loopIndex = mutableMapOf<Int, IrLoop>()
|
||||
|
||||
val localDeserializer = LocalDeclarationDeserializer(rootFunction, context.moduleDescriptor!!)
|
||||
|
||||
val descriptorDeserializer = IrDescriptorDeserializer(
|
||||
context, descriptorIndex, rootFunction, localDeserializer)
|
||||
|
||||
|
||||
fun deserializeKotlinType(proto: KonanIr.KotlinType)
|
||||
= descriptorDeserializer.deserializeKotlinType(proto)
|
||||
|
||||
fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor)
|
||||
= descriptorDeserializer.deserializeDescriptor(proto)
|
||||
|
||||
fun deserializeTypeMap(descriptor: CallableDescriptor, proto: KonanIr.TypeMap):
|
||||
Map<TypeParameterDescriptor, KotlinType> {
|
||||
val typeMap = mutableMapOf<TypeParameterDescriptor, KotlinType>()
|
||||
val pairProtos = proto.getPairList()
|
||||
pairProtos.forEachIndexed { index, pair ->
|
||||
val typeParameter = descriptor.original.typeParameters[index]
|
||||
|
||||
typeMap.put(typeParameter,
|
||||
deserializeKotlinType(pair.getType()))
|
||||
}
|
||||
context.log("### deserialized typeMap = $typeMap")
|
||||
return typeMap
|
||||
}
|
||||
|
||||
fun deserializeBlockBody(proto: KonanIr.IrBlockBody,
|
||||
start: Int, end: Int): IrBlockBody {
|
||||
|
||||
val statements = mutableListOf<IrStatement>()
|
||||
|
||||
val statementProtos = proto.getStatementList()
|
||||
statementProtos.forEach {
|
||||
statements.add(deserializeStatement(it) as IrStatement)
|
||||
}
|
||||
|
||||
return IrBlockBodyImpl(start, end, statements)
|
||||
}
|
||||
|
||||
fun deserializeBranch(proto: KonanIr.IrBranch, start: Int, end: Int): IrBranch {
|
||||
|
||||
val condition = deserializeExpression(proto.getCondition())
|
||||
val result = deserializeExpression(proto.getResult())
|
||||
|
||||
return IrBranchImpl(start, end, condition, result)
|
||||
}
|
||||
|
||||
fun deserializeCatch(proto: KonanIr.IrCatch, start: Int, end: Int): IrCatch {
|
||||
val parameter = deserializeDescriptor(proto.getParameter()) as VariableDescriptor
|
||||
val result = deserializeExpression(proto.getResult())
|
||||
|
||||
return IrCatchImpl(start, end, parameter, result)
|
||||
}
|
||||
|
||||
fun deserializeStatement(proto: KonanIr.IrStatement): IrElement {
|
||||
val start = proto.getCoordinates().getStartOffset()
|
||||
val end = proto.getCoordinates().getEndOffset()
|
||||
//val statement = proto.getStatement()
|
||||
val element = when {
|
||||
proto.hasBlockBody()
|
||||
-> deserializeBlockBody(proto.getBlockBody(), start, end)
|
||||
proto.hasBranch()
|
||||
-> deserializeBranch(proto.getBranch(), start, end)
|
||||
proto.hasCatch()
|
||||
-> deserializeCatch(proto.getCatch(), start, end)
|
||||
proto.hasDeclaration()
|
||||
-> deserializeDeclaration(proto.getDeclaration())
|
||||
proto.hasExpression()
|
||||
-> deserializeExpression(proto.getExpression())
|
||||
else -> {
|
||||
TODO("Statement deserialization not implemented}")
|
||||
}
|
||||
}
|
||||
|
||||
context.log("Deserialized statement: ${ir2string(element)}")
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
fun deserializeBlock(proto: KonanIr.IrBlock, start: Int, end: Int, type: KotlinType): IrBlock {
|
||||
val statements = mutableListOf<IrStatement>()
|
||||
val statementProtos = proto.getStatementList()
|
||||
statementProtos.forEach {
|
||||
statements.add(deserializeStatement(it) as IrStatement)
|
||||
}
|
||||
|
||||
val block = IrBlockImpl(start, end, type, null, statements)
|
||||
|
||||
// TODO: Need to set isTransparentScope somehow
|
||||
return block
|
||||
}
|
||||
|
||||
fun deserializeCall(proto: KonanIr.IrCall, start: Int, end: Int, type: KotlinType): IrCall {
|
||||
val descriptor = deserializeDescriptor(proto.getDescriptor()) as CallableDescriptor
|
||||
|
||||
val typeArgs = deserializeTypeMap(descriptor, proto.getTypeMap())
|
||||
val superDescriptor = if (proto.hasSuper()) {
|
||||
deserializeDescriptor(proto.getSuper()) as ClassDescriptor
|
||||
} else null
|
||||
|
||||
val call: IrCall = when (proto.kind) {
|
||||
KonanIr.IrCall.Primitive.NOT_PRIMITIVE ->
|
||||
// TODO: implement the last three args here.
|
||||
IrCallImpl(start, end, type, descriptor, typeArgs , null, superDescriptor)
|
||||
KonanIr.IrCall.Primitive.NULLARY ->
|
||||
IrNullaryPrimitiveImpl(start, end, null, descriptor)
|
||||
KonanIr.IrCall.Primitive.UNARY ->
|
||||
IrUnaryPrimitiveImpl(start, end, null, descriptor)
|
||||
KonanIr.IrCall.Primitive.BINARY ->
|
||||
IrBinaryPrimitiveImpl(start, end, null, descriptor)
|
||||
}
|
||||
|
||||
descriptor.valueParameters.mapIndexed { i, valueParameterDescriptor ->
|
||||
call.putValueArgument(i, deserializeExpression(proto.getValueArgument(i)))
|
||||
}
|
||||
|
||||
if (proto.hasDispatchReceiver()) {
|
||||
call.dispatchReceiver = deserializeExpression(proto.dispatchReceiver)
|
||||
}
|
||||
if (proto.hasExtensionReceiver()) {
|
||||
call.extensionReceiver = deserializeExpression(proto.extensionReceiver)
|
||||
}
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
fun deserializeCallableReference(proto: KonanIr.IrCallableReference,
|
||||
start: Int, end: Int, type: KotlinType): IrCallableReference {
|
||||
|
||||
val descriptor = deserializeDescriptor(proto.getDescriptor()) as CallableDescriptor
|
||||
if (descriptor.typeParameters.isNotEmpty()) error("We can't deserialize typa arguments")
|
||||
val typeMap = deserializeTypeMap(descriptor, proto.getTypeMap())
|
||||
|
||||
val callable = IrCallableReferenceImpl(start, end, type, descriptor, typeMap, null)
|
||||
return callable
|
||||
}
|
||||
|
||||
fun deserializeDelegatingConstructorCall(proto: KonanIr.IrDelegatingConstructorCall, start: Int, end: Int, type: KotlinType): IrDelegatingConstructorCall {
|
||||
val descriptor = deserializeDescriptor(proto.getDescriptor()) as ClassConstructorDescriptor
|
||||
val typeArgs = deserializeTypeMap(descriptor, proto.getTypeMap())
|
||||
|
||||
// TODO: implement the last three args here.
|
||||
val call = IrDelegatingConstructorCallImpl(start, end, descriptor, typeArgs)
|
||||
|
||||
descriptor.valueParameters.mapIndexed { i, valueParameterDescriptor ->
|
||||
call.putValueArgument(i, deserializeExpression(proto.getValueArgument(i)))
|
||||
}
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
fun deserializeGetValue(proto: KonanIr.IrGetValue, start: Int, end: Int, type: KotlinType): IrGetValue {
|
||||
val descriptor = deserializeDescriptor(proto.descriptor) as ValueDescriptor
|
||||
|
||||
// TODO: origin!
|
||||
return IrGetValueImpl(start, end, descriptor, null)
|
||||
}
|
||||
|
||||
fun deserializeGetObject(proto: KonanIr.IrGetObject, start: Int, end: Int, type: KotlinType): IrGetObjectValue {
|
||||
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor
|
||||
return IrGetObjectValueImpl(start, end, type, descriptor)
|
||||
}
|
||||
|
||||
fun deserializeInstanceInitializerCall(proto: KonanIr.IrInstanceInitializerCall, start: Int, end: Int, type: KotlinType): IrInstanceInitializerCall {
|
||||
val descriptor = deserializeDescriptor(proto.getDescriptor()) as ClassDescriptor
|
||||
|
||||
// TODO: implement the last three args here.
|
||||
return IrInstanceInitializerCallImpl(start, end, descriptor)
|
||||
}
|
||||
|
||||
|
||||
fun deserializeReturn(proto: KonanIr.IrReturn, start: Int, end: Int, type: KotlinType): IrReturn {
|
||||
val descriptor =
|
||||
deserializeDescriptor(proto.getReturnTarget()) as CallableDescriptor
|
||||
val value = deserializeExpression(proto.getValue())
|
||||
return IrReturnImpl(start, end, type, descriptor, value)
|
||||
}
|
||||
|
||||
fun deserializeSetVariable(proto: KonanIr.IrSetVariable, start: Int, end: Int, type: KotlinType): IrSetVariable {
|
||||
val descriptor = deserializeDescriptor(proto.getDescriptor()) as VariableDescriptor
|
||||
val value = deserializeExpression(proto.getValue())
|
||||
val setVar = IrSetVariableImpl(start, end, descriptor, null)
|
||||
setVar.value = value
|
||||
return setVar
|
||||
}
|
||||
|
||||
fun deserializeStringConcat(proto: KonanIr.IrStringConcat, start: Int, end: Int, type: KotlinType): IrStringConcatenation {
|
||||
val argumentProtos = proto.getArgumentList()
|
||||
val arguments = mutableListOf<IrExpression>()
|
||||
|
||||
argumentProtos.forEach {
|
||||
arguments.add(deserializeExpression(it) as IrExpression)
|
||||
}
|
||||
return IrStringConcatenationImpl(start, end, type, arguments)
|
||||
}
|
||||
|
||||
fun deserializeThrow(proto: KonanIr.IrThrow, start: Int, end: Int, type: KotlinType): IrThrowImpl {
|
||||
return IrThrowImpl(start, end, type, deserializeExpression(proto.getValue()))
|
||||
}
|
||||
|
||||
fun deserializeTry(proto: KonanIr.IrTry, start: Int, end: Int, type: KotlinType): IrTryImpl {
|
||||
val result = deserializeExpression(proto.getResult())
|
||||
val catches = mutableListOf<IrCatch>()
|
||||
proto.getCatchList().forEach {
|
||||
catches.add(deserializeStatement(it) as IrCatch)
|
||||
}
|
||||
val finallyExpression =
|
||||
if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null
|
||||
return IrTryImpl(start, end, type, result, catches, finallyExpression)
|
||||
}
|
||||
|
||||
fun deserializeTypeOperator(operator: KonanIr.IrTypeOperator): IrTypeOperator {
|
||||
when (operator) {
|
||||
KonanIr.IrTypeOperator.CAST
|
||||
-> return IrTypeOperator.CAST
|
||||
KonanIr.IrTypeOperator.IMPLICIT_CAST
|
||||
-> return IrTypeOperator.IMPLICIT_CAST
|
||||
KonanIr.IrTypeOperator.IMPLICIT_NOTNULL
|
||||
-> return IrTypeOperator.IMPLICIT_NOTNULL
|
||||
KonanIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
-> return IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
KonanIr.IrTypeOperator.SAFE_CAST
|
||||
-> return IrTypeOperator.SAFE_CAST
|
||||
KonanIr.IrTypeOperator.INSTANCEOF
|
||||
-> return IrTypeOperator.INSTANCEOF
|
||||
KonanIr.IrTypeOperator.NOT_INSTANCEOF
|
||||
-> return IrTypeOperator.NOT_INSTANCEOF
|
||||
else -> error("Unknown type operator")
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeTypeOp(proto: KonanIr.IrTypeOp, start: Int, end: Int, type: KotlinType) : IrTypeOperatorCall {
|
||||
val operator = deserializeTypeOperator(proto.getOperator())
|
||||
val operand = deserializeKotlinType(proto.getOperand())
|
||||
val argument = deserializeExpression(proto.getArgument())
|
||||
return IrTypeOperatorCallImpl(start, end, type, operator, operand, argument)
|
||||
}
|
||||
|
||||
fun deserializeVararg(proto: KonanIr.IrVararg, start: Int, end: Int, type: KotlinType): IrVararg {
|
||||
val elementType = deserializeKotlinType(proto.getElementType())
|
||||
return IrVarargImpl(start, end, type, elementType)
|
||||
}
|
||||
|
||||
fun deserializeWhen(proto: KonanIr.IrWhen, start: Int, end: Int, type: KotlinType): IrWhen {
|
||||
val branches = mutableListOf<IrBranch>()
|
||||
|
||||
proto.getBranchList().forEach {
|
||||
branches.add(deserializeStatement(it) as IrBranch)
|
||||
}
|
||||
|
||||
// TODO: provide some origin!
|
||||
return IrWhenImpl(start, end, type, null, branches)
|
||||
}
|
||||
|
||||
fun deserializeWhile(proto: KonanIr.IrWhile, start: Int, end: Int, type: KotlinType): IrWhileLoop {
|
||||
// we create the IrLoop before deserializing the body, so that
|
||||
// IrBreak statements have something to put into 'loop' field.
|
||||
val loop = IrWhileLoopImpl(start, end, type, null)
|
||||
|
||||
val loopId = proto.getLoopId()
|
||||
loopIndex.getOrPut(loopId){loop}
|
||||
|
||||
val condition = deserializeExpression(proto.getCondition())
|
||||
val label = if (proto.hasLabel()) proto.getLabel() else null
|
||||
val body = if (proto.hasBody()) deserializeExpression(proto.getBody()) else null
|
||||
|
||||
loop.label = label
|
||||
loop.condition = condition
|
||||
loop.body = body
|
||||
|
||||
return loop
|
||||
}
|
||||
|
||||
fun deserializeBreak(proto: KonanIr.IrBreak, start: Int, end: Int, type: KotlinType): IrBreak {
|
||||
val label = if(proto.hasLabel()) proto.getLabel() else null
|
||||
val loopId = proto.getLoopId()
|
||||
val loop = loopIndex[loopId]!!
|
||||
val irBreak = IrBreakImpl(start, end, type, loop)
|
||||
irBreak.label = label
|
||||
|
||||
return irBreak
|
||||
}
|
||||
|
||||
fun deserializeConst(proto: KonanIr.IrConst, start: Int, end: Int, type: KotlinType): IrExpression {
|
||||
|
||||
when {
|
||||
proto.hasNull()
|
||||
-> return IrConstImpl.constNull(start, end, type)
|
||||
proto.hasBoolean()
|
||||
-> return IrConstImpl.boolean(start, end, type, proto.getBoolean())
|
||||
proto.hasInt()
|
||||
-> return IrConstImpl.int(start, end, type, proto.getInt())
|
||||
proto.hasString()
|
||||
-> return IrConstImpl.string(start, end, type, proto.getString())
|
||||
proto.hasDouble()
|
||||
-> return IrConstImpl.double(start, end, type, proto.getDouble())
|
||||
else -> {
|
||||
TODO("Not all const types have been implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeOperation(proto: KonanIr.IrOperation, start: Int, end: Int, type: KotlinType): IrExpression {
|
||||
when {
|
||||
proto.hasBlock()
|
||||
-> return deserializeBlock(proto.getBlock(), start, end, type)
|
||||
proto.hasBreak()
|
||||
-> return deserializeBreak(proto.getBreak(), start, end, type)
|
||||
proto.hasCall()
|
||||
-> return deserializeCall(proto.getCall(), start, end, type)
|
||||
proto.hasCallableReference()
|
||||
-> return deserializeCallableReference(proto.getCallableReference(), start, end, type)
|
||||
proto.hasConst()
|
||||
-> return deserializeConst(proto.getConst(), start, end, type)
|
||||
proto.hasDelegatingConstructorCall()
|
||||
-> return deserializeDelegatingConstructorCall(proto.getDelegatingConstructorCall(), start, end, type)
|
||||
proto.hasGetValue()
|
||||
-> return deserializeGetValue(proto.getGetValue(), start, end, type)
|
||||
proto.hasGetObject()
|
||||
-> return deserializeGetObject(proto.getGetObject(), start, end, type)
|
||||
proto.hasInstanceInitializerCall()
|
||||
-> return deserializeInstanceInitializerCall(proto.getInstanceInitializerCall(), start, end, type)
|
||||
proto.hasReturn()
|
||||
-> return deserializeReturn(proto.getReturn(), start, end, type)
|
||||
proto.hasSetVariable()
|
||||
-> return deserializeSetVariable(proto.getSetVariable(), start, end, type)
|
||||
proto.hasStringConcat()
|
||||
-> return deserializeStringConcat(proto.getStringConcat(), start, end, type)
|
||||
proto.hasThrow()
|
||||
-> return deserializeThrow(proto.getThrow(), start, end, type)
|
||||
proto.hasTry()
|
||||
-> return deserializeTry(proto.getTry(), start, end, type)
|
||||
proto.hasTypeOp()
|
||||
-> return deserializeTypeOp(proto.getTypeOp(), start, end, type)
|
||||
proto.hasVararg()
|
||||
-> return deserializeVararg(proto.getVararg(), start, end, type)
|
||||
proto.hasWhen()
|
||||
-> return deserializeWhen(proto.getWhen(), start, end, type)
|
||||
proto.hasWhile()
|
||||
-> return deserializeWhile(proto.getWhile(), start, end, type)
|
||||
else -> {
|
||||
TODO("Expression deserialization not implemented}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeExpression(proto: KonanIr.IrExpression): IrExpression {
|
||||
val start = proto.getCoordinates().getStartOffset()
|
||||
val end = proto.getCoordinates().getEndOffset()
|
||||
val type = deserializeKotlinType(proto.getType())
|
||||
val operation = proto.getOperation()
|
||||
val expression = deserializeOperation(operation, start, end, type)
|
||||
|
||||
context.log("Deserialized expression: ${ir2string(expression)}")
|
||||
return expression
|
||||
}
|
||||
|
||||
fun deserializeIrClass(proto: KonanIr.IrClass, descriptor: ClassDescriptor, start: Int, end: Int, origin: IrDeclarationOrigin): IrClass {
|
||||
val members = mutableListOf<IrDeclaration>()
|
||||
|
||||
proto.getMemberList().forEach {
|
||||
members.add(deserializeDeclaration(it))
|
||||
}
|
||||
|
||||
val clazz = IrClassImpl(start, end, origin, descriptor, members)
|
||||
return clazz
|
||||
|
||||
}
|
||||
|
||||
fun deserializeIrFunction(proto: KonanIr.IrFunc, descriptor: FunctionDescriptor,
|
||||
start: Int, end: Int, origin: IrDeclarationOrigin): IrFunction {
|
||||
|
||||
val body = deserializeStatement(proto.getBody())
|
||||
val function = IrFunctionImpl(start, end, origin,
|
||||
descriptor as FunctionDescriptor, body as IrBody)
|
||||
|
||||
return function
|
||||
}
|
||||
|
||||
fun deserializeIrVariable(proto: KonanIr.IrVar, descriptor: VariableDescriptor,
|
||||
start: Int, end: Int, origin: IrDeclarationOrigin): IrVariable {
|
||||
|
||||
val initializer = deserializeExpression(proto.getInitializer())
|
||||
val variable = IrVariableImpl(start, end, origin, descriptor, initializer)
|
||||
|
||||
return variable
|
||||
}
|
||||
|
||||
fun deserializeDeclaration(proto: KonanIr.IrDeclaration): IrDeclaration {
|
||||
|
||||
val descriptor = deserializeDescriptor(proto.descriptor)
|
||||
|
||||
val start = proto.getCoordinates().getStartOffset()
|
||||
val end = proto.getCoordinates().getEndOffset()
|
||||
val origin = DEFINED // TODO: retore the real origins
|
||||
val declarator = proto.getDeclarator()
|
||||
|
||||
val declaration = when {
|
||||
declarator.hasIrClass()
|
||||
-> deserializeIrClass(declarator.getIrClass(),
|
||||
descriptor as ClassDescriptor, start, end, origin)
|
||||
declarator.hasFunction()
|
||||
-> deserializeIrFunction(declarator.getFunction(),
|
||||
descriptor as FunctionDescriptor, start, end, origin)
|
||||
declarator.hasVariable()
|
||||
-> deserializeIrVariable(declarator.getVariable(),
|
||||
descriptor as VariableDescriptor, start, end, origin)
|
||||
else -> {
|
||||
TODO("Declaration deserialization not implemented")
|
||||
}
|
||||
}
|
||||
context.log("Deserialized declaration: ${ir2string(declaration)}")
|
||||
return declaration
|
||||
}
|
||||
|
||||
fun decodeDeclaration(): IrDeclaration {
|
||||
val proto = (rootFunction as DeserializedSimpleFunctionDescriptor).proto
|
||||
|
||||
if (!proto.hasExtension(KonanLinkData.inlineIrBody)) {
|
||||
error("$rootFunction doesn't have ir serialized.")
|
||||
}
|
||||
|
||||
val inlineProto = proto.getExtension(KonanLinkData.inlineIrBody)
|
||||
val base64 = inlineProto.encodedIr
|
||||
val byteArray = base64Decode(base64)
|
||||
val irProto = KonanIr.IrDeclaration.parseFrom(byteArray)
|
||||
return deserializeDeclaration(irProto)
|
||||
}
|
||||
}
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package org.jetbrains.kotlin.backend.konan.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorVisitor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.EmptyDescriptorVisitorVoid
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.DeepVisitor
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.base64Encode
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.base64Decode
|
||||
import org.jetbrains.kotlin.backend.konan.PhaseManager
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPhase
|
||||
import org.jetbrains.kotlin.serialization.MutableTypeTable
|
||||
import org.jetbrains.kotlin.serialization.KonanLinkData
|
||||
import org.jetbrains.kotlin.backend.common.validateIrFunction
|
||||
|
||||
internal class DeserializerDriver(val context: Context) {
|
||||
|
||||
val descriptorIndex = IrDeserializationDescriptorIndex(context.irBuiltIns)
|
||||
|
||||
internal fun deserializeInlineBody(descriptor: FunctionDescriptor): IrDeclaration? {
|
||||
if (!descriptor.isInline()) return null
|
||||
|
||||
if (descriptor !is DeserializedSimpleFunctionDescriptor) {
|
||||
return null
|
||||
}
|
||||
|
||||
var deserializedIr: IrDeclaration? = null
|
||||
PhaseManager(context).phase(KonanPhase.DESERIALIZER) {
|
||||
context.log("### IR deserialization attempt:\t$descriptor")
|
||||
try {
|
||||
deserializedIr = IrDeserializer(context, descriptorIndex, descriptor).decodeDeclaration()
|
||||
context.log("${deserializedIr!!.descriptor}")
|
||||
context.log(ir2stringWhole(deserializedIr!!))
|
||||
context.log("IR deserialization SUCCESS:\t$descriptor")
|
||||
} catch(e: Throwable) {
|
||||
context.log("IR deserialization FAILURE:\t$descriptor")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
return deserializedIr
|
||||
}
|
||||
|
||||
internal fun dumpAllInlineBodies() {
|
||||
if (! context.phase!!.verbose) return
|
||||
context.log("Now deserializing all inlines for debugging purpose.")
|
||||
context.moduleDescriptor!!.accept(
|
||||
InlineBodiesPrinterVisitor(InlineBodyPrinter()), Unit)
|
||||
}
|
||||
|
||||
|
||||
inner class InlineBodiesPrinterVisitor(worker: EmptyDescriptorVisitorVoid): DeepVisitor<Unit>(worker) { }
|
||||
|
||||
inner class InlineBodyPrinter: EmptyDescriptorVisitorVoid() {
|
||||
|
||||
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): Boolean {
|
||||
if (descriptor is DeserializedSimpleFunctionDescriptor) {
|
||||
this@DeserializerDriver.deserializeInlineBody(descriptor)
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
|
||||
|
||||
// TODO Come up with a better file name.
|
||||
|
||||
internal fun NameResolverImpl.getDescriptorByFqNameIndex(
|
||||
module: ModuleDescriptor,
|
||||
nameTable: ProtoBuf.QualifiedNameTable,
|
||||
fqNameIndex: Int): DeclarationDescriptor {
|
||||
|
||||
val packageName = this.getPackageFqName(fqNameIndex)
|
||||
// TODO: Here we are using internals of NameresolverImpl.
|
||||
// Consider extending NameResolver.
|
||||
val proto = nameTable.getQualifiedName(fqNameIndex)
|
||||
when (proto.kind) {
|
||||
QualifiedName.Kind.CLASS,
|
||||
QualifiedName.Kind.LOCAL ->
|
||||
return module.findClassAcrossModuleDependencies(this.getClassId(fqNameIndex))!!
|
||||
QualifiedName.Kind.PACKAGE ->
|
||||
return module.getPackage(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1532,6 +1532,15 @@ task inline23(type: RunKonanTest) {
|
||||
source = "codegen/inline/inline23.kt"
|
||||
}
|
||||
|
||||
task deserialized_inline0(type: RunKonanTest) {
|
||||
source = "serialization/deserialized_inline0.kt"
|
||||
flags = ["--enable", "deserializer"]
|
||||
}
|
||||
task deserialized_listof0(type: RunKonanTest) {
|
||||
source = "serialization/deserialized_listof0.kt"
|
||||
flags = ["--enable", "deserializer"]
|
||||
}
|
||||
|
||||
kotlinNativeInterop {
|
||||
sysstat {
|
||||
pkg 'sysstat'
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
fun inline_todo() {
|
||||
try {
|
||||
TODO("OK")
|
||||
} catch (e: Throwable) {
|
||||
println(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
fun inline_maxof() {
|
||||
println(maxOf(10, 17))
|
||||
println(maxOf(17, 13))
|
||||
println(maxOf(17, 17))
|
||||
}
|
||||
|
||||
fun inline_assert() {
|
||||
//assert(true)
|
||||
}
|
||||
|
||||
fun inline_areEqual() {
|
||||
val a = 17
|
||||
val b = "some string"
|
||||
println(konan.internal.areEqual(a, 17))
|
||||
println(konan.internal.areEqual(a, a))
|
||||
println(konan.internal.areEqual(17, 17))
|
||||
println(konan.internal.areEqual(b, "some string"))
|
||||
println(konan.internal.areEqual("some string", b))
|
||||
println(konan.internal.areEqual(b, b))
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
inline_todo()
|
||||
inline_assert()
|
||||
inline_maxof()
|
||||
inline_areEqual()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
fun test_arrayList() {
|
||||
val l = listOf(1, 2, 3)
|
||||
val m = listOf<Int>()
|
||||
val n = l + m
|
||||
println(n)
|
||||
}
|
||||
|
||||
fun <T> test_arrayList2(x: T, y: T, z: T) {
|
||||
val l = listOf<T>(x, y, z)
|
||||
val m = listOf<T>()
|
||||
val n = m + l
|
||||
println(l)
|
||||
}
|
||||
|
||||
fun test_arrayList3() {
|
||||
val l = listOf<String>()
|
||||
val m = listOf<String>("a", "b", "c")
|
||||
val n = l + m
|
||||
println(n)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
test_arrayList()
|
||||
test_arrayList2<Int>(5, 6, 7)
|
||||
test_arrayList2<String>("a", "b", "c")
|
||||
test_arrayList3()
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ abstract class KonanTest extends JavaExec {
|
||||
String testData = null
|
||||
int expectedExitStatus = 0
|
||||
List<String> arguments = null
|
||||
List<String> flags = null
|
||||
|
||||
boolean enabled = true
|
||||
boolean run = true
|
||||
@@ -193,7 +194,7 @@ class TestFailedException extends RuntimeException {
|
||||
@ParallelizableTask
|
||||
class RunKonanTest extends KonanTest {
|
||||
void compileTest(List<String> filesToCompile, String exe) {
|
||||
runCompiler(filesToCompile, exe, [])
|
||||
runCompiler(filesToCompile, exe, flags?:[])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user