| // Copyright (c) 2015, 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 dart2js.universe.world_impact; |
| |
| import '../elements/entities.dart'; |
| import '../util/util.dart' show Setlet; |
| import 'use.dart'; |
| |
| /// Describes how an element (e.g. a method) impacts the closed-world |
| /// semantics of a program. |
| /// |
| /// A [WorldImpact] contains information about how a program element affects our |
| /// understanding of what's live in a program. For example, it can indicate |
| /// that a method uses a certain feature, or allocates a specific type. |
| /// |
| /// The impact object can be computed locally by inspecting just the resolution |
| /// information of that element alone. The compiler uses [Universe] and |
| /// [World] to combine the information discovered in the impact objects of |
| /// all elements reachable in an application. |
| class WorldImpact { |
| const WorldImpact(); |
| |
| /// [member] may be `null` when the impact is for something that is not a |
| /// member, e.g. a constant, or external or native dependencies. |
| MemberEntity? get member => null; |
| |
| Iterable<DynamicUse> get dynamicUses => const []; |
| |
| Iterable<StaticUse> get staticUses => const []; |
| |
| // TODO(johnniwinther): Replace this by called constructors with type |
| // arguments. |
| // TODO(johnniwinther): Collect all checked types for checked mode separately |
| // to support serialization. |
| |
| Iterable<TypeUse> get typeUses => const []; |
| |
| Iterable<ConstantUse> get constantUses => const []; |
| |
| void _forEach<U>( |
| Iterable<U> uses, void Function(MemberEntity?, U) visitUse) => |
| uses.forEach((use) => visitUse(member, use)); |
| |
| void forEachDynamicUse(void Function(MemberEntity?, DynamicUse) visitUse) => |
| _forEach(dynamicUses, visitUse); |
| void forEachStaticUse(void Function(MemberEntity?, StaticUse) visitUse) => |
| _forEach(staticUses, visitUse); |
| void forEachTypeUse(void Function(MemberEntity?, TypeUse) visitUse) => |
| _forEach(typeUses, visitUse); |
| void forEachConstantUse(void Function(MemberEntity?, ConstantUse) visitUse) => |
| _forEach(constantUses, visitUse); |
| |
| bool get isEmpty => true; |
| |
| @override |
| String toString() => dump(this); |
| |
| static String dump(WorldImpact worldImpact) { |
| StringBuffer sb = StringBuffer(); |
| printOn(sb, worldImpact); |
| return sb.toString(); |
| } |
| |
| static void printOn(StringBuffer sb, WorldImpact worldImpact) { |
| sb.write('member: ${worldImpact.member}'); |
| |
| void add(String title, Iterable iterable) { |
| if (iterable.isNotEmpty) { |
| sb.write('\n $title:'); |
| iterable.forEach((e) => sb.write('\n $e')); |
| } |
| } |
| |
| add('dynamic uses', worldImpact.dynamicUses); |
| add('static uses', worldImpact.staticUses); |
| add('type uses', worldImpact.typeUses); |
| add('constant uses', worldImpact.constantUses); |
| } |
| } |
| |
| abstract class WorldImpactBuilder extends WorldImpact { |
| void registerDynamicUse(DynamicUse dynamicUse); |
| void registerTypeUse(TypeUse typeUse); |
| void registerStaticUse(StaticUse staticUse); |
| void registerConstantUse(ConstantUse constantUse); |
| } |
| |
| class WorldImpactBuilderImpl extends WorldImpactBuilder { |
| /// The [MemberEntity] associated with this set of impacts. Maybe null. |
| @override |
| final MemberEntity? member; |
| |
| // TODO(johnniwinther): Do we benefit from lazy initialization of the |
| // [Setlet]s? |
| Set<DynamicUse>? _dynamicUses; |
| Set<StaticUse>? _staticUses; |
| Set<TypeUse>? _typeUses; |
| Set<ConstantUse>? _constantUses; |
| |
| WorldImpactBuilderImpl([this.member]); |
| |
| WorldImpactBuilderImpl.internal( |
| this._dynamicUses, this._staticUses, this._typeUses, this._constantUses, |
| {this.member}); |
| |
| @override |
| bool get isEmpty => |
| _dynamicUses == null && |
| _staticUses == null && |
| _typeUses == null && |
| _constantUses == null; |
| |
| /// Copy uses in [impact] to this impact builder. |
| void addImpact(WorldImpact impact) { |
| if (impact.isEmpty) return; |
| impact.dynamicUses.forEach(registerDynamicUse); |
| impact.staticUses.forEach(registerStaticUse); |
| impact.typeUses.forEach(registerTypeUse); |
| impact.constantUses.forEach(registerConstantUse); |
| } |
| |
| @override |
| void registerDynamicUse(DynamicUse dynamicUse) { |
| assert((dynamicUse as dynamic) != null); // TODO(48820): Remove when sound. |
| (_dynamicUses ??= Setlet()).add(dynamicUse); |
| } |
| |
| @override |
| Iterable<DynamicUse> get dynamicUses { |
| return _dynamicUses ?? const []; |
| } |
| |
| @override |
| void registerTypeUse(TypeUse typeUse) { |
| assert((typeUse as dynamic) != null); // TODO(48820): Remove when sound. |
| (_typeUses ??= Setlet()).add(typeUse); |
| } |
| |
| @override |
| Iterable<TypeUse> get typeUses { |
| return _typeUses ?? const []; |
| } |
| |
| @override |
| void registerStaticUse(StaticUse staticUse) { |
| assert((staticUse as dynamic) != null); // TODO(48820): Remove when sound. |
| (_staticUses ??= Setlet()).add(staticUse); |
| } |
| |
| @override |
| Iterable<StaticUse> get staticUses { |
| return _staticUses ?? const []; |
| } |
| |
| @override |
| void registerConstantUse(ConstantUse constantUse) { |
| assert((constantUse as dynamic) != null); // TODO(48820): Remove when sound. |
| (_constantUses ??= Setlet()).add(constantUse); |
| } |
| |
| @override |
| Iterable<ConstantUse> get constantUses { |
| return _constantUses ?? const []; |
| } |
| } |
| |
| /// Mutable implementation of [WorldImpact] used to transform |
| /// [ResolutionImpact] or [CodegenImpact] to [WorldImpact]. |
| class TransformedWorldImpact extends WorldImpactBuilder { |
| final WorldImpact worldImpact; |
| |
| Setlet<StaticUse>? _staticUses; |
| Setlet<TypeUse>? _typeUses; |
| Setlet<DynamicUse>? _dynamicUses; |
| Setlet<ConstantUse>? _constantUses; |
| |
| TransformedWorldImpact(this.worldImpact); |
| |
| @override |
| MemberEntity? get member => worldImpact.member; |
| |
| @override |
| bool get isEmpty { |
| return worldImpact.isEmpty && |
| _staticUses == null && |
| _typeUses == null && |
| _dynamicUses == null && |
| _constantUses == null; |
| } |
| |
| @override |
| Iterable<DynamicUse> get dynamicUses { |
| return _dynamicUses ?? worldImpact.dynamicUses; |
| } |
| |
| @override |
| void registerDynamicUse(DynamicUse dynamicUse) { |
| _dynamicUses ??= Setlet.of(worldImpact.dynamicUses); |
| _dynamicUses!.add(dynamicUse); |
| } |
| |
| @override |
| void registerTypeUse(TypeUse typeUse) { |
| _typeUses ??= Setlet.of(worldImpact.typeUses); |
| _typeUses!.add(typeUse); |
| } |
| |
| @override |
| Iterable<TypeUse> get typeUses { |
| return _typeUses ?? worldImpact.typeUses; |
| } |
| |
| @override |
| void registerStaticUse(StaticUse staticUse) { |
| _staticUses ??= Setlet.of(worldImpact.staticUses); |
| _staticUses!.add(staticUse); |
| } |
| |
| @override |
| Iterable<StaticUse> get staticUses { |
| return _staticUses ?? worldImpact.staticUses; |
| } |
| |
| @override |
| Iterable<ConstantUse> get constantUses { |
| return _constantUses ?? worldImpact.constantUses; |
| } |
| |
| @override |
| void registerConstantUse(ConstantUse constantUse) { |
| _constantUses ??= Setlet.of(worldImpact.constantUses); |
| _constantUses!.add(constantUse); |
| } |
| |
| @override |
| String toString() { |
| StringBuffer sb = StringBuffer(); |
| sb.write('TransformedWorldImpact($worldImpact)'); |
| WorldImpact.printOn(sb, this); |
| return sb.toString(); |
| } |
| } |