OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 21 matching lines...) Expand all Loading... |
32 show PackageBundleAssembler; | 32 show PackageBundleAssembler; |
33 import 'package:analyzer/src/summary/summary_sdk.dart'; | 33 import 'package:analyzer/src/summary/summary_sdk.dart'; |
34 import 'package:analyzer/src/task/strong/ast_properties.dart' | 34 import 'package:analyzer/src/task/strong/ast_properties.dart' |
35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast; | 35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast; |
36 import 'package:path/path.dart' show separator; | 36 import 'package:path/path.dart' show separator; |
37 | 37 |
38 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 38 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
39 import '../js_ast/js_ast.dart' as JS; | 39 import '../js_ast/js_ast.dart' as JS; |
40 import '../js_ast/js_ast.dart' show js; | 40 import '../js_ast/js_ast.dart' show js; |
41 import 'ast_builder.dart' show AstBuilder; | 41 import 'ast_builder.dart' show AstBuilder; |
42 import 'class_property_model.dart'; | |
43 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; | 42 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; |
44 import 'element_helpers.dart'; | 43 import 'element_helpers.dart'; |
45 import 'element_loader.dart' show ElementLoader; | 44 import 'element_loader.dart' show ElementLoader; |
46 import 'extension_types.dart' show ExtensionTypeSet; | 45 import 'extension_types.dart' show ExtensionTypeSet; |
47 import 'js_interop.dart'; | 46 import 'js_interop.dart'; |
48 import 'js_metalet.dart' as JS; | 47 import 'js_metalet.dart' as JS; |
49 import 'js_names.dart' as JS; | 48 import 'js_names.dart' as JS; |
50 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; | 49 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; |
51 import 'module_builder.dart' show pathToJSIdentifier; | 50 import 'module_builder.dart' show pathToJSIdentifier; |
52 import 'nullable_type_inference.dart' show NullableTypeInference; | 51 import 'nullable_type_inference.dart' show NullableTypeInference; |
| 52 import 'property_model.dart'; |
53 import 'reify_coercions.dart' show CoercionReifier; | 53 import 'reify_coercions.dart' show CoercionReifier; |
54 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; | 54 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; |
55 import 'type_utilities.dart'; | 55 import 'type_utilities.dart'; |
56 | 56 |
57 class CodeGenerator extends GeneralizingAstVisitor | 57 class CodeGenerator extends GeneralizingAstVisitor |
58 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { | 58 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { |
59 final AnalysisContext context; | 59 final AnalysisContext context; |
60 final SummaryDataStore summaryData; | 60 final SummaryDataStore summaryData; |
61 | 61 |
62 final CompilerOptions options; | 62 final CompilerOptions options; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 | 149 |
150 List<TypeParameterType> _typeParamInConst = null; | 150 List<TypeParameterType> _typeParamInConst = null; |
151 | 151 |
152 /// Whether we are currently generating code for the body of a `JS()` call. | 152 /// Whether we are currently generating code for the body of a `JS()` call. |
153 bool _isInForeignJS = false; | 153 bool _isInForeignJS = false; |
154 | 154 |
155 /// Information about virtual and overridden fields/getters/setters in the | 155 /// Information about virtual and overridden fields/getters/setters in the |
156 /// class we're currently compiling, or `null` if we aren't compiling a class. | 156 /// class we're currently compiling, or `null` if we aren't compiling a class. |
157 ClassPropertyModel _classProperties; | 157 ClassPropertyModel _classProperties; |
158 | 158 |
| 159 /// Information about virtual fields for all libraries in the current build |
| 160 /// unit. |
| 161 final virtualFields = new VirtualFieldModel(); |
| 162 |
159 CodeGenerator( | 163 CodeGenerator( |
160 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) | 164 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) |
161 : context = c, | 165 : context = c, |
162 rules = new StrongTypeSystemImpl(c.typeProvider), | 166 rules = new StrongTypeSystemImpl(c.typeProvider), |
163 types = c.typeProvider, | 167 types = c.typeProvider, |
164 _asyncStreamIterator = | 168 _asyncStreamIterator = |
165 _getLibrary(c, 'dart:async').getType('StreamIterator').type, | 169 _getLibrary(c, 'dart:async').getType('StreamIterator').type, |
166 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), | 170 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), |
167 interceptorClass = | 171 interceptorClass = |
168 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), | 172 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 } | 243 } |
240 | 244 |
241 JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) { | 245 JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) { |
242 if (_moduleItems.isNotEmpty) { | 246 if (_moduleItems.isNotEmpty) { |
243 throw new StateError('Can only call emitModule once.'); | 247 throw new StateError('Can only call emitModule once.'); |
244 } | 248 } |
245 | 249 |
246 // Transform the AST to make coercions explicit. | 250 // Transform the AST to make coercions explicit. |
247 compilationUnits = CoercionReifier.reify(compilationUnits); | 251 compilationUnits = CoercionReifier.reify(compilationUnits); |
248 | 252 |
249 if (compilationUnits.any((u) => _isDartRuntime( | 253 if (compilationUnits.any((u) => isSdkInternalRuntime( |
250 resolutionMap.elementDeclaredByCompilationUnit(u).library))) { | 254 resolutionMap.elementDeclaredByCompilationUnit(u).library))) { |
251 // Don't allow these to be renamed when we're building the SDK. | 255 // Don't allow these to be renamed when we're building the SDK. |
252 // There is JS code in dart:* that depends on their names. | 256 // There is JS code in dart:* that depends on their names. |
253 _runtimeModule = new JS.Identifier('dart'); | 257 _runtimeModule = new JS.Identifier('dart'); |
254 _extensionSymbolsModule = new JS.Identifier('dartx'); | 258 _extensionSymbolsModule = new JS.Identifier('dartx'); |
255 } else { | 259 } else { |
256 // Otherwise allow these to be renamed so users can write them. | 260 // Otherwise allow these to be renamed so users can write them. |
257 _runtimeModule = new JS.TemporaryId('dart'); | 261 _runtimeModule = new JS.TemporaryId('dart'); |
258 _extensionSymbolsModule = new JS.TemporaryId('dartx'); | 262 _extensionSymbolsModule = new JS.TemporaryId('dartx'); |
259 } | 263 } |
260 _typeTable = new TypeTable(_runtimeModule); | 264 _typeTable = new TypeTable(_runtimeModule); |
261 | 265 |
262 // Initialize our library variables. | 266 // Initialize our library variables. |
263 var items = <JS.ModuleItem>[]; | 267 var items = <JS.ModuleItem>[]; |
264 for (var unit in compilationUnits) { | 268 for (var unit in compilationUnits) { |
265 var library = | 269 var library = |
266 resolutionMap.elementDeclaredByCompilationUnit(unit).library; | 270 resolutionMap.elementDeclaredByCompilationUnit(unit).library; |
267 if (unit.element != library.definingCompilationUnit) continue; | 271 if (unit.element != library.definingCompilationUnit) continue; |
268 | 272 |
269 var libraryTemp = _isDartRuntime(library) | 273 var libraryTemp = isSdkInternalRuntime(library) |
270 ? _runtimeModule | 274 ? _runtimeModule |
271 : new JS.TemporaryId(jsLibraryName(_libraryRoot, library)); | 275 : new JS.TemporaryId(jsLibraryName(_libraryRoot, library)); |
272 _libraries[library] = libraryTemp; | 276 _libraries[library] = libraryTemp; |
273 items.add(new JS.ExportDeclaration( | 277 items.add(new JS.ExportDeclaration( |
274 js.call('const # = Object.create(null)', [libraryTemp]))); | 278 js.call('const # = Object.create(null)', [libraryTemp]))); |
275 | 279 |
276 // dart:_runtime has a magic module that holds extension method symbols. | 280 // dart:_runtime has a magic module that holds extension method symbols. |
277 // TODO(jmesserly): find a cleaner design for this. | 281 // TODO(jmesserly): find a cleaner design for this. |
278 if (_isDartRuntime(library)) { | 282 if (isSdkInternalRuntime(library)) { |
279 items.add(new JS.ExportDeclaration(js | 283 items.add(new JS.ExportDeclaration(js |
280 .call('const # = Object.create(null)', [_extensionSymbolsModule]))); | 284 .call('const # = Object.create(null)', [_extensionSymbolsModule]))); |
281 } | 285 } |
282 } | 286 } |
283 | 287 |
284 // Collect all Element -> Node mappings, in case we need to forward declare | 288 // Collect all Element -> Node mappings, in case we need to forward declare |
285 // any nodes. | 289 // any nodes. |
286 var nodes = new HashMap<Element, AstNode>.identity(); | 290 var nodes = new HashMap<Element, AstNode>.identity(); |
287 var sdkBootstrappingFns = new List<FunctionElement>(); | 291 var sdkBootstrappingFns = new List<FunctionElement>(); |
288 for (var unit in compilationUnits) { | 292 for (var unit in compilationUnits) { |
289 if (_isDartRuntime( | 293 if (isSdkInternalRuntime( |
290 resolutionMap.elementDeclaredByCompilationUnit(unit).library)) { | 294 resolutionMap.elementDeclaredByCompilationUnit(unit).library)) { |
291 sdkBootstrappingFns.addAll( | 295 sdkBootstrappingFns.addAll( |
292 resolutionMap.elementDeclaredByCompilationUnit(unit).functions); | 296 resolutionMap.elementDeclaredByCompilationUnit(unit).functions); |
293 } | 297 } |
294 _collectElements(unit, nodes); | 298 _collectElements(unit, nodes); |
295 } | 299 } |
296 _loader = new ElementLoader(nodes); | 300 _loader = new ElementLoader(nodes); |
297 if (compilationUnits.isNotEmpty) { | 301 if (compilationUnits.isNotEmpty) { |
298 _constants = new ConstFieldVisitor(context, | 302 _constants = new ConstFieldVisitor(context, |
299 dummySource: resolutionMap | 303 dummySource: resolutionMap |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 if (classElem.typeParameters.isNotEmpty) { | 827 if (classElem.typeParameters.isNotEmpty) { |
824 // Generic classes will be defined inside a function that closes over the | 828 // Generic classes will be defined inside a function that closes over the |
825 // type parameter. So we can use their local variable name directly. | 829 // type parameter. So we can use their local variable name directly. |
826 className = new JS.Identifier(classElem.name); | 830 className = new JS.Identifier(classElem.name); |
827 } else { | 831 } else { |
828 className = _emitTopLevelName(classElem); | 832 className = _emitTopLevelName(classElem); |
829 } | 833 } |
830 | 834 |
831 var extensions = _extensionsToImplement(classElem); | 835 var extensions = _extensionsToImplement(classElem); |
832 var savedClassProperties = _classProperties; | 836 var savedClassProperties = _classProperties; |
833 _classProperties = new ClassPropertyModel.build(classElem, extensions); | 837 _classProperties = |
| 838 new ClassPropertyModel.build(virtualFields, classElem, extensions); |
834 | 839 |
835 var classExpr = _emitClassExpression( | 840 var classExpr = _emitClassExpression( |
836 classElem, _emitClassMethods(node, ctors, fields), | 841 classElem, _emitClassMethods(node, ctors, fields), |
837 fields: allFields); | 842 fields: allFields); |
838 | 843 |
839 var body = <JS.Statement>[]; | 844 var body = <JS.Statement>[]; |
840 _initExtensionSymbols(classElem, methods, fields, body); | 845 _initExtensionSymbols(classElem, methods, fields, body); |
841 _emitSuperHelperSymbols(_superHelperSymbols, body); | 846 _emitSuperHelperSymbols(_superHelperSymbols, body); |
842 | 847 |
843 // Emit the class, e.g. `core.Object = class Object { ... }` | 848 // Emit the class, e.g. `core.Object = class Object { ... }` |
(...skipping 1669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2513 var fn = _emitFunction(node.functionExpression); | 2518 var fn = _emitFunction(node.functionExpression); |
2514 | 2519 |
2515 if (currentLibrary.source.isInSystemLibrary && | 2520 if (currentLibrary.source.isInSystemLibrary && |
2516 _isInlineJSFunction(node.functionExpression)) { | 2521 _isInlineJSFunction(node.functionExpression)) { |
2517 fn = _simplifyPassThroughArrowFunCallBody(fn); | 2522 fn = _simplifyPassThroughArrowFunCallBody(fn); |
2518 } | 2523 } |
2519 | 2524 |
2520 var element = resolutionMap.elementDeclaredByFunctionDeclaration(node); | 2525 var element = resolutionMap.elementDeclaredByFunctionDeclaration(node); |
2521 var nameExpr = _emitTopLevelName(element); | 2526 var nameExpr = _emitTopLevelName(element); |
2522 body.add(annotate(js.statement('# = #', [nameExpr, fn]), node, element)); | 2527 body.add(annotate(js.statement('# = #', [nameExpr, fn]), node, element)); |
2523 if (!_isDartRuntime(element.library)) { | 2528 if (!isSdkInternalRuntime(element.library)) { |
2524 body.add(_emitFunctionTagged(nameExpr, element.type, topLevel: true) | 2529 body.add(_emitFunctionTagged(nameExpr, element.type, topLevel: true) |
2525 .toStatement()); | 2530 .toStatement()); |
2526 } | 2531 } |
2527 | 2532 |
2528 return _statement(body); | 2533 return _statement(body); |
2529 } | 2534 } |
2530 | 2535 |
2531 bool _isInlineJSFunction(FunctionExpression functionExpression) { | 2536 bool _isInlineJSFunction(FunctionExpression functionExpression) { |
2532 var body = functionExpression.body; | 2537 var body = functionExpression.body; |
2533 if (body is ExpressionFunctionBody) { | 2538 if (body is ExpressionFunctionBody) { |
(...skipping 1552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4086 eagerInit = _loader.isLoaded(element); | 4091 eagerInit = _loader.isLoaded(element); |
4087 } else { | 4092 } else { |
4088 // TODO(jmesserly): we're visiting the initializer here, and again | 4093 // TODO(jmesserly): we're visiting the initializer here, and again |
4089 // later on when we emit lazy fields. That seems busted. | 4094 // later on when we emit lazy fields. That seems busted. |
4090 jsInit = _visitInitializer(field); | 4095 jsInit = _visitInitializer(field); |
4091 eagerInit = false; | 4096 eagerInit = false; |
4092 } | 4097 } |
4093 | 4098 |
4094 // Treat dart:runtime stuff as safe to eagerly evaluate. | 4099 // Treat dart:runtime stuff as safe to eagerly evaluate. |
4095 // TODO(jmesserly): it'd be nice to avoid this special case. | 4100 // TODO(jmesserly): it'd be nice to avoid this special case. |
4096 var isJSTopLevel = field.isFinal && _isDartRuntime(element.library); | 4101 var isJSTopLevel = field.isFinal && isSdkInternalRuntime(element.library); |
4097 if (eagerInit || isJSTopLevel) { | 4102 if (eagerInit || isJSTopLevel) { |
4098 // Remember that we emitted it this way, so re-export can take advantage | 4103 // Remember that we emitted it this way, so re-export can take advantage |
4099 // of this fact. | 4104 // of this fact. |
4100 _eagerTopLevelFields.add(element); | 4105 _eagerTopLevelFields.add(element); |
4101 | 4106 |
4102 return annotate( | 4107 return annotate( |
4103 js.statement('# = #;', [_emitTopLevelName(element), jsInit]), | 4108 js.statement('# = #;', [_emitTopLevelName(element), jsInit]), |
4104 field, | 4109 field, |
4105 element); | 4110 element); |
4106 } | 4111 } |
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5016 } | 5021 } |
5017 return _callHelper('#(#, #)', | 5022 return _callHelper('#(#, #)', |
5018 [_emitDynamicOperationName('dload'), _visit(target), name]); | 5023 [_emitDynamicOperationName('dload'), _visit(target), name]); |
5019 } | 5024 } |
5020 | 5025 |
5021 var jsTarget = _emitTarget(target, member, isStatic); | 5026 var jsTarget = _emitTarget(target, member, isStatic); |
5022 bool isSuper = jsTarget is JS.Super; | 5027 bool isSuper = jsTarget is JS.Super; |
5023 if (isSuper && | 5028 if (isSuper && |
5024 !member.isSynthetic && | 5029 !member.isSynthetic && |
5025 member is FieldElementImpl && | 5030 member is FieldElementImpl && |
5026 !member.isVirtual) { | 5031 !virtualFields.isVirtual(member)) { |
5027 // If super.x is a sealed field, then x is an instance property since | 5032 // If super.x is a sealed field, then x is an instance property since |
5028 // subclasses cannot override x. | 5033 // subclasses cannot override x. |
5029 jsTarget = new JS.This(); | 5034 jsTarget = new JS.This(); |
5030 } | 5035 } |
5031 | 5036 |
5032 JS.Expression result; | 5037 JS.Expression result; |
5033 if (member != null && member is MethodElement && !isStatic) { | 5038 if (member != null && member is MethodElement && !isStatic) { |
5034 // Tear-off methods: explicitly bind it. | 5039 // Tear-off methods: explicitly bind it. |
5035 // To be safe always use the symbolized name when binding on a native | 5040 // To be safe always use the symbolized name when binding on a native |
5036 // class as bind assumes the name will match the name class sigatures | 5041 // class as bind assumes the name will match the name class sigatures |
(...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6013 | 6018 |
6014 bool operator ==(Object other) => identical(this, other); | 6019 bool operator ==(Object other) => identical(this, other); |
6015 } | 6020 } |
6016 | 6021 |
6017 bool isLibraryPrefix(Expression node) => | 6022 bool isLibraryPrefix(Expression node) => |
6018 node is SimpleIdentifier && node.staticElement is PrefixElement; | 6023 node is SimpleIdentifier && node.staticElement is PrefixElement; |
6019 | 6024 |
6020 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 6025 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
6021 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 6026 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
6022 | 6027 |
6023 bool _isDartRuntime(LibraryElement l) => | |
6024 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | |
6025 | |
6026 /// Returns `true` if [target] is a prefix for a deferred library and [name] | 6028 /// Returns `true` if [target] is a prefix for a deferred library and [name] |
6027 /// is "loadLibrary". | 6029 /// is "loadLibrary". |
6028 /// | 6030 /// |
6029 /// If so, the expression should be compiled to call the runtime's | 6031 /// If so, the expression should be compiled to call the runtime's |
6030 /// "loadLibrary" helper function. | 6032 /// "loadLibrary" helper function. |
6031 bool _isDeferredLoadLibrary(Expression target, SimpleIdentifier name) { | 6033 bool _isDeferredLoadLibrary(Expression target, SimpleIdentifier name) { |
6032 if (name.name != "loadLibrary") return false; | 6034 if (name.name != "loadLibrary") return false; |
6033 | 6035 |
6034 if (target is! SimpleIdentifier) return false; | 6036 if (target is! SimpleIdentifier) return false; |
6035 var targetIdentifier = target as SimpleIdentifier; | 6037 var targetIdentifier = target as SimpleIdentifier; |
6036 | 6038 |
6037 if (targetIdentifier.staticElement is! PrefixElement) return false; | 6039 if (targetIdentifier.staticElement is! PrefixElement) return false; |
6038 var prefix = targetIdentifier.staticElement as PrefixElement; | 6040 var prefix = targetIdentifier.staticElement as PrefixElement; |
6039 | 6041 |
6040 // The library the prefix is referring to must come from a deferred import. | 6042 // The library the prefix is referring to must come from a deferred import. |
6041 var containingLibrary = resolutionMap | 6043 var containingLibrary = resolutionMap |
6042 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 6044 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
6043 .library; | 6045 .library; |
6044 var imports = containingLibrary.getImportsWithPrefix(prefix); | 6046 var imports = containingLibrary.getImportsWithPrefix(prefix); |
6045 return imports.length == 1 && imports[0].isDeferred; | 6047 return imports.length == 1 && imports[0].isDeferred; |
6046 } | 6048 } |
OLD | NEW |