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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart

Issue 1195573003: dart2js cps: Refactor and optimize string concatenations. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Remove renegade linebreak Created 5 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 library dart2js.ir_builder_task; 5 library dart2js.ir_builder_task;
6 6
7 import '../closure.dart' as closurelib; 7 import '../closure.dart' as closurelib;
8 import '../closure.dart' hide ClosureScope; 8 import '../closure.dart' hide ClosureScope;
9 import '../constants/expressions.dart'; 9 import '../constants/expressions.dart';
10 import '../dart_types.dart'; 10 import '../dart_types.dart';
11 import '../dart2jslib.dart'; 11 import '../dart2jslib.dart';
12 import '../elements/elements.dart'; 12 import '../elements/elements.dart';
13 import '../elements/modelx.dart' show SynthesizedConstructorElementX, 13 import '../elements/modelx.dart' show SynthesizedConstructorElementX,
14 ConstructorBodyElementX, FunctionSignatureX; 14 ConstructorBodyElementX, FunctionSignatureX;
15 import '../io/source_information.dart'; 15 import '../io/source_information.dart';
16 import '../js_backend/js_backend.dart' show JavaScriptBackend; 16 import '../js_backend/js_backend.dart' show JavaScriptBackend;
17 import '../resolution/semantic_visitor.dart'; 17 import '../resolution/semantic_visitor.dart';
18 import '../resolution/operators.dart' as op; 18 import '../resolution/operators.dart' as op;
19 import '../tree/tree.dart' as ast; 19 import '../tree/tree.dart' as ast;
20 import '../universe/universe.dart' show SelectorKind, CallStructure; 20 import '../universe/universe.dart' show SelectorKind, CallStructure;
21 import '../constants/values.dart' show ConstantValue;
21 import 'cps_ir_nodes.dart' as ir; 22 import 'cps_ir_nodes.dart' as ir;
22 import 'cps_ir_builder.dart'; 23 import 'cps_ir_builder.dart';
23 24
24 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode); 25 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode);
25 26
26 /// This task provides the interface to build IR nodes from [ast.Node]s, which 27 /// This task provides the interface to build IR nodes from [ast.Node]s, which
27 /// is used from the [CpsFunctionCompiler] to generate code. 28 /// is used from the [CpsFunctionCompiler] to generate code.
28 /// 29 ///
29 /// This class is mainly there to correctly measure how long building the IR 30 /// This class is mainly there to correctly measure how long building the IR
30 /// takes. 31 /// takes.
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 variableElement: variableElement, 336 variableElement: variableElement,
336 variableSelector: selector, 337 variableSelector: selector,
337 buildBody: subbuild(node.body), 338 buildBody: subbuild(node.body),
338 target: elements.getTargetDefinition(node), 339 target: elements.getTargetDefinition(node),
339 closureScope: getClosureScopeForNode(node)); 340 closureScope: getClosureScopeForNode(node));
340 } 341 }
341 342
342 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { 343 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
343 assert(irBuilder.isOpen); 344 assert(irBuilder.isOpen);
344 if (node.modifiers.isConst) { 345 if (node.modifiers.isConst) {
345 for (ast.SendSet definition in node.definitions.nodes) { 346 // Do nothing.
346 assert(!definition.arguments.isEmpty); 347 // handleLocalConstantGet inlines the constant at use-site.
347 assert(definition.arguments.tail.isEmpty);
348 VariableElement element = elements[definition];
349 ConstantExpression value = getConstantForVariable(element);
350 irBuilder.declareLocalConstant(element, value);
351 }
352 } else { 348 } else {
353 for (ast.Node definition in node.definitions.nodes) { 349 for (ast.Node definition in node.definitions.nodes) {
354 Element element = elements[definition]; 350 Element element = elements[definition];
355 ir.Primitive initialValue; 351 ir.Primitive initialValue;
356 // Definitions are either SendSets if there is an initializer, or 352 // Definitions are either SendSets if there is an initializer, or
357 // Identifiers if there is no initializer. 353 // Identifiers if there is no initializer.
358 if (definition is ast.SendSet) { 354 if (definition is ast.SendSet) {
359 assert(!definition.arguments.isEmpty); 355 assert(!definition.arguments.isEmpty);
360 assert(definition.arguments.tail.isEmpty); 356 assert(definition.arguments.tail.isEmpty);
361 initialValue = visit(definition.arguments.head); 357 initialValue = visit(definition.arguments.head);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 ir.Primitive visitLiteralNull(ast.LiteralNull node) { 435 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
440 assert(irBuilder.isOpen); 436 assert(irBuilder.isOpen);
441 return irBuilder.buildNullConstant(); 437 return irBuilder.buildNullConstant();
442 } 438 }
443 439
444 ir.Primitive visitLiteralString(ast.LiteralString node) { 440 ir.Primitive visitLiteralString(ast.LiteralString node) {
445 assert(irBuilder.isOpen); 441 assert(irBuilder.isOpen);
446 return irBuilder.buildDartStringConstant(node.dartString); 442 return irBuilder.buildDartStringConstant(node.dartString);
447 } 443 }
448 444
449 ConstantExpression getConstantForNode(ast.Node node) { 445 ConstantValue getConstantForNode(ast.Node node) {
450 ConstantExpression constant = 446 ConstantValue constant =
451 irBuilder.state.constants.getConstantForNode(node, elements); 447 irBuilder.state.constants.getConstantValueForNode(node, elements);
452 assert(invariant(node, constant != null, 448 assert(invariant(node, constant != null,
453 message: 'No constant computed for $node')); 449 message: 'No constant computed for $node'));
454 return constant; 450 return constant;
455 } 451 }
456 452
457 ConstantExpression getConstantForVariable(VariableElement element) { 453 ConstantValue getConstantForVariable(VariableElement element) {
458 ConstantExpression constant = 454 ConstantValue constant =
459 irBuilder.state.constants.getConstantForVariable(element); 455 irBuilder.state.constants.getConstantValueForVariable(element);
460 assert(invariant(element, constant != null, 456 assert(invariant(element, constant != null,
461 message: 'No constant computed for $element')); 457 message: 'No constant computed for $element'));
462 return constant; 458 return constant;
463 } 459 }
464 460
465 /// Builds a constant pulling the value from the constant environment. 461 ir.Primitive buildConstantExpression(ConstantExpression expression) {
466 // TODO(johnniwinther): Remove this when [IrBuilder.buildConstant] only takes 462 return irBuilder.buildConstant(
467 // a [ConstantExpression].
468 ir.Primitive buildConstant(ConstantExpression expression) {
469 return irBuilder.buildConstant(expression,
470 irBuilder.state.constants.getConstantValue(expression)); 463 irBuilder.state.constants.getConstantValue(expression));
471 } 464 }
472 465
473 ir.Primitive visitLiteralList(ast.LiteralList node) { 466 ir.Primitive visitLiteralList(ast.LiteralList node) {
474 if (node.isConst) { 467 if (node.isConst) {
475 return translateConstant(node); 468 return translateConstant(node);
476 } 469 }
477 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); 470 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
478 InterfaceType type = elements.getType(node); 471 InterfaceType type = elements.getType(node);
479 return irBuilder.buildListLiteral(type, values); 472 return irBuilder.buildListLiteral(type, values);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 /// Returns `true` if [node] is a super call. 550 /// Returns `true` if [node] is a super call.
558 // TODO(johnniwinther): Remove the need for this. 551 // TODO(johnniwinther): Remove the need for this.
559 bool isSuperCall(ast.Send node) { 552 bool isSuperCall(ast.Send node) {
560 return node != null && node.receiver != null && node.receiver.isSuper(); 553 return node != null && node.receiver != null && node.receiver.isSuper();
561 } 554 }
562 555
563 @override 556 @override
564 ir.Primitive handleConstantGet( 557 ir.Primitive handleConstantGet(
565 ast.Node node, 558 ast.Node node,
566 ConstantExpression constant, _) { 559 ConstantExpression constant, _) {
567 return buildConstant(constant); 560 return buildConstantExpression(constant);
568 } 561 }
569 562
570 /// If [node] is null, returns this. 563 /// If [node] is null, returns this.
571 /// Otherwise visits [node] and returns the result. 564 /// Otherwise visits [node] and returns the result.
572 ir.Primitive translateReceiver(ast.Expression node) { 565 ir.Primitive translateReceiver(ast.Expression node) {
573 return node != null ? visit(node) : irBuilder.buildThis(); 566 return node != null ? visit(node) : irBuilder.buildThis();
574 } 567 }
575 568
576 @override 569 @override
577 ir.Primitive handleDynamicGet( 570 ir.Primitive handleDynamicGet(
(...skipping 16 matching lines...) Expand all
594 return irBuilder.buildIfNotNullSend( 587 return irBuilder.buildIfNotNullSend(
595 target, 588 target,
596 nested(() => irBuilder.buildDynamicGet(target, selector))); 589 nested(() => irBuilder.buildDynamicGet(target, selector)));
597 } 590 }
598 591
599 @override 592 @override
600 ir.Primitive visitDynamicTypeLiteralGet( 593 ir.Primitive visitDynamicTypeLiteralGet(
601 ast.Send node, 594 ast.Send node,
602 ConstantExpression constant, 595 ConstantExpression constant,
603 _) { 596 _) {
604 return buildConstant(constant); 597 return buildConstantExpression(constant);
605 } 598 }
606 599
607 @override 600 @override
608 ir.Primitive visitLocalVariableGet( 601 ir.Primitive visitLocalVariableGet(
609 ast.Send node, 602 ast.Send node,
610 LocalVariableElement element, 603 LocalVariableElement element,
611 _) { 604 _) {
612 return element.isConst 605 return element.isConst
613 ? buildConstant(getConstantForVariable(element)) 606 ? irBuilder.buildConstant(getConstantForVariable(element))
614 : irBuilder.buildLocalVariableGet(element); 607 : irBuilder.buildLocalVariableGet(element);
615 } 608 }
616 609
617 @override 610 @override
618 ir.Primitive handleLocalGet( 611 ir.Primitive handleLocalGet(
619 ast.Send node, 612 ast.Send node,
620 LocalElement element, 613 LocalElement element,
621 _) { 614 _) {
622 return irBuilder.buildLocalVariableGet(element); 615 return irBuilder.buildLocalVariableGet(element);
623 } 616 }
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 translateDynamicArguments(arguments, callStructure)); 906 translateDynamicArguments(arguments, callStructure));
914 } 907 }
915 908
916 @override 909 @override
917 ir.Primitive handleConstantInvoke( 910 ir.Primitive handleConstantInvoke(
918 ast.Send node, 911 ast.Send node,
919 ConstantExpression constant, 912 ConstantExpression constant,
920 ast.NodeList arguments, 913 ast.NodeList arguments,
921 CallStructure callStructure, 914 CallStructure callStructure,
922 _) { 915 _) {
923 ir.Primitive target = buildConstant(constant); 916 ir.Primitive target = buildConstantExpression(constant);
924 return translateCallInvoke(target, arguments, callStructure); 917 return translateCallInvoke(target, arguments, callStructure);
925 } 918 }
926 919
927 @override 920 @override
928 ir.Primitive handleDynamicInvoke( 921 ir.Primitive handleDynamicInvoke(
929 ast.Send node, 922 ast.Send node,
930 ast.Node receiver, 923 ast.Node receiver,
931 ast.NodeList arguments, 924 ast.NodeList arguments,
932 Selector selector, 925 Selector selector,
933 _) { 926 _) {
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
1250 return irBuilder.buildStaticSetterSet(setter, visit(rhs)); 1243 return irBuilder.buildStaticSetterSet(setter, visit(rhs));
1251 } 1244 }
1252 1245
1253 @override 1246 @override
1254 ir.Primitive handleTypeLiteralConstantCompounds( 1247 ir.Primitive handleTypeLiteralConstantCompounds(
1255 ast.SendSet node, 1248 ast.SendSet node,
1256 ConstantExpression constant, 1249 ConstantExpression constant,
1257 CompoundRhs rhs, 1250 CompoundRhs rhs,
1258 arg) { 1251 arg) {
1259 return translateCompounds( 1252 return translateCompounds(
1260 getValue: () => buildConstant(constant), 1253 getValue: () => buildConstantExpression(constant),
1261 rhs: rhs, 1254 rhs: rhs,
1262 setValue: (value) {}); // The binary operator will throw before this. 1255 setValue: (value) {}); // The binary operator will throw before this.
1263 } 1256 }
1264 1257
1265 @override 1258 @override
1266 ir.Primitive handleDynamicCompounds( 1259 ir.Primitive handleDynamicCompounds(
1267 ast.Send node, 1260 ast.Send node,
1268 ast.Node receiver, 1261 ast.Node receiver,
1269 CompoundRhs rhs, 1262 CompoundRhs rhs,
1270 Selector getterSelector, 1263 Selector getterSelector,
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
1471 setValue: (ir.Primitive result) { 1464 setValue: (ir.Primitive result) {
1472 if (isSetterValid) { 1465 if (isSetterValid) {
1473 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result); 1466 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result);
1474 } else { 1467 } else {
1475 buildInstanceNoSuchMethod( 1468 buildInstanceNoSuchMethod(
1476 new Selector.indexSet(), <ir.Primitive>[indexValue, result]); 1469 new Selector.indexSet(), <ir.Primitive>[indexValue, result]);
1477 } 1470 }
1478 }); 1471 });
1479 } 1472 }
1480 1473
1474 /// Evaluates a string interpolation and appends each part to [accumulator]
1475 /// (after stringify conversion).
1476 void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) {
1477 if (node is ast.StringJuxtaposition) {
1478 buildStringParts(node.first, accumulator);
1479 buildStringParts(node.second, accumulator);
1480 } else if (node is ast.StringInterpolation) {
1481 buildStringParts(node.string, accumulator);
1482 Iterator<ast.Node> it = node.parts.iterator;
karlklose 2015/06/19 08:33:45 How about: for (ast.StringInterpolationPart part
asgerf 2015/06/19 11:04:34 I would love to, but NodeList is not an Iterable.
Kevin Millikin (Google) 2015/06/19 11:36:13 But it has .iterator.
asgerf 2015/06/19 12:00:52 Ah, I thought it really had to be an Iterable. Don
1483 while (it.moveNext()) {
1484 ast.StringInterpolationPart part = it.current;
1485 buildStringParts(part.expression, accumulator);
1486 buildStringParts(part.string, accumulator);
1487 }
1488 } else if (node is ast.LiteralString) {
1489 // Empty strings often occur at the end of a string interpolation,
1490 // do not bother to include them.
1491 if (!node.dartString.isEmpty) {
1492 accumulator.add(irBuilder.buildDartStringConstant(node.dartString));
1493 }
1494 } else if (node is ast.ParenthesizedExpression) {
1495 buildStringParts(node, accumulator);
1496 } else {
1497 ir.Primitive value = visit(node);
1498 accumulator.add(irBuilder.buildStringify(value));
1499 }
1500 }
1501
1481 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { 1502 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
1482 assert(irBuilder.isOpen); 1503 List<ir.Primitive> parts = <ir.Primitive>[];
karlklose 2015/06/19 08:33:44 Shouldn't we keep the assert? (here and in the fun
asgerf 2015/06/19 11:04:34 Done.
1483 ir.Primitive first = visit(node.first); 1504 buildStringParts(node, parts);
1484 ir.Primitive second = visit(node.second); 1505 return irBuilder.buildStringConcatenation(parts);
1485 return irBuilder.buildStringConcatenation([first, second]);
1486 } 1506 }
1487 1507
1488 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) { 1508 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) {
1489 assert(irBuilder.isOpen); 1509 List<ir.Primitive> parts = <ir.Primitive>[];
1490 List<ir.Primitive> arguments = []; 1510 buildStringParts(node, parts);
1491 arguments.add(visitLiteralString(node.string)); 1511 return irBuilder.buildStringConcatenation(parts);
1492 var it = node.parts.iterator;
1493 while (it.moveNext()) {
1494 ast.StringInterpolationPart part = it.current;
1495 arguments.add(visit(part.expression));
1496 arguments.add(visitLiteralString(part.string));
1497 }
1498 return irBuilder.buildStringConcatenation(arguments);
1499 } 1512 }
1500 1513
1501 ir.Primitive translateConstant(ast.Node node) { 1514 ir.Primitive translateConstant(ast.Node node) {
1502 assert(irBuilder.isOpen); 1515 assert(irBuilder.isOpen);
1503 return buildConstant(getConstantForNode(node)); 1516 return irBuilder.buildConstant(getConstantForNode(node));
1504 } 1517 }
1505 1518
1506 ir.Primitive visitThrow(ast.Throw node) { 1519 ir.Primitive visitThrow(ast.Throw node) {
1507 assert(irBuilder.isOpen); 1520 assert(irBuilder.isOpen);
1508 // This function is not called for throw expressions occurring as 1521 // This function is not called for throw expressions occurring as
1509 // statements. 1522 // statements.
1510 return irBuilder.buildNonTailThrow(visit(node.expression)); 1523 return irBuilder.buildNonTailThrow(visit(node.expression));
1511 } 1524 }
1512 1525
1513 ir.Primitive buildStaticNoSuchMethod( 1526 ir.Primitive buildStaticNoSuchMethod(
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
2047 JavaScriptBackend get _backend => _compiler.backend; 2060 JavaScriptBackend get _backend => _compiler.backend;
2048 2061
2049 GlobalProgramInformation(this._compiler); 2062 GlobalProgramInformation(this._compiler);
2050 2063
2051 /// Returns [true], if the analysis could not determine that the type 2064 /// Returns [true], if the analysis could not determine that the type
2052 /// arguments for the class [cls] are never used in the program. 2065 /// arguments for the class [cls] are never used in the program.
2053 bool requiresRuntimeTypesFor(ClassElement cls) { 2066 bool requiresRuntimeTypesFor(ClassElement cls) {
2054 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls); 2067 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls);
2055 } 2068 }
2056 2069
2057 FunctionElement get throwTypeErrorHelper => _backend.getThrowTypeError(); 2070 FunctionElement get stringifyFunction {
2071 return _backend.getStringInterpolationHelper();
2072 }
2073
2074 FunctionElement get throwTypeErrorHelper => _backend.getThrowTypeError();
karlklose 2015/06/19 08:33:45 Revert this change.
asgerf 2015/06/19 11:04:34 Done.
2058 2075
2059 ClassElement get nullClass => _compiler.nullClass; 2076 ClassElement get nullClass => _compiler.nullClass;
2060 2077
2061 DartType unaliasType(DartType type) => type.unalias(_compiler); 2078 DartType unaliasType(DartType type) => type.unalias(_compiler);
2062 } 2079 }
2063 2080
2064 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. 2081 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
2065 class JsIrBuilderVisitor extends IrBuilderVisitor { 2082 class JsIrBuilderVisitor extends IrBuilderVisitor {
2066 /// Promote the type of [irBuilder] to [JsIrBuilder]. 2083 /// Promote the type of [irBuilder] to [JsIrBuilder].
2067 JsIrBuilder get irBuilder => super.irBuilder; 2084 JsIrBuilder get irBuilder => super.irBuilder;
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after
2793 [irBuilder.buildStringConstant(element.name)]); 2810 [irBuilder.buildStringConstant(element.name)]);
2794 } 2811 }
2795 2812
2796 @override 2813 @override
2797 ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) { 2814 ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) {
2798 SourceInformation src = sourceInformationBuilder.buildGet(node); 2815 SourceInformation src = sourceInformationBuilder.buildGet(node);
2799 return buildStaticFieldGet(field, src); 2816 return buildStaticFieldGet(field, src);
2800 } 2817 }
2801 2818
2802 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) { 2819 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
2803 ConstantExpression constant = 2820 ConstantValue constant = getConstantForVariable(field);
2804 backend.constants.getConstantForVariable(field);
2805 if (constant != null && !field.isAssignable) { 2821 if (constant != null && !field.isAssignable) {
2806 return buildConstant(constant); 2822 return irBuilder.buildConstant(constant);
2807 } else if (backend.constants.lazyStatics.contains(field)) { 2823 } else if (backend.constants.lazyStatics.contains(field)) {
2808 return irBuilder.buildStaticFieldLazyGet(field, src); 2824 return irBuilder.buildStaticFieldLazyGet(field, src);
2809 } else { 2825 } else {
2810 return irBuilder.buildStaticFieldGet(field, src); 2826 return irBuilder.buildStaticFieldGet(field, src);
2811 } 2827 }
2812 } 2828 }
2813 } 2829 }
2814 2830
2815 /// Perform simple post-processing on the initial CPS-translated root term. 2831 /// Perform simple post-processing on the initial CPS-translated root term.
2816 /// 2832 ///
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2862 } 2878 }
2863 2879
2864 processSetStatic(ir.SetStatic node) { 2880 processSetStatic(ir.SetStatic node) {
2865 node.body = replacementFor(node.body); 2881 node.body = replacementFor(node.body);
2866 } 2882 }
2867 2883
2868 processContinuation(ir.Continuation node) { 2884 processContinuation(ir.Continuation node) {
2869 node.body = replacementFor(node.body); 2885 node.body = replacementFor(node.body);
2870 } 2886 }
2871 } 2887 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698