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

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 1203423003: dart2js cps: Better fallthrough analysis and eliminate "return null". (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update tests 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.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) 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 code_generator; 5 library code_generator;
6 6
7 import 'glue.dart'; 7 import 'glue.dart';
8 8
9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; 9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
10 import '../../tree_ir/tree_ir_nodes.dart' show BuiltinOperator; 10 import '../../tree_ir/tree_ir_nodes.dart' show BuiltinOperator;
(...skipping 28 matching lines...) Expand all
39 /// Maps variables to their name. 39 /// Maps variables to their name.
40 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; 40 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
41 41
42 /// Maps local constants to their name. 42 /// Maps local constants to their name.
43 Maplet<VariableElement, String> constantNames = 43 Maplet<VariableElement, String> constantNames =
44 new Maplet<VariableElement, String>(); 44 new Maplet<VariableElement, String>();
45 45
46 /// Variable names that have already been used. Used to avoid name clashes. 46 /// Variable names that have already been used. Used to avoid name clashes.
47 Set<String> usedVariableNames = new Set<String>(); 47 Set<String> usedVariableNames = new Set<String>();
48 48
49 /// Input to [visitStatement]. Denotes the statement that will execute next 49 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack();
50 /// if the statements produced by [visitStatement] complete normally.
51 /// Set to null if control will fall over the end of the method.
52 tree_ir.Statement fallthrough = null;
53 50
54 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>(); 51 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
55 52
56 List<js.Statement> accumulator = new List<js.Statement>(); 53 List<js.Statement> accumulator = new List<js.Statement>();
57 54
58 CodeGenerator(this.glue, this.registry); 55 CodeGenerator(this.glue, this.registry);
59 56
60 /// Generates JavaScript code for the body of [function]. 57 /// Generates JavaScript code for the body of [function].
61 js.Fun buildFunction(tree_ir.FunctionDefinition function) { 58 js.Fun buildFunction(tree_ir.FunctionDefinition function) {
62 currentFunction = function.element; 59 currentFunction = function.element;
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 398
402 @override 399 @override
403 js.Expression visitAssign(tree_ir.Assign node) { 400 js.Expression visitAssign(tree_ir.Assign node) {
404 return new js.Assignment( 401 return new js.Assignment(
405 buildVariableAccess(node.variable), 402 buildVariableAccess(node.variable),
406 visitExpression(node.value)); 403 visitExpression(node.value));
407 } 404 }
408 405
409 @override 406 @override
410 void visitContinue(tree_ir.Continue node) { 407 void visitContinue(tree_ir.Continue node) {
411 tree_ir.Statement fallthrough = this.fallthrough; 408 tree_ir.Statement next = fallthrough.target;
412 if (node.target.binding == fallthrough) { 409 if (node.target.binding == next) {
413 // Fall through to continue target 410 // Fall through to continue target
414 } else if (fallthrough is tree_ir.Continue && 411 fallthrough.use();
415 fallthrough.target == node.target) { 412 } else if (next is tree_ir.Continue && next.target == node.target) {
416 // Fall through to equivalent continue 413 // Fall through to equivalent continue
414 fallthrough.use();
417 } else { 415 } else {
418 usedLabels.add(node.target); 416 usedLabels.add(node.target);
419 accumulator.add(new js.Continue(node.target.name)); 417 accumulator.add(new js.Continue(node.target.name));
420 } 418 }
421 } 419 }
422 420
423 @override 421 @override
422 void visitBreak(tree_ir.Break node) {
423 tree_ir.Statement next = fallthrough.target;
424 if (node.target.binding.next == next) {
425 // Fall through to break target
426 fallthrough.use();
427 } else if (next is tree_ir.Break && next.target == node.target) {
428 // Fall through to equivalent break
429 fallthrough.use();
430 } else {
431 usedLabels.add(node.target);
432 accumulator.add(new js.Break(node.target.name));
433 }
434 }
435
436 @override
424 void visitExpressionStatement(tree_ir.ExpressionStatement node) { 437 void visitExpressionStatement(tree_ir.ExpressionStatement node) {
425 accumulator.add(new js.ExpressionStatement( 438 accumulator.add(new js.ExpressionStatement(
426 visitExpression(node.expression))); 439 visitExpression(node.expression)));
427 visitStatement(node.next); 440 visitStatement(node.next);
428 } 441 }
429 442
430 @override 443 @override
431 void visitIf(tree_ir.If node) { 444 void visitIf(tree_ir.If node) {
432 accumulator.add(new js.If(visitExpression(node.condition), 445 js.Expression condition = visitExpression(node.condition);
433 buildBodyStatement(node.thenStatement), 446 int usesBefore = fallthrough.useCount;
434 buildBodyStatement(node.elseStatement))); 447 js.Statement thenBody = buildBodyStatement(node.thenStatement);
448 bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
449 if (thenHasFallthrough) {
450 js.Statement elseBody = buildBodyStatement(node.elseStatement);
451 accumulator.add(new js.If(condition, thenBody, elseBody));
452 } else {
453 // The 'then' body cannot complete normally, so emit a short 'if'
454 // and put the 'else' body after it.
455 accumulator.add(new js.If.noElse(condition, thenBody));
456 visitStatement(node.elseStatement);
457 }
435 } 458 }
436 459
437 @override 460 @override
438 void visitLabeledStatement(tree_ir.LabeledStatement node) { 461 void visitLabeledStatement(tree_ir.LabeledStatement node) {
439 accumulator.add(buildLabeled(() => buildBodyStatement(node.body), 462 accumulator.add(buildLabeled(() => buildBodyStatement(node.body),
440 node.label, 463 node.label,
441 node.next)); 464 node.next));
442 visitStatement(node.next); 465 visitStatement(node.next);
443 } 466 }
444 467
445 js.Statement buildLabeled(js.Statement buildBody(), 468 js.Statement buildLabeled(js.Statement buildBody(),
446 tree_ir.Label label, 469 tree_ir.Label label,
447 tree_ir.Statement fallthroughStatement) { 470 tree_ir.Statement fallthroughStatement) {
448 tree_ir.Statement savedFallthrough = fallthrough; 471 fallthrough.push(fallthroughStatement);
449 fallthrough = fallthroughStatement;
450 js.Statement result = buildBody(); 472 js.Statement result = buildBody();
451 if (usedLabels.remove(label)) { 473 if (usedLabels.remove(label)) {
452 result = new js.LabeledStatement(label.name, result); 474 result = new js.LabeledStatement(label.name, result);
453 } 475 }
454 fallthrough = savedFallthrough; 476 fallthrough.pop();
455 return result; 477 return result;
456 } 478 }
457 479
458 @override
459 void visitBreak(tree_ir.Break node) {
460 tree_ir.Statement fallthrough = this.fallthrough;
461 if (node.target.binding.next == fallthrough) {
462 // Fall through to break target
463 } else if (fallthrough is tree_ir.Break &&
464 fallthrough.target == node.target) {
465 // Fall through to equivalent break
466 } else {
467 usedLabels.add(node.target);
468 accumulator.add(new js.Break(node.target.name));
469 }
470 }
471
472 /// Returns the current [accumulator] wrapped in a block if neccessary. 480 /// Returns the current [accumulator] wrapped in a block if neccessary.
473 js.Statement _bodyAsStatement() { 481 js.Statement _bodyAsStatement() {
474 if (accumulator.length == 0) { 482 if (accumulator.length == 0) {
475 return new js.EmptyStatement(); 483 return new js.EmptyStatement();
476 } 484 }
477 if (accumulator.length == 1) { 485 if (accumulator.length == 1) {
478 return accumulator.single; 486 return accumulator.single;
479 } 487 }
480 return new js.Block(accumulator); 488 return new js.Block(accumulator);
481 } 489 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 node)); 525 node));
518 visitStatement(node.next); 526 visitStatement(node.next);
519 } 527 }
520 528
521 @override 529 @override
522 void visitWhileTrue(tree_ir.WhileTrue node) { 530 void visitWhileTrue(tree_ir.WhileTrue node) {
523 accumulator.add( 531 accumulator.add(
524 buildWhile(new js.LiteralBool(true), node.body, node.label, node)); 532 buildWhile(new js.LiteralBool(true), node.body, node.label, node));
525 } 533 }
526 534
535 bool isNull(tree_ir.Expression node) {
536 return node is tree_ir.Constant && node.value.isNull;
537 }
538
527 @override 539 @override
528 void visitReturn(tree_ir.Return node) { 540 void visitReturn(tree_ir.Return node) {
529 accumulator.add(new js.Return(visitExpression(node.value))); 541 if (isNull(node.value) && fallthrough.target == null) {
542 // Do nothing. Implicitly return JS undefined by falling over the end.
543 registry.registerCompileTimeConstant(new NullConstantValue());
544 fallthrough.use();
545 } else {
546 accumulator.add(new js.Return(visitExpression(node.value)));
547 }
530 } 548 }
531 549
532 @override 550 @override
533 void visitThrow(tree_ir.Throw node) { 551 void visitThrow(tree_ir.Throw node) {
534 accumulator.add(new js.Throw(visitExpression(node.value))); 552 accumulator.add(new js.Throw(visitExpression(node.value)));
535 } 553 }
536 554
537 @override 555 @override
538 void visitRethrow(tree_ir.Rethrow node) { 556 void visitRethrow(tree_ir.Rethrow node) {
539 glue.reportInternalError('rethrow seen in JavaScript output'); 557 glue.reportInternalError('rethrow seen in JavaScript output');
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 return js.js("typeof # === 'number' && Math.floor(#) === #", args); 781 return js.js("typeof # === 'number' && Math.floor(#) === #", args);
764 } 782 }
765 } 783 }
766 784
767 visitFunctionExpression(tree_ir.FunctionExpression node) { 785 visitFunctionExpression(tree_ir.FunctionExpression node) {
768 // FunctionExpressions are currently unused. 786 // FunctionExpressions are currently unused.
769 // We might need them if we want to emit raw JS nested functions. 787 // We might need them if we want to emit raw JS nested functions.
770 throw 'FunctionExpressions should not be used'; 788 throw 'FunctionExpressions should not be used';
771 } 789 }
772 } 790 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698