IR: move serialization to serialization.common
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:backend-common"))
|
||||
compile(project(":compiler:ir.backend.common"))
|
||||
compile(project(":compiler:ir.tree"))
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,710 @@
|
||||
syntax = "proto2";
|
||||
package org.jetbrains.kotlin.backend.common.serialization;
|
||||
|
||||
option java_outer_classname = "KotlinIr";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
message DescriptorReference {
|
||||
required String package_fq_name = 1;
|
||||
required String class_fq_name = 2;
|
||||
required String name = 3;
|
||||
optional UniqId uniq_id = 4;
|
||||
optional bool is_getter = 5 [default = false];
|
||||
optional bool is_setter = 6 [default = false];
|
||||
optional bool is_backing_field = 7 [default = false];
|
||||
optional bool is_fake_override = 8 [default = false];
|
||||
optional bool is_default_constructor = 9 [default = false];
|
||||
optional bool is_enum_entry = 10 [default = false];
|
||||
optional bool is_enum_special = 11 [default = false];
|
||||
optional bool is_type_parameter = 12 [default = false];
|
||||
}
|
||||
|
||||
message UniqId {
|
||||
required uint64 index = 1;
|
||||
required bool isLocal = 2;
|
||||
}
|
||||
|
||||
message Coordinates {
|
||||
required int32 start_offset = 1;
|
||||
required int32 end_offset = 2;
|
||||
}
|
||||
|
||||
message Visibility {
|
||||
required String name = 1;
|
||||
}
|
||||
|
||||
message IrStatementOrigin {
|
||||
required String name = 1;
|
||||
}
|
||||
|
||||
enum KnownOrigin {
|
||||
CUSTOM = 1;
|
||||
DEFINED = 2;
|
||||
FAKE_OVERRIDE = 3;
|
||||
FOR_LOOP_ITERATOR = 4;
|
||||
FOR_LOOP_VARIABLE = 5;
|
||||
FOR_LOOP_IMPLICIT_VARIABLE = 6;
|
||||
PROPERTY_BACKING_FIELD = 7;
|
||||
DEFAULT_PROPERTY_ACCESSOR = 8;
|
||||
DELEGATE = 9;
|
||||
DELEGATED_PROPERTY_ACCESSOR = 10;
|
||||
DELEGATED_MEMBER = 11;
|
||||
ENUM_CLASS_SPECIAL_MEMBER = 12;
|
||||
FUNCTION_FOR_DEFAULT_PARAMETER = 13;
|
||||
FILE_CLASS = 14;
|
||||
GENERATED_DATA_CLASS_MEMBER = 15;
|
||||
GENERATED_INLINE_CLASS_MEMBER = 16;
|
||||
LOCAL_FUNCTION_FOR_LAMBDA = 17;
|
||||
CATCH_PARAMETER = 19;
|
||||
INSTANCE_RECEIVER = 20;
|
||||
PRIMARY_CONSTRUCTOR_PARAMETER = 21;
|
||||
IR_TEMPORARY_VARIABLE = 22;
|
||||
IR_EXTERNAL_DECLARATION_STUB = 23;
|
||||
IR_EXTERNAL_JAVA_DECLARATION_STUB = 24;
|
||||
IR_BUILTINS_STUB = 25;
|
||||
BRIDGE = 26;
|
||||
FIELD_FOR_ENUM_ENTRY = 27;
|
||||
FIELD_FOR_ENUM_VALUES = 28;
|
||||
FIELD_FOR_OBJECT_INSTANCE = 29;
|
||||
}
|
||||
|
||||
message IrDeclarationOrigin {
|
||||
oneof either {
|
||||
KnownOrigin origin = 1;
|
||||
String custom = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------ Top Level---------------------------------------------- */
|
||||
|
||||
message IrDeclarationContainer {
|
||||
repeated IrDeclaration declaration = 1;
|
||||
}
|
||||
|
||||
message FileEntry {
|
||||
required String name = 1;
|
||||
repeated int32 line_start_offsets = 2;
|
||||
}
|
||||
|
||||
message IrFile {
|
||||
repeated UniqId declaration_id = 1;
|
||||
required FileEntry file_entry = 2;
|
||||
required String fq_name = 3;
|
||||
required Annotations annotations = 4;
|
||||
repeated IrSymbol explicitly_exported_to_compiler = 5;
|
||||
}
|
||||
|
||||
message IrModule {
|
||||
required String name = 1;
|
||||
repeated IrFile file = 2;
|
||||
required IrSymbolTable symbol_table = 3;
|
||||
required IrTypeTable type_table = 4;
|
||||
required StringTable string_table = 5;
|
||||
}
|
||||
|
||||
/* ------ String Table ------------------------------------------ */
|
||||
|
||||
message String {
|
||||
required int32 index = 1;
|
||||
}
|
||||
|
||||
message StringTable {
|
||||
repeated string strings = 1;
|
||||
}
|
||||
|
||||
/* ------ IrSymbols --------------------------------------------- */
|
||||
|
||||
enum IrSymbolKind {
|
||||
FUNCTION_SYMBOL = 1;
|
||||
CONSTRUCTOR_SYMBOL = 2;
|
||||
ENUM_ENTRY_SYMBOL = 3;
|
||||
FIELD_SYMBOL = 4;
|
||||
VALUE_PARAMETER_SYMBOL = 5;
|
||||
RETURNABLE_BLOCK_SYMBOL = 6;
|
||||
CLASS_SYMBOL = 7;
|
||||
TYPE_PARAMETER_SYMBOL = 8;
|
||||
VARIABLE_SYMBOL = 9;
|
||||
ANONYMOUS_INIT_SYMBOL = 10;
|
||||
|
||||
STANDALONE_FIELD_SYMBOL = 11; // For fields without properties. WrappedFieldDescriptor, rather than WrappedPropertyDescriptor.
|
||||
RECEIVER_PARAMETER_SYMBOL = 12; // ReceiverParameterDescriptor rather than ValueParameterDescriptor.
|
||||
}
|
||||
|
||||
message IrSymbolData {
|
||||
required IrSymbolKind kind = 1;
|
||||
required UniqId uniq_id = 2;
|
||||
required UniqId top_level_uniq_id = 3;
|
||||
optional String fqname = 4;
|
||||
optional DescriptorReference descriptor_reference = 5;
|
||||
}
|
||||
|
||||
message IrSymbol {
|
||||
required int32 index = 1;
|
||||
}
|
||||
|
||||
message IrSymbolTable {
|
||||
repeated IrSymbolData symbols = 1;
|
||||
}
|
||||
|
||||
/* ------ IrTypes --------------------------------------------- */
|
||||
|
||||
enum IrTypeVariance { // Should we import metadata variance, or better stay separate?
|
||||
IN = 0;
|
||||
OUT = 1;
|
||||
INV = 2;
|
||||
}
|
||||
|
||||
message Annotations {
|
||||
repeated IrCall annotation = 1;
|
||||
}
|
||||
|
||||
message TypeArguments {
|
||||
repeated IrTypeIndex type_argument = 1;
|
||||
}
|
||||
|
||||
message IrStarProjection {
|
||||
optional bool void = 1;
|
||||
}
|
||||
|
||||
message IrTypeProjection {
|
||||
required IrTypeVariance variance = 1;
|
||||
required IrTypeIndex type = 2;
|
||||
}
|
||||
|
||||
message IrTypeArgument {
|
||||
oneof kind {
|
||||
IrStarProjection star = 1;
|
||||
IrTypeProjection type = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message IrSimpleType {
|
||||
required Annotations annotations = 1;
|
||||
required IrSymbol classifier = 2;
|
||||
required bool has_question_mark = 3;
|
||||
repeated IrTypeArgument argument = 4;
|
||||
}
|
||||
|
||||
message IrDynamicType {
|
||||
required Annotations annotations = 1;
|
||||
}
|
||||
|
||||
message IrErrorType {
|
||||
required Annotations annotations = 1;
|
||||
}
|
||||
|
||||
message IrType {
|
||||
oneof kind {
|
||||
IrSimpleType simple = 1;
|
||||
IrDynamicType dynamic = 2;
|
||||
IrErrorType error = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message IrTypeTable {
|
||||
repeated IrType types = 1;
|
||||
}
|
||||
|
||||
message IrTypeIndex {
|
||||
required int32 index = 1;
|
||||
}
|
||||
|
||||
/* ------ IrExpressions --------------------------------------------- */
|
||||
|
||||
message IrBreak {
|
||||
required int32 loop_id = 1;
|
||||
optional String label = 2;
|
||||
}
|
||||
|
||||
message IrBlock {
|
||||
required bool is_lambda_origin = 1;
|
||||
repeated IrStatement statement = 2;
|
||||
}
|
||||
|
||||
message MemberAccessCommon {
|
||||
optional IrExpression dispatch_receiver = 1;
|
||||
optional IrExpression extension_receiver = 2;
|
||||
repeated NullableIrExpression value_argument = 3;
|
||||
required TypeArguments type_arguments = 4;
|
||||
}
|
||||
|
||||
message IrCall {
|
||||
enum Primitive {
|
||||
NOT_PRIMITIVE = 1;
|
||||
NULLARY = 2;
|
||||
BINARY = 4;
|
||||
}
|
||||
required Primitive kind = 1;
|
||||
required IrSymbol symbol = 2;
|
||||
required MemberAccessCommon member_access = 3;
|
||||
optional IrSymbol super = 4;
|
||||
}
|
||||
|
||||
message IrFunctionReference {
|
||||
required IrSymbol symbol = 1;
|
||||
optional IrStatementOrigin origin = 2;
|
||||
required MemberAccessCommon member_access = 3;
|
||||
}
|
||||
|
||||
|
||||
message IrPropertyReference {
|
||||
optional IrSymbol field = 1;
|
||||
optional IrSymbol getter = 2;
|
||||
optional IrSymbol setter = 3;
|
||||
optional IrStatementOrigin origin = 4;
|
||||
required MemberAccessCommon member_access = 5;
|
||||
optional DescriptorReference descriptor_reference = 6; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
|
||||
}
|
||||
|
||||
message IrComposite {
|
||||
repeated IrStatement statement = 1;
|
||||
}
|
||||
|
||||
message IrClassReference {
|
||||
required IrSymbol class_symbol = 1;
|
||||
required IrTypeIndex class_type = 2;
|
||||
}
|
||||
|
||||
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 IrContinue {
|
||||
required int32 loop_id = 1;
|
||||
optional String label = 2;
|
||||
}
|
||||
|
||||
message IrDelegatingConstructorCall {
|
||||
required IrSymbol symbol = 1;
|
||||
required MemberAccessCommon member_access = 2;
|
||||
}
|
||||
|
||||
message IrDoWhile {
|
||||
required Loop loop = 1;
|
||||
}
|
||||
|
||||
message IrEnumConstructorCall {
|
||||
required IrSymbol symbol = 1;
|
||||
required MemberAccessCommon member_access = 2;
|
||||
}
|
||||
|
||||
message IrGetClass {
|
||||
required IrExpression argument = 1;
|
||||
}
|
||||
|
||||
message IrGetEnumValue {
|
||||
required IrSymbol symbol = 2;
|
||||
}
|
||||
|
||||
message FieldAccessCommon {
|
||||
required IrSymbol symbol = 1;
|
||||
optional IrSymbol super = 2;
|
||||
optional IrExpression receiver = 3;
|
||||
}
|
||||
|
||||
message IrGetField {
|
||||
required FieldAccessCommon field_access = 1;
|
||||
}
|
||||
|
||||
message IrGetValue {
|
||||
required IrSymbol symbol = 1;
|
||||
}
|
||||
|
||||
message IrGetObject {
|
||||
required IrSymbol symbol = 1;
|
||||
}
|
||||
|
||||
message IrInstanceInitializerCall {
|
||||
required IrSymbol symbol = 1;
|
||||
}
|
||||
|
||||
message Loop {
|
||||
required int32 loop_id = 1;
|
||||
required IrExpression condition = 2;
|
||||
optional String label = 3;
|
||||
optional IrExpression body = 4;
|
||||
}
|
||||
|
||||
message IrReturn {
|
||||
required IrSymbol return_target = 1;
|
||||
required IrExpression value = 2;
|
||||
}
|
||||
|
||||
message IrSetField {
|
||||
required FieldAccessCommon field_access = 1;
|
||||
required IrExpression value = 2;
|
||||
}
|
||||
|
||||
message IrSetVariable {
|
||||
required IrSymbol symbol = 1;
|
||||
required IrExpression value = 2;
|
||||
}
|
||||
|
||||
message IrSpreadElement {
|
||||
required IrExpression expression = 1;
|
||||
required Coordinates coordinates = 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 IrTypeIndex operand = 2;
|
||||
required IrExpression argument = 3;
|
||||
}
|
||||
|
||||
message IrVararg {
|
||||
required IrTypeIndex element_type = 1;
|
||||
repeated IrVarargElement element = 2;
|
||||
}
|
||||
|
||||
message IrVarargElement {
|
||||
oneof vararg_element {
|
||||
IrExpression expression = 1;
|
||||
IrSpreadElement spread_element = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message IrWhen {
|
||||
repeated IrStatement branch = 1;
|
||||
}
|
||||
|
||||
message IrWhile {
|
||||
required Loop loop = 1;
|
||||
}
|
||||
|
||||
/* ------ Dynamic expression --------------------------------------------- */
|
||||
|
||||
message IrDynamicMemberExpression {
|
||||
required String memberName = 1;
|
||||
required IrExpression receiver = 2;
|
||||
}
|
||||
|
||||
message IrDynamicOperatorExpression {
|
||||
enum IrDynamicOperator {
|
||||
UNARY_PLUS = 1;
|
||||
UNARY_MINUS = 2;
|
||||
EXCL = 3;
|
||||
PREFIX_INCREMENT = 4;
|
||||
POSTFIX_INCREMENT = 5;
|
||||
PREFIX_DECREMENT = 6;
|
||||
POSTFIX_DECREMENT = 7;
|
||||
|
||||
BINARY_PLUS = 8;
|
||||
BINARY_MINUS = 9;
|
||||
MUL = 10;
|
||||
DIV = 11;
|
||||
MOD = 12;
|
||||
GT = 13;
|
||||
LT = 14;
|
||||
GE = 15;
|
||||
LE = 16;
|
||||
EQEQ = 17;
|
||||
EXCLEQ = 18;
|
||||
EQEQEQ = 19;
|
||||
EXCLEQEQ = 20;
|
||||
ANDAND = 21;
|
||||
OROR = 22;
|
||||
|
||||
EQ = 23;
|
||||
PLUSEQ = 24;
|
||||
MINUSEQ = 25;
|
||||
MULEQ = 26;
|
||||
DIVEQ = 27;
|
||||
MODEQ = 28;
|
||||
|
||||
ARRAY_ACCESS = 29;
|
||||
INVOKE = 30;
|
||||
}
|
||||
required IrDynamicOperator operator = 1;
|
||||
required IrExpression receiver = 2;
|
||||
repeated IrExpression argument = 3;
|
||||
}
|
||||
|
||||
// TODO: we need an extension mechanism to accomodate new
|
||||
// IR operators in upcoming releases.
|
||||
message IrOperation {
|
||||
oneof operation {
|
||||
IrBlock block = 1;
|
||||
IrBreak break = 2;
|
||||
IrCall call = 3;
|
||||
IrClassReference class_reference = 4;
|
||||
IrComposite composite = 5;
|
||||
IrConst const = 6;
|
||||
IrContinue continue = 7;
|
||||
IrDelegatingConstructorCall delegating_constructor_call = 8;
|
||||
IrDoWhile do_while = 9;
|
||||
IrEnumConstructorCall enum_constructor_call = 10;
|
||||
IrFunctionReference function_reference = 11;
|
||||
IrGetClass get_class = 12;
|
||||
IrGetEnumValue get_enum_value = 13;
|
||||
IrGetField get_field = 14;
|
||||
IrGetObject get_object = 15;
|
||||
IrGetValue get_value = 16;
|
||||
IrInstanceInitializerCall instance_initializer_call = 17;
|
||||
IrPropertyReference property_reference = 18;
|
||||
IrReturn return = 19;
|
||||
IrSetField set_field = 20;
|
||||
IrSetVariable set_variable = 21;
|
||||
IrStringConcat string_concat = 22;
|
||||
IrThrow throw = 23;
|
||||
IrTry try = 24;
|
||||
IrTypeOp type_op = 25;
|
||||
IrVararg vararg = 26;
|
||||
IrWhen when = 27;
|
||||
IrWhile while = 28;
|
||||
IrDynamicMemberExpression dynamic_member = 29;
|
||||
IrDynamicOperatorExpression dynamic_operator = 30;
|
||||
}
|
||||
}
|
||||
|
||||
enum IrTypeOperator {
|
||||
CAST = 1;
|
||||
IMPLICIT_CAST = 2;
|
||||
IMPLICIT_NOTNULL = 3;
|
||||
IMPLICIT_COERCION_TO_UNIT = 4;
|
||||
IMPLICIT_INTEGER_COERCION = 5;
|
||||
SAFE_CAST = 6;
|
||||
INSTANCEOF = 7;
|
||||
NOT_INSTANCEOF = 8;
|
||||
SAM_CONVERSION = 9;
|
||||
}
|
||||
|
||||
|
||||
message IrExpression {
|
||||
required IrOperation operation = 1;
|
||||
required IrTypeIndex type = 2;
|
||||
required Coordinates coordinates = 3;
|
||||
}
|
||||
|
||||
message NullableIrExpression {
|
||||
optional IrExpression expression = 1;
|
||||
}
|
||||
|
||||
/* ------ Declarations --------------------------------------------- */
|
||||
|
||||
message IrTypeAlias {
|
||||
// Nothing for now.
|
||||
}
|
||||
|
||||
message IrFunction {
|
||||
required IrSymbol symbol = 1;
|
||||
required IrFunctionBase base = 2;
|
||||
required ModalityKind modality = 3;
|
||||
required bool is_tailrec = 4;
|
||||
required bool is_suspend = 5;
|
||||
repeated IrSymbol overridden = 6;
|
||||
//optional UniqId corresponding_property = 7;
|
||||
}
|
||||
|
||||
message IrFunctionBase {
|
||||
required String name = 1;
|
||||
required Visibility visibility = 2;
|
||||
required bool is_inline = 3;
|
||||
required bool is_external = 4;
|
||||
required IrTypeParameterContainer type_parameters = 5;
|
||||
optional IrDeclaration dispatch_receiver = 6;
|
||||
optional IrDeclaration extension_receiver = 7;
|
||||
repeated IrDeclaration value_parameter = 8;
|
||||
optional IrStatement body = 9;
|
||||
required IrTypeIndex return_type = 10;
|
||||
}
|
||||
|
||||
message IrConstructor {
|
||||
required IrSymbol symbol = 1;
|
||||
required IrFunctionBase base = 2;
|
||||
required bool is_primary = 3;
|
||||
|
||||
}
|
||||
|
||||
message IrField {
|
||||
required IrSymbol symbol = 1;
|
||||
optional IrExpression initializer = 2;
|
||||
required String name = 3;
|
||||
required Visibility visibility = 4;
|
||||
required bool is_final = 5;
|
||||
required bool is_external = 6;
|
||||
required bool is_static = 7;
|
||||
required IrTypeIndex type = 8;
|
||||
}
|
||||
|
||||
message IrProperty {
|
||||
optional DescriptorReference descriptor_reference = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
|
||||
required String name = 2;
|
||||
required Visibility visibility = 3;
|
||||
required ModalityKind modality = 4;
|
||||
required bool is_var = 5;
|
||||
required bool is_const = 6;
|
||||
required bool is_lateinit = 7;
|
||||
required bool is_delegated = 8;
|
||||
required bool is_external = 9;
|
||||
optional IrField backing_field = 10;
|
||||
optional IrFunction getter = 11;
|
||||
optional IrFunction setter = 12;
|
||||
}
|
||||
|
||||
message IrVariable {
|
||||
required String name = 1;
|
||||
required IrSymbol symbol = 2;
|
||||
required IrTypeIndex type = 3;
|
||||
required bool is_var = 4;
|
||||
required bool is_const = 5;
|
||||
required bool is_lateinit = 6;
|
||||
optional IrExpression initializer = 7;
|
||||
}
|
||||
|
||||
enum ClassKind {
|
||||
CLASS = 1;
|
||||
INTERFACE = 2;
|
||||
ENUM_CLASS = 3;
|
||||
ENUM_ENTRY = 4;
|
||||
ANNOTATION_CLASS = 5;
|
||||
OBJECT = 6;
|
||||
}
|
||||
|
||||
enum ModalityKind { // It is ModalityKind to not clash with Modality in descriptor metadata.
|
||||
FINAL_MODALITY = 1;
|
||||
SEALED_MODALITY = 2;
|
||||
OPEN_MODALITY = 3;
|
||||
ABSTRACT_MODALITY = 4;
|
||||
}
|
||||
|
||||
message IrValueParameter {
|
||||
required IrSymbol symbol = 1;
|
||||
required String name = 2;
|
||||
required int32 index = 3;
|
||||
required IrTypeIndex type = 4;
|
||||
optional IrTypeIndex vararg_element_type = 5;
|
||||
required bool is_crossinline = 6;
|
||||
required bool is_noinline = 7;
|
||||
optional IrExpression default_value = 8;
|
||||
}
|
||||
|
||||
message IrTypeParameter {
|
||||
required IrSymbol symbol = 1;
|
||||
required String name = 2;
|
||||
required int32 index = 3;
|
||||
required IrTypeVariance variance = 4;
|
||||
repeated IrTypeIndex super_type = 5;
|
||||
required bool is_reified = 6;
|
||||
}
|
||||
|
||||
message IrTypeParameterContainer {
|
||||
repeated IrDeclaration type_parameter = 1;
|
||||
}
|
||||
|
||||
message IrClass {
|
||||
required IrSymbol symbol = 1;
|
||||
required String name = 2;
|
||||
required ClassKind kind = 3;
|
||||
required Visibility visibility = 4;
|
||||
required ModalityKind modality = 5;
|
||||
// TODO: consider using flags for the booleans.
|
||||
required bool is_companion = 6;
|
||||
required bool is_inner = 7;
|
||||
required bool is_data = 8;
|
||||
required bool is_external = 9;
|
||||
required bool is_inline = 10;
|
||||
optional IrDeclaration this_receiver = 11;
|
||||
required IrTypeParameterContainer type_parameters = 12;
|
||||
required IrDeclarationContainer declaration_container = 13;
|
||||
repeated IrTypeIndex super_type = 14;
|
||||
}
|
||||
|
||||
message IrEnumEntry {
|
||||
required IrSymbol symbol = 1;
|
||||
optional IrExpression initializer = 2;
|
||||
optional IrDeclaration corresponding_class = 3;
|
||||
required String name = 4;
|
||||
}
|
||||
|
||||
message IrAnonymousInit {
|
||||
required IrSymbol symbol = 1;
|
||||
required IrStatement body = 2;
|
||||
}
|
||||
|
||||
// TODO: we need an extension mechanism to accomodate new
|
||||
// IR operators in upcoming releases.
|
||||
message IrDeclarator {
|
||||
oneof declarator {
|
||||
IrAnonymousInit ir_anonymous_init = 1;
|
||||
IrClass ir_class = 2;
|
||||
IrConstructor ir_constructor = 3;
|
||||
IrEnumEntry ir_enum_entry = 4;
|
||||
IrField ir_field = 5;
|
||||
IrFunction ir_function = 6;
|
||||
IrProperty ir_property = 7;
|
||||
IrTypeAlias ir_type_alias = 8;
|
||||
IrTypeParameter ir_type_parameter = 9;
|
||||
IrVariable ir_variable = 10;
|
||||
IrValueParameter ir_value_parameter = 11;
|
||||
}
|
||||
}
|
||||
|
||||
message IrDeclaration {
|
||||
required IrDeclarationOrigin origin = 1;
|
||||
required Coordinates coordinates = 2;
|
||||
required Annotations annotations = 3;
|
||||
required IrDeclarator declarator = 4;
|
||||
}
|
||||
|
||||
/* ------- IrStatements --------------------------------------------- */
|
||||
|
||||
message IrBranch {
|
||||
required IrExpression condition = 1;
|
||||
required IrExpression result = 2;
|
||||
}
|
||||
|
||||
message IrBlockBody {
|
||||
repeated IrStatement statement = 1;
|
||||
}
|
||||
|
||||
message IrCatch {
|
||||
required IrDeclaration catch_parameter = 1;
|
||||
required IrExpression result = 2;
|
||||
}
|
||||
|
||||
enum IrSyntheticBodyKind {
|
||||
ENUM_VALUES = 1;
|
||||
ENUM_VALUEOF = 2;
|
||||
}
|
||||
|
||||
message IrSyntheticBody {
|
||||
required IrSyntheticBodyKind kind = 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
IrSyntheticBody synthetic_body = 7;
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright 2010-2019 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.common.library
|
||||
|
||||
import java.io.File
|
||||
import java.io.RandomAccessFile
|
||||
import java.nio.MappedByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.Files
|
||||
|
||||
data class DeclarationId(val id: Long, val isLocal: Boolean)
|
||||
|
||||
|
||||
fun File.map(mode: FileChannel.MapMode = FileChannel.MapMode.READ_ONLY,
|
||||
start: Long = 0, size: Long = -1): MappedByteBuffer {
|
||||
val file = RandomAccessFile(path,
|
||||
if (mode == FileChannel.MapMode.READ_ONLY) "r" else "rw")
|
||||
val fileSize = if (mode == FileChannel.MapMode.READ_ONLY)
|
||||
file.length() else size.also { assert(size != -1L) }
|
||||
val channel = file.channel
|
||||
return channel.map(mode, start, fileSize)
|
||||
.also { channel.close() } // Channel close closes the file also.
|
||||
}
|
||||
|
||||
class CombinedIrFileReader(file: File) {
|
||||
private val buffer = file.map(FileChannel.MapMode.READ_ONLY)
|
||||
private val declarationToOffsetSize = mutableMapOf<DeclarationId, Pair<Int, Int>>()
|
||||
|
||||
init {
|
||||
val declarationsCount = buffer.int
|
||||
for (i in 0 until declarationsCount) {
|
||||
val id = buffer.long
|
||||
val isLocal = buffer.int != 0
|
||||
val offset = buffer.int
|
||||
val size = buffer.int
|
||||
declarationToOffsetSize[DeclarationId(id, isLocal)] = offset to size
|
||||
}
|
||||
}
|
||||
|
||||
fun declarationBytes(id: DeclarationId): ByteArray {
|
||||
val offsetSize = declarationToOffsetSize[id] ?: throw Error("No declaration with $id here")
|
||||
val result = ByteArray(offsetSize.second)
|
||||
buffer.position(offsetSize.first)
|
||||
buffer.get(result, 0, offsetSize.second)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private const val SINGLE_INDEX_RECORD_SIZE = 20 // sizeof(Long) + 3 * sizeof(Int).
|
||||
private const val INDEX_HEADER_SIZE = 4 // sizeof(Int).
|
||||
|
||||
class CombinedIrFileWriter(val declarationCount: Int) {
|
||||
private var currentDeclaration = 0
|
||||
private var currentPosition = 0
|
||||
private val file = Files.createTempFile("ir", "").toFile()
|
||||
private val randomAccessFile = RandomAccessFile(file.path, "rw")
|
||||
|
||||
init {
|
||||
randomAccessFile.writeInt(declarationCount)
|
||||
assert(randomAccessFile.filePointer.toInt() == INDEX_HEADER_SIZE)
|
||||
for (i in 0 until declarationCount) {
|
||||
randomAccessFile.writeLong(-1) // id
|
||||
randomAccessFile.writeInt(-1) // isLocal
|
||||
randomAccessFile.writeInt(-1) // offset
|
||||
randomAccessFile.writeInt(-1) // size
|
||||
}
|
||||
currentPosition = randomAccessFile.filePointer.toInt()
|
||||
assert(currentPosition == INDEX_HEADER_SIZE + SINGLE_INDEX_RECORD_SIZE * declarationCount)
|
||||
}
|
||||
|
||||
fun skipDeclaration() {
|
||||
currentDeclaration++
|
||||
}
|
||||
|
||||
fun addDeclaration(id: DeclarationId, bytes: ByteArray) {
|
||||
randomAccessFile.seek((currentDeclaration * SINGLE_INDEX_RECORD_SIZE + INDEX_HEADER_SIZE).toLong())
|
||||
randomAccessFile.writeLong(id.id)
|
||||
randomAccessFile.writeInt(if (id.isLocal) 1 else 0)
|
||||
randomAccessFile.writeInt(currentPosition)
|
||||
randomAccessFile.writeInt(bytes.size)
|
||||
randomAccessFile.seek(currentPosition.toLong())
|
||||
randomAccessFile.write(bytes)
|
||||
assert(randomAccessFile.filePointer < Int.MAX_VALUE.toLong())
|
||||
currentPosition = randomAccessFile.filePointer.toInt()
|
||||
currentDeclaration++
|
||||
}
|
||||
|
||||
fun finishWriting(): File {
|
||||
assert(currentDeclaration == declarationCount)
|
||||
randomAccessFile.close()
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
|
||||
class DescriptorTable {
|
||||
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
|
||||
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
|
||||
descriptors.getOrPut(descriptor) { uniqId.index }
|
||||
}
|
||||
fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor]
|
||||
}
|
||||
|
||||
// TODO: We don't manage id clashes anyhow now.
|
||||
abstract class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: DescriptorTable, mangler: KotlinMangler): KotlinMangler by mangler {
|
||||
|
||||
private val builtInsTable = mutableMapOf<IrSymbol, UniqId>()
|
||||
private val table = mutableMapOf<IrDeclaration, UniqId>()
|
||||
val descriptors = descriptorTable
|
||||
protected abstract var currentIndex: Long
|
||||
|
||||
open fun loadKnownBuiltins(): Long {
|
||||
builtIns.knownBuiltins.forEach {
|
||||
builtInsTable[it] = UniqId(currentIndex++, false)
|
||||
}
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
fun uniqIdByDeclaration(value: IrDeclaration) = (value as? IrSymbolOwner)?.let { builtInsTable[it.symbol] } ?: table.getOrPut(value) {
|
||||
computeUniqIdByDeclaration(value)
|
||||
}
|
||||
|
||||
open protected fun computeUniqIdByDeclaration(value: IrDeclaration): UniqId {
|
||||
val index = if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
|
||||
!value.isExported()
|
||||
|| value is IrVariable
|
||||
|| (value is IrTypeParameter && value.parent !is IrClass)
|
||||
|| value is IrValueParameter
|
||||
|| value is IrAnonymousInitializerImpl
|
||||
) {
|
||||
UniqId(currentIndex++, true)
|
||||
} else {
|
||||
UniqId(value.hashedMangle, false)
|
||||
}
|
||||
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
// This is what we pre-populate tables with
|
||||
val IrBuiltIns.knownBuiltins
|
||||
get() = irBuiltInsSymbols
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.UniqIdKey
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.backend.common.serialization.resolveFakeOverrideMaybeAbstract
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
|
||||
abstract class DescriptorReferenceDeserializer(
|
||||
val currentModule: ModuleDescriptor,
|
||||
val resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>
|
||||
) : DescriptorUniqIdAware {
|
||||
|
||||
|
||||
protected abstract fun resolveSpecialDescriptor(fqn: FqName): DeclarationDescriptor
|
||||
protected abstract fun checkIfSpecialDescriptorId(id: Long): Boolean
|
||||
protected abstract fun getDescriptorIdOrNull(descriptor: DeclarationDescriptor): Long?
|
||||
|
||||
protected fun getContributedDescriptors(packageFqNameString: String, name: String): Collection<DeclarationDescriptor> {
|
||||
val packageFqName = packageFqNameString.let {
|
||||
if (it == "<root>") FqName.ROOT else FqName(it)
|
||||
}// TODO: would we store an empty string in the protobuf?
|
||||
|
||||
val memberScope = currentModule.getPackage(packageFqName).memberScope
|
||||
return getContributedDescriptors(memberScope, name)
|
||||
}
|
||||
|
||||
protected fun getContributedDescriptors(memberScope: MemberScope, name: String): Collection<DeclarationDescriptor> {
|
||||
val contributedNameString = if (name.startsWith("<get-") || name.startsWith("<set-")) {
|
||||
|
||||
name.substring(5, name.length - 1) // FIXME: rework serialization format.
|
||||
} else {
|
||||
name
|
||||
}
|
||||
val contributedName = Name.identifier(contributedNameString)
|
||||
return memberScope.getContributedFunctions(contributedName, NoLookupLocation.FROM_BACKEND) +
|
||||
memberScope.getContributedVariables(contributedName, NoLookupLocation.FROM_BACKEND) +
|
||||
listOfNotNull(memberScope.getContributedClassifier(contributedName, NoLookupLocation.FROM_BACKEND))
|
||||
|
||||
}
|
||||
|
||||
protected class ClassMembers(val defaultConstructor: ClassConstructorDescriptor?,
|
||||
val members: Map<Long, DeclarationDescriptor>,
|
||||
val realMembers: Map<Long, DeclarationDescriptor>)
|
||||
|
||||
private fun computeUniqIdIndex(descriptor: DeclarationDescriptor) = descriptor.getUniqId() ?: getDescriptorIdOrNull(descriptor)
|
||||
|
||||
protected fun getMembers(members: Collection<DeclarationDescriptor>): ClassMembers {
|
||||
val allMembersMap = mutableMapOf<Long, DeclarationDescriptor>()
|
||||
val realMembersMap = mutableMapOf<Long, DeclarationDescriptor>()
|
||||
var classConstructorDescriptor: ClassConstructorDescriptor? = null
|
||||
members.forEach { member ->
|
||||
if (member is ClassConstructorDescriptor)
|
||||
classConstructorDescriptor = member
|
||||
val realMembers =
|
||||
if (member is CallableMemberDescriptor && member.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
|
||||
member.resolveFakeOverrideMaybeAbstract()
|
||||
else
|
||||
setOf(member)
|
||||
|
||||
computeUniqIdIndex(member)?.let { allMembersMap[it] = member }
|
||||
realMembers.mapNotNull { computeUniqIdIndex(it) }.forEach { realMembersMap[it] = member }
|
||||
}
|
||||
return ClassMembers(classConstructorDescriptor, allMembersMap, realMembersMap)
|
||||
}
|
||||
|
||||
open fun deserializeDescriptorReference(
|
||||
packageFqNameString: String,
|
||||
classFqNameString: String,
|
||||
name: String,
|
||||
index: Long?,
|
||||
isEnumEntry: Boolean = false,
|
||||
isEnumSpecial: Boolean = false,
|
||||
isDefaultConstructor: Boolean = false,
|
||||
isFakeOverride: Boolean = false,
|
||||
isGetter: Boolean = false,
|
||||
isSetter: Boolean = false,
|
||||
isTypeParameter: Boolean = false
|
||||
): DeclarationDescriptor {
|
||||
val packageFqName = packageFqNameString.let {
|
||||
if (it == "<root>") FqName.ROOT else FqName(it)
|
||||
}// TODO: whould we store an empty string in the protobuf?
|
||||
|
||||
val classFqName = if (classFqNameString == "<root>") FqName.ROOT else FqName(classFqNameString)
|
||||
val protoIndex = index
|
||||
|
||||
val (clazz, members) = if (classFqNameString == "" || classFqNameString == "<root>") {
|
||||
Pair(null, getContributedDescriptors(packageFqNameString, name))
|
||||
} else {
|
||||
val clazz = currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, classFqName, false))!!
|
||||
Pair(clazz, getContributedDescriptors(clazz.unsubstitutedMemberScope, name) + clazz.getConstructors())
|
||||
}
|
||||
|
||||
// TODO: This is still native specific. Eliminate.
|
||||
if (packageFqNameString.startsWith("cnames.") || packageFqNameString.startsWith("objcnames.")) {
|
||||
val descriptor =
|
||||
currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, FqName(name), false))!!
|
||||
if (!descriptor.fqNameUnsafe.asString().startsWith("cnames") && !descriptor.fqNameUnsafe.asString().startsWith(
|
||||
"objcnames"
|
||||
)
|
||||
) {
|
||||
if (descriptor is DeserializedClassDescriptor) {
|
||||
val uniqId = UniqId(descriptor.getUniqId()!!, false)
|
||||
val newKey = UniqIdKey(null, uniqId)
|
||||
val oldKey = UniqIdKey(null, UniqId(protoIndex!!, false))
|
||||
|
||||
resolvedForwardDeclarations.put(oldKey, newKey)
|
||||
} else {
|
||||
/* ??? */
|
||||
}
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
|
||||
if (isEnumEntry) {
|
||||
val memberScope = (clazz as DeserializedClassDescriptor).getUnsubstitutedMemberScope()
|
||||
return memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND)!!
|
||||
}
|
||||
|
||||
if (isEnumSpecial) {
|
||||
return clazz!!.getStaticScope()
|
||||
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single()
|
||||
}
|
||||
|
||||
if (isTypeParameter) {
|
||||
return clazz!!.declaredTypeParameters.first { it.name.asString() == name }
|
||||
}
|
||||
|
||||
if (protoIndex?.let { checkIfSpecialDescriptorId(it) } == true) {
|
||||
return resolveSpecialDescriptor(packageFqName.child(Name.identifier(name)))
|
||||
}
|
||||
|
||||
val membersWithIndices = getMembers(members)
|
||||
|
||||
return when {
|
||||
isDefaultConstructor -> membersWithIndices.defaultConstructor
|
||||
|
||||
else -> {
|
||||
val map = if (isFakeOverride) membersWithIndices.realMembers else membersWithIndices.members
|
||||
map[protoIndex]?.let { member ->
|
||||
when {
|
||||
member is PropertyDescriptor && isSetter -> member.setter!!
|
||||
member is PropertyDescriptor && isGetter -> member.getter!!
|
||||
else -> member
|
||||
}
|
||||
}
|
||||
}
|
||||
} ?:
|
||||
error("Could not find serialized descriptor for index: ${index} ${packageFqName},${classFqName},${name}")
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.isReal
|
||||
import org.jetbrains.kotlin.ir.util.original
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of given method.
|
||||
*
|
||||
* TODO: this method is actually a part of resolve and probably duplicates another one
|
||||
*/
|
||||
fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimpleFunction {
|
||||
if (this.isReal) {
|
||||
return this
|
||||
}
|
||||
|
||||
val visited = mutableSetOf<IrSimpleFunction>()
|
||||
val realSupers = mutableSetOf<IrSimpleFunction>()
|
||||
|
||||
fun findRealSupers(function: IrSimpleFunction) {
|
||||
if (function in visited) return
|
||||
visited += function
|
||||
if (function.isReal) {
|
||||
realSupers += function
|
||||
} else {
|
||||
function.overriddenSymbols.forEach { findRealSupers(it.owner) }
|
||||
}
|
||||
}
|
||||
|
||||
findRealSupers(this)
|
||||
|
||||
if (realSupers.size > 1) {
|
||||
visited.clear()
|
||||
|
||||
fun excludeOverridden(function: IrSimpleFunction) {
|
||||
if (function in visited) return
|
||||
visited += function
|
||||
function.overriddenSymbols.forEach {
|
||||
realSupers.remove(it.owner)
|
||||
excludeOverridden(it.owner)
|
||||
}
|
||||
}
|
||||
|
||||
realSupers.toList().forEach { excludeOverridden(it) }
|
||||
}
|
||||
|
||||
return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT }
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of given method.
|
||||
*
|
||||
* TODO: this method is actually a part of resolve and probably duplicates another one
|
||||
*/
|
||||
internal fun IrSimpleFunction.resolveFakeOverrideMaybeAbstract() = this.resolveFakeOverride(allowAbstract = true)
|
||||
|
||||
internal fun IrProperty.resolveFakeOverrideMaybeAbstract() = this.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!
|
||||
|
||||
internal fun IrField.resolveFakeOverrideMaybeAbstract() = this.correspondingProperty!!.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!.backingField
|
||||
|
||||
val IrSimpleFunction.target: IrSimpleFunction
|
||||
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
|
||||
|
||||
val IrFunction.target: IrFunction get() = when (this) {
|
||||
is IrSimpleFunction -> this.target
|
||||
is IrConstructor -> this
|
||||
else -> error(this)
|
||||
}
|
||||
+1168
File diff suppressed because it is too large
Load Diff
+1188
File diff suppressed because it is too large
Load Diff
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
class SerializedIr (
|
||||
val module: ByteArray,
|
||||
val combinedDeclarationFilePath: String
|
||||
)
|
||||
+60898
File diff suppressed because it is too large
Load Diff
+445
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrLoopBase
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite.newInstance
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
|
||||
abstract class KotlinIrLinker(
|
||||
val logger: LoggingContext,
|
||||
val builtIns: IrBuiltIns,
|
||||
val symbolTable: SymbolTable,
|
||||
val exportedDependencies: List<ModuleDescriptor>,
|
||||
private val forwardModuleDescriptor: ModuleDescriptor?,
|
||||
private val firstKnownBuiltinsIndex: Long
|
||||
) : DescriptorUniqIdAware, IrDeserializer {
|
||||
|
||||
protected val deserializedSymbols = mutableMapOf<UniqIdKey, IrSymbol>()
|
||||
private val reachableTopLevels = mutableSetOf<UniqIdKey>()
|
||||
private val deserializedTopLevels = mutableSetOf<UniqIdKey>()
|
||||
|
||||
//TODO: This is Native specific. Eliminate me.
|
||||
private val forwardDeclarations = mutableSetOf<IrSymbol>()
|
||||
val resolvedForwardDeclarations = mutableMapOf<UniqIdKey, UniqIdKey>()
|
||||
|
||||
protected val deserializersForModules = mutableMapOf<ModuleDescriptor, IrDeserializerForModule>()
|
||||
val fileAnnotations = mutableMapOf<IrFile, KotlinIr.Annotations>()
|
||||
|
||||
inner class IrDeserializerForModule(
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val moduleProto: KotlinIr.IrModule,
|
||||
private val deserializationStrategy: DeserializationStrategy
|
||||
) : IrModuleDeserializer(logger, builtIns, symbolTable) {
|
||||
|
||||
private var moduleLoops = mutableMapOf<Int, IrLoopBase>()
|
||||
|
||||
// This is a heavy initializer
|
||||
val module = deserializeIrModuleHeader(moduleProto)
|
||||
|
||||
private fun referenceDeserializedSymbol(
|
||||
proto: KotlinIr.IrSymbolData,
|
||||
descriptor: DeclarationDescriptor?
|
||||
): IrSymbol = when (proto.kind) {
|
||||
KotlinIr.IrSymbolKind.ANONYMOUS_INIT_SYMBOL ->
|
||||
IrAnonymousInitializerSymbolImpl(
|
||||
descriptor as ClassDescriptor?
|
||||
?: WrappedClassDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.CLASS_SYMBOL ->
|
||||
symbolTable.referenceClass(
|
||||
descriptor as ClassDescriptor?
|
||||
?: WrappedClassDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.CONSTRUCTOR_SYMBOL ->
|
||||
symbolTable.referenceConstructor(
|
||||
descriptor as ClassConstructorDescriptor?
|
||||
?: WrappedClassConstructorDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.TYPE_PARAMETER_SYMBOL ->
|
||||
symbolTable.referenceTypeParameter(
|
||||
descriptor as TypeParameterDescriptor?
|
||||
?: WrappedTypeParameterDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.ENUM_ENTRY_SYMBOL ->
|
||||
symbolTable.referenceEnumEntry(
|
||||
descriptor as ClassDescriptor?
|
||||
?: WrappedEnumEntryDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.STANDALONE_FIELD_SYMBOL ->
|
||||
symbolTable.referenceField(WrappedFieldDescriptor())
|
||||
|
||||
KotlinIr.IrSymbolKind.FIELD_SYMBOL ->
|
||||
symbolTable.referenceField(
|
||||
descriptor as PropertyDescriptor?
|
||||
?: WrappedPropertyDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.FUNCTION_SYMBOL ->
|
||||
symbolTable.referenceSimpleFunction(
|
||||
descriptor as FunctionDescriptor?
|
||||
?: WrappedSimpleFunctionDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.VARIABLE_SYMBOL ->
|
||||
IrVariableSymbolImpl(
|
||||
descriptor as VariableDescriptor?
|
||||
?: WrappedVariableDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.VALUE_PARAMETER_SYMBOL ->
|
||||
IrValueParameterSymbolImpl(
|
||||
descriptor as ParameterDescriptor?
|
||||
?: WrappedValueParameterDescriptor()
|
||||
)
|
||||
KotlinIr.IrSymbolKind.RECEIVER_PARAMETER_SYMBOL ->
|
||||
IrValueParameterSymbolImpl(
|
||||
descriptor as ParameterDescriptor? ?: WrappedReceiverParameterDescriptor()
|
||||
)
|
||||
else -> TODO("Unexpected classifier symbol kind: ${proto.kind}")
|
||||
}
|
||||
|
||||
override fun deserializeIrSymbol(proto: KotlinIr.IrSymbol): IrSymbol {
|
||||
val symbolData = moduleProto.symbolTable.getSymbols(proto.index)
|
||||
return deserializeIrSymbolData(symbolData)
|
||||
}
|
||||
|
||||
override fun deserializeIrType(proto: KotlinIr.IrTypeIndex): IrType {
|
||||
val typeData = moduleProto.typeTable.getTypes(proto.index)
|
||||
return deserializeIrTypeData(typeData)
|
||||
}
|
||||
|
||||
override fun deserializeString(proto: KotlinIr.String): String =
|
||||
moduleProto.stringTable.getStrings(proto.index)
|
||||
|
||||
override fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoopBase) =
|
||||
moduleLoops.getOrPut(loopIndex, loopBuilder)
|
||||
|
||||
private fun deserializeIrSymbolData(proto: KotlinIr.IrSymbolData): IrSymbol {
|
||||
val key = proto.uniqId.uniqIdKey(moduleDescriptor)
|
||||
val topLevelKey = proto.topLevelUniqId.uniqIdKey(moduleDescriptor)
|
||||
|
||||
if (!deserializedTopLevels.contains(topLevelKey)) reachableTopLevels.add(topLevelKey)
|
||||
|
||||
val symbol = deserializedSymbols.getOrPut(key) {
|
||||
val descriptor = if (proto.hasDescriptorReference()) {
|
||||
deserializeDescriptorReference(proto.descriptorReference)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
resolvedForwardDeclarations[key]?.let {
|
||||
if (!deserializedTopLevels.contains(it)) reachableTopLevels.add(it) // Assuming forward declarations are always top levels.
|
||||
}
|
||||
|
||||
descriptor?.module?.let {
|
||||
if (!deserializersForModules.containsKey(it) && !it.isForwardDeclarationModule) {
|
||||
deserializeIrModuleHeader(it)!!
|
||||
}
|
||||
}
|
||||
|
||||
referenceDeserializedSymbol(proto, descriptor)
|
||||
}
|
||||
if (symbol.descriptor is ClassDescriptor &&
|
||||
symbol.descriptor !is WrappedDeclarationDescriptor<*> &&
|
||||
symbol.descriptor.module.isForwardDeclarationModule
|
||||
) {
|
||||
forwardDeclarations.add(symbol)
|
||||
}
|
||||
|
||||
return symbol
|
||||
}
|
||||
|
||||
override fun deserializeDescriptorReference(proto: KotlinIr.DescriptorReference) =
|
||||
descriptorReferenceDeserializer.deserializeDescriptorReference(
|
||||
deserializeString(proto.packageFqName),
|
||||
deserializeString(proto.classFqName),
|
||||
deserializeString(proto.name),
|
||||
if (proto.hasUniqId()) proto.uniqId.index else null,
|
||||
isEnumEntry = proto.isEnumEntry,
|
||||
isEnumSpecial = proto.isEnumSpecial,
|
||||
isDefaultConstructor = proto.isDefaultConstructor,
|
||||
isFakeOverride = proto.isFakeOverride,
|
||||
isGetter = proto.isGetter,
|
||||
isSetter = proto.isSetter,
|
||||
isTypeParameter = proto.isTypeParameter
|
||||
)
|
||||
// TODO: this is JS specific. Eliminate me.
|
||||
override fun getPrimitiveTypeOrNull(symbol: IrClassifierSymbol, hasQuestionMark: Boolean) =
|
||||
this@KotlinIrLinker.getPrimitiveTypeOrNull(symbol, hasQuestionMark)
|
||||
|
||||
fun deserializeIrFile(fileProto: KotlinIr.IrFile): IrFile {
|
||||
|
||||
val fileEntry = NaiveSourceBasedFileEntryImpl(
|
||||
this.deserializeString(fileProto.fileEntry.name),
|
||||
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
|
||||
)
|
||||
|
||||
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
|
||||
val fqName = this.deserializeString(fileProto.fqName)
|
||||
.let { if (it == "<root>") FqName.ROOT else FqName(it) }
|
||||
|
||||
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
|
||||
|
||||
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
|
||||
val file = IrFileImpl(fileEntry, symbol, fqName)
|
||||
|
||||
// We deserialize file annotations on first file use.
|
||||
fileAnnotations.put(file, fileProto.annotations)
|
||||
|
||||
fileProto.declarationIdList.forEach {
|
||||
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
|
||||
reversedFileIndex.put(uniqIdKey, file)
|
||||
}
|
||||
|
||||
when (deserializationStrategy) {
|
||||
DeserializationStrategy.EXPLICITLY_EXPORTED -> {
|
||||
fileProto.explicitlyExportedToCompilerList.forEach {
|
||||
val symbolProto = moduleProto.symbolTable.getSymbols(it.index)
|
||||
reachableTopLevels.add(symbolProto.topLevelUniqId.uniqIdKey(moduleDescriptor))
|
||||
}
|
||||
}
|
||||
DeserializationStrategy.ALL -> {
|
||||
fileProto.declarationIdList.forEach {
|
||||
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
|
||||
reachableTopLevels.add(uniqIdKey)
|
||||
}
|
||||
}
|
||||
else -> error("Unixpected deserialization strategy")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
fun deserializeIrModuleHeader(
|
||||
proto: KotlinIr.IrModule
|
||||
): IrModuleFragment {
|
||||
val files = proto.fileList.map {
|
||||
deserializeIrFile(it)
|
||||
}
|
||||
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
|
||||
module.patchDeclarationParents(null)
|
||||
return module
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this is JS specific. Eliminate me.
|
||||
protected open fun getPrimitiveTypeOrNull(symbol: IrClassifierSymbol, hasQuestionMark: Boolean): IrSimpleType? = null
|
||||
|
||||
protected abstract val descriptorReferenceDeserializer: DescriptorReferenceDeserializer
|
||||
|
||||
protected val indexAfterKnownBuiltins = loadKnownBuiltinSymbols()
|
||||
|
||||
private fun loadKnownBuiltinSymbols(): Long {
|
||||
var currentIndex = firstKnownBuiltinsIndex
|
||||
builtIns.knownBuiltins.forEach {
|
||||
deserializedSymbols[UniqIdKey(null, UniqId(currentIndex, isLocal = false))] = it
|
||||
assert(symbolTable.referenceSimpleFunction(it.descriptor) == it)
|
||||
currentIndex++
|
||||
}
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
private val ByteArray.codedInputStream: org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
get() {
|
||||
val codedInputStream = org.jetbrains.kotlin.protobuf.CodedInputStream.newInstance(this)
|
||||
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
|
||||
return codedInputStream
|
||||
}
|
||||
|
||||
private val reversedFileIndex = mutableMapOf<UniqIdKey, IrFile>()
|
||||
|
||||
private val UniqIdKey.moduleOfOrigin
|
||||
get() =
|
||||
this.moduleDescriptor ?: reversedFileIndex[this]?.packageFragmentDescriptor?.containingDeclaration
|
||||
|
||||
private fun deserializeTopLevelDeclaration(uniqIdKey: UniqIdKey): IrDeclaration {
|
||||
val proto = loadTopLevelDeclarationProto(uniqIdKey)
|
||||
return deserializersForModules[uniqIdKey.moduleOfOrigin]!!
|
||||
.deserializeDeclaration(proto, reversedFileIndex[uniqIdKey]!!)
|
||||
}
|
||||
|
||||
protected abstract fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId): ByteArray
|
||||
|
||||
private fun loadTopLevelDeclarationProto(uniqIdKey: UniqIdKey): KotlinIr.IrDeclaration {
|
||||
val stream = reader(uniqIdKey.moduleOfOrigin!!, uniqIdKey.uniqId).codedInputStream
|
||||
return KotlinIr.IrDeclaration.parseFrom(stream, newInstance())
|
||||
}
|
||||
|
||||
private fun deserializeFileAnnotationsIfFirstUse(module: ModuleDescriptor, file: IrFile) {
|
||||
val annotations = fileAnnotations[file] ?: return
|
||||
file.annotations.addAll(deserializersForModules[module]!!.deserializeAnnotations(annotations))
|
||||
fileAnnotations.remove(file)
|
||||
}
|
||||
|
||||
private fun deserializeAllReachableTopLevels() {
|
||||
do {
|
||||
val key = reachableTopLevels.first()
|
||||
val moduleOfOrigin = key.moduleOfOrigin
|
||||
|
||||
if (deserializedSymbols[key]?.isBound == true ||
|
||||
// The key.moduleOrigin is null for uniqIds that we haven't seen in any of the library headers.
|
||||
// Just skip it for now and handle it elsewhere.
|
||||
moduleOfOrigin == null
|
||||
) {
|
||||
|
||||
reachableTopLevels.remove(key)
|
||||
deserializedTopLevels.add(key)
|
||||
continue
|
||||
}
|
||||
|
||||
val reachable = deserializeTopLevelDeclaration(key)
|
||||
val file = reversedFileIndex[key]!!
|
||||
file.declarations.add(reachable)
|
||||
reachable.patchDeclarationParents(file)
|
||||
deserializeFileAnnotationsIfFirstUse(moduleOfOrigin, file)
|
||||
|
||||
reachableTopLevels.remove(key)
|
||||
deserializedTopLevels.add(key)
|
||||
} while (reachableTopLevels.isNotEmpty())
|
||||
}
|
||||
|
||||
private fun findDeserializedDeclarationForDescriptor(descriptor: DeclarationDescriptor): DeclarationDescriptor? {
|
||||
val topLevelDescriptor = descriptor.findTopLevelDescriptor()
|
||||
|
||||
// This is Native specific. Try to eliminate.
|
||||
if (topLevelDescriptor.module.isForwardDeclarationModule) return null
|
||||
|
||||
if (topLevelDescriptor !is DeserializedClassDescriptor && topLevelDescriptor !is DeserializedCallableMemberDescriptor) {
|
||||
return null
|
||||
}
|
||||
|
||||
val descriptorUniqId = topLevelDescriptor.getUniqId()
|
||||
?: error("could not get descriptor uniq id for $topLevelDescriptor")
|
||||
val uniqId = UniqId(descriptorUniqId, isLocal = false)
|
||||
val topLevelKey = UniqIdKey(topLevelDescriptor.module, uniqId)
|
||||
|
||||
// This top level descriptor doesn't have a serialized IR declaration.
|
||||
if (topLevelKey.moduleOfOrigin == null) return null
|
||||
|
||||
reachableTopLevels.add(topLevelKey)
|
||||
|
||||
deserializeAllReachableTopLevels()
|
||||
return topLevelDescriptor
|
||||
}
|
||||
|
||||
override fun findDeserializedDeclaration(symbol: IrSymbol): IrDeclaration? {
|
||||
|
||||
if (!symbol.isBound) {
|
||||
findDeserializedDeclarationForDescriptor(symbol.descriptor) ?: return null
|
||||
}
|
||||
|
||||
assert(symbol.isBound) {
|
||||
"findDeserializedDeclaration: symbol ${symbol} is unbound, descriptor = ${symbol.descriptor}, hash = ${symbol.descriptor.hashCode()}"
|
||||
}
|
||||
|
||||
return symbol.owner as IrDeclaration
|
||||
}
|
||||
|
||||
override fun findDeserializedDeclaration(propertyDescriptor: PropertyDescriptor): IrProperty? {
|
||||
val topLevelDesecriptor = findDeserializedDeclarationForDescriptor(propertyDescriptor)
|
||||
if (topLevelDesecriptor == null) return null
|
||||
|
||||
return symbolTable.propertyTable[propertyDescriptor]
|
||||
?: error("findDeserializedDeclaration: property descriptor $propertyDescriptor} is not present in propertyTable after deserialization}")
|
||||
}
|
||||
|
||||
// TODO: This is Native specific. Eliminate me.
|
||||
override fun declareForwardDeclarations() {
|
||||
if (forwardModuleDescriptor == null) return
|
||||
|
||||
val packageFragments = forwardDeclarations.map { it.descriptor.findPackage() }.distinct()
|
||||
|
||||
// We don't bother making a real IR module here, as we have no need in it any later.
|
||||
// All we need is just to declare forward declarations in the symbol table
|
||||
// In case you need a full fledged module, turn the forEach into a map and collect
|
||||
// produced files into an IrModuleFragment.
|
||||
|
||||
packageFragments.forEach { packageFragment ->
|
||||
val symbol = IrFileSymbolImpl(packageFragment)
|
||||
val file = IrFileImpl(NaiveSourceBasedFileEntryImpl("forward declarations pseudo-file"), symbol)
|
||||
val symbols = forwardDeclarations
|
||||
.filter { !it.isBound }
|
||||
.filter { it.descriptor.findPackage() == packageFragment }
|
||||
val declarations = symbols.map {
|
||||
|
||||
val classDescriptor = it.descriptor as ClassDescriptor
|
||||
val declaration = symbolTable.declareClass(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
|
||||
classDescriptor,
|
||||
classDescriptor.modality
|
||||
) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) }
|
||||
.also {
|
||||
it.parent = file
|
||||
}
|
||||
declaration
|
||||
|
||||
}
|
||||
file.declarations.addAll(declarations)
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeIrModuleHeader(
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
byteArray: ByteArray,
|
||||
deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED
|
||||
): IrModuleFragment {
|
||||
val deserializerForModule = deserializersForModules.getOrPut(moduleDescriptor) {
|
||||
val proto = KotlinIr.IrModule.parseFrom(byteArray.codedInputStream, newInstance())
|
||||
IrDeserializerForModule(moduleDescriptor, proto, deserializationStrategy)
|
||||
}
|
||||
// The IrModule and its IrFiles have been created during module initialization.
|
||||
return deserializerForModule.module
|
||||
}
|
||||
|
||||
abstract val ModuleDescriptor.irHeader: ByteArray?
|
||||
|
||||
fun deserializeIrModuleHeader(moduleDescriptor: ModuleDescriptor): IrModuleFragment? =
|
||||
// TODO: do we really allow libraries without any IR?
|
||||
moduleDescriptor.irHeader?.let { header ->
|
||||
// TODO: consider skip deserializing explicitly exported declarations for libraries.
|
||||
// Now it's not valid because of all dependencies that must be computed.
|
||||
val deserializationStrategy =
|
||||
if (exportedDependencies.contains(moduleDescriptor)) {
|
||||
DeserializationStrategy.ALL
|
||||
} else {
|
||||
DeserializationStrategy.EXPLICITLY_EXPORTED
|
||||
}
|
||||
deserializeIrModuleHeader(moduleDescriptor, header, deserializationStrategy)
|
||||
}
|
||||
}
|
||||
|
||||
enum class DeserializationStrategy {
|
||||
ONLY_REFERENCED,
|
||||
ALL,
|
||||
EXPLICITLY_EXPORTED
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
interface KotlinMangler {
|
||||
val String.hashMangle: Long
|
||||
val IrDeclaration.hashedMangle: Long
|
||||
fun IrDeclaration.isExported(): Boolean
|
||||
val IrFunction.functionName: String
|
||||
|
||||
}
|
||||
|
||||
abstract class KotlinManglerImpl: KotlinMangler {
|
||||
override val IrDeclaration.hashedMangle: Long
|
||||
get() = this.uniqSymbolName().hashMangle
|
||||
|
||||
|
||||
// We can't call "with (super) { this.isExported() }" in children.
|
||||
// So provide a hook.
|
||||
protected open fun IrDeclaration.isPlatformSpecificExported(): Boolean = false
|
||||
|
||||
/**
|
||||
* Defines whether the declaration is exported, i.e. visible from other modules.
|
||||
*
|
||||
* Exported declarations must have predictable and stable ABI
|
||||
* that doesn't depend on any internal transformations (e.g. IR lowering),
|
||||
* and so should be computable from the descriptor itself without checking a backend state.
|
||||
*/
|
||||
override tailrec fun IrDeclaration.isExported(): Boolean {
|
||||
// TODO: revise
|
||||
val descriptorAnnotations = this.descriptor.annotations
|
||||
|
||||
if (this.isPlatformSpecificExported()) return true
|
||||
|
||||
if (descriptorAnnotations.hasAnnotation(publishedApiAnnotation)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (this.isAnonymousObject)
|
||||
return false
|
||||
|
||||
if (this is IrConstructor && constructedClass.kind.isSingleton) {
|
||||
// Currently code generator can access the constructor of the singleton,
|
||||
// so ignore visibility of the constructor itself.
|
||||
return constructedClass.isExported()
|
||||
}
|
||||
|
||||
if (this is IrFunction) {
|
||||
val descriptor = this.descriptor
|
||||
// TODO: this code is required because accessor doesn't have a reference to property.
|
||||
if (descriptor is PropertyAccessorDescriptor) {
|
||||
val property = descriptor.correspondingProperty
|
||||
if (property.annotations.hasAnnotation(publishedApiAnnotation)) return true
|
||||
}
|
||||
}
|
||||
|
||||
val visibility = when (this) {
|
||||
is IrClass -> this.visibility
|
||||
is IrFunction -> this.visibility
|
||||
is IrProperty -> this.visibility
|
||||
is IrField -> this.visibility
|
||||
else -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* note: about INTERNAL - with support of friend modules we let frontend to deal with internal declarations.
|
||||
*/
|
||||
if (visibility != null && !visibility.isPublicAPI && visibility != Visibilities.INTERNAL) {
|
||||
// If the declaration is explicitly marked as non-public,
|
||||
// then it must not be accessible from other modules.
|
||||
return false
|
||||
}
|
||||
|
||||
val parent = this.parent
|
||||
if (parent is IrDeclaration) {
|
||||
return parent.isExported()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
|
||||
|
||||
protected fun acyclicTypeMangler(visited: MutableSet<IrTypeParameter>, type: IrType): String {
|
||||
val descriptor = (type.classifierOrNull as? IrTypeParameterSymbol)?.owner
|
||||
if (descriptor != null) {
|
||||
val upperBounds = if (visited.contains(descriptor)) "" else {
|
||||
|
||||
visited.add(descriptor)
|
||||
|
||||
descriptor.superTypes.map {
|
||||
val bound = acyclicTypeMangler(visited, it)
|
||||
if (bound == "kotlin.Any?") "" else "_$bound"
|
||||
}.joinToString("")
|
||||
}
|
||||
return "#GENERIC${if (type.isMarkedNullable()) "?" else ""}$upperBounds"
|
||||
}
|
||||
|
||||
var hashString = type.getClass()?.run { fqNameSafe.asString() } ?: "<dynamic>"
|
||||
|
||||
when (type) {
|
||||
is IrSimpleType -> {
|
||||
if (!type.arguments.isEmpty()) {
|
||||
hashString += "<${type.arguments.map {
|
||||
when (it) {
|
||||
is IrStarProjection -> "#STAR"
|
||||
is IrTypeProjection -> {
|
||||
val variance = it.variance.label
|
||||
val projection = if (variance == "") "" else "${variance}_"
|
||||
projection + acyclicTypeMangler(visited, it.type)
|
||||
}
|
||||
else -> error(it)
|
||||
}
|
||||
}.joinToString(",")}>"
|
||||
}
|
||||
|
||||
if (type.hasQuestionMark) hashString += "?"
|
||||
}
|
||||
!is IrDynamicType -> {
|
||||
error(type)
|
||||
}
|
||||
}
|
||||
return hashString
|
||||
}
|
||||
|
||||
protected fun typeToHashString(type: IrType) = acyclicTypeMangler(mutableSetOf(), type)
|
||||
|
||||
val IrValueParameter.extensionReceiverNamePart: String
|
||||
get() = "@${typeToHashString(this.type)}."
|
||||
|
||||
open val IrFunction.argsPart get() = this.valueParameters.map {
|
||||
"${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}"
|
||||
}.joinToString(";")
|
||||
|
||||
open val IrFunction.signature: String
|
||||
get() {
|
||||
val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
|
||||
val argsPart = this.argsPart
|
||||
// Distinguish value types and references - it's needed for calling virtual methods through bridges.
|
||||
// Also is function has type arguments - frontend allows exactly matching overrides.
|
||||
val signatureSuffix =
|
||||
when {
|
||||
this.typeParameters.isNotEmpty() -> "Generic"
|
||||
returnType.isInlined() -> "ValueType"
|
||||
!returnType.isUnitOrNullableUnit() -> typeToHashString(returnType)
|
||||
else -> ""
|
||||
}
|
||||
return "$extensionReceiverPart($argsPart)$signatureSuffix"
|
||||
}
|
||||
|
||||
open val IrFunction.platformSpecificFunctionName: String? get() = null
|
||||
|
||||
// TODO: rename to indicate that it has signature included
|
||||
override val IrFunction.functionName: String
|
||||
get() {
|
||||
// TODO: Again. We can't call super in children, so provide a hook for now.
|
||||
this.platformSpecificFunctionName ?. let { return it }
|
||||
val name = this.name.mangleIfInternal(this.module, this.visibility)
|
||||
return "$name$signature"
|
||||
}
|
||||
|
||||
fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility: Visibility): String =
|
||||
if (visibility != Visibilities.INTERNAL) {
|
||||
this.asString()
|
||||
} else {
|
||||
val moduleName = moduleDescriptor.name.asString()
|
||||
.let { it.substring(1, it.lastIndex) } // Remove < and >.
|
||||
|
||||
"$this\$$moduleName"
|
||||
}
|
||||
|
||||
val IrField.symbolName: String
|
||||
get() {
|
||||
val containingDeclarationPart = parent.fqNameSafe.let {
|
||||
if (it.isRoot) "" else "$it."
|
||||
}
|
||||
return "kfield:$containingDeclarationPart$name"
|
||||
|
||||
}
|
||||
|
||||
val IrClass.typeInfoSymbolName: String
|
||||
get() {
|
||||
assert(this.isExported())
|
||||
return "ktype:" + this.fqNameSafe.toString()
|
||||
}
|
||||
|
||||
val IrTypeParameter.symbolName: String
|
||||
get() {
|
||||
val containingDeclarationPart = parent.fqNameSafe
|
||||
return "ktypeparam:$containingDeclarationPart$name"
|
||||
}
|
||||
|
||||
// This is a little extension over what's used in real mangling
|
||||
// since some declarations never appear in the bitcode symbols.
|
||||
|
||||
internal fun IrDeclaration.uniqSymbolName(): String = when (this) {
|
||||
is IrFunction
|
||||
-> this.uniqFunctionName
|
||||
is IrProperty
|
||||
-> this.symbolName
|
||||
is IrClass
|
||||
-> this.typeInfoSymbolName
|
||||
is IrField
|
||||
-> this.symbolName
|
||||
is IrEnumEntry
|
||||
-> this.symbolName
|
||||
is IrTypeParameter
|
||||
-> this.symbolName
|
||||
else -> error("Unexpected exported declaration: $this")
|
||||
}
|
||||
|
||||
private val IrDeclarationParent.fqNameUnique: FqName
|
||||
get() = when (this) {
|
||||
is IrPackageFragment -> this.fqName
|
||||
is IrDeclaration -> this.parent.fqNameUnique.child(this.uniqName)
|
||||
else -> error(this)
|
||||
}
|
||||
|
||||
private val IrDeclaration.uniqName: Name
|
||||
get() = when (this) {
|
||||
is IrSimpleFunction -> Name.special("<${this.uniqFunctionName}>")
|
||||
else -> this.name
|
||||
}
|
||||
|
||||
private val IrProperty.symbolName: String
|
||||
get() {
|
||||
val extensionReceiver: String = getter!!.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
|
||||
|
||||
val containingDeclarationPart = parent.fqNameSafe.let {
|
||||
if (it.isRoot) "" else "$it."
|
||||
}
|
||||
return "kprop:$containingDeclarationPart$extensionReceiver$name"
|
||||
}
|
||||
|
||||
private val IrEnumEntry.symbolName: String
|
||||
get() {
|
||||
val containingDeclarationPart = parent.fqNameSafe.let {
|
||||
if (it.isRoot) "" else "$it."
|
||||
}
|
||||
return "kenumentry:$containingDeclarationPart$name"
|
||||
}
|
||||
|
||||
// This is basicly the same as .symbolName, but disambiguates external functions with the same C name.
|
||||
// In addition functions appearing in fq sequence appear as <full signature>.
|
||||
private val IrFunction.uniqFunctionName: String
|
||||
get() {
|
||||
val parent = this.parent
|
||||
|
||||
val containingDeclarationPart = parent.fqNameUnique.let {
|
||||
if (it.isRoot) "" else "$it."
|
||||
}
|
||||
|
||||
return "kfun:$containingDeclarationPart#$functionName"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
|
||||
internal val DeclarationDescriptor.isExpectMember: Boolean
|
||||
get() = this is MemberDescriptor && this.isExpect
|
||||
|
||||
internal val DeclarationDescriptor.isSerializableExpectClass: Boolean
|
||||
get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this)
|
||||
|
||||
internal tailrec fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
|
||||
return if (this is PackageFragmentDescriptor) this
|
||||
else this.containingDeclaration!!.findPackage()
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.findTopLevelDescriptor(): DeclarationDescriptor {
|
||||
return if (this.containingDeclaration is org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor) this.propertyIfAccessor
|
||||
else this.containingDeclaration!!.findTopLevelDescriptor()
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: this method is actually a part of resolve and probably duplicates another one
|
||||
*/
|
||||
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverrideMaybeAbstract(): Set<T> {
|
||||
if (this.kind.isReal) {
|
||||
return setOf(this)
|
||||
} else {
|
||||
val overridden = OverridingUtil.getOverriddenDeclarations(this)
|
||||
val filtered = OverridingUtil.filterOutOverridden(overridden)
|
||||
// TODO: is it correct to take first?
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return filtered as Set<T>
|
||||
}
|
||||
}
|
||||
|
||||
// This is Native specific. Try to eliminate.
|
||||
val ModuleDescriptor.isForwardDeclarationModule get() =
|
||||
name == Name.special("<forward declarations>")
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.isAccessor
|
||||
import org.jetbrains.kotlin.ir.util.isGetter
|
||||
import org.jetbrains.kotlin.ir.util.isSetter
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
|
||||
|
||||
open class DescriptorReferenceSerializer(
|
||||
val declarationTable: DeclarationTable,
|
||||
val serializeString: (String) -> KotlinIr.String,
|
||||
mangler: KotlinMangler): KotlinMangler by mangler {
|
||||
|
||||
// Not all exported descriptors are deserialized, some a synthesized anew during metadata deserialization.
|
||||
// Those created descriptors can't carry the uniqIdIndex, since it is available only for deserialized descriptors.
|
||||
// So we record the uniq id of some other "discoverable" descriptor for which we know for sure that it will be
|
||||
// available as deserialized descriptor, plus the path to find the needed descriptor from that one.
|
||||
fun serializeDescriptorReference(declaration: IrDeclaration): KotlinIr.DescriptorReference? {
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
|
||||
if (!declaration.isExported() &&
|
||||
!((declaration as? IrDeclarationWithVisibility)?.visibility == Visibilities.INVISIBLE_FAKE)) {
|
||||
return null
|
||||
}
|
||||
if (declaration is IrAnonymousInitializer) return null
|
||||
|
||||
if (descriptor is ParameterDescriptor ||
|
||||
(descriptor is VariableDescriptor && descriptor !is PropertyDescriptor)
|
||||
|| (declaration is IrTypeParameter && declaration.parent !is IrClass)
|
||||
) return null
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration!!
|
||||
|
||||
val (packageFqName, classFqName) = when (containingDeclaration) {
|
||||
is ClassDescriptor -> {
|
||||
val classId = containingDeclaration.classId ?: return null
|
||||
Pair(classId.packageFqName.toString(), classId.relativeClassName.toString())
|
||||
}
|
||||
is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "")
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val isAccessor = declaration.isAccessor
|
||||
val isBackingField = declaration is IrField && declaration.correspondingProperty != null
|
||||
val isFakeOverride = declaration.origin == IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
val isDefaultConstructor =
|
||||
descriptor is ClassConstructorDescriptor && containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.OBJECT
|
||||
val isEnumEntry = descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY
|
||||
val isEnumSpecial = declaration.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER
|
||||
val isTypeParameter = declaration is IrTypeParameter && declaration.parent is IrClass
|
||||
|
||||
|
||||
val realDeclaration = if (isFakeOverride) {
|
||||
when (declaration) {
|
||||
is IrSimpleFunction -> declaration.resolveFakeOverrideMaybeAbstract()
|
||||
is IrField -> declaration.resolveFakeOverrideMaybeAbstract()
|
||||
is IrProperty -> declaration.resolveFakeOverrideMaybeAbstract()
|
||||
else -> error("Unexpected fake override declaration")
|
||||
}
|
||||
} else {
|
||||
declaration
|
||||
}
|
||||
|
||||
val discoverableDescriptorsDeclaration: IrDeclaration? = if (isAccessor) {
|
||||
(realDeclaration as IrSimpleFunction).correspondingProperty!!
|
||||
} else if (isBackingField) {
|
||||
(realDeclaration as IrField).correspondingProperty!!
|
||||
} else if (isDefaultConstructor || isEnumEntry) {
|
||||
null
|
||||
} else {
|
||||
realDeclaration
|
||||
}
|
||||
|
||||
val uniqId = discoverableDescriptorsDeclaration?.let { declarationTable.uniqIdByDeclaration(it) }
|
||||
uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) }
|
||||
|
||||
val proto = KotlinIr.DescriptorReference.newBuilder()
|
||||
.setPackageFqName(serializeString(packageFqName))
|
||||
.setClassFqName(serializeString(classFqName))
|
||||
.setName(serializeString(descriptor.name.toString()))
|
||||
|
||||
if (uniqId != null) proto.setUniqId(protoUniqId(uniqId))
|
||||
|
||||
if (isFakeOverride) {
|
||||
proto.setIsFakeOverride(true)
|
||||
}
|
||||
|
||||
if (isBackingField) {
|
||||
proto.setIsBackingField(true)
|
||||
}
|
||||
|
||||
if (isAccessor) {
|
||||
if (declaration.isGetter)
|
||||
proto.setIsGetter(true)
|
||||
else if (declaration.isSetter)
|
||||
proto.setIsSetter(true)
|
||||
else
|
||||
error("A property accessor which is neither a getter, nor a setter: $descriptor")
|
||||
} else if (isDefaultConstructor) {
|
||||
proto.setIsDefaultConstructor(true)
|
||||
} else if (isEnumEntry) {
|
||||
proto.setIsEnumEntry(true)
|
||||
} else if (isEnumSpecial) {
|
||||
proto.setIsEnumSpecial(true)
|
||||
} else if (isTypeParameter) {
|
||||
proto.setIsTypeParameter(true)
|
||||
}
|
||||
|
||||
return proto.build()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
//import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataProtoBuf
|
||||
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
|
||||
// This is an abstract uniqIdIndex any serialized IR declarations gets.
|
||||
// It is either isLocal and then just gets and ordinary number within its module.
|
||||
// Or is visible across modules and then gets a hash of mangled name as its index.
|
||||
data class UniqId (
|
||||
val index: Long,
|
||||
val isLocal: Boolean
|
||||
)
|
||||
|
||||
// isLocal=true in UniqId is good while we dealing with a single current module.
|
||||
// To disambiguate module local declarations of different modules we use UniqIdKey.
|
||||
// It has moduleDescriptor specified for isLocal=true uniqIds.
|
||||
|
||||
// TODO: make sure UniqId is really uniq for any global declaration
|
||||
|
||||
data class UniqIdKey private constructor(val uniqId: UniqId, val moduleDescriptor: ModuleDescriptor?) {
|
||||
constructor(moduleDescriptor: ModuleDescriptor?, uniqId: UniqId)
|
||||
: this(uniqId, if (uniqId.isLocal) moduleDescriptor!! else null)
|
||||
}
|
||||
|
||||
fun protoUniqId(uniqId: UniqId): KotlinIr.UniqId =
|
||||
KotlinIr.UniqId.newBuilder()
|
||||
.setIndex(uniqId.index)
|
||||
.setIsLocal(uniqId.isLocal)
|
||||
.build()
|
||||
|
||||
fun KotlinIr.UniqId.uniqId(): UniqId = UniqId(this.index, this.isLocal)
|
||||
fun KotlinIr.UniqId.uniqIdKey(moduleDescriptor: ModuleDescriptor) =
|
||||
UniqIdKey(moduleDescriptor, this.uniqId())
|
||||
|
||||
fun <T, M:GeneratedMessageLite.ExtendableMessage<M>> M.tryGetExtension(extension: GeneratedMessageLite.GeneratedExtension<M, T>)
|
||||
= if (this.hasExtension(extension)) this.getExtension<T>(extension) else null
|
||||
|
||||
interface DescriptorUniqIdAware {
|
||||
fun DeclarationDescriptor.getUniqId(): Long?
|
||||
}
|
||||
|
||||
//val UniqId.declarationFileName: String get() = "$index${if (isLocal) "L" else "G"}.kjd"
|
||||
Reference in New Issue
Block a user