blob: 17adabc1229607257725887e08aeccfb48aa1f7a [file] [log] [blame]
// Copyright (c) 2019, 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.
library vm.bytecode.ast_remover;
import 'package:kernel/ast.dart' hide MapEntry;
import '../metadata/bytecode.dart';
/// Drops kernel AST for members with bytecode.
/// Can preserve removed AST and restore it if needed.
class ASTRemover extends Transformer {
final BytecodeMetadataRepository metadata;
final droppedAST = <Member, dynamic>{};
ASTRemover(Component component)
: metadata = component.metadata[new BytecodeMetadataRepository().tag];
@override
TreeNode defaultMember(Member node) {
if (_hasBytecode(node)) {
if (node is Field) {
droppedAST[node] = node.initializer;
node.initializer = null;
} else if (node is Constructor) {
droppedAST[node] =
new _DroppedConstructor(node.initializers, node.function.body);
node.initializers = <Initializer>[];
node.function.body = null;
} else if (node.function != null) {
droppedAST[node] = node.function.body;
node.function.body = null;
}
}
// Instance field initializers do not form separate functions, and bytecode
// is not attached to instance fields (it is included into constructors).
// When VM reads a constructor from kernel, it also reads and translates
// instance field initializers. So, their ASTs can be dropped only if
// bytecode was generated for all generative constructors.
if (node is Field && !node.isStatic && node.initializer != null) {
if (node.enclosingClass.constructors.every(_hasBytecode)) {
droppedAST[node] = node.initializer;
node.initializer = null;
}
}
return node;
}
bool _hasBytecode(Member node) =>
metadata != null && metadata.mapping.containsKey(node);
void restoreAST() {
droppedAST.forEach((Member node, dynamic dropped) {
if (node is Field) {
node.initializer = dropped;
} else if (node is Constructor) {
_DroppedConstructor droppedConstructor = dropped;
node.initializers = droppedConstructor.initializers;
node.function.body = droppedConstructor.body;
} else {
node.function.body = dropped;
}
});
}
}
class _DroppedConstructor {
final List<Initializer> initializers;
final Statement body;
_DroppedConstructor(this.initializers, this.body);
}