blob: 570b5494aa8cb9bc8cc76dfd99d8797d6e4d9a73 [file] [log] [blame]
// Copyright (c) 2023, 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.
import 'package:kernel/ast.dart';
/// Repository for persistent closure IDs.
class ClosureIdMetadataRepository extends MetadataRepository<int> {
static const String repositoryTag = 'vm.closure-id';
@override
String get tag => repositoryTag;
// For a LocalFunction: id within an enclosing Member,
// with 0 reserved for the tear-off of the Member.
//
// For a Member: number of nested closures.
@override
final Map<TreeNode, int> mapping = {};
@override
void writeToBinary(int metadata, Node node, BinarySink sink) {
sink.writeUInt30(metadata);
}
@override
int readFromBinary(Node node, BinarySource source) {
return source.readUInt30();
}
/// Return closure ID within the enclosing [Member], or -1
/// if closure was not indexed.
///
/// Closures should be indexed within enclosing [Member]
/// using [indexClosures].
int getClosureId(LocalFunction closure) => mapping[closure] ?? -1;
/// Assign IDs for all closures within [member].
void indexClosures(Member member) {
if (mapping.containsKey(member)) {
return;
}
_ClosureIndexer indexer = _ClosureIndexer(this, member);
member.accept(indexer);
mapping[member] = indexer.index - _ClosureIndexer.firstClosureIndex;
}
}
class _ClosureIndexer extends RecursiveVisitor {
// Zero is reserved for tear-offs.
static int firstClosureIndex = 1;
final ClosureIdMetadataRepository _repository;
final Member member;
int index = firstClosureIndex;
_ClosureIndexer(this._repository, this.member);
@override
void visitFunctionDeclaration(FunctionDeclaration node) =>
_visitLocalFunction(node);
@override
void visitFunctionExpression(FunctionExpression node) =>
_visitLocalFunction(node);
void _visitLocalFunction(LocalFunction node) {
assert(index > 0);
_repository.mapping[node] = index++;
node.visitChildren(this);
}
}