| Index: pkg/compiler/lib/src/kernel/env.dart
|
| diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..74ec5ba43b58f626a36da6dce42f71f749a1f618
|
| --- /dev/null
|
| +++ b/pkg/compiler/lib/src/kernel/env.dart
|
| @@ -0,0 +1,409 @@
|
| +// Copyright (c) 2017, 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.kernel.env;
|
| +
|
| +import 'package:kernel/ast.dart' as ir;
|
| +import 'package:kernel/clone.dart';
|
| +import 'package:kernel/type_algebra.dart';
|
| +
|
| +import '../common.dart';
|
| +import '../common/resolution.dart';
|
| +import '../constants/constructors.dart';
|
| +import '../constants/expressions.dart';
|
| +import '../constants/values.dart';
|
| +import '../elements/entities.dart';
|
| +import '../elements/types.dart';
|
| +import '../ordered_typeset.dart';
|
| +import '../ssa/kernel_impact.dart';
|
| +import 'element_map.dart';
|
| +import 'element_map_impl.dart';
|
| +import 'element_map_mixins.dart';
|
| +
|
| +/// Environment for fast lookup of program libraries.
|
| +class ProgramEnv {
|
| + final Set<ir.Program> programs = new Set<ir.Program>();
|
| +
|
| + Map<Uri, LibraryEnv> _libraryMap;
|
| +
|
| + /// TODO(johnniwinther): Handle arbitrary load order if needed.
|
| + ir.Member get mainMethod => programs.first?.mainMethod;
|
| +
|
| + void addProgram(ir.Program program) {
|
| + if (programs.add(program)) {
|
| + if (_libraryMap != null) {
|
| + _addLibraries(program);
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _addLibraries(ir.Program program) {
|
| + for (ir.Library library in program.libraries) {
|
| + _libraryMap[library.importUri] = new LibraryEnv(library);
|
| + }
|
| + }
|
| +
|
| + void _ensureLibraryMap() {
|
| + if (_libraryMap == null) {
|
| + _libraryMap = <Uri, LibraryEnv>{};
|
| + for (ir.Program program in programs) {
|
| + _addLibraries(program);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /// Return the [LibraryEnv] for the library with the canonical [uri].
|
| + LibraryEnv lookupLibrary(Uri uri) {
|
| + _ensureLibraryMap();
|
| + return _libraryMap[uri];
|
| + }
|
| +
|
| + /// Calls [f] for each library in this environment.
|
| + void forEachLibrary(void f(LibraryEnv library)) {
|
| + _ensureLibraryMap();
|
| + _libraryMap.values.forEach(f);
|
| + }
|
| +
|
| + /// Returns the number of libraries in this environment.
|
| + int get length {
|
| + _ensureLibraryMap();
|
| + return _libraryMap.length;
|
| + }
|
| +}
|
| +
|
| +/// Environment for fast lookup of library classes and members.
|
| +class LibraryEnv {
|
| + final ir.Library library;
|
| +
|
| + Map<String, ClassEnv> _classMap;
|
| + Map<String, ir.Member> _memberMap;
|
| + Map<String, ir.Member> _setterMap;
|
| +
|
| + LibraryEnv(this.library);
|
| +
|
| + void _ensureClassMap() {
|
| + if (_classMap == null) {
|
| + _classMap = <String, ClassEnv>{};
|
| + for (ir.Class cls in library.classes) {
|
| + _classMap[cls.name] = new ClassEnv(cls);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /// Return the [ClassEnv] for the class [name] in [library].
|
| + ClassEnv lookupClass(String name) {
|
| + _ensureClassMap();
|
| + return _classMap[name];
|
| + }
|
| +
|
| + /// Calls [f] for each class in this library.
|
| + void forEachClass(void f(ClassEnv cls)) {
|
| + _ensureClassMap();
|
| + _classMap.values.forEach(f);
|
| + }
|
| +
|
| + void _ensureMemberMaps() {
|
| + if (_memberMap == null) {
|
| + _memberMap = <String, ir.Member>{};
|
| + _setterMap = <String, ir.Member>{};
|
| + for (ir.Member member in library.members) {
|
| + if (member is ir.Procedure) {
|
| + if (member.kind == ir.ProcedureKind.Setter) {
|
| + _setterMap[member.name.name] = member;
|
| + } else {
|
| + _memberMap[member.name.name] = member;
|
| + }
|
| + } else if (member is ir.Field) {
|
| + _memberMap[member.name.name] = member;
|
| + if (member.isMutable) {
|
| + _setterMap[member.name.name] = member;
|
| + }
|
| + } else {
|
| + throw new SpannableAssertionFailure(
|
| + NO_LOCATION_SPANNABLE, "Unexpected library member node: $member");
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /// Return the [ir.Member] for the member [name] in [library].
|
| + ir.Member lookupMember(String name, {bool setter: false}) {
|
| + _ensureMemberMaps();
|
| + return setter ? _setterMap[name] : _memberMap[name];
|
| + }
|
| +
|
| + void forEachMember(void f(ir.Member member)) {
|
| + _ensureMemberMaps();
|
| + _memberMap.values.forEach(f);
|
| + for (ir.Member member in _setterMap.values) {
|
| + if (member is ir.Procedure) {
|
| + f(member);
|
| + } else {
|
| + // Skip fields; these are also in _memberMap.
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/// Environment for fast lookup of class members.
|
| +class ClassEnv {
|
| + final ir.Class cls;
|
| + bool isMixinApplication;
|
| + final bool isUnnamedMixinApplication;
|
| +
|
| + InterfaceType thisType;
|
| + InterfaceType rawType;
|
| + InterfaceType supertype;
|
| + InterfaceType mixedInType;
|
| + List<InterfaceType> interfaces;
|
| + OrderedTypeSet orderedTypeSet;
|
| +
|
| + Map<String, ir.Member> _constructorMap;
|
| + Map<String, ir.Member> _memberMap;
|
| + Map<String, ir.Member> _setterMap;
|
| +
|
| + Iterable<ConstantValue> _metadata;
|
| +
|
| + ClassEnv(this.cls)
|
| + // TODO(johnniwinther): Change this to use a property on [cls] when such
|
| + // is added to kernel.
|
| + : isUnnamedMixinApplication =
|
| + cls.name.contains('+') || cls.name.contains('&');
|
| +
|
| + /// Copied from 'package:kernel/transformations/mixin_full_resolution.dart'.
|
| + ir.Constructor _buildForwardingConstructor(
|
| + CloneVisitor cloner, ir.Constructor superclassConstructor) {
|
| + var superFunction = superclassConstructor.function;
|
| +
|
| + // We keep types and default values for the parameters but always mark the
|
| + // parameters as final (since we just forward them to the super
|
| + // constructor).
|
| + ir.VariableDeclaration cloneVariable(ir.VariableDeclaration variable) {
|
| + ir.VariableDeclaration clone = cloner.clone(variable);
|
| + clone.isFinal = true;
|
| + return clone;
|
| + }
|
| +
|
| + // Build a [FunctionNode] which has the same parameters as the one in the
|
| + // superclass constructor.
|
| + var positionalParameters =
|
| + superFunction.positionalParameters.map(cloneVariable).toList();
|
| + var namedParameters =
|
| + superFunction.namedParameters.map(cloneVariable).toList();
|
| + var function = new ir.FunctionNode(new ir.EmptyStatement(),
|
| + positionalParameters: positionalParameters,
|
| + namedParameters: namedParameters,
|
| + requiredParameterCount: superFunction.requiredParameterCount,
|
| + returnType: const ir.VoidType());
|
| +
|
| + // Build a [SuperInitializer] which takes all positional/named parameters
|
| + // and forward them to the super class constructor.
|
| + var positionalArguments = <ir.Expression>[];
|
| + for (var variable in positionalParameters) {
|
| + positionalArguments.add(new ir.VariableGet(variable));
|
| + }
|
| + var namedArguments = <ir.NamedExpression>[];
|
| + for (var variable in namedParameters) {
|
| + namedArguments.add(
|
| + new ir.NamedExpression(variable.name, new ir.VariableGet(variable)));
|
| + }
|
| + var superInitializer = new ir.SuperInitializer(superclassConstructor,
|
| + new ir.Arguments(positionalArguments, named: namedArguments));
|
| +
|
| + // Assemble the constructor.
|
| + return new ir.Constructor(function,
|
| + name: superclassConstructor.name,
|
| + initializers: <ir.Initializer>[superInitializer]);
|
| + }
|
| +
|
| + void _ensureMaps() {
|
| + if (_memberMap == null) {
|
| + _memberMap = <String, ir.Member>{};
|
| + _setterMap = <String, ir.Member>{};
|
| + _constructorMap = <String, ir.Member>{};
|
| +
|
| + void addMembers(ir.Class c, {bool includeStatic}) {
|
| + for (ir.Member member in c.members) {
|
| + if (member is ir.Constructor ||
|
| + member is ir.Procedure &&
|
| + member.kind == ir.ProcedureKind.Factory) {
|
| + if (!includeStatic) continue;
|
| + _constructorMap[member.name.name] = member;
|
| + } else if (member is ir.Procedure) {
|
| + if (!includeStatic && member.isStatic) continue;
|
| + if (member.kind == ir.ProcedureKind.Setter) {
|
| + _setterMap[member.name.name] = member;
|
| + } else {
|
| + _memberMap[member.name.name] = member;
|
| + }
|
| + } else if (member is ir.Field) {
|
| + if (!includeStatic && member.isStatic) continue;
|
| + _memberMap[member.name.name] = member;
|
| + if (member.isMutable) {
|
| + _setterMap[member.name.name] = member;
|
| + }
|
| + _memberMap[member.name.name] = member;
|
| + } else {
|
| + throw new SpannableAssertionFailure(
|
| + NO_LOCATION_SPANNABLE, "Unexpected class member node: $member");
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (cls.mixedInClass != null) {
|
| + addMembers(cls.mixedInClass, includeStatic: false);
|
| + }
|
| + addMembers(cls, includeStatic: true);
|
| +
|
| + if (isUnnamedMixinApplication && _constructorMap.isEmpty) {
|
| + // Unnamed mixin applications have no constructors when read from .dill.
|
| + // For each generative constructor in the superclass we make a
|
| + // corresponding forwarding constructor in the subclass.
|
| + //
|
| + // This code is copied from
|
| + // 'package:kernel/transformations/mixin_full_resolution.dart'
|
| + var superclassSubstitution = getSubstitutionMap(cls.supertype);
|
| + var superclassCloner =
|
| + new CloneVisitor(typeSubstitution: superclassSubstitution);
|
| + for (var superclassConstructor in cls.superclass.constructors) {
|
| + var forwardingConstructor = _buildForwardingConstructor(
|
| + superclassCloner, superclassConstructor);
|
| + cls.addMember(forwardingConstructor);
|
| + _constructorMap[forwardingConstructor.name.name] =
|
| + forwardingConstructor;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /// Return the [ir.Member] for the member [name] in [library].
|
| + ir.Member lookupMember(String name, {bool setter: false}) {
|
| + _ensureMaps();
|
| + return setter ? _setterMap[name] : _memberMap[name];
|
| + }
|
| +
|
| + /// Return the [ir.Member] for the member [name] in [library].
|
| + ir.Member lookupConstructor(String name) {
|
| + _ensureMaps();
|
| + return _constructorMap[name];
|
| + }
|
| +
|
| + void forEachMember(void f(ir.Member member)) {
|
| + _ensureMaps();
|
| + _memberMap.values.forEach(f);
|
| + for (ir.Member member in _setterMap.values) {
|
| + if (member is ir.Procedure) {
|
| + f(member);
|
| + } else {
|
| + // Skip fields; these are also in _memberMap.
|
| + }
|
| + }
|
| + }
|
| +
|
| + void forEachConstructor(void f(ir.Member member)) {
|
| + _ensureMaps();
|
| + _constructorMap.values.forEach(f);
|
| + }
|
| +
|
| + Iterable<ConstantValue> getMetadata(KernelToElementMapBase elementMap) {
|
| + return _metadata ??= elementMap.getMetadata(cls.annotations);
|
| + }
|
| +}
|
| +
|
| +class MemberData {
|
| + final ir.Member node;
|
| + Iterable<ConstantValue> _metadata;
|
| +
|
| + MemberData(this.node);
|
| +
|
| + ResolutionImpact getWorldImpact(KernelToElementMapForImpact elementMap) {
|
| + return buildKernelImpact(node, elementMap);
|
| + }
|
| +
|
| + Iterable<ConstantValue> getMetadata(KernelToElementMapBase elementMap) {
|
| + return _metadata ??= elementMap.getMetadata(node.annotations);
|
| + }
|
| +}
|
| +
|
| +class FunctionData extends MemberData {
|
| + final ir.FunctionNode functionNode;
|
| + FunctionType _type;
|
| +
|
| + FunctionData(ir.Member node, this.functionNode) : super(node);
|
| +
|
| + FunctionType getFunctionType(KernelToElementMapBase elementMap) {
|
| + return _type ??= elementMap.getFunctionType(functionNode);
|
| + }
|
| +
|
| + void forEachParameter(KernelToElementMapForBuilding elementMap,
|
| + void f(DartType type, String name, ConstantValue defaultValue)) {
|
| + void handleParameter(ir.VariableDeclaration node, {bool isOptional: true}) {
|
| + DartType type = elementMap.getDartType(node.type);
|
| + String name = node.name;
|
| + ConstantValue defaultValue;
|
| + if (isOptional) {
|
| + if (node.initializer != null) {
|
| + defaultValue = elementMap.getConstantValue(node.initializer);
|
| + } else {
|
| + defaultValue = new NullConstantValue();
|
| + }
|
| + }
|
| + f(type, name, defaultValue);
|
| + }
|
| +
|
| + for (int i = 0; i < functionNode.positionalParameters.length; i++) {
|
| + handleParameter(functionNode.positionalParameters[i],
|
| + isOptional: i < functionNode.requiredParameterCount);
|
| + }
|
| + functionNode.namedParameters.toList()
|
| + ..sort(namedOrdering)
|
| + ..forEach(handleParameter);
|
| + }
|
| +}
|
| +
|
| +class ConstructorData extends FunctionData {
|
| + ConstantConstructor _constantConstructor;
|
| +
|
| + ConstructorData(ir.Member node, ir.FunctionNode functionNode)
|
| + : super(node, functionNode);
|
| +
|
| + ConstantConstructor getConstructorConstant(
|
| + KernelToElementMapBase elementMap, ConstructorEntity constructor) {
|
| + if (_constantConstructor == null) {
|
| + if (node is ir.Constructor && constructor.isConst) {
|
| + _constantConstructor =
|
| + new Constantifier(elementMap).computeConstantConstructor(node);
|
| + } else {
|
| + throw new SpannableAssertionFailure(
|
| + constructor,
|
| + "Unexpected constructor $constructor in "
|
| + "KernelWorldBuilder._getConstructorConstant");
|
| + }
|
| + }
|
| + return _constantConstructor;
|
| + }
|
| +}
|
| +
|
| +class FieldData extends MemberData {
|
| + ConstantExpression _constant;
|
| +
|
| + FieldData(ir.Field node) : super(node);
|
| +
|
| + ir.Field get node => super.node;
|
| +
|
| + ConstantExpression getFieldConstant(
|
| + KernelToElementMapBase elementMap, FieldEntity field) {
|
| + if (_constant == null) {
|
| + if (node.isConst) {
|
| + _constant = new Constantifier(elementMap).visit(node.initializer);
|
| + } else {
|
| + throw new SpannableAssertionFailure(
|
| + field,
|
| + "Unexpected field $field in "
|
| + "KernelWorldBuilder._getConstructorConstant");
|
| + }
|
| + }
|
| + return _constant;
|
| + }
|
| +}
|
|
|