OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library dart2js.kernel.env; |
| 6 |
| 7 import 'package:kernel/ast.dart' as ir; |
| 8 import 'package:kernel/clone.dart'; |
| 9 import 'package:kernel/type_algebra.dart'; |
| 10 |
| 11 import '../common.dart'; |
| 12 import '../common/resolution.dart'; |
| 13 import '../constants/constructors.dart'; |
| 14 import '../constants/expressions.dart'; |
| 15 import '../constants/values.dart'; |
| 16 import '../elements/entities.dart'; |
| 17 import '../elements/types.dart'; |
| 18 import '../ordered_typeset.dart'; |
| 19 import '../ssa/kernel_impact.dart'; |
| 20 import 'element_map.dart'; |
| 21 import 'element_map_impl.dart'; |
| 22 import 'element_map_mixins.dart'; |
| 23 |
| 24 /// Environment for fast lookup of program libraries. |
| 25 class ProgramEnv { |
| 26 final Set<ir.Program> programs = new Set<ir.Program>(); |
| 27 |
| 28 Map<Uri, LibraryEnv> _libraryMap; |
| 29 |
| 30 /// TODO(johnniwinther): Handle arbitrary load order if needed. |
| 31 ir.Member get mainMethod => programs.first?.mainMethod; |
| 32 |
| 33 void addProgram(ir.Program program) { |
| 34 if (programs.add(program)) { |
| 35 if (_libraryMap != null) { |
| 36 _addLibraries(program); |
| 37 } |
| 38 } |
| 39 } |
| 40 |
| 41 void _addLibraries(ir.Program program) { |
| 42 for (ir.Library library in program.libraries) { |
| 43 _libraryMap[library.importUri] = new LibraryEnv(library); |
| 44 } |
| 45 } |
| 46 |
| 47 void _ensureLibraryMap() { |
| 48 if (_libraryMap == null) { |
| 49 _libraryMap = <Uri, LibraryEnv>{}; |
| 50 for (ir.Program program in programs) { |
| 51 _addLibraries(program); |
| 52 } |
| 53 } |
| 54 } |
| 55 |
| 56 /// Return the [LibraryEnv] for the library with the canonical [uri]. |
| 57 LibraryEnv lookupLibrary(Uri uri) { |
| 58 _ensureLibraryMap(); |
| 59 return _libraryMap[uri]; |
| 60 } |
| 61 |
| 62 /// Calls [f] for each library in this environment. |
| 63 void forEachLibrary(void f(LibraryEnv library)) { |
| 64 _ensureLibraryMap(); |
| 65 _libraryMap.values.forEach(f); |
| 66 } |
| 67 |
| 68 /// Returns the number of libraries in this environment. |
| 69 int get length { |
| 70 _ensureLibraryMap(); |
| 71 return _libraryMap.length; |
| 72 } |
| 73 } |
| 74 |
| 75 /// Environment for fast lookup of library classes and members. |
| 76 class LibraryEnv { |
| 77 final ir.Library library; |
| 78 |
| 79 Map<String, ClassEnv> _classMap; |
| 80 Map<String, ir.Member> _memberMap; |
| 81 Map<String, ir.Member> _setterMap; |
| 82 |
| 83 LibraryEnv(this.library); |
| 84 |
| 85 void _ensureClassMap() { |
| 86 if (_classMap == null) { |
| 87 _classMap = <String, ClassEnv>{}; |
| 88 for (ir.Class cls in library.classes) { |
| 89 _classMap[cls.name] = new ClassEnv(cls); |
| 90 } |
| 91 } |
| 92 } |
| 93 |
| 94 /// Return the [ClassEnv] for the class [name] in [library]. |
| 95 ClassEnv lookupClass(String name) { |
| 96 _ensureClassMap(); |
| 97 return _classMap[name]; |
| 98 } |
| 99 |
| 100 /// Calls [f] for each class in this library. |
| 101 void forEachClass(void f(ClassEnv cls)) { |
| 102 _ensureClassMap(); |
| 103 _classMap.values.forEach(f); |
| 104 } |
| 105 |
| 106 void _ensureMemberMaps() { |
| 107 if (_memberMap == null) { |
| 108 _memberMap = <String, ir.Member>{}; |
| 109 _setterMap = <String, ir.Member>{}; |
| 110 for (ir.Member member in library.members) { |
| 111 if (member is ir.Procedure) { |
| 112 if (member.kind == ir.ProcedureKind.Setter) { |
| 113 _setterMap[member.name.name] = member; |
| 114 } else { |
| 115 _memberMap[member.name.name] = member; |
| 116 } |
| 117 } else if (member is ir.Field) { |
| 118 _memberMap[member.name.name] = member; |
| 119 if (member.isMutable) { |
| 120 _setterMap[member.name.name] = member; |
| 121 } |
| 122 } else { |
| 123 throw new SpannableAssertionFailure( |
| 124 NO_LOCATION_SPANNABLE, "Unexpected library member node: $member"); |
| 125 } |
| 126 } |
| 127 } |
| 128 } |
| 129 |
| 130 /// Return the [ir.Member] for the member [name] in [library]. |
| 131 ir.Member lookupMember(String name, {bool setter: false}) { |
| 132 _ensureMemberMaps(); |
| 133 return setter ? _setterMap[name] : _memberMap[name]; |
| 134 } |
| 135 |
| 136 void forEachMember(void f(ir.Member member)) { |
| 137 _ensureMemberMaps(); |
| 138 _memberMap.values.forEach(f); |
| 139 for (ir.Member member in _setterMap.values) { |
| 140 if (member is ir.Procedure) { |
| 141 f(member); |
| 142 } else { |
| 143 // Skip fields; these are also in _memberMap. |
| 144 } |
| 145 } |
| 146 } |
| 147 } |
| 148 |
| 149 /// Environment for fast lookup of class members. |
| 150 class ClassEnv { |
| 151 final ir.Class cls; |
| 152 bool isMixinApplication; |
| 153 final bool isUnnamedMixinApplication; |
| 154 |
| 155 InterfaceType thisType; |
| 156 InterfaceType rawType; |
| 157 InterfaceType supertype; |
| 158 InterfaceType mixedInType; |
| 159 List<InterfaceType> interfaces; |
| 160 OrderedTypeSet orderedTypeSet; |
| 161 |
| 162 Map<String, ir.Member> _constructorMap; |
| 163 Map<String, ir.Member> _memberMap; |
| 164 Map<String, ir.Member> _setterMap; |
| 165 |
| 166 Iterable<ConstantValue> _metadata; |
| 167 |
| 168 ClassEnv(this.cls) |
| 169 // TODO(johnniwinther): Change this to use a property on [cls] when such |
| 170 // is added to kernel. |
| 171 : isUnnamedMixinApplication = |
| 172 cls.name.contains('+') || cls.name.contains('&'); |
| 173 |
| 174 /// Copied from 'package:kernel/transformations/mixin_full_resolution.dart'. |
| 175 ir.Constructor _buildForwardingConstructor( |
| 176 CloneVisitor cloner, ir.Constructor superclassConstructor) { |
| 177 var superFunction = superclassConstructor.function; |
| 178 |
| 179 // We keep types and default values for the parameters but always mark the |
| 180 // parameters as final (since we just forward them to the super |
| 181 // constructor). |
| 182 ir.VariableDeclaration cloneVariable(ir.VariableDeclaration variable) { |
| 183 ir.VariableDeclaration clone = cloner.clone(variable); |
| 184 clone.isFinal = true; |
| 185 return clone; |
| 186 } |
| 187 |
| 188 // Build a [FunctionNode] which has the same parameters as the one in the |
| 189 // superclass constructor. |
| 190 var positionalParameters = |
| 191 superFunction.positionalParameters.map(cloneVariable).toList(); |
| 192 var namedParameters = |
| 193 superFunction.namedParameters.map(cloneVariable).toList(); |
| 194 var function = new ir.FunctionNode(new ir.EmptyStatement(), |
| 195 positionalParameters: positionalParameters, |
| 196 namedParameters: namedParameters, |
| 197 requiredParameterCount: superFunction.requiredParameterCount, |
| 198 returnType: const ir.VoidType()); |
| 199 |
| 200 // Build a [SuperInitializer] which takes all positional/named parameters |
| 201 // and forward them to the super class constructor. |
| 202 var positionalArguments = <ir.Expression>[]; |
| 203 for (var variable in positionalParameters) { |
| 204 positionalArguments.add(new ir.VariableGet(variable)); |
| 205 } |
| 206 var namedArguments = <ir.NamedExpression>[]; |
| 207 for (var variable in namedParameters) { |
| 208 namedArguments.add( |
| 209 new ir.NamedExpression(variable.name, new ir.VariableGet(variable))); |
| 210 } |
| 211 var superInitializer = new ir.SuperInitializer(superclassConstructor, |
| 212 new ir.Arguments(positionalArguments, named: namedArguments)); |
| 213 |
| 214 // Assemble the constructor. |
| 215 return new ir.Constructor(function, |
| 216 name: superclassConstructor.name, |
| 217 initializers: <ir.Initializer>[superInitializer]); |
| 218 } |
| 219 |
| 220 void _ensureMaps() { |
| 221 if (_memberMap == null) { |
| 222 _memberMap = <String, ir.Member>{}; |
| 223 _setterMap = <String, ir.Member>{}; |
| 224 _constructorMap = <String, ir.Member>{}; |
| 225 |
| 226 void addMembers(ir.Class c, {bool includeStatic}) { |
| 227 for (ir.Member member in c.members) { |
| 228 if (member is ir.Constructor || |
| 229 member is ir.Procedure && |
| 230 member.kind == ir.ProcedureKind.Factory) { |
| 231 if (!includeStatic) continue; |
| 232 _constructorMap[member.name.name] = member; |
| 233 } else if (member is ir.Procedure) { |
| 234 if (!includeStatic && member.isStatic) continue; |
| 235 if (member.kind == ir.ProcedureKind.Setter) { |
| 236 _setterMap[member.name.name] = member; |
| 237 } else { |
| 238 _memberMap[member.name.name] = member; |
| 239 } |
| 240 } else if (member is ir.Field) { |
| 241 if (!includeStatic && member.isStatic) continue; |
| 242 _memberMap[member.name.name] = member; |
| 243 if (member.isMutable) { |
| 244 _setterMap[member.name.name] = member; |
| 245 } |
| 246 _memberMap[member.name.name] = member; |
| 247 } else { |
| 248 throw new SpannableAssertionFailure( |
| 249 NO_LOCATION_SPANNABLE, "Unexpected class member node: $member"); |
| 250 } |
| 251 } |
| 252 } |
| 253 |
| 254 if (cls.mixedInClass != null) { |
| 255 addMembers(cls.mixedInClass, includeStatic: false); |
| 256 } |
| 257 addMembers(cls, includeStatic: true); |
| 258 |
| 259 if (isUnnamedMixinApplication && _constructorMap.isEmpty) { |
| 260 // Unnamed mixin applications have no constructors when read from .dill. |
| 261 // For each generative constructor in the superclass we make a |
| 262 // corresponding forwarding constructor in the subclass. |
| 263 // |
| 264 // This code is copied from |
| 265 // 'package:kernel/transformations/mixin_full_resolution.dart' |
| 266 var superclassSubstitution = getSubstitutionMap(cls.supertype); |
| 267 var superclassCloner = |
| 268 new CloneVisitor(typeSubstitution: superclassSubstitution); |
| 269 for (var superclassConstructor in cls.superclass.constructors) { |
| 270 var forwardingConstructor = _buildForwardingConstructor( |
| 271 superclassCloner, superclassConstructor); |
| 272 cls.addMember(forwardingConstructor); |
| 273 _constructorMap[forwardingConstructor.name.name] = |
| 274 forwardingConstructor; |
| 275 } |
| 276 } |
| 277 } |
| 278 } |
| 279 |
| 280 /// Return the [ir.Member] for the member [name] in [library]. |
| 281 ir.Member lookupMember(String name, {bool setter: false}) { |
| 282 _ensureMaps(); |
| 283 return setter ? _setterMap[name] : _memberMap[name]; |
| 284 } |
| 285 |
| 286 /// Return the [ir.Member] for the member [name] in [library]. |
| 287 ir.Member lookupConstructor(String name) { |
| 288 _ensureMaps(); |
| 289 return _constructorMap[name]; |
| 290 } |
| 291 |
| 292 void forEachMember(void f(ir.Member member)) { |
| 293 _ensureMaps(); |
| 294 _memberMap.values.forEach(f); |
| 295 for (ir.Member member in _setterMap.values) { |
| 296 if (member is ir.Procedure) { |
| 297 f(member); |
| 298 } else { |
| 299 // Skip fields; these are also in _memberMap. |
| 300 } |
| 301 } |
| 302 } |
| 303 |
| 304 void forEachConstructor(void f(ir.Member member)) { |
| 305 _ensureMaps(); |
| 306 _constructorMap.values.forEach(f); |
| 307 } |
| 308 |
| 309 Iterable<ConstantValue> getMetadata(KernelToElementMapBase elementMap) { |
| 310 return _metadata ??= elementMap.getMetadata(cls.annotations); |
| 311 } |
| 312 } |
| 313 |
| 314 class MemberData { |
| 315 final ir.Member node; |
| 316 Iterable<ConstantValue> _metadata; |
| 317 |
| 318 MemberData(this.node); |
| 319 |
| 320 ResolutionImpact getWorldImpact(KernelToElementMapForImpact elementMap) { |
| 321 return buildKernelImpact(node, elementMap); |
| 322 } |
| 323 |
| 324 Iterable<ConstantValue> getMetadata(KernelToElementMapBase elementMap) { |
| 325 return _metadata ??= elementMap.getMetadata(node.annotations); |
| 326 } |
| 327 } |
| 328 |
| 329 class FunctionData extends MemberData { |
| 330 final ir.FunctionNode functionNode; |
| 331 FunctionType _type; |
| 332 |
| 333 FunctionData(ir.Member node, this.functionNode) : super(node); |
| 334 |
| 335 FunctionType getFunctionType(KernelToElementMapBase elementMap) { |
| 336 return _type ??= elementMap.getFunctionType(functionNode); |
| 337 } |
| 338 |
| 339 void forEachParameter(KernelToElementMapForBuilding elementMap, |
| 340 void f(DartType type, String name, ConstantValue defaultValue)) { |
| 341 void handleParameter(ir.VariableDeclaration node, {bool isOptional: true}) { |
| 342 DartType type = elementMap.getDartType(node.type); |
| 343 String name = node.name; |
| 344 ConstantValue defaultValue; |
| 345 if (isOptional) { |
| 346 if (node.initializer != null) { |
| 347 defaultValue = elementMap.getConstantValue(node.initializer); |
| 348 } else { |
| 349 defaultValue = new NullConstantValue(); |
| 350 } |
| 351 } |
| 352 f(type, name, defaultValue); |
| 353 } |
| 354 |
| 355 for (int i = 0; i < functionNode.positionalParameters.length; i++) { |
| 356 handleParameter(functionNode.positionalParameters[i], |
| 357 isOptional: i < functionNode.requiredParameterCount); |
| 358 } |
| 359 functionNode.namedParameters.toList() |
| 360 ..sort(namedOrdering) |
| 361 ..forEach(handleParameter); |
| 362 } |
| 363 } |
| 364 |
| 365 class ConstructorData extends FunctionData { |
| 366 ConstantConstructor _constantConstructor; |
| 367 |
| 368 ConstructorData(ir.Member node, ir.FunctionNode functionNode) |
| 369 : super(node, functionNode); |
| 370 |
| 371 ConstantConstructor getConstructorConstant( |
| 372 KernelToElementMapBase elementMap, ConstructorEntity constructor) { |
| 373 if (_constantConstructor == null) { |
| 374 if (node is ir.Constructor && constructor.isConst) { |
| 375 _constantConstructor = |
| 376 new Constantifier(elementMap).computeConstantConstructor(node); |
| 377 } else { |
| 378 throw new SpannableAssertionFailure( |
| 379 constructor, |
| 380 "Unexpected constructor $constructor in " |
| 381 "KernelWorldBuilder._getConstructorConstant"); |
| 382 } |
| 383 } |
| 384 return _constantConstructor; |
| 385 } |
| 386 } |
| 387 |
| 388 class FieldData extends MemberData { |
| 389 ConstantExpression _constant; |
| 390 |
| 391 FieldData(ir.Field node) : super(node); |
| 392 |
| 393 ir.Field get node => super.node; |
| 394 |
| 395 ConstantExpression getFieldConstant( |
| 396 KernelToElementMapBase elementMap, FieldEntity field) { |
| 397 if (_constant == null) { |
| 398 if (node.isConst) { |
| 399 _constant = new Constantifier(elementMap).visit(node.initializer); |
| 400 } else { |
| 401 throw new SpannableAssertionFailure( |
| 402 field, |
| 403 "Unexpected field $field in " |
| 404 "KernelWorldBuilder._getConstructorConstant"); |
| 405 } |
| 406 } |
| 407 return _constant; |
| 408 } |
| 409 } |
OLD | NEW |