| 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 |