blob: a014c585c82618c888e987a6096c75293108092b [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';
/// Helper for looking up object library data from an [ir.Component] node.
class ComponentLookup {
final ir.Component _component;
/// Cache of [_LibraryData] for libraries in [_component].
Map<Uri, _LibraryData> _libraryMap;
ComponentLookup(this._component);
/// Returns the [_LibraryData] object for the library with the [canonicalUri].
_LibraryData getLibraryDataByUri(Uri canonicalUri) {
if (_libraryMap == null) {
_libraryMap = {};
for (ir.Library library in _component.libraries) {
_libraryMap[library.importUri] = new _LibraryData(library);
}
}
_LibraryData data = _libraryMap[canonicalUri];
assert(data != null, "No library found for $canonicalUri.");
return data;
}
}
/// Returns a name uniquely identifying a member within its enclosing library
/// or class.
String _computeMemberName(ir.Member member) {
if (member.name.isPrivate &&
member.name.libraryName != member.enclosingLibrary.reference) {
// TODO(33732): Handle noSuchMethod forwarders for private members from
// other libraries.
return null;
}
String name = member.name.name;
if (member is ir.Constructor) {
name = '.$name';
} else if (member is ir.Procedure) {
if (member.kind == ir.ProcedureKind.Factory) {
name = '.$name';
} else if (member.kind == ir.ProcedureKind.Setter) {
name += "=";
}
}
return name;
}
/// Helper for looking up classes and members from an [ir.Library] node.
class _LibraryData {
/// The [ir.Library] that defines the library.
final ir.Library node;
/// Cache of [_ClassData] for classes in this library.
Map<String, _ClassData> _classesByName;
Map<ir.Class, _ClassData> _classesByNode;
/// Cache of [ir.Typedef] nodes for typedefs in this library.
Map<String, ir.Typedef> _typedefs;
/// Cache of [_MemberData] for members in this library.
Map<String, _MemberData> _membersByName;
Map<ir.Member, _MemberData> _membersByNode;
_LibraryData(this.node);
void _ensureClasses() {
if (_classesByName == null) {
_classesByName = {};
_classesByNode = {};
for (ir.Class cls in node.classes) {
assert(
!_classesByName.containsKey(cls.name),
"Duplicate class '${cls.name}' in $_classesByName "
"trying to add $cls.");
assert(
!_classesByNode.containsKey(cls),
"Duplicate class '${cls.name}' in $_classesByNode "
"trying to add $cls.");
_classesByNode[cls] = _classesByName[cls.name] = new _ClassData(cls);
}
}
}
/// Returns the [_ClassData] for the class [name] in this library.
_ClassData lookupClassByName(String name) {
_ensureClasses();
return _classesByName[name];
}
/// Returns the [_ClassData] for the class [node] in this library.
_ClassData lookupClassByNode(ir.Class node) {
_ensureClasses();
return _classesByNode[node];
}
ir.Typedef lookupTypedef(String name) {
if (_typedefs == null) {
_typedefs = {};
for (ir.Typedef typedef in node.typedefs) {
assert(
!_typedefs.containsKey(typedef.name),
"Duplicate typedef '${typedef.name}' in $_typedefs "
"trying to add $typedef.");
_typedefs[typedef.name] = typedef;
}
}
return _typedefs[name];
}
void _ensureMembers() {
if (_membersByName == null) {
_membersByName = {};
_membersByNode = {};
for (ir.Member member in node.members) {
String name = _computeMemberName(member);
if (name == null) continue;
assert(
!_membersByName.containsKey(name),
"Duplicate member '$name' in $_membersByName "
"trying to add $member.");
assert(
!_membersByNode.containsKey(member),
"Duplicate member '$name' in $_membersByNode "
"trying to add $member.");
_membersByNode[member] = _membersByName[name] = new _MemberData(member);
}
}
}
/// Returns the [_MemberData] for the member uniquely identified by [name] in
/// this library.
_MemberData lookupMemberDataByName(String name) {
_ensureMembers();
return _membersByName[name];
}
/// Returns the [_MemberData] for the member [node] in this library.
_MemberData lookupMemberDataByNode(ir.Member node) {
_ensureMembers();
return _membersByNode[node];
}
@override
String toString() => '_LibraryData($node(${identityHashCode(node)}))';
}
/// Helper for looking up members from an [ir.Class] node.
class _ClassData {
/// The [ir.Class] that defines the class.
final ir.Class node;
/// Cache of [_MemberData] for members in this class.
Map<String, _MemberData> _membersByName;
Map<ir.Member, _MemberData> _membersByNode;
_ClassData(this.node);
void _ensureMembers() {
if (_membersByName == null) {
_membersByName = {};
_membersByNode = {};
for (ir.Member member in node.members) {
String name = _computeMemberName(member);
if (name == null) continue;
assert(
!_membersByName.containsKey(name),
"Duplicate member '$name' in $_membersByName "
"trying to add $member.");
assert(
!_membersByNode.containsKey(member),
"Duplicate member '$name' in $_membersByNode "
"trying to add $member.");
_membersByNode[member] = _membersByName[name] = new _MemberData(member);
}
}
}
/// Returns the [_MemberData] for the member uniquely identified by [name] in
/// this class.
_MemberData lookupMemberDataByName(String name) {
_ensureMembers();
return _membersByName[name];
}
/// Returns the [_MemberData] for the member [node] in this class.
_MemberData lookupMemberDataByNode(ir.Member node) {
_ensureMembers();
return _membersByNode[node];
}
@override
String toString() => '_ClassData($node(${identityHashCode(node)}))';
}
/// Helper for looking up child [ir.TreeNode]s of a [ir.Member] node.
class _MemberData {
/// The [ir.Member] that defines the member.
final ir.Member node;
/// Cached index to [ir.TreeNode] map used for deserialization of
/// [ir.TreeNode]s.
Map<int, ir.TreeNode> _indexToNodeMap;
/// Cached [ir.TreeNode] to index map used for serialization of
/// [ir.TreeNode]s.
Map<ir.TreeNode, int> _nodeToIndexMap;
/// Cached [ir.ConstantExpression] to [_ConstantNodeIndexerVisitor] map used
/// for fast serialization/deserialization of constant references.
Map<ir.ConstantExpression, _ConstantNodeIndexerVisitor> _constantIndexMap;
_MemberData(this.node);
void _ensureMaps() {
if (_indexToNodeMap == null) {
_indexToNodeMap = {};
_nodeToIndexMap = {};
node.accept(
new _TreeNodeIndexerVisitor(_indexToNodeMap, _nodeToIndexMap));
}
}
_ConstantNodeIndexerVisitor _createConstantIndexer(
ir.ConstantExpression node) {
_ConstantNodeIndexerVisitor indexer = new _ConstantNodeIndexerVisitor();
node.constant.accept(indexer);
return indexer;
}
ir.Constant getConstantByIndex(ir.ConstantExpression node, int index) {
_constantIndexMap ??= {};
_ConstantNodeIndexerVisitor indexer =
_constantIndexMap[node] ??= _createConstantIndexer(node);
return indexer.getConstant(index);
}
int getIndexByConstant(ir.ConstantExpression node, ir.Constant constant) {
_constantIndexMap ??= {};
_ConstantNodeIndexerVisitor indexer =
_constantIndexMap[node] ??= _createConstantIndexer(node);
return indexer.getIndex(constant);
}
/// Returns the [ir.TreeNode] corresponding to [index] in this member.
ir.TreeNode getTreeNodeByIndex(int index) {
_ensureMaps();
ir.TreeNode treeNode = _indexToNodeMap[index];
assert(treeNode != null, "No TreeNode found for index $index in $node.");
return treeNode;
}
/// Returns the index corresponding to [ir.TreeNode] in this member.
int getIndexByTreeNode(ir.TreeNode node) {
_ensureMaps();
int index = _nodeToIndexMap[node];
assert(index != null, "No index found for ${node.runtimeType}.");
return index;
}
@override
String toString() => '_MemberData($node(${identityHashCode(node)}))';
}