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

Side by Side Diff: pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart

Issue 1526333002: dart2js cps: Clone small constants to use site. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments and fix regression on chain assignments Created 5 years 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 tree_ir_builder; 5 library tree_ir_builder;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../constants/values.dart'; 8 import '../constants/values.dart';
9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
10 import '../elements/elements.dart'; 10 import '../elements/elements.dart';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 * particular, intermediate values and blocks used for local control flow are 46 * particular, intermediate values and blocks used for local control flow are
47 * still all named. 47 * still all named.
48 */ 48 */
49 class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ { 49 class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
50 final InternalErrorFunction internalError; 50 final InternalErrorFunction internalError;
51 51
52 final Map<cps_ir.Primitive, Variable> primitive2variable = 52 final Map<cps_ir.Primitive, Variable> primitive2variable =
53 <cps_ir.Primitive, Variable>{}; 53 <cps_ir.Primitive, Variable>{};
54 final Map<cps_ir.MutableVariable, Variable> mutable2variable = 54 final Map<cps_ir.MutableVariable, Variable> mutable2variable =
55 <cps_ir.MutableVariable, Variable>{}; 55 <cps_ir.MutableVariable, Variable>{};
56 final Set<cps_ir.Constant> inlinedConstants = new Set<cps_ir.Constant>();
56 57
57 // Continuations with more than one use are replaced with Tree labels. This 58 // Continuations with more than one use are replaced with Tree labels. This
58 // is the mapping from continuations to labels. 59 // is the mapping from continuations to labels.
59 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; 60 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
60 61
61 ExecutableElement currentElement; 62 ExecutableElement currentElement;
62 /// The 'this' Parameter for currentElement or the enclosing method. 63 /// The 'this' Parameter for currentElement or the enclosing method.
63 cps_ir.Parameter thisParameter; 64 cps_ir.Parameter thisParameter;
64 cps_ir.Continuation returnContinuation; 65 cps_ir.Continuation returnContinuation;
65 66
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 return primitive2variable.putIfAbsent(primitive, 103 return primitive2variable.putIfAbsent(primitive,
103 () => new Variable(currentElement, primitive.hint)); 104 () => new Variable(currentElement, primitive.hint));
104 } 105 }
105 106
106 /// Obtains a reference to the tree Variable corresponding to the IR primitive 107 /// Obtains a reference to the tree Variable corresponding to the IR primitive
107 /// referred to by [reference]. 108 /// referred to by [reference].
108 /// This increments the reference count for the given variable, so the 109 /// This increments the reference count for the given variable, so the
109 /// returned expression must be used in the tree. 110 /// returned expression must be used in the tree.
110 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { 111 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) {
111 cps_ir.Primitive prim = reference.definition.effectiveDefinition; 112 cps_ir.Primitive prim = reference.definition.effectiveDefinition;
113 if (prim is cps_ir.Constant && inlinedConstants.contains(prim)) {
114 return new Constant(prim.value);
115 }
112 if (thisParameter != null && prim == thisParameter) { 116 if (thisParameter != null && prim == thisParameter) {
113 return new This(); 117 return new This();
114 } 118 }
115 return new VariableUse(getVariable(prim)); 119 return new VariableUse(getVariable(prim));
116 } 120 }
117 121
118 Expression getVariableUseOrNull( 122 Expression getVariableUseOrNull(
119 cps_ir.Reference<cps_ir.Primitive> reference) { 123 cps_ir.Reference<cps_ir.Primitive> reference) {
120 return reference == null ? null : getVariableUse(reference); 124 return reference == null ? null : getVariableUse(reference);
121 } 125 }
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 return result; 276 return result;
273 } 277 }
274 278
275 /// Translates a CPS primitive to a tree expression. 279 /// Translates a CPS primitive to a tree expression.
276 /// 280 ///
277 /// This simply calls the visit method for the primitive. 281 /// This simply calls the visit method for the primitive.
278 translatePrimitive(cps_ir.Primitive prim) { 282 translatePrimitive(cps_ir.Primitive prim) {
279 return prim.accept(this); 283 return prim.accept(this);
280 } 284 }
281 285
286 /************************ CONSTANT COPYING *****************************/
287
288 /// Estimate of the number of characters needed to emit a use of the given
289 /// constant.
290 int constantSize(PrimitiveConstantValue value) {
291 // TODO(asgerf): We could interface with the emitter to get the exact size.
292 if (value is StringConstantValue) {
293 // Account for the quotes, but ignore the cost of encoding non-ASCII
294 // characters to avoid traversing the string and depending on encoding.
295 return value.length + 2;
296 } else if (value is BoolConstantValue) {
297 return 2; // Printed as !0 and !1 when minified
298 } else {
299 // TODO(asgerf): Get the exact length of numbers using '1e10' notation.
300 return '${value.primitiveValue}'.length;
301 }
302 }
303
304 /// The number of uses [prim] has, or `-1` if it is used in a phi assignment.
305 int countNonPhiUses(cps_ir.Primitive prim) {
306 int count = 0;
307 for (cps_ir.Reference ref = prim.firstRef; ref != null; ref = ref.next) {
308 cps_ir.Node use = ref.parent;
309 if (use is cps_ir.InvokeContinuation) {
310 return -1;
311 }
312 count++;
313 }
314 return count;
315 }
316
317 /// True if the given [constant] should be copied to every use site.
318 bool shouldCopyToUses(cps_ir.Constant constant) {
319 if (!constant.value.isPrimitive) return false;
320 if (constant.hasAtMostOneUse) return true;
321 int uses = countNonPhiUses(constant);
322 if (uses == -1) return false; // Copying might prevent elimination of a phi.
323 int size = constantSize(constant.value);
324 // Compare the expected code size output of copying vs sharing.
325 const int USE = 2; // Minified locals usually have length 2.
326 const int ASSIGN = USE + 2; // Variable and '=' and ';'
327 const int BIAS = 2; // Artificial bias to slightly favor copying.
328 int costOfSharing = USE * uses + size + ASSIGN + BIAS;
329 int costOfCopying = size * uses;
330 return costOfCopying <= costOfSharing;
331 }
332
282 /************************ INTERIOR EXPRESSIONS ************************/ 333 /************************ INTERIOR EXPRESSIONS ************************/
283 // 334 //
284 // Visit methods for interior expressions must return a function: 335 // Visit methods for interior expressions must return a function:
285 // 336 //
286 // (Statement next) => <result statement> 337 // (Statement next) => <result statement>
287 // 338 //
288 339
289 NodeCallback visitLetPrim(cps_ir.LetPrim node) { 340 NodeCallback visitLetPrim(cps_ir.LetPrim node) {
341 if (node.primitive is cps_ir.Constant && shouldCopyToUses(node.primitive)) {
342 inlinedConstants.add(node.primitive);
343 return (Statement next) => next;
344 }
290 Variable variable = getVariable(node.primitive); 345 Variable variable = getVariable(node.primitive);
291 var value = translatePrimitive(node.primitive); 346 var value = translatePrimitive(node.primitive);
292 if (value is Expression) { 347 if (value is Expression) {
293 if (node.primitive.hasAtLeastOneUse) { 348 if (node.primitive.hasAtLeastOneUse) {
294 return (Statement next) => Assign.makeStatement(variable, value, next); 349 return (Statement next) => Assign.makeStatement(variable, value, next);
295 } else { 350 } else {
296 return (Statement next) => new ExpressionStatement(value, next); 351 return (Statement next) => new ExpressionStatement(value, next);
297 } 352 }
298 } else { 353 } else {
299 assert(value is NodeCallback); 354 assert(value is NodeCallback);
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node'); 754 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
700 } 755 }
701 756
702 visitFunctionDefinition(cps_ir.FunctionDefinition node) { 757 visitFunctionDefinition(cps_ir.FunctionDefinition node) {
703 unexpectedNode(node); 758 unexpectedNode(node);
704 } 759 }
705 visitParameter(cps_ir.Parameter node) => unexpectedNode(node); 760 visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
706 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node); 761 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
707 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node); 762 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
708 } 763 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698