blob: b63b9a2c3c4076f27ede830810a05d73bb35162a [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of 'serialization.dart';
/// Base implementation of [DataSink] using [DataSinkMixin] to implement
/// convenience methods.
abstract class AbstractDataSink extends DataSinkMixin implements DataSink {
/// If `true`, serialization of every data kind is preceded by a [DataKind]
/// value.
///
/// This is used for debugging data inconsistencies between serialization
/// and deserialization.
final bool useDataKinds;
/// Visitor used for serializing [DartType]s.
DartTypeWriter _dartTypeWriter;
/// Stack of tags used when [useDataKinds] is `true` to help debugging section
/// inconsistencies between serialization and deserialization.
List<String> _tags;
/// Map of [_MemberData] object for serialized kernel member nodes.
Map<ir.Member, _MemberData> _memberData = {};
AbstractDataSink({this.useDataKinds: false}) {
_dartTypeWriter = new DartTypeWriter(this);
}
void begin(String tag) {
if (useDataKinds) {
_tags ??= <String>[];
_tags.add(tag);
_begin(tag);
}
}
void end(Object tag) {
if (useDataKinds) {
_end(tag);
String existingTag = _tags.removeLast();
assert(existingTag == tag,
"Unexpected tag end. Expected $existingTag, found $tag.");
}
}
@override
void writeSourceSpan(SourceSpan value) {
_writeDataKind(DataKind.sourceSpan);
_writeUri(value.uri);
_writeInt(value.begin);
_writeInt(value.end);
}
@override
void writeDartType(DartType value, {bool allowNull: false}) {
_writeDataKind(DataKind.dartType);
_writeDartType(value, [], allowNull: allowNull);
}
void _writeDartType(
DartType value, List<FunctionTypeVariable> functionTypeVariables,
{bool allowNull: false}) {
if (value == null) {
if (!allowNull) {
throw new UnsupportedError("Missing DartType is not allowed.");
}
writeEnum(DartTypeKind.none);
} else {
_dartTypeWriter.visit(value, functionTypeVariables);
}
}
@override
void writeMemberNode(ir.Member value) {
_writeDataKind(DataKind.memberNode);
_writeMemberNode(value);
}
void _writeMemberNode(ir.Member value) {
ir.Class cls = value.enclosingClass;
if (cls != null) {
_writeEnum(MemberContextKind.cls);
_writeClassNode(cls);
_writeString(_computeMemberName(value));
} else {
_writeEnum(MemberContextKind.library);
_writeLibraryNode(value.enclosingLibrary);
_writeString(_computeMemberName(value));
}
}
@override
void writeClassNode(ir.Class value) {
_writeDataKind(DataKind.classNode);
_writeClassNode(value);
}
void _writeClassNode(ir.Class value) {
_writeLibraryNode(value.enclosingLibrary);
_writeString(value.name);
}
@override
void writeLibraryNode(ir.Library value) {
_writeDataKind(DataKind.libraryNode);
_writeLibraryNode(value);
}
void _writeLibraryNode(ir.Library value) {
_writeUri(value.importUri);
}
@override
void writeEnum(dynamic value) {
_writeDataKind(DataKind.enumValue);
_writeEnum(value);
}
@override
void writeBool(bool value) {
assert(value != null);
_writeDataKind(DataKind.bool);
_writeInt(value ? 1 : 0);
}
@override
void writeUri(Uri value) {
assert(value != null);
_writeDataKind(DataKind.uri);
_writeUri(value);
}
@override
void writeString(String value) {
assert(value != null);
_writeDataKind(DataKind.string);
_writeString(value);
}
@override
void writeInt(int value) {
assert(value != null);
assert(value >= 0 && value >> 30 == 0);
_writeDataKind(DataKind.int);
_writeInt(value);
}
void writeTreeNode(ir.TreeNode value) {
_writeDataKind(DataKind.treeNode);
_writeTreeNode(value);
}
void _writeTreeNode(ir.TreeNode value) {
if (value is ir.Class) {
_writeEnum(_TreeNodeKind.cls);
_writeClassNode(value);
} else if (value is ir.Member) {
_writeEnum(_TreeNodeKind.member);
_writeMemberNode(value);
} else if (value is ir.VariableDeclaration &&
value.parent is ir.FunctionDeclaration) {
_writeEnum(_TreeNodeKind.functionDeclarationVariable);
_writeTreeNode(value.parent);
} else if (value is ir.FunctionNode) {
_writeEnum(_TreeNodeKind.functionNode);
_writeFunctionNode(value);
} else if (value is ir.TypeParameter) {
_writeEnum(_TreeNodeKind.typeParameter);
_writeTypeParameter(value);
} else {
_writeEnum(_TreeNodeKind.node);
ir.TreeNode member = value;
while (member is! ir.Member) {
if (member == null) {
throw new UnsupportedError("No enclosing member of TreeNode "
"$value (${value.runtimeType})");
}
member = member.parent;
}
_writeMemberNode(member);
_MemberData memberData = _memberData[member] ??= new _MemberData(member);
int index = memberData.getIndexByTreeNode(value);
assert(index != null, "No index found for ${value.runtimeType}.");
_writeInt(index);
}
}
void _writeFunctionNode(ir.FunctionNode value) {
ir.TreeNode parent = value.parent;
if (parent is ir.Procedure) {
_writeEnum(_FunctionNodeKind.procedure);
_writeMemberNode(parent);
} else if (parent is ir.Constructor) {
_writeEnum(_FunctionNodeKind.constructor);
_writeMemberNode(parent);
} else if (parent is ir.FunctionExpression) {
_writeEnum(_FunctionNodeKind.functionExpression);
_writeTreeNode(parent);
} else if (parent is ir.FunctionDeclaration) {
_writeEnum(_FunctionNodeKind.functionDeclaration);
_writeTreeNode(parent);
} else {
throw new UnsupportedError(
"Unsupported FunctionNode parent ${parent.runtimeType}");
}
}
@override
void writeTypeParameterNode(ir.TypeParameter value) {
_writeDataKind(DataKind.typeParameterNode);
_writeTypeParameter(value);
}
void _writeTypeParameter(ir.TypeParameter value) {
ir.TreeNode parent = value.parent;
if (parent is ir.Class) {
_writeEnum(_TypeParameterKind.cls);
_writeClassNode(parent);
_writeInt(parent.typeParameters.indexOf(value));
} else if (parent is ir.FunctionNode) {
_writeEnum(_TypeParameterKind.functionNode);
_writeFunctionNode(parent);
_writeInt(parent.typeParameters.indexOf(value));
} else {
throw new UnsupportedError(
"Unsupported TypeParameter parent ${parent.runtimeType}");
}
}
void _writeDataKind(DataKind kind) {
if (useDataKinds) _writeEnum(kind);
}
void writeLibrary(IndexedLibrary value) {
writeInt(value.libraryIndex);
}
void writeClass(IndexedClass value) {
writeInt(value.classIndex);
}
void writeTypedef(IndexedTypedef value) {
writeInt(value.typedefIndex);
}
void writeMember(IndexedMember value) {
writeInt(value.memberIndex);
}
void writeLocal(Local local) {
if (local is JLocal) {
writeEnum(LocalKind.jLocal);
writeMember(local.memberContext);
writeInt(local.localIndex);
} else if (local is ThisLocal) {
writeEnum(LocalKind.thisLocal);
writeClass(local.enclosingClass);
} else if (local is BoxLocal) {
writeEnum(LocalKind.boxLocal);
writeClass(local.container);
} else if (local is AnonymousClosureLocal) {
writeEnum(LocalKind.anonymousClosureLocal);
writeClass(local.closureClass);
} else if (local is TypeVariableLocal) {
writeEnum(LocalKind.typeVariableLocal);
writeDartType(local.typeVariable);
} else {
throw new UnsupportedError("Unsupported local ${local.runtimeType}");
}
}
@override
void writeConstant(ConstantValue value) {
_writeDataKind(DataKind.constant);
_writeConstant(value);
}
void _writeConstant(ConstantValue value) {
_writeEnum(value.kind);
switch (value.kind) {
case ConstantValueKind.BOOL:
BoolConstantValue constant = value;
writeBool(constant.boolValue);
break;
case ConstantValueKind.INT:
IntConstantValue constant = value;
writeString(constant.intValue.toString());
break;
case ConstantValueKind.DOUBLE:
DoubleConstantValue constant = value;
ByteData data = new ByteData(8);
data.setFloat64(0, constant.doubleValue);
writeInt(data.getUint16(0));
writeInt(data.getUint16(2));
writeInt(data.getUint16(4));
writeInt(data.getUint16(6));
break;
case ConstantValueKind.STRING:
StringConstantValue constant = value;
writeString(constant.stringValue);
break;
case ConstantValueKind.NULL:
break;
default:
// TODO(johnniwinther): Support remaining constant values.
throw new UnsupportedError(
"Unexpected constant value kind ${value.kind}.");
}
}
/// Actual serialization of a section begin tag, implemented by subclasses.
void _begin(String tag);
/// Actual serialization of a section end tag, implemented by subclasses.
void _end(String tag);
/// Actual serialization of a URI value, implemented by subclasses.
void _writeUri(Uri value);
/// Actual serialization of a String value, implemented by subclasses.
void _writeString(String value);
/// Actual serialization of a non-negative integer value, implemented by
/// subclasses.
void _writeInt(int value);
/// Actual serialization of an enum value, implemented by subclasses.
void _writeEnum(dynamic value);
}