From 52f5e34dbfed9d2e594d969bbefc0f39cf75c213 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Fri, 8 Feb 2019 10:16:58 +0000 Subject: [PATCH] Move JsToFrontendMap to js_world_builder and add toBackendConstant. We had two implementations of TypeConverter. These are now merged. Since native behavior can contain free function type variables the type converter currently conditionally allow these. Change-Id: I4591d4b628a9eb75b1316a1884e82b31f2fca97f Reviewed-on: https://dart-review.googlesource.com/c/92286 Commit-Queue: Johnni Winther Reviewed-by: Sigmund Cherem --- .../src/js_backend/allocator_analysis.dart | 3 +- .../lib/src/js_model/element_map_impl.dart | 33 -- pkg/compiler/lib/src/js_model/elements.dart | 176 -------- .../lib/src/js_model/js_world_builder.dart | 375 +++++++++++++----- 4 files changed, 274 insertions(+), 313 deletions(-) diff --git a/pkg/compiler/lib/src/js_backend/allocator_analysis.dart b/pkg/compiler/lib/src/js_backend/allocator_analysis.dart index cc5408bd9ce..123f627a678 100644 --- a/pkg/compiler/lib/src/js_backend/allocator_analysis.dart +++ b/pkg/compiler/lib/src/js_backend/allocator_analysis.dart @@ -5,7 +5,8 @@ import 'package:kernel/ast.dart' as ir; import '../constants/values.dart'; -import '../js_model/elements.dart' show JsToFrontendMap, JField; +import '../js_model/elements.dart' show JField; +import '../js_model/js_world_builder.dart'; import '../kernel/element_map.dart'; import '../kernel/kernel_strategy.dart'; import '../kernel/kelements.dart' show KClass, KField; diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart index a8b90090e34..ad03cc0c253 100644 --- a/pkg/compiler/lib/src/js_model/element_map_impl.dart +++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart @@ -2555,39 +2555,6 @@ class JsEvaluationEnvironment extends EvaluationEnvironmentBase { bool get enableAssertions => _elementMap.options.enableUserAssertions; } -class JsToFrontendMapImpl extends JsToFrontendMapBase - implements JsToFrontendMap { - final JsKernelToElementMap _backend; - - JsToFrontendMapImpl(this._backend); - - LibraryEntity toBackendLibrary(covariant IndexedLibrary library) { - return _backend.libraries.getEntity(library.libraryIndex); - } - - ClassEntity toBackendClass(covariant IndexedClass cls) { - return _backend.classes.getEntity(cls.classIndex); - } - - MemberEntity toBackendMember(covariant IndexedMember member) { - return _backend.members.getEntity(member.memberIndex); - } - - TypedefEntity toBackendTypedef(covariant IndexedTypedef typedef) { - return _backend.typedefs.getEntity(typedef.typedefIndex); - } - - TypeVariableEntity toBackendTypeVariable(TypeVariableEntity typeVariable) { - if (typeVariable is KLocalTypeVariable) { - failedAt( - typeVariable, "Local function type variables are not supported."); - } - IndexedTypeVariable indexedTypeVariable = typeVariable; - return _backend.typeVariables - .getEntity(indexedTypeVariable.typeVariableIndex); - } -} - /// [EntityLookup] implementation used to deserialize [JsKernelToElementMap]. /// /// Since data objects and environments are registered together with their diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart index d61469f2f17..4afe45a045b 100644 --- a/pkg/compiler/lib/src/js_model/elements.dart +++ b/pkg/compiler/lib/src/js_model/elements.dart @@ -13,182 +13,6 @@ import '../serialization/serialization.dart'; import '../universe/class_set.dart' show ClassHierarchyNodesMapKey; import 'closure.dart'; -/// Map from 'frontend' to 'backend' elements. -/// -/// Frontend elements are what we read in, these typically represents concepts -/// in Dart. Backend elements are what we generate, these may include elements -/// that do not correspond to a Dart concept, such as closure classes. -/// -/// Querying for the frontend element for a backend-only element throws an -/// exception. -abstract class JsToFrontendMap { - LibraryEntity toBackendLibrary(LibraryEntity library); - - ClassEntity toBackendClass(ClassEntity cls); - - /// Returns the backend member corresponding to [member]. If a member isn't - /// live, it doesn't have a corresponding backend member and `null` is - /// returned instead. - MemberEntity toBackendMember(MemberEntity member); - - DartType toBackendType(DartType type); - - Set toBackendLibrarySet(Iterable set) { - return set.map(toBackendLibrary).toSet(); - } - - Set toBackendClassSet(Iterable set) { - // TODO(johnniwinther): Filter unused classes. - return set.map(toBackendClass).toSet(); - } - - Set toBackendMemberSet(Iterable set) { - return set.map(toBackendMember).where((MemberEntity member) { - // Members that are not live don't have a corresponding backend member. - return member != null; - }).toSet(); - } - - Set toBackendFieldSet(Iterable set) { - Set newSet = new Set(); - for (FieldEntity element in set) { - FieldEntity backendField = toBackendMember(element); - if (backendField != null) { - // Members that are not live don't have a corresponding backend member. - newSet.add(backendField); - } - } - return newSet; - } - - Set toBackendFunctionSet(Iterable set) { - Set newSet = new Set(); - for (FunctionEntity element in set) { - FunctionEntity backendFunction = toBackendMember(element); - if (backendFunction != null) { - // Members that are not live don't have a corresponding backend member. - newSet.add(backendFunction); - } - } - return newSet; - } - - Map toBackendLibraryMap( - Map map, V convert(V value)) { - return convertMap(map, toBackendLibrary, convert); - } - - Map toBackendClassMap( - Map map, V convert(V value)) { - return convertMap(map, toBackendClass, convert); - } - - Map toBackendMemberMap( - Map map, V convert(V value)) { - return convertMap(map, toBackendMember, convert); - } -} - -E identity(E element) => element; - -Map convertMap( - Map map, K convertKey(K key), V convertValue(V value)) { - Map newMap = {}; - map.forEach((K key, V value) { - K newKey = convertKey(key); - V newValue = convertValue(value); - if (newKey != null && newValue != null) { - // Entities that are not used don't have a corresponding backend entity. - newMap[newKey] = newValue; - } - }); - return newMap; -} - -abstract class JsToFrontendMapBase extends JsToFrontendMap { - DartType toBackendType(DartType type) => - type == null ? null : const TypeConverter().visit(type, _toBackendEntity); - - Entity _toBackendEntity(Entity entity) { - if (entity is ClassEntity) return toBackendClass(entity); - assert(entity is TypeVariableEntity); - return toBackendTypeVariable(entity); - } - - TypeVariableEntity toBackendTypeVariable(TypeVariableEntity typeVariable); -} - -typedef Entity EntityConverter(Entity cls); - -class TypeConverter implements DartTypeVisitor { - const TypeConverter(); - - @override - DartType visit(DartType type, EntityConverter converter) { - return type.accept(this, converter); - } - - List visitList(List types, EntityConverter converter) { - List list = []; - for (DartType type in types) { - list.add(visit(type, converter)); - } - return list; - } - - @override - DartType visitDynamicType(DynamicType type, EntityConverter converter) { - return const DynamicType(); - } - - @override - DartType visitInterfaceType(InterfaceType type, EntityConverter converter) { - return new InterfaceType( - converter(type.element), visitList(type.typeArguments, converter)); - } - - @override - DartType visitTypedefType(TypedefType type, EntityConverter converter) { - return new TypedefType( - converter(type.element), - visitList(type.typeArguments, converter), - visit(type.unaliased, converter)); - } - - @override - DartType visitFunctionType(FunctionType type, EntityConverter converter) { - return new FunctionType( - visit(type.returnType, converter), - visitList(type.parameterTypes, converter), - visitList(type.optionalParameterTypes, converter), - type.namedParameters, - visitList(type.namedParameterTypes, converter), - type.typeVariables); - } - - @override - DartType visitTypeVariableType( - TypeVariableType type, EntityConverter converter) { - return new TypeVariableType(converter(type.element)); - } - - @override - DartType visitFunctionTypeVariable( - FunctionTypeVariable type, EntityConverter converter) { - return type; - } - - @override - DartType visitVoidType(VoidType type, EntityConverter converter) { - return const VoidType(); - } - - @override - DartType visitFutureOrType(FutureOrType type, EntityConverter converter) { - return new FutureOrType(visit(type.typeArgument, converter)); - } -} - const String jsElementPrefix = 'j:'; class JLibrary extends IndexedLibrary { diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart index b5bc25adf94..3b39476511a 100644 --- a/pkg/compiler/lib/src/js_model/js_world_builder.dart +++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart @@ -5,10 +5,12 @@ import 'package:kernel/ast.dart' as ir; import '../closure.dart'; +import '../common.dart'; import '../common_elements.dart'; import '../constants/values.dart'; import '../deferred_load.dart'; import '../elements/entities.dart'; +import '../elements/indexed.dart'; import '../elements/names.dart'; import '../elements/types.dart'; import '../inferrer/abstract_value_domain.dart'; @@ -303,7 +305,12 @@ class JsClosedWorldBuilder { NativeData _convertNativeData( JsToFrontendMap map, NativeDataImpl nativeData) { convertNativeBehaviorType(type) { - if (type is DartType) return map.toBackendType(type); + if (type is DartType) { + // TODO(johnniwinther): Avoid free variables in types. If the type + // pulled from a generic function type it might contain a function + // type variable that should probably have been replaced by its bound. + return map.toBackendType(type, allowFreeVariables: true); + } assert(type is SpecialType); return type; } @@ -452,18 +459,6 @@ class JsClosedWorldBuilder { OutputUnitData _convertOutputUnitData(JsToFrontendMapImpl map, OutputUnitData data, ClosureData closureDataLookup) { - Entity toBackendEntity(Entity entity) { - if (entity is ClassEntity) return map.toBackendClass(entity); - if (entity is MemberEntity) return map.toBackendMember(entity); - if (entity is TypedefEntity) return map.toBackendTypedef(entity); - if (entity is TypeVariableEntity) { - return map.toBackendTypeVariable(entity); - } - assert( - entity is LibraryEntity, 'unexpected entity ${entity.runtimeType}'); - return map.toBackendLibrary(entity); - } - // Convert front-end maps containing K-class and K-local function keys to a // backend map using J-classes as keys. Map convertClassMap( @@ -471,7 +466,7 @@ class JsClosedWorldBuilder { Map localFunctionMap) { var result = {}; classMap.forEach((ClassEntity entity, OutputUnit unit) { - ClassEntity backendEntity = toBackendEntity(entity); + ClassEntity backendEntity = map.toBackendClass(entity); if (backendEntity != null) { // If [entity] isn't used it doesn't have a corresponding backend // entity. @@ -496,7 +491,7 @@ class JsClosedWorldBuilder { Map localFunctionMap) { var result = {}; memberMap.forEach((MemberEntity entity, OutputUnit unit) { - MemberEntity backendEntity = toBackendEntity(entity); + MemberEntity backendEntity = map.toBackendMember(entity); if (backendEntity != null) { // If [entity] isn't used it doesn't have a corresponding backend // entity. @@ -514,17 +509,13 @@ class JsClosedWorldBuilder { return result; } - ConstantValue toBackendConstant(ConstantValue constant) { - return constant.accept(new ConstantConverter(toBackendEntity), null); - } - return new OutputUnitData.from( data, map.toBackendLibrary, convertClassMap, convertMemberMap, (m) => convertMap( - m, toBackendConstant, (v) => v)); + m, map.toBackendConstant, (v) => v)); } } @@ -597,12 +588,259 @@ class JsClosureRtiNeed implements ClosureRtiNeed { rtiNeed.instantiationNeedsTypeArguments(functionType, typeArgumentCount); } -class ConstantConverter implements ConstantValueVisitor { - final Entity Function(Entity) toBackendEntity; - final TypeConverter typeConverter; +/// Map from 'frontend' to 'backend' elements. +/// +/// Frontend elements are what we read in, these typically represents concepts +/// in Dart. Backend elements are what we generate, these may include elements +/// that do not correspond to a Dart concept, such as closure classes. +/// +/// Querying for the frontend element for a backend-only element throws an +/// exception. +abstract class JsToFrontendMap { + LibraryEntity toBackendLibrary(LibraryEntity library); - ConstantConverter(this.toBackendEntity) - : typeConverter = new TypeConverter(toBackendEntity); + ClassEntity toBackendClass(ClassEntity cls); + + /// Returns the backend member corresponding to [member]. If a member isn't + /// live, it doesn't have a corresponding backend member and `null` is + /// returned instead. + MemberEntity toBackendMember(MemberEntity member); + + DartType toBackendType(DartType type, {bool allowFreeVariables: false}); + + ConstantValue toBackendConstant(ConstantValue value); + + Set toBackendLibrarySet(Iterable set) { + return set.map(toBackendLibrary).toSet(); + } + + Set toBackendClassSet(Iterable set) { + // TODO(johnniwinther): Filter unused classes. + return set.map(toBackendClass).toSet(); + } + + Set toBackendMemberSet(Iterable set) { + return set.map(toBackendMember).where((MemberEntity member) { + // Members that are not live don't have a corresponding backend member. + return member != null; + }).toSet(); + } + + Set toBackendFieldSet(Iterable set) { + Set newSet = new Set(); + for (FieldEntity element in set) { + FieldEntity backendField = toBackendMember(element); + if (backendField != null) { + // Members that are not live don't have a corresponding backend member. + newSet.add(backendField); + } + } + return newSet; + } + + Set toBackendFunctionSet(Iterable set) { + Set newSet = new Set(); + for (FunctionEntity element in set) { + FunctionEntity backendFunction = toBackendMember(element); + if (backendFunction != null) { + // Members that are not live don't have a corresponding backend member. + newSet.add(backendFunction); + } + } + return newSet; + } + + Map toBackendLibraryMap( + Map map, V convert(V value)) { + return convertMap(map, toBackendLibrary, convert); + } + + Map toBackendClassMap( + Map map, V convert(V value)) { + return convertMap(map, toBackendClass, convert); + } + + Map toBackendMemberMap( + Map map, V convert(V value)) { + return convertMap(map, toBackendMember, convert); + } +} + +E identity(E element) => element; + +Map convertMap( + Map map, K convertKey(K key), V convertValue(V value)) { + Map newMap = {}; + map.forEach((K key, V value) { + K newKey = convertKey(key); + V newValue = convertValue(value); + if (newKey != null && newValue != null) { + // Entities that are not used don't have a corresponding backend entity. + newMap[newKey] = newValue; + } + }); + return newMap; +} + +class JsToFrontendMapImpl extends JsToFrontendMap { + final JsKernelToElementMap _backend; + + JsToFrontendMapImpl(this._backend); + + DartType toBackendType(DartType type, {bool allowFreeVariables: false}) => + type == null + ? null + : new _TypeConverter(allowFreeVariables: allowFreeVariables) + .visit(type, toBackendEntity); + + Entity toBackendEntity(Entity entity) { + if (entity is ClassEntity) return toBackendClass(entity); + if (entity is MemberEntity) return toBackendMember(entity); + if (entity is TypedefEntity) return toBackendTypedef(entity); + if (entity is TypeVariableEntity) { + return toBackendTypeVariable(entity); + } + assert(entity is LibraryEntity, 'unexpected entity ${entity.runtimeType}'); + return toBackendLibrary(entity); + } + + LibraryEntity toBackendLibrary(covariant IndexedLibrary library) { + return _backend.libraries.getEntity(library.libraryIndex); + } + + ClassEntity toBackendClass(covariant IndexedClass cls) { + return _backend.classes.getEntity(cls.classIndex); + } + + MemberEntity toBackendMember(covariant IndexedMember member) { + return _backend.members.getEntity(member.memberIndex); + } + + TypedefEntity toBackendTypedef(covariant IndexedTypedef typedef) { + return _backend.typedefs.getEntity(typedef.typedefIndex); + } + + TypeVariableEntity toBackendTypeVariable(TypeVariableEntity typeVariable) { + if (typeVariable is KLocalTypeVariable) { + failedAt( + typeVariable, "Local function type variables are not supported."); + } + IndexedTypeVariable indexedTypeVariable = typeVariable; + return _backend.typeVariables + .getEntity(indexedTypeVariable.typeVariableIndex); + } + + ConstantValue toBackendConstant(ConstantValue constant) { + return constant.accept(new _ConstantConverter(toBackendEntity), null); + } +} + +typedef Entity _EntityConverter(Entity cls); + +class _TypeConverter implements DartTypeVisitor { + final bool allowFreeVariables; + + Map _functionTypeVariables = + {}; + + _TypeConverter({this.allowFreeVariables: false}); + + List convertTypes( + List types, _EntityConverter converter) => + visitList(types, converter); + + @override + DartType visit(DartType type, _EntityConverter converter) { + return type.accept(this, converter); + } + + List visitList(List types, _EntityConverter converter) { + List list = []; + for (DartType type in types) { + list.add(visit(type, converter)); + } + return list; + } + + @override + DartType visitDynamicType(DynamicType type, _EntityConverter converter) { + return const DynamicType(); + } + + @override + DartType visitInterfaceType(InterfaceType type, _EntityConverter converter) { + return new InterfaceType( + converter(type.element), visitList(type.typeArguments, converter)); + } + + @override + DartType visitTypedefType(TypedefType type, _EntityConverter converter) { + return new TypedefType( + converter(type.element), + visitList(type.typeArguments, converter), + visit(type.unaliased, converter)); + } + + @override + DartType visitTypeVariableType( + TypeVariableType type, _EntityConverter converter) { + return new TypeVariableType(converter(type.element)); + } + + @override + DartType visitFunctionType(FunctionType type, _EntityConverter converter) { + List typeVariables = []; + for (FunctionTypeVariable typeVariable in type.typeVariables) { + typeVariables.add(_functionTypeVariables[typeVariable] = + new FunctionTypeVariable(typeVariable.index)); + } + for (FunctionTypeVariable typeVariable in type.typeVariables) { + _functionTypeVariables[typeVariable].bound = typeVariable.bound != null + ? visit(typeVariable.bound, converter) + : null; + } + DartType returnType = visit(type.returnType, converter); + List parameterTypes = visitList(type.parameterTypes, converter); + List optionalParameterTypes = + visitList(type.optionalParameterTypes, converter); + List namedParameterTypes = + visitList(type.namedParameterTypes, converter); + for (FunctionTypeVariable typeVariable in type.typeVariables) { + _functionTypeVariables.remove(typeVariable); + } + return new FunctionType(returnType, parameterTypes, optionalParameterTypes, + type.namedParameters, namedParameterTypes, typeVariables); + } + + @override + DartType visitFunctionTypeVariable( + FunctionTypeVariable type, _EntityConverter converter) { + DartType result = _functionTypeVariables[type]; + if (result == null && allowFreeVariables) { + return type; + } + assert(result != null, + "Function type variable $type not found in $_functionTypeVariables"); + return result; + } + + @override + DartType visitVoidType(VoidType type, _EntityConverter converter) { + return const VoidType(); + } + + @override + DartType visitFutureOrType(FutureOrType type, _EntityConverter converter) { + return new FutureOrType(visit(type.typeArgument, converter)); + } +} + +class _ConstantConverter implements ConstantValueVisitor { + final Entity Function(Entity) toBackendEntity; + final _TypeConverter typeConverter; + + _ConstantConverter(this.toBackendEntity) + : typeConverter = new _TypeConverter(); ConstantValue visitNull(NullConstantValue constant, _) => constant; ConstantValue visitInt(IntConstantValue constant, _) => constant; @@ -613,12 +851,12 @@ class ConstantConverter implements ConstantValueVisitor { ConstantValue visitNonConstant(NonConstantValue constant, _) => constant; ConstantValue visitFunction(FunctionConstantValue constant, _) { - return new FunctionConstantValue( - toBackendEntity(constant.element), typeConverter.visit(constant.type)); + return new FunctionConstantValue(toBackendEntity(constant.element), + typeConverter.visit(constant.type, toBackendEntity)); } ConstantValue visitList(ListConstantValue constant, _) { - DartType type = typeConverter.visit(constant.type); + DartType type = typeConverter.visit(constant.type, toBackendEntity); List entries = _handleValues(constant.entries); if (identical(entries, constant.entries) && type == constant.type) { return constant; @@ -627,7 +865,7 @@ class ConstantConverter implements ConstantValueVisitor { } ConstantValue visitMap(MapConstantValue constant, _) { - var type = typeConverter.visit(constant.type); + var type = typeConverter.visit(constant.type, toBackendEntity); List keys = _handleValues(constant.keys); List values = _handleValues(constant.values); if (identical(keys, constant.keys) && @@ -639,7 +877,7 @@ class ConstantConverter implements ConstantValueVisitor { } ConstantValue visitConstructed(ConstructedConstantValue constant, _) { - DartType type = typeConverter.visit(constant.type); + DartType type = typeConverter.visit(constant.type, toBackendEntity); Map fields = {}; constant.fields.forEach((f, v) { FieldEntity backendField = toBackendEntity(f); @@ -650,8 +888,9 @@ class ConstantConverter implements ConstantValueVisitor { } ConstantValue visitType(TypeConstantValue constant, _) { - DartType type = typeConverter.visit(constant.type); - DartType representedType = typeConverter.visit(constant.representedType); + DartType type = typeConverter.visit(constant.type, toBackendEntity); + DartType representedType = + typeConverter.visit(constant.representedType, toBackendEntity); if (type == constant.type && representedType == constant.representedType) { return constant; } @@ -673,7 +912,7 @@ class ConstantConverter implements ConstantValueVisitor { ConstantValue visitInstantiation(InstantiationConstantValue constant, _) { ConstantValue function = constant.function.accept(this, null); List typeArguments = - typeConverter.convertTypes(constant.typeArguments); + typeConverter.convertTypes(constant.typeArguments, toBackendEntity); return new InstantiationConstantValue(typeArguments, function); } @@ -690,73 +929,3 @@ class ConstantConverter implements ConstantValueVisitor { return result ?? values; } } - -class TypeConverter implements DartTypeVisitor { - final Entity Function(Entity) toBackendEntity; - - TypeConverter(this.toBackendEntity); - - Map _functionTypeVariables = - {}; - - DartType visit(DartType type, [_]) => type.accept(this, null); - - List convertTypes(List types) => _visitList(types); - - DartType visitVoidType(VoidType type, _) => type; - DartType visitDynamicType(DynamicType type, _) => type; - - DartType visitTypeVariableType(TypeVariableType type, _) { - return new TypeVariableType(toBackendEntity(type.element)); - } - - DartType visitFunctionTypeVariable(FunctionTypeVariable type, _) { - DartType result = _functionTypeVariables[type]; - assert(result != null, - "Function type variable $type not found in $_functionTypeVariables"); - return result; - } - - DartType visitFunctionType(FunctionType type, _) { - List typeVariables = []; - for (FunctionTypeVariable typeVariable in type.typeVariables) { - typeVariables.add(_functionTypeVariables[typeVariable] = - new FunctionTypeVariable(typeVariable.index)); - } - for (FunctionTypeVariable typeVariable in type.typeVariables) { - _functionTypeVariables[typeVariable].bound = - typeVariable.bound?.accept(this, null); - } - DartType returnType = type.returnType.accept(this, null); - List parameterTypes = _visitList(type.parameterTypes); - List optionalParameterTypes = - _visitList(type.optionalParameterTypes); - List namedParameterTypes = _visitList(type.namedParameterTypes); - for (FunctionTypeVariable typeVariable in type.typeVariables) { - _functionTypeVariables.remove(typeVariable); - } - return new FunctionType(returnType, parameterTypes, optionalParameterTypes, - type.namedParameters, namedParameterTypes, typeVariables); - } - - DartType visitInterfaceType(InterfaceType type, _) { - ClassEntity element = toBackendEntity(type.element); - List args = _visitList(type.typeArguments); - return new InterfaceType(element, args); - } - - DartType visitTypedefType(TypedefType type, _) { - TypedefEntity element = toBackendEntity(type.element); - List args = _visitList(type.typeArguments); - DartType unaliased = visit(type.unaliased); - return new TypedefType(element, args, unaliased); - } - - @override - DartType visitFutureOrType(FutureOrType type, _) { - return new FutureOrType(visit(type.typeArgument)); - } - - List _visitList(List list) => - list.map((t) => t.accept(this, null)).toList(); -}