Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(558)

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 2061373003: implement user-defined nSM, Object members on functions (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: fix Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/side_effect_analysis.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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';
OLDNEW
« no previous file with comments | « lib/runtime/dart_sdk.js ('k') | lib/src/compiler/side_effect_analysis.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698