Chromium Code Reviews| 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 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
| 6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
| 7 | 7 |
| 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 // any nodes. | 248 // any nodes. |
| 249 var nodes = new HashMap<Element, AstNode>.identity(); | 249 var nodes = new HashMap<Element, AstNode>.identity(); |
| 250 var sdkBootstrappingFns = new List<FunctionElement>(); | 250 var sdkBootstrappingFns = new List<FunctionElement>(); |
| 251 for (var unit in compilationUnits) { | 251 for (var unit in compilationUnits) { |
| 252 if (_isDartRuntime(unit.element.library)) { | 252 if (_isDartRuntime(unit.element.library)) { |
| 253 sdkBootstrappingFns.addAll(unit.element.functions); | 253 sdkBootstrappingFns.addAll(unit.element.functions); |
| 254 } | 254 } |
| 255 _collectElements(unit, nodes); | 255 _collectElements(unit, nodes); |
| 256 } | 256 } |
| 257 _loader = new ElementLoader(nodes); | 257 _loader = new ElementLoader(nodes); |
| 258 if (compilationUnits.isNotEmpty) { | |
| 259 _constField = new ConstFieldVisitor(types, | |
| 260 dummySource: compilationUnits.first.element.source); | |
| 261 } | |
| 258 | 262 |
| 259 // Add implicit dart:core dependency so it is first. | 263 // Add implicit dart:core dependency so it is first. |
| 260 emitLibraryName(dartCoreLibrary); | 264 emitLibraryName(dartCoreLibrary); |
| 261 | 265 |
| 262 // Emit SDK bootstrapping functions first, if any. | 266 // Emit SDK bootstrapping functions first, if any. |
| 263 sdkBootstrappingFns.forEach(_emitDeclaration); | 267 sdkBootstrappingFns.forEach(_emitDeclaration); |
| 264 | 268 |
| 265 // Visit each compilation unit and emit its code. | 269 // Visit each compilation unit and emit its code. |
| 266 // | 270 // |
| 267 // NOTE: declarations are not necessarily emitted in this order. | 271 // NOTE: declarations are not necessarily emitted in this order. |
| 268 // Order will be changed as needed so the resulting code can execute. | 272 // Order will be changed as needed so the resulting code can execute. |
| 269 // This is done by forward declaring items. | 273 // This is done by forward declaring items. |
| 270 compilationUnits.forEach(visitCompilationUnit); | 274 compilationUnits.forEach(_finishDeclarationsInUnit); |
| 271 | 275 |
| 272 // Declare imports | 276 // Declare imports |
| 273 _finishImports(items); | 277 _finishImports(items); |
| 274 | 278 |
| 275 // Discharge the type table cache variables and | 279 // Discharge the type table cache variables and |
| 276 // hoisted definitions. | 280 // hoisted definitions. |
| 277 items.addAll(_typeTable.discharge()); | 281 items.addAll(_typeTable.discharge()); |
| 278 | 282 |
| 279 // Add the module's code (produced by visiting compilation units, above) | 283 // Add the module's code (produced by visiting compilation units, above) |
| 280 _copyAndFlattenBlocks(items, _moduleItems); | 284 _copyAndFlattenBlocks(items, _moduleItems); |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 432 return _visit(node); | 436 return _visit(node); |
| 433 }); | 437 }); |
| 434 | 438 |
| 435 if (item != null) _moduleItems.add(item); | 439 if (item != null) _moduleItems.add(item); |
| 436 } | 440 } |
| 437 | 441 |
| 438 void _declareBeforeUse(Element e) { | 442 void _declareBeforeUse(Element e) { |
| 439 _loader.declareBeforeUse(e, _emitDeclaration); | 443 _loader.declareBeforeUse(e, _emitDeclaration); |
| 440 } | 444 } |
| 441 | 445 |
| 442 @override | 446 void _finishDeclarationsInUnit(CompilationUnit unit) { |
| 443 void visitCompilationUnit(CompilationUnit unit) { | 447 // NOTE: this method isn't the right place to initialize |
| 444 _constField = new ConstFieldVisitor(types, unit.element.source); | 448 // per-compilation-unit state. Declarations can be visited out of order, |
| 445 | 449 // this is only to catch things that haven't been emitted yet. |
| 450 // | |
| 451 // See _emitDeclaration. | |
| 446 for (var declaration in unit.declarations) { | 452 for (var declaration in unit.declarations) { |
| 447 var element = declaration.element; | 453 var element = declaration.element; |
| 448 if (element != null) { | 454 if (element != null) { |
| 449 _emitDeclaration(element); | 455 _emitDeclaration(element); |
| 450 } else { | 456 } else { |
| 451 declaration.accept(this); | 457 declaration.accept(this); |
| 452 } | 458 } |
| 453 } | 459 } |
| 454 for (var directive in unit.directives) { | 460 for (var directive in unit.directives) { |
| 455 directive.accept(this); | 461 directive.accept(this); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 | 701 |
| 696 // If this is a JavaScript type, emit it now and then exit. | 702 // If this is a JavaScript type, emit it now and then exit. |
| 697 var jsTypeDef = _emitJsType(classElem); | 703 var jsTypeDef = _emitJsType(classElem); |
| 698 if (jsTypeDef != null) return jsTypeDef; | 704 if (jsTypeDef != null) return jsTypeDef; |
| 699 | 705 |
| 700 var ctors = <ConstructorDeclaration>[]; | 706 var ctors = <ConstructorDeclaration>[]; |
| 701 var fields = <FieldDeclaration>[]; | 707 var fields = <FieldDeclaration>[]; |
| 702 var staticFields = <FieldDeclaration>[]; | 708 var staticFields = <FieldDeclaration>[]; |
| 703 var methods = <MethodDeclaration>[]; | 709 var methods = <MethodDeclaration>[]; |
| 704 | 710 |
| 705 // True if a "call" method or getter exists. This can also be | 711 // True if a "call" method or getter exists. |
| 706 // "noSuchMethod" method, because nSM could implement "call". | |
| 707 bool isCallable = false; | 712 bool isCallable = false; |
| 708 for (var member in node.members) { | 713 for (var member in node.members) { |
| 709 if (member is ConstructorDeclaration) { | 714 if (member is ConstructorDeclaration) { |
| 710 ctors.add(member); | 715 ctors.add(member); |
| 711 } else if (member is FieldDeclaration) { | 716 } else if (member is FieldDeclaration) { |
| 712 (member.isStatic ? staticFields : fields).add(member); | 717 (member.isStatic ? staticFields : fields).add(member); |
| 713 } else if (member is MethodDeclaration) { | 718 } else if (member is MethodDeclaration) { |
| 714 methods.add(member); | 719 methods.add(member); |
| 715 var name = member.name.name; | 720 if (member.name.name == 'call' && !member.isSetter) { |
|
Jennifer Messerly
2016/06/21 20:21:46
When I merged, I had to fix how recently implement
| |
| 716 if (name == 'call' && !member.isSetter) { | 721 // |
| 717 isCallable = true; | 722 // Make sure "call" has a statically known function type: |
| 718 } else if (name == 'noSuchMethod' && | 723 // |
| 719 !member.isGetter && | 724 // - if it's a method, then it does because all methods do, |
| 720 !member.isSetter && | 725 // - if it's a getter, check the return type. |
| 721 // Exclude SDK because we know they don't use nSM to implement call. | 726 // |
| 722 !classElem.library.source.isInSystemLibrary) { | 727 // Other cases like a getter returning dynamic/Object/Function will be |
| 723 isCallable = true; | 728 // handled at runtime by the dynamic call mechanism. So we only |
| 729 // concern ourselves with statically known function types. | |
| 730 // | |
| 731 // For the same reason, we can ignore "noSuchMethod". | |
| 732 // call-implemented-by-nSM will be dispatched by dcall at runtime. | |
| 733 // | |
| 734 isCallable = !member.isGetter || member.returnType is FunctionType; | |
| 724 } | 735 } |
| 725 } | 736 } |
| 726 } | 737 } |
| 727 | 738 |
| 728 JS.Expression className; | 739 JS.Expression className; |
| 729 if (classElem.typeParameters.isNotEmpty) { | 740 if (classElem.typeParameters.isNotEmpty) { |
| 730 // Generic classes will be defined inside a function that closes over the | 741 // Generic classes will be defined inside a function that closes over the |
| 731 // type parameter. So we can use their local variable name directly. | 742 // type parameter. So we can use their local variable name directly. |
| 732 className = new JS.Identifier(classElem.name); | 743 className = new JS.Identifier(classElem.name); |
| 733 } else { | 744 } else { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 785 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. | 796 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. |
| 786 JS.Expression _emitCallableClass(JS.ClassExpression classExpr, | 797 JS.Expression _emitCallableClass(JS.ClassExpression classExpr, |
| 787 ConstructorElement unnamedCtor) { | 798 ConstructorElement unnamedCtor) { |
| 788 var ctor = new JS.NamedFunction( | 799 var ctor = new JS.NamedFunction( |
| 789 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); | 800 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); |
| 790 | 801 |
| 791 // Name the constructor function the same as the class. | 802 // Name the constructor function the same as the class. |
| 792 return js.call('dart.callableClass(#, #)', [ctor, classExpr]); | 803 return js.call('dart.callableClass(#, #)', [ctor, classExpr]); |
| 793 } | 804 } |
| 794 | 805 |
| 795 JS.Fun _emitCallableClassConstructor( | 806 /// Emits a constructor that ensures instances of this class are callable as |
| 796 ConstructorElement ctor) { | 807 /// functions in JavaScript. |
| 808 JS.Fun _emitCallableClassConstructor(ConstructorElement ctor) { | |
| 797 | 809 |
| 798 return js.call( | 810 return js.call( |
| 799 r'''function (...args) { | 811 r'''function (...args) { |
| 800 const self = this; | 812 const self = this; |
| 801 function call(...args) { | 813 function call(...args) { |
| 802 return self.call.apply(self, args); | 814 return self.call.apply(self, args); |
| 803 } | 815 } |
| 804 call.__proto__ = this.__proto__; | 816 call.__proto__ = this.__proto__; |
| 805 call.#.apply(call, args); | 817 call.#.apply(call, args); |
| 806 return call; | 818 return call; |
| (...skipping 3497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4304 /// For example `null.toString()` is legal in Dart, so we need to generate | 4316 /// For example `null.toString()` is legal in Dart, so we need to generate |
| 4305 /// that as `dart.toString(obj)`. | 4317 /// that as `dart.toString(obj)`. |
| 4306 bool _isObjectMemberCall(Expression target, String memberName) { | 4318 bool _isObjectMemberCall(Expression target, String memberName) { |
| 4307 if (!isObjectMember(memberName)) { | 4319 if (!isObjectMember(memberName)) { |
| 4308 return false; | 4320 return false; |
| 4309 } | 4321 } |
| 4310 | 4322 |
| 4311 // Check if the target could be `null`, is dynamic, or may be an extension | 4323 // Check if the target could be `null`, is dynamic, or may be an extension |
| 4312 // native type. In all of those cases we need defensive code generation. | 4324 // native type. In all of those cases we need defensive code generation. |
| 4313 var type = getStaticType(target); | 4325 var type = getStaticType(target); |
| 4326 | |
| 4314 return isNullable(target) || | 4327 return isNullable(target) || |
| 4328 type is FunctionType || | |
| 4315 type.isDynamic || | 4329 type.isDynamic || |
| 4316 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); | 4330 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); |
| 4317 } | 4331 } |
| 4318 | 4332 |
| 4319 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 4333 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
| 4320 JS.Expression _emitAccess( | 4334 JS.Expression _emitAccess( |
| 4321 Expression target, SimpleIdentifier memberId, DartType resultType) { | 4335 Expression target, SimpleIdentifier memberId, DartType resultType) { |
| 4322 Element member = memberId.staticElement; | 4336 Element member = memberId.staticElement; |
| 4323 if (member is PropertyAccessorElement) { | 4337 if (member is PropertyAccessorElement) { |
| 4324 member = (member as PropertyAccessorElement).variable; | 4338 member = (member as PropertyAccessorElement).variable; |
| (...skipping 877 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5202 } | 5216 } |
| 5203 | 5217 |
| 5204 bool isLibraryPrefix(Expression node) => | 5218 bool isLibraryPrefix(Expression node) => |
| 5205 node is SimpleIdentifier && node.staticElement is PrefixElement; | 5219 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 5206 | 5220 |
| 5207 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 5221 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 5208 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 5222 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 5209 | 5223 |
| 5210 bool _isDartRuntime(LibraryElement l) => | 5224 bool _isDartRuntime(LibraryElement l) => |
| 5211 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 5225 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |