[KLIB] Implement special encoding for Klib data

This commit is contained in:
Roman Artemev
2020-01-27 16:01:45 +03:00
committed by romanart
parent 7688197841
commit e81a7f10c1
6 changed files with 384 additions and 0 deletions
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization.encodings
inline class BinaryCoordinates(private val decoded: BinaryLattice) {
private fun diff(): Int = decoded.second
val startOffset: Int get() = decoded.first
val endOffset: Int get() = startOffset + diff()
companion object {
fun encode(startOffset: Int, endOffset: Int): Long {
assert(startOffset <= endOffset)
return BinaryLattice.encode(startOffset, endOffset - startOffset)
}
fun decode(code: Long) = BinaryCoordinates(BinaryLattice.decode(code)).also { assert(it.startOffset <= it.endOffset) }
}
}
@@ -0,0 +1,229 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization.encodings
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
import org.jetbrains.kotlin.types.Variance
inline class ClassFlags(val flags: Long) {
val modality: Modality get() = ProtoEnumFlags.modality(Flags.MODALITY.get(flags.toInt()))
val visibility: Visibility get() = ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags.toInt()))
val kind: ClassKind get() = ProtoEnumFlags.classKind(Flags.CLASS_KIND.get(flags.toInt()))
val isCompanion: Boolean get() = Flags.CLASS_KIND.get(flags.toInt()) == ProtoBuf.Class.Kind.COMPANION_OBJECT
val isInner: Boolean get() = Flags.IS_INNER.get(flags.toInt())
val isData: Boolean get() = Flags.IS_DATA.get(flags.toInt())
val isInline: Boolean get() = Flags.IS_INLINE_CLASS.get(flags.toInt())
val isExpect: Boolean get() = Flags.IS_EXPECT_CLASS.get(flags.toInt())
val isExternal: Boolean get() = Flags.IS_EXTERNAL_CLASS.get(flags.toInt())
val isFun: Boolean get() = Flags.IS_FUN_INTERFACE.get(flags.toInt())
companion object {
fun encode(clazz: IrClass): Long {
return clazz.run {
val hasAnnotation = annotations.isNotEmpty()
val visibility = ProtoEnumFlags.visibility(visibility)
val modality = ProtoEnumFlags.modality(modality)
val kind = ProtoEnumFlags.classKind(kind, isCompanion)
val flags =
Flags.getClassFlags(hasAnnotation, visibility, modality, kind, isInner, isData, isExternal, isExpect, isInline, isFun)
flags.toLong()
}
}
fun decode(code: Long) = ClassFlags(code)
}
}
inline class FunctionFlags(val flags: Long) {
val modality: Modality get() = ProtoEnumFlags.modality(Flags.MODALITY.get(flags.toInt()))
val visibility: Visibility get() = ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags.toInt()))
val isOperator: Boolean get() = Flags.IS_OPERATOR.get(flags.toInt())
val isInline: Boolean get() = Flags.IS_INLINE.get(flags.toInt())
val isTailrec: Boolean get() = Flags.IS_TAILREC.get(flags.toInt())
val isExternal: Boolean get() = Flags.IS_EXTERNAL_FUNCTION.get(flags.toInt())
val isSuspend: Boolean get() = Flags.IS_SUSPEND.get(flags.toInt())
val isExpect: Boolean get() = Flags.IS_EXPECT_FUNCTION.get(flags.toInt())
val isFakeOverride: Boolean get() = kind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
val isPrimary: Boolean get() = Flags.IS_PRIMARY.get(flags.toInt())
private fun kind(): CallableMemberDescriptor.Kind = ProtoEnumFlags.memberKind(Flags.MEMBER_KIND.get(flags.toInt()))
companion object {
fun encode(function: IrSimpleFunction): Long {
function.run {
val hasAnnotation = annotations.isNotEmpty()
val visibility = ProtoEnumFlags.visibility(visibility)
val modality = ProtoEnumFlags.modality(modality)
val kind = if (isFakeOverride) ProtoBuf.MemberKind.FAKE_OVERRIDE else ProtoBuf.MemberKind.DECLARATION
val flags = Flags.getFunctionFlags(
hasAnnotation, visibility, modality, kind,
isOperator, false, isInline, isTailrec, isExternal, isSuspend, isExpect
)
return flags.toLong()
}
}
fun encode(constructor: IrConstructor): Long {
constructor.run {
val hasAnnotation = annotations.isNotEmpty()
val visibility = ProtoEnumFlags.visibility(visibility)
val flags = Flags.getConstructorFlags(hasAnnotation, visibility, isInline, isExternal, isExpect, isPrimary)
return flags.toLong()
}
}
fun decode(code: Long) = FunctionFlags(code)
}
}
inline class PropertyFlags(val flags: Long) {
val modality: Modality get() = ProtoEnumFlags.modality(Flags.MODALITY.get(flags.toInt()))
val visibility: Visibility get() = ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags.toInt()))
val isVar: Boolean get() = Flags.IS_VAR.get(flags.toInt())
val isConst: Boolean get() = Flags.IS_CONST.get(flags.toInt())
val isLateinit: Boolean get() = Flags.IS_LATEINIT.get(flags.toInt())
val isExternal: Boolean get() = Flags.IS_EXTERNAL_PROPERTY.get(flags.toInt())
val isDelegated: Boolean get() = Flags.IS_DELEGATED.get(flags.toInt())
val isExpect: Boolean get() = Flags.IS_EXPECT_PROPERTY.get(flags.toInt())
val isFakeOverride: Boolean get() = kind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
private fun kind(): CallableMemberDescriptor.Kind = ProtoEnumFlags.memberKind(Flags.MEMBER_KIND.get(flags.toInt()))
companion object {
fun encode(property: IrProperty): Long {
return property.run {
val hasAnnotation = annotations.isNotEmpty()
val visibility = ProtoEnumFlags.visibility(visibility)
val modality = ProtoEnumFlags.modality(modality)
val kind = if (isFakeOverride) ProtoBuf.MemberKind.FAKE_OVERRIDE else ProtoBuf.MemberKind.DECLARATION
val hasGetter = getter != null
val hasSetter = setter != null
val flags = Flags.getPropertyFlags(
hasAnnotation, visibility, modality, kind,
isVar, hasGetter, hasSetter, false, isConst, isLateinit, isExternal, isDelegated, isExpect
)
flags.toLong()
}
}
fun decode(code: Long) = PropertyFlags(code)
}
}
inline class ValueParameterFlags(val flags: Long) {
val isCrossInline: Boolean get() = Flags.IS_CROSSINLINE.get(flags.toInt())
val isNoInline: Boolean get() = Flags.IS_NOINLINE.get(flags.toInt())
companion object {
fun encode(param: IrValueParameter): Long {
return param.run {
Flags.getValueParameterFlags(annotations.isNotEmpty(), defaultValue != null, isCrossinline, isNoinline).toLong()
}
}
fun decode(code: Long) = ValueParameterFlags(code)
}
}
inline class TypeAliasFlags(val flags: Long) {
val visibility: Visibility get() = ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags.toInt()))
val isActual: Boolean get() = Flags.IS_ACTUAL.get(flags.toInt())
companion object {
fun encode(typeAlias: IrTypeAlias): Long {
return typeAlias.run {
val visibility = ProtoEnumFlags.visibility(visibility)
Flags.getTypeAliasFlags(annotations.isNotEmpty(), visibility, isActual).toLong()
}
}
fun decode(code: Long) = TypeAliasFlags(code)
}
}
inline class TypeParameterFlags(val flags: Long) {
val variance: Variance get() = ProtoEnumFlags.variance(Flags.VARIANCE.get(flags.toInt()))
val isReified: Boolean get() = Flags.IS_REIFIED.get(flags.toInt())
companion object {
fun encode(typeParameter: IrTypeParameter): Long {
return typeParameter.run {
val variance = ProtoEnumFlags.variance(variance)
Flags.getTypeParameterFlags(annotations.isNotEmpty(), variance, isReified).toLong()
}
}
fun decode(code: Long) = TypeParameterFlags(code)
}
}
inline class FieldFlags(val flags: Long) {
val visibility: Visibility get() = ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags.toInt()))
val isFinal: Boolean get() = Flags.IS_FINAL.get(flags.toInt())
val isExternal: Boolean get() = Flags.IS_EXTERNAL_FIELD.get(flags.toInt())
val isStatic: Boolean get() = Flags.IS_STATIC.get(flags.toInt())
val isFakeOverride: Boolean get() = Flags.IS_FAKE_OVERRIDE.get(flags.toInt())
companion object {
fun encode(field: IrField): Long {
return field.run {
val visibility = ProtoEnumFlags.visibility(visibility)
Flags.getFieldFlags(annotations.isNotEmpty(), visibility, isFinal, isExternal, isStatic, isFakeOverride).toLong()
}
}
fun decode(code: Long) = FieldFlags(code)
}
}
inline class LocalVariableFlags(val flags: Long) {
val isVar: Boolean get() = Flags.IS_LOCAL_VAR.get(flags.toInt())
val isConst: Boolean get() = Flags.IS_LOCAL_CONST.get(flags.toInt())
val isLateinit: Boolean get() = Flags.IS_LOCAL_LATEINIT.get(flags.toInt())
companion object {
fun encode(variable: IrVariable): Long {
return variable.run {
Flags.getLocalFlags(annotations.isNotEmpty(), isVar, isConst, isLateinit).toLong()
}
}
fun encode(delegate: IrLocalDelegatedProperty): Long {
return delegate.run {
Flags.getLocalFlags(annotations.isNotEmpty(), isVar, false, false).toLong()
}
}
fun decode(code: Long) = LocalVariableFlags(code)
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization.encodings
inline class BinaryLattice(private val code: Long) {
val first: Int get() = decodeInt(code)
val second: Int get() = decodeInt(code ushr 1)
companion object {
private fun interleaveBits(input: Int): Long {
var word = input.toLong() and 0x0FFFFFFFFL
word = word xor (word shl 16) and 0x0000ffff0000ffffL
word = word xor (word shl 8) and 0x00ff00ff00ff00ffL
word = word xor (word shl 4) and 0x0f0f0f0f0f0f0f0fL
word = word xor (word shl 2) and 0x3333333333333333L
word = word xor (word shl 1) and 0x5555555555555555L
return word
}
private fun decodeInt(xx: Long): Int {
var x = xx
x = x and 0x5555555555555555L
x = x xor (x shr 1) and 0x3333333333333333L
x = x xor (x shr 2) and 0x0f0f0f0f0f0f0f0fL
x = x xor (x shr 4) and 0x00ff00ff00ff00ffL
x = x xor (x shr 8) and 0x0000ffff0000ffffL
x = x xor (x shr 16) and 0x00000000FFFFFFFFL
return x.toInt()
}
fun encode(f: Int, s: Int): Long {
return interleaveBits(f) or (interleaveBits(s) shl 1)
}
fun decode(code: Long) = BinaryLattice(code)
}
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization.encodings
inline class BinaryNameAndType(private val decoded: BinaryLattice) {
val nameIndex: Int get() = decoded.first
val typeIndex: Int get() = decoded.second
companion object {
fun encode(nameIndex: Int, typeIndex: Int): Long = BinaryLattice.encode(nameIndex, typeIndex)
fun decode(code: Long) = BinaryNameAndType(BinaryLattice.decode(code))
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization.encodings
inline class BinarySymbolData(val code: Long) {
enum class SymbolKind {
FUNCTION_SYMBOL,
CONSTRUCTOR_SYMBOL,
ENUM_ENTRY_SYMBOL,
FIELD_SYMBOL,
VALUE_PARAMETER_SYMBOL,
RETURNABLE_BLOCK_SYMBOL,
CLASS_SYMBOL,
TYPE_PARAMETER_SYMBOL,
VARIABLE_SYMBOL,
ANONYMOUS_INIT_SYMBOL,
STANDALONE_FIELD_SYMBOL, // For fields without properties. WrappedFieldDescriptor, rather than WrappedPropertyDescriptor.
RECEIVER_PARAMETER_SYMBOL, // ReceiverParameterDescriptor rather than ValueParameterDescriptor.
PROPERTY_SYMBOL,
LOCAL_DELEGATED_PROPERTY_SYMBOL,
TYPEALIAS_SYMBOL;
}
private fun symbolKindId(): Int = (code and 0xFF).toInt()
val signatureId: Int get() = (code ushr 8).toInt()
val kind: SymbolKind
get() = SymbolKind.values()[symbolKindId()]
companion object {
fun encode(kind: SymbolKind, signatureId: Int): Long {
val kindId = kind.ordinal
return (signatureId.toLong() shl 8) or kindId.toLong()
}
fun decode(code: Long) = BinarySymbolData(code)
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization.encodings
import org.jetbrains.kotlin.types.Variance
inline class BinaryTypeProjection(val code: Long) {
private fun varianceId(): Int = (code and 0x3L).toInt() - 1
val isStarProjection: Boolean get() = code == 0L
val variance: Variance
get() {
assert(!isStarProjection)
return Variance.values()[varianceId()]
}
val typeIndex: Int get() = (code ushr 2).toInt()
companion object {
fun encodeType(variance: Variance, typeIndex: Int): Long {
val vId = variance.ordinal + 1
return (typeIndex.toLong() shl 2) or vId.toLong()
}
fun decode(code: Long) = BinaryTypeProjection(code)
const val STAR_CODE = 0L
}
}