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

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

Issue 2362563004: re-land fix #27110 with proper DDC side of changes (Closed)
Patch Set: add tests Created 4 years, 3 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
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
2 // 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
3 // BSD-style license that can be found in the LICENSE file. 4 // BSD-style license that can be found in the LICENSE file.
4 5
5 import 'dart:collection' show HashMap, HashSet; 6 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max; 7 import 'dart:math' show min, max;
7 8
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 11 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
11 import 'package:analyzer/dart/element/element.dart'; 12 import 'package:analyzer/dart/element/element.dart';
(...skipping 10 matching lines...) Expand all
22 show StrongTypeSystemImpl; 23 show StrongTypeSystemImpl;
23 import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit; 24 import 'package:analyzer/src/summary/idl.dart' show UnlinkedUnit;
24 import 'package:analyzer/src/summary/link.dart' as summary_link; 25 import 'package:analyzer/src/summary/link.dart' as summary_link;
25 import 'package:analyzer/src/summary/package_bundle_reader.dart'; 26 import 'package:analyzer/src/summary/package_bundle_reader.dart';
26 import 'package:analyzer/src/summary/summarize_ast.dart' 27 import 'package:analyzer/src/summary/summarize_ast.dart'
27 show serializeAstUnlinked; 28 show serializeAstUnlinked;
28 import 'package:analyzer/src/summary/summarize_elements.dart' 29 import 'package:analyzer/src/summary/summarize_elements.dart'
29 show PackageBundleAssembler; 30 show PackageBundleAssembler;
30 import 'package:analyzer/src/summary/summary_sdk.dart'; 31 import 'package:analyzer/src/summary/summary_sdk.dart';
31 import 'package:analyzer/src/task/strong/ast_properties.dart' 32 import 'package:analyzer/src/task/strong/ast_properties.dart'
32 show isDynamicInvoke, setIsDynamicInvoke; 33 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast;
33 import 'package:path/path.dart' show separator; 34 import 'package:path/path.dart' show separator;
34 35
35 import '../closure/closure_annotator.dart' show ClosureAnnotator; 36 import '../closure/closure_annotator.dart' show ClosureAnnotator;
36 import '../js_ast/js_ast.dart' as JS; 37 import '../js_ast/js_ast.dart' as JS;
37 import '../js_ast/js_ast.dart' show js; 38 import '../js_ast/js_ast.dart' show js;
38 import 'ast_builder.dart' show AstBuilder; 39 import 'ast_builder.dart' show AstBuilder;
39 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; 40 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile;
40 import 'element_helpers.dart'; 41 import 'element_helpers.dart';
41 import 'element_loader.dart' show ElementLoader; 42 import 'element_loader.dart' show ElementLoader;
42 import 'extension_types.dart' show ExtensionTypeSet; 43 import 'extension_types.dart' show ExtensionTypeSet;
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 return js.call('dart.asInt(#)', jsFrom); 553 return js.call('dart.asInt(#)', jsFrom);
553 } 554 }
554 555
555 // A no-op in JavaScript. 556 // A no-op in JavaScript.
556 return jsFrom; 557 return jsFrom;
557 } 558 }
558 559
559 var type = _emitType(to, 560 var type = _emitType(to,
560 nameType: options.nameTypeTests || options.hoistTypeTests, 561 nameType: options.nameTypeTests || options.hoistTypeTests,
561 hoistType: options.hoistTypeTests); 562 hoistType: options.hoistTypeTests);
562 if (isReifiedCoercion(node)) { 563 if (CoercionReifier.isImplicitCast(node)) {
563 return js.call('#._check(#)', [type, jsFrom]); 564 return js.call('#._check(#)', [type, jsFrom]);
564 } else { 565 } else {
565 return js.call('#.as(#)', [type, jsFrom]); 566 return js.call('#.as(#)', [type, jsFrom]);
566 } 567 }
567 } 568 }
568 569
569 bool isReifiedCoercion(AstNode node) {
570 // TODO(sra): Find a better way to recognize reified coercion, since we
571 // can't set the isSynthetic attribute.
572 return (node is AsExpression) && (node.asOperator.offset == 0);
573 }
574
575 @override 570 @override
576 visitIsExpression(IsExpression node) { 571 visitIsExpression(IsExpression node) {
577 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. 572 // Generate `is` as `dart.is` or `typeof` depending on the RHS type.
578 JS.Expression result; 573 JS.Expression result;
579 var type = node.type.type; 574 var type = node.type.type;
580 var lhs = _visit(node.expression); 575 var lhs = _visit(node.expression);
581 var typeofName = _jsTypeofName(type); 576 var typeofName = _jsTypeofName(type);
582 if (typeofName != null) { 577 if (typeofName != null) {
583 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]); 578 result = js.call('typeof # == #', [lhs, js.string(typeofName, "'")]);
584 } else { 579 } else {
(...skipping 1338 matching lines...) Expand 10 before | Expand all | Expand 10 after
1923 if (redirect != null) { 1918 if (redirect != null) {
1924 var newKeyword = redirect.staticElement.isFactory ? '' : 'new'; 1919 var newKeyword = redirect.staticElement.isFactory ? '' : 'new';
1925 // Pass along all arguments verbatim, and let the callee handle them. 1920 // Pass along all arguments verbatim, and let the callee handle them.
1926 // TODO(jmesserly): we'll need something different once we have 1921 // TODO(jmesserly): we'll need something different once we have
1927 // rest/spread support, but this should work for now. 1922 // rest/spread support, but this should work for now.
1928 var params = 1923 var params =
1929 visitFormalParameterList(node.parameters, destructure: false); 1924 visitFormalParameterList(node.parameters, destructure: false);
1930 1925
1931 var fun = new JS.Fun( 1926 var fun = new JS.Fun(
1932 params, 1927 params,
1933 js.statement( 1928 js.statement('{ return $newKeyword #(#); }',
1934 '{ return $newKeyword #(#); }', [_visit(redirect), params]), 1929 [_visit(redirect) as JS.Node, params]),
1935 returnType: returnType); 1930 returnType: returnType);
1936 return annotate( 1931 return annotate(
1937 new JS.Method(name, fun, isStatic: true), node, node.element); 1932 new JS.Method(name, fun, isStatic: true), node, node.element);
1938 } 1933 }
1939 1934
1940 // For const constructors we need to ensure default values are 1935 // For const constructors we need to ensure default values are
1941 // available for use by top-level constant initializers. 1936 // available for use by top-level constant initializers.
1942 ClassDeclaration cls = node.parent; 1937 ClassDeclaration cls = node.parent;
1943 if (node.constKeyword != null) _loader.startTopLevel(cls.element); 1938 if (node.constKeyword != null) _loader.startTopLevel(cls.element);
1944 var params = visitFormalParameterList(node.parameters); 1939 var params = visitFormalParameterList(node.parameters);
(...skipping 1062 matching lines...) Expand 10 before | Expand all | Expand 10 after
3007 var t = _bindValue(vars, 't', x, context: x); 3002 var t = _bindValue(vars, 't', x, context: x);
3008 return new JS.MetaLet(vars, [ 3003 return new JS.MetaLet(vars, [
3009 js.call('# == null ? # : #', [_visit(t), _emitSet(x, right), _visit(t)]) 3004 js.call('# == null ? # : #', [_visit(t), _emitSet(x, right), _visit(t)])
3010 ]); 3005 ]);
3011 } 3006 }
3012 3007
3013 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions 3008 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions
3014 // (for example, x is IndexExpression) we evaluate those once. 3009 // (for example, x is IndexExpression) we evaluate those once.
3015 var vars = <JS.MetaLetVariable, JS.Expression>{}; 3010 var vars = <JS.MetaLetVariable, JS.Expression>{};
3016 var lhs = _bindLeftHandSide(vars, left, context: context); 3011 var lhs = _bindLeftHandSide(vars, left, context: context);
3017 var inc = AstBuilder.binaryExpression(lhs, op, right); 3012 Expression inc = AstBuilder.binaryExpression(lhs, op, right)
3018 inc.staticElement = element; 3013 ..staticElement = element
3019 inc.staticType = getStaticType(left); 3014 ..staticType = getStaticType(lhs);
3015
3016 var castTo = getImplicitAssignmentCast(left);
3017 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo);
3020 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); 3018 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]);
3021 } 3019 }
3022 3020
3023 JS.Expression _emitSet(Expression lhs, Expression rhs) { 3021 JS.Expression _emitSet(Expression lhs, Expression rhs) {
3024 if (lhs is IndexExpression) { 3022 if (lhs is IndexExpression) {
3025 var target = _getTarget(lhs); 3023 var target = _getTarget(lhs);
3026 if (_useNativeJsIndexer(target.staticType)) { 3024 if (_useNativeJsIndexer(target.staticType)) {
3027 return js 3025 return js
3028 .call('#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]); 3026 .call('#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]);
3029 } 3027 }
(...skipping 1507 matching lines...) Expand 10 before | Expand all | Expand 10 after
4537 _createTemporary('_', nodeTarget.staticType, nullable: false); 4535 _createTemporary('_', nodeTarget.staticType, nullable: false);
4538 var baseNode = _stripNullAwareOp(node, param); 4536 var baseNode = _stripNullAwareOp(node, param);
4539 tail.add( 4537 tail.add(
4540 new JS.ArrowFun(<JS.Parameter>[_visit(param)], _visit(baseNode))); 4538 new JS.ArrowFun(<JS.Parameter>[_visit(param)], _visit(baseNode)));
4541 node = nodeTarget; 4539 node = nodeTarget;
4542 } else { 4540 } else {
4543 break; 4541 break;
4544 } 4542 }
4545 } 4543 }
4546 if (tail.isEmpty) return _visit(node); 4544 if (tail.isEmpty) return _visit(node);
4547 return js.call('dart.nullSafe(#, #)', [_visit(node), tail.reversed]); 4545 return js.call(
4546 'dart.nullSafe(#, #)', [_visit(node) as JS.Expression, tail.reversed]);
4548 } 4547 }
4549 4548
4550 static Token _getOperator(Expression node) { 4549 static Token _getOperator(Expression node) {
4551 if (node is PropertyAccess) return node.operator; 4550 if (node is PropertyAccess) return node.operator;
4552 if (node is MethodInvocation) return node.operator; 4551 if (node is MethodInvocation) return node.operator;
4553 return null; 4552 return null;
4554 } 4553 }
4555 4554
4556 // TODO(jmesserly): this is dropping source location. 4555 // TODO(jmesserly): this is dropping source location.
4557 Expression _stripNullAwareOp(Expression node, Expression newTarget) { 4556 Expression _stripNullAwareOp(Expression node, Expression newTarget) {
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
4690 var vars = <JS.MetaLetVariable, JS.Expression>{}; 4689 var vars = <JS.MetaLetVariable, JS.Expression>{};
4691 var l = _visit(_bindValue(vars, 'l', target)); 4690 var l = _visit(_bindValue(vars, 'l', target));
4692 return new JS.MetaLet(vars, [ 4691 return new JS.MetaLet(vars, [
4693 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).call(#, #)', 4692 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #]).call(#, #)',
4694 [l, l, memberName, memberName, l, _visitList(args)]) 4693 [l, l, memberName, memberName, l, _visitList(args)])
4695 ]); 4694 ]);
4696 } 4695 }
4697 // dynamic dispatch 4696 // dynamic dispatch
4698 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name]; 4697 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name];
4699 if (dynamicHelper != null) { 4698 if (dynamicHelper != null) {
4700 return js.call( 4699 return js.call('dart.$dynamicHelper(#, #)',
4701 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); 4700 [_visit(target) as JS.Expression, _visitList(args)]);
4702 } else { 4701 } else {
4703 return js.call('dart.dsend(#, #, #)', 4702 return js.call('dart.dsend(#, #, #)',
4704 [_visit(target), memberName, _visitList(args)]); 4703 [_visit(target), memberName, _visitList(args)]);
4705 } 4704 }
4706 } 4705 }
4707 4706
4708 // Generic dispatch to a statically known method. 4707 // Generic dispatch to a statically known method.
4709 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); 4708 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]);
4710 } 4709 }
4711 4710
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
5045 5044
5046 if (isConst) return _cacheConst(emitList); 5045 if (isConst) return _cacheConst(emitList);
5047 return emitList(); 5046 return emitList();
5048 } 5047 }
5049 5048
5050 @override 5049 @override
5051 visitMapLiteral(MapLiteral node) { 5050 visitMapLiteral(MapLiteral node) {
5052 // TODO(jmesserly): we can likely make these faster. 5051 // TODO(jmesserly): we can likely make these faster.
5053 JS.Expression emitMap() { 5052 JS.Expression emitMap() {
5054 var entries = node.entries; 5053 var entries = node.entries;
5055 var mapArguments = null; 5054 Object mapArguments = null;
5056 var type = node.staticType as InterfaceType; 5055 var type = node.staticType as InterfaceType;
5057 var typeArgs = type.typeArguments; 5056 var typeArgs = type.typeArguments;
5058 var reifyTypeArgs = typeArgs.any((t) => !t.isDynamic); 5057 var reifyTypeArgs = typeArgs.any((t) => !t.isDynamic);
5059 if (entries.isEmpty && !reifyTypeArgs) { 5058 if (entries.isEmpty && !reifyTypeArgs) {
5060 mapArguments = []; 5059 mapArguments = [];
5061 } else if (entries.every((e) => e.key is StringLiteral)) { 5060 } else if (entries.every((e) => e.key is StringLiteral)) {
5062 // Use JS object literal notation if possible, otherwise use an array. 5061 // Use JS object literal notation if possible, otherwise use an array.
5063 // We could do this any time all keys are non-nullable String type. 5062 // We could do this any time all keys are non-nullable String type.
5064 // For now, support StringLiteral as the common non-nullable String case . 5063 // For now, support StringLiteral as the common non-nullable String case .
5065 var props = <JS.Property>[]; 5064 var props = <JS.Property>[];
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
5167 if (node is BinaryExpression) { 5166 if (node is BinaryExpression) {
5168 JS.Expression shortCircuit(String code) { 5167 JS.Expression shortCircuit(String code) {
5169 return finish(js.call(code, 5168 return finish(js.call(code,
5170 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); 5169 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)]));
5171 } 5170 }
5172 5171
5173 var op = node.operator.type.lexeme; 5172 var op = node.operator.type.lexeme;
5174 if (op == '&&') return shortCircuit('# && #'); 5173 if (op == '&&') return shortCircuit('# && #');
5175 if (op == '||') return shortCircuit('# || #'); 5174 if (op == '||') return shortCircuit('# || #');
5176 } 5175 }
5177 if (isReifiedCoercion(node)) { 5176 if (node is AsExpression && CoercionReifier.isImplicitCast(node)) {
5178 AsExpression asNode = node; 5177 assert(node.staticType == types.boolType);
5179 assert(asNode.staticType == types.boolType); 5178 return js.call('dart.test(#)', _visit(node.expression));
5180 return js.call('dart.test(#)', _visit(asNode.expression));
5181 } 5179 }
5182 JS.Expression result = _visit(node); 5180 JS.Expression result = _visit(node);
5183 if (isNullable(node)) result = js.call('dart.test(#)', result); 5181 if (isNullable(node)) result = js.call('dart.test(#)', result);
5184 return result; 5182 return result;
5185 } 5183 }
5186 5184
5187 /// Like [_emitMemberName], but for declaration sites. 5185 /// Like [_emitMemberName], but for declaration sites.
5188 /// 5186 ///
5189 /// Unlike call sites, we always have an element available, so we can use it 5187 /// Unlike call sites, we always have an element available, so we can use it
5190 /// directly rather than computing the relevant options for [_emitMemberName]. 5188 /// directly rather than computing the relevant options for [_emitMemberName].
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
5451 if (uri.scheme == 'package') { 5449 if (uri.scheme == 'package') {
5452 // Strip the package name. 5450 // Strip the package name.
5453 // TODO(vsm): This is not unique if an escaped '/'appears in a filename. 5451 // TODO(vsm): This is not unique if an escaped '/'appears in a filename.
5454 // E.g., "foo/bar.dart" and "foo$47bar.dart" would collide. 5452 // E.g., "foo/bar.dart" and "foo$47bar.dart" would collide.
5455 qualifiedPath = uri.pathSegments.skip(1).join(separator); 5453 qualifiedPath = uri.pathSegments.skip(1).join(separator);
5456 } else if (uri.toFilePath().startsWith(libraryRoot)) { 5454 } else if (uri.toFilePath().startsWith(libraryRoot)) {
5457 qualifiedPath = 5455 qualifiedPath =
5458 uri.path.substring(libraryRoot.length).replaceAll('/', separator); 5456 uri.path.substring(libraryRoot.length).replaceAll('/', separator);
5459 } else { 5457 } else {
5460 // We don't have a unique name. 5458 // We don't have a unique name.
5461 throw 'Invalid library root. $libraryRoot does not contain ${uri.toFilePath( )}'; 5459 throw 'Invalid library root. $libraryRoot does not contain ${uri
5460 .toFilePath()}';
5462 } 5461 }
5463 return pathToJSIdentifier(qualifiedPath); 5462 return pathToJSIdentifier(qualifiedPath);
5464 } 5463 }
5465 5464
5466 /// Shorthand for identifier-like property names. 5465 /// Shorthand for identifier-like property names.
5467 /// For now, we emit them as strings and the printer restores them to 5466 /// For now, we emit them as strings and the printer restores them to
5468 /// identifiers if it can. 5467 /// identifiers if it can.
5469 // TODO(jmesserly): avoid the round tripping through quoted form. 5468 // TODO(jmesserly): avoid the round tripping through quoted form.
5470 JS.LiteralString _propertyName(String name) => js.string(name, "'"); 5469 JS.LiteralString _propertyName(String name) => js.string(name, "'");
5471 5470
5472 // TODO(jacobr): we would like to do something like the following 5471 // TODO(jacobr): we would like to do something like the following
5473 // but we don't have summary support yet. 5472 // but we don't have summary support yet.
5474 // bool _supportJsExtensionMethod(AnnotatedNode node) => 5473 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
5475 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 5474 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
5476 5475
5477 /// A special kind of element created by the compiler, signifying a temporary 5476 /// A special kind of element created by the compiler, signifying a temporary
5478 /// variable. These objects use instance equality, and should be shared 5477 /// variable. These objects use instance equality, and should be shared
5479 /// everywhere in the tree where they are treated as the same variable. 5478 /// everywhere in the tree where they are treated as the same variable.
5480 class TemporaryVariableElement extends LocalVariableElementImpl { 5479 class TemporaryVariableElement extends LocalVariableElementImpl {
5481 final JS.Expression jsVariable; 5480 final JS.Expression jsVariable;
5481
5482 TemporaryVariableElement.forNode(Identifier name, this.jsVariable) 5482 TemporaryVariableElement.forNode(Identifier name, this.jsVariable)
5483 : super.forNode(name); 5483 : super.forNode(name);
5484 5484
5485 int get hashCode => identityHashCode(this); 5485 int get hashCode => identityHashCode(this);
5486
5486 bool operator ==(Object other) => identical(this, other); 5487 bool operator ==(Object other) => identical(this, other);
5487 } 5488 }
5488 5489
5489 bool isLibraryPrefix(Expression node) => 5490 bool isLibraryPrefix(Expression node) =>
5490 node is SimpleIdentifier && node.staticElement is PrefixElement; 5491 node is SimpleIdentifier && node.staticElement is PrefixElement;
5491 5492
5492 LibraryElement _getLibrary(AnalysisContext c, String uri) => 5493 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
5493 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 5494 c.computeLibraryElement(c.sourceFactory.forUri(uri));
5494 5495
5495 bool _isDartRuntime(LibraryElement l) => 5496 bool _isDartRuntime(LibraryElement l) =>
5496 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 5497 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « pkg/dev_compiler/lib/js/legacy/dart_sdk.js ('k') | pkg/dev_compiler/lib/src/compiler/reify_coercions.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698