Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
| 6 | 6 |
| 7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/interpreter/bytecode-flags.h" | 10 #include "src/interpreter/bytecode-flags.h" |
| (...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 438 generator_->set_execution_result(this); | 438 generator_->set_execution_result(this); |
| 439 } | 439 } |
| 440 | 440 |
| 441 virtual ~ExpressionResultScope() { | 441 virtual ~ExpressionResultScope() { |
| 442 generator_->set_execution_result(outer_); | 442 generator_->set_execution_result(outer_); |
| 443 DCHECK(result_identified() || generator_->HasStackOverflow()); | 443 DCHECK(result_identified() || generator_->HasStackOverflow()); |
| 444 } | 444 } |
| 445 | 445 |
| 446 bool IsEffect() const { return kind_ == Expression::kEffect; } | 446 bool IsEffect() const { return kind_ == Expression::kEffect; } |
| 447 bool IsValue() const { return kind_ == Expression::kValue; } | 447 bool IsValue() const { return kind_ == Expression::kValue; } |
| 448 bool IsTest() const { return kind_ == Expression::kTest; } | |
| 448 | 449 |
| 449 virtual void SetResultInAccumulator() = 0; | 450 virtual void SetResultInAccumulator() = 0; |
| 450 virtual void SetResultInRegister(Register reg) = 0; | 451 virtual void SetResultInRegister(Register reg) = 0; |
| 451 | 452 |
| 452 protected: | 453 protected: |
| 453 ExpressionResultScope* outer() const { return outer_; } | 454 ExpressionResultScope* outer() const { return outer_; } |
| 454 BytecodeArrayBuilder* builder() const { return generator_->builder(); } | 455 BytecodeArrayBuilder* builder() const { return generator_->builder(); } |
| 455 BytecodeGenerator* generator() const { return generator_; } | 456 BytecodeGenerator* generator() const { return generator_; } |
| 456 const RegisterAllocationScope* allocator() const { return &allocator_; } | 457 const RegisterAllocationScope* allocator() const { return &allocator_; } |
| 457 | 458 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 if (generator()->HasStackOverflow() && !result_identified()) { | 529 if (generator()->HasStackOverflow() && !result_identified()) { |
| 529 SetResultInAccumulator(); | 530 SetResultInAccumulator(); |
| 530 } | 531 } |
| 531 return result_register_; | 532 return result_register_; |
| 532 } | 533 } |
| 533 | 534 |
| 534 private: | 535 private: |
| 535 Register result_register_; | 536 Register result_register_; |
| 536 }; | 537 }; |
| 537 | 538 |
| 539 enum class BytecodeGenerator::ControlFallthrough { THEN, ELSE, NONE }; | |
|
rmcilroy
2016/08/12 11:15:25
Just define this in the header. Also, enum class u
klaasb
2016/08/12 16:00:12
Done.
| |
| 540 | |
| 541 // Scoped class used for generating multiple jumps to the same location | |
| 542 class BytecodeGenerator::BytecodeLabels { | |
|
rmcilroy
2016/08/12 11:15:26
How about moving this to bytecode-label.h/cc?
klaasb
2016/08/12 16:00:12
Done.
| |
| 543 public: | |
| 544 BytecodeLabels() = default; | |
| 545 | |
| 546 BytecodeLabel* New() { | |
| 547 labels_.emplace_back(); | |
| 548 return &labels_.back(); | |
| 549 } | |
| 550 | |
| 551 void Bind(BytecodeArrayBuilder* builder) { | |
| 552 for (auto label : labels_) { | |
| 553 builder->Bind(&label); | |
| 554 } | |
| 555 } | |
| 556 | |
| 557 private: | |
| 558 std::vector<BytecodeLabel> labels_; | |
|
rmcilroy
2016/08/12 11:15:25
use ZoneVector (which means you will need to pass
klaasb
2016/08/12 16:00:13
Done.
| |
| 559 | |
| 560 DISALLOW_COPY_AND_ASSIGN(BytecodeLabels); | |
| 561 }; | |
| 562 | |
| 563 // Scoped class used when the result of the current expression to be | |
| 564 // evaluated is only tested with jumps to two branches. | |
| 565 class BytecodeGenerator::ControlResultScope final | |
| 566 : public ExpressionResultScope { | |
| 567 public: | |
| 568 ControlResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels, | |
| 569 BytecodeLabels* else_labels, | |
| 570 ControlFallthrough fallthrough) | |
| 571 : ExpressionResultScope(generator, Expression::kTest), | |
| 572 then_labels_(then_labels), | |
| 573 else_labels_(else_labels), | |
| 574 fallthrough_(fallthrough), | |
| 575 has_result_(true) {} | |
| 576 | |
| 577 virtual void SetResultInAccumulator() { | |
| 578 DCHECK(has_result_); | |
|
rmcilroy
2016/08/12 11:15:26
No need for these DCHECKS - the set_result_identif
klaasb
2016/08/12 16:00:12
Done.
| |
| 579 set_result_identified(); | |
| 580 } | |
| 581 | |
| 582 virtual void SetResultInRegister(Register reg) { | |
| 583 DCHECK(has_result_); | |
| 584 builder()->LoadAccumulatorWithRegister(reg); | |
| 585 set_result_identified(); | |
| 586 } | |
| 587 | |
| 588 // Used when code special cases for ControlResultScope and consumes any | |
| 589 // possible value by testing and jumping to a then/else label. | |
| 590 void SetNoResult() { | |
|
rmcilroy
2016/08/12 11:15:25
How about SetResultConsumedByTest
klaasb
2016/08/12 16:00:12
Done.
| |
| 591 DCHECK(has_result_); | |
| 592 has_result_ = false; | |
| 593 set_result_identified(); | |
| 594 } | |
| 595 | |
| 596 bool HasResultValue() { return has_result_; } | |
|
rmcilroy
2016/08/12 11:15:26
ResultConsumedByTest() (and invert the boolean)
klaasb
2016/08/12 16:00:13
Done.
| |
| 597 | |
| 598 BytecodeLabel* NewThenLabel() { return then_labels_->New(); } | |
| 599 BytecodeLabel* NewElseLabel() { return else_labels_->New(); } | |
| 600 | |
| 601 BytecodeLabels* ThenLabels() { return then_labels_; } | |
| 602 BytecodeLabels* ElseLabels() { return else_labels_; } | |
| 603 | |
| 604 ControlFallthrough Fallthrough() { return fallthrough_; } | |
| 605 ControlFallthrough InvertedFallthrough() { | |
|
rmcilroy
2016/08/12 11:15:26
These are all getters, so lowercase - then_labels,
klaasb
2016/08/12 16:00:12
Done.
| |
| 606 switch (fallthrough_) { | |
| 607 case ControlFallthrough::THEN: | |
| 608 return ControlFallthrough::ELSE; | |
| 609 case ControlFallthrough::ELSE: | |
| 610 return ControlFallthrough::THEN; | |
| 611 default: | |
| 612 return ControlFallthrough::NONE; | |
| 613 } | |
| 614 } | |
| 615 | |
| 616 private: | |
| 617 BytecodeLabels* then_labels_; | |
| 618 BytecodeLabels* else_labels_; | |
| 619 ControlFallthrough fallthrough_; | |
| 620 bool has_result_; | |
| 621 | |
| 622 DISALLOW_COPY_AND_ASSIGN(ControlResultScope); | |
| 623 }; | |
| 624 | |
| 538 // Used to build a list of global declaration initial value pairs. | 625 // Used to build a list of global declaration initial value pairs. |
| 539 class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { | 626 class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { |
| 540 public: | 627 public: |
| 541 GlobalDeclarationsBuilder(Isolate* isolate, Zone* zone) | 628 GlobalDeclarationsBuilder(Isolate* isolate, Zone* zone) |
| 542 : isolate_(isolate), | 629 : isolate_(isolate), |
| 543 declarations_(0, zone), | 630 declarations_(0, zone), |
| 544 constant_pool_entry_(0), | 631 constant_pool_entry_(0), |
| 545 has_constant_pool_entry_(false) {} | 632 has_constant_pool_entry_(false) {} |
| 546 | 633 |
| 547 void AddFunctionDeclaration(FeedbackVectorSlot slot, FunctionLiteral* func) { | 634 void AddFunctionDeclaration(FeedbackVectorSlot slot, FunctionLiteral* func) { |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 972 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | 1059 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 973 builder()->SetStatementPosition(stmt); | 1060 builder()->SetStatementPosition(stmt); |
| 974 VisitForEffect(stmt->expression()); | 1061 VisitForEffect(stmt->expression()); |
| 975 } | 1062 } |
| 976 | 1063 |
| 977 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { | 1064 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
| 978 } | 1065 } |
| 979 | 1066 |
| 980 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { | 1067 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { |
| 981 builder()->SetStatementPosition(stmt); | 1068 builder()->SetStatementPosition(stmt); |
| 982 BytecodeLabel else_label, end_label; | 1069 BytecodeLabel end_label; |
|
rmcilroy
2016/08/12 11:15:26
nit - move end_label into inner else branch too.
klaasb
2016/08/12 16:00:12
Done.
| |
| 983 if (stmt->condition()->ToBooleanIsTrue()) { | 1070 if (stmt->condition()->ToBooleanIsTrue()) { |
| 984 // Generate then block unconditionally as always true. | 1071 // Generate then block unconditionally as always true. |
| 985 Visit(stmt->then_statement()); | 1072 Visit(stmt->then_statement()); |
| 986 } else if (stmt->condition()->ToBooleanIsFalse()) { | 1073 } else if (stmt->condition()->ToBooleanIsFalse()) { |
| 987 // Generate else block unconditionally if it exists. | 1074 // Generate else block unconditionally if it exists. |
| 988 if (stmt->HasElseStatement()) { | 1075 if (stmt->HasElseStatement()) { |
| 989 Visit(stmt->else_statement()); | 1076 Visit(stmt->else_statement()); |
| 990 } | 1077 } |
| 991 } else { | 1078 } else { |
| 992 // TODO(oth): If then statement is BreakStatement or | 1079 // TODO(oth): If then statement is BreakStatement or |
| 993 // ContinueStatement we can reduce number of generated | 1080 // ContinueStatement we can reduce number of generated |
| 994 // jump/jump_ifs here. See BasicLoops test. | 1081 // jump/jump_ifs here. See BasicLoops test. |
| 995 VisitForAccumulatorValue(stmt->condition()); | 1082 BytecodeLabels then_labels; |
|
rmcilroy
2016/08/12 11:15:26
nit - BytecodeLabels then_labels, else_labels;
klaasb
2016/08/12 16:00:12
Done.
| |
| 996 builder()->JumpIfFalse(&else_label); | 1083 BytecodeLabels else_labels; |
| 1084 VisitForControl(stmt->condition(), &then_labels, &else_labels, | |
| 1085 ControlFallthrough::THEN); | |
| 1086 | |
| 1087 then_labels.Bind(builder()); | |
| 997 Visit(stmt->then_statement()); | 1088 Visit(stmt->then_statement()); |
| 1089 | |
| 998 if (stmt->HasElseStatement()) { | 1090 if (stmt->HasElseStatement()) { |
| 999 builder()->Jump(&end_label); | 1091 builder()->Jump(&end_label); |
| 1000 builder()->Bind(&else_label); | 1092 } |
| 1093 else_labels.Bind(builder()); | |
| 1094 if (stmt->HasElseStatement()) { | |
|
rmcilroy
2016/08/12 11:15:26
could you keep the if/else form:
if (stmt->HasEls
klaasb
2016/08/12 16:00:12
Done.
| |
| 1001 Visit(stmt->else_statement()); | 1095 Visit(stmt->else_statement()); |
| 1002 } else { | |
| 1003 builder()->Bind(&else_label); | |
| 1004 } | 1096 } |
| 1005 builder()->Bind(&end_label); | 1097 builder()->Bind(&end_label); |
| 1006 } | 1098 } |
| 1007 } | 1099 } |
| 1008 | 1100 |
| 1009 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( | 1101 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( |
| 1010 SloppyBlockFunctionStatement* stmt) { | 1102 SloppyBlockFunctionStatement* stmt) { |
| 1011 Visit(stmt->statement()); | 1103 Visit(stmt->statement()); |
| 1012 } | 1104 } |
| 1013 | 1105 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1102 if (stmt->cond()->ToBooleanIsFalse()) { | 1194 if (stmt->cond()->ToBooleanIsFalse()) { |
| 1103 VisitIterationBody(stmt, &loop_builder); | 1195 VisitIterationBody(stmt, &loop_builder); |
| 1104 } else if (stmt->cond()->ToBooleanIsTrue()) { | 1196 } else if (stmt->cond()->ToBooleanIsTrue()) { |
| 1105 VisitIterationHeader(stmt, &loop_builder); | 1197 VisitIterationHeader(stmt, &loop_builder); |
| 1106 VisitIterationBody(stmt, &loop_builder); | 1198 VisitIterationBody(stmt, &loop_builder); |
| 1107 loop_builder.JumpToHeader(); | 1199 loop_builder.JumpToHeader(); |
| 1108 } else { | 1200 } else { |
| 1109 VisitIterationHeader(stmt, &loop_builder); | 1201 VisitIterationHeader(stmt, &loop_builder); |
| 1110 VisitIterationBody(stmt, &loop_builder); | 1202 VisitIterationBody(stmt, &loop_builder); |
| 1111 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1203 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
| 1204 // TODO(klaasb) VisitForControl for loop conditions | |
| 1112 VisitForAccumulatorValue(stmt->cond()); | 1205 VisitForAccumulatorValue(stmt->cond()); |
| 1113 loop_builder.JumpToHeaderIfTrue(); | 1206 loop_builder.JumpToHeaderIfTrue(); |
| 1114 } | 1207 } |
| 1115 loop_builder.EndLoop(); | 1208 loop_builder.EndLoop(); |
| 1116 } | 1209 } |
| 1117 | 1210 |
| 1118 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | 1211 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
| 1119 if (stmt->cond()->ToBooleanIsFalse()) { | 1212 if (stmt->cond()->ToBooleanIsFalse()) { |
| 1120 // If the condition is false there is no need to generate the loop. | 1213 // If the condition is false there is no need to generate the loop. |
| 1121 return; | 1214 return; |
| 1122 } | 1215 } |
| 1123 | 1216 |
| 1124 LoopBuilder loop_builder(builder()); | 1217 LoopBuilder loop_builder(builder()); |
| 1125 VisitIterationHeader(stmt, &loop_builder); | 1218 VisitIterationHeader(stmt, &loop_builder); |
| 1126 if (!stmt->cond()->ToBooleanIsTrue()) { | 1219 if (!stmt->cond()->ToBooleanIsTrue()) { |
| 1127 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1220 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
| 1221 // TODO(klaasb) VisitForControl for loop conditions | |
| 1128 VisitForAccumulatorValue(stmt->cond()); | 1222 VisitForAccumulatorValue(stmt->cond()); |
| 1129 loop_builder.BreakIfFalse(); | 1223 loop_builder.BreakIfFalse(); |
| 1130 } | 1224 } |
| 1131 VisitIterationBody(stmt, &loop_builder); | 1225 VisitIterationBody(stmt, &loop_builder); |
| 1132 loop_builder.JumpToHeader(); | 1226 loop_builder.JumpToHeader(); |
| 1133 loop_builder.EndLoop(); | 1227 loop_builder.EndLoop(); |
| 1134 } | 1228 } |
| 1135 | 1229 |
| 1136 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { | 1230 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
| 1137 if (stmt->init() != nullptr) { | 1231 if (stmt->init() != nullptr) { |
| 1138 Visit(stmt->init()); | 1232 Visit(stmt->init()); |
| 1139 } | 1233 } |
| 1140 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { | 1234 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { |
| 1141 // If the condition is known to be false there is no need to generate | 1235 // If the condition is known to be false there is no need to generate |
| 1142 // body, next or condition blocks. Init block should be generated. | 1236 // body, next or condition blocks. Init block should be generated. |
| 1143 return; | 1237 return; |
| 1144 } | 1238 } |
| 1145 | 1239 |
| 1146 LoopBuilder loop_builder(builder()); | 1240 LoopBuilder loop_builder(builder()); |
| 1147 VisitIterationHeader(stmt, &loop_builder); | 1241 VisitIterationHeader(stmt, &loop_builder); |
| 1148 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { | 1242 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { |
| 1149 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1243 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
| 1244 // TODO(klaasb) VisitForControl for loop conditions | |
| 1150 VisitForAccumulatorValue(stmt->cond()); | 1245 VisitForAccumulatorValue(stmt->cond()); |
| 1151 loop_builder.BreakIfFalse(); | 1246 loop_builder.BreakIfFalse(); |
| 1152 } | 1247 } |
| 1153 VisitIterationBody(stmt, &loop_builder); | 1248 VisitIterationBody(stmt, &loop_builder); |
| 1154 if (stmt->next() != nullptr) { | 1249 if (stmt->next() != nullptr) { |
| 1155 builder()->SetStatementPosition(stmt->next()); | 1250 builder()->SetStatementPosition(stmt->next()); |
| 1156 Visit(stmt->next()); | 1251 Visit(stmt->next()); |
| 1157 } | 1252 } |
| 1158 loop_builder.JumpToHeader(); | 1253 loop_builder.JumpToHeader(); |
| 1159 loop_builder.EndLoop(); | 1254 loop_builder.EndLoop(); |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1558 native_function_literals_.push_back(std::make_pair(expr, entry)); | 1653 native_function_literals_.push_back(std::make_pair(expr, entry)); |
| 1559 execution_result()->SetResultInAccumulator(); | 1654 execution_result()->SetResultInAccumulator(); |
| 1560 } | 1655 } |
| 1561 | 1656 |
| 1562 void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { | 1657 void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { |
| 1563 VisitBlock(expr->block()); | 1658 VisitBlock(expr->block()); |
| 1564 VisitVariableProxy(expr->result()); | 1659 VisitVariableProxy(expr->result()); |
| 1565 } | 1660 } |
| 1566 | 1661 |
| 1567 void BytecodeGenerator::VisitConditional(Conditional* expr) { | 1662 void BytecodeGenerator::VisitConditional(Conditional* expr) { |
| 1568 // TODO(rmcilroy): Spot easy cases where there code would not need to | 1663 if (expr->condition()->ToBooleanIsTrue()) { |
| 1569 // emit the then block or the else block, e.g. condition is | 1664 // Generate then block unconditionally as always true. |
| 1570 // obviously true/1/false/0. | 1665 VisitForAccumulatorValue(expr->then_expression()); |
| 1666 } else if (expr->condition()->ToBooleanIsFalse()) { | |
| 1667 // Generate else block unconditionally if it exists. | |
| 1668 VisitForAccumulatorValue(expr->else_expression()); | |
| 1669 } else { | |
| 1670 BytecodeLabel end_label; | |
| 1671 BytecodeLabels then_labels; | |
| 1672 BytecodeLabels else_labels; | |
|
rmcilroy
2016/08/12 11:15:26
nit - BytecodeLabels then_labels, else_labels;
klaasb
2016/08/12 16:00:12
Done.
| |
| 1571 | 1673 |
| 1572 BytecodeLabel else_label, end_label; | 1674 VisitForControl(expr->condition(), &then_labels, &else_labels, |
| 1675 ControlFallthrough::THEN); | |
| 1573 | 1676 |
| 1574 VisitForAccumulatorValue(expr->condition()); | 1677 then_labels.Bind(builder()); |
| 1575 builder()->JumpIfFalse(&else_label); | 1678 VisitForAccumulatorValue(expr->then_expression()); |
| 1679 builder()->Jump(&end_label); | |
| 1576 | 1680 |
| 1577 VisitForAccumulatorValue(expr->then_expression()); | 1681 else_labels.Bind(builder()); |
| 1578 builder()->Jump(&end_label); | 1682 VisitForAccumulatorValue(expr->else_expression()); |
| 1579 | 1683 builder()->Bind(&end_label); |
| 1580 builder()->Bind(&else_label); | 1684 } |
| 1581 VisitForAccumulatorValue(expr->else_expression()); | |
| 1582 builder()->Bind(&end_label); | |
| 1583 | 1685 |
| 1584 execution_result()->SetResultInAccumulator(); | 1686 execution_result()->SetResultInAccumulator(); |
| 1585 } | 1687 } |
| 1586 | 1688 |
| 1587 void BytecodeGenerator::VisitLiteral(Literal* expr) { | 1689 void BytecodeGenerator::VisitLiteral(Literal* expr) { |
| 1588 if (!execution_result()->IsEffect()) { | 1690 if (!execution_result()->IsEffect()) { |
| 1589 const AstValue* raw_value = expr->raw_value(); | 1691 const AstValue* raw_value = expr->raw_value(); |
| 1590 if (raw_value->IsSmi()) { | 1692 if (raw_value->IsSmi()) { |
| 1591 builder()->LoadLiteral(raw_value->AsSmi()); | 1693 builder()->LoadLiteral(raw_value->AsSmi()); |
| 1592 } else if (raw_value->IsUndefined()) { | 1694 } else if (raw_value->IsUndefined()) { |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1861 } | 1963 } |
| 1862 | 1964 |
| 1863 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 1965 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| 1864 FeedbackVectorSlot slot, | 1966 FeedbackVectorSlot slot, |
| 1865 TypeofMode typeof_mode) { | 1967 TypeofMode typeof_mode) { |
| 1866 switch (variable->location()) { | 1968 switch (variable->location()) { |
| 1867 case VariableLocation::LOCAL: { | 1969 case VariableLocation::LOCAL: { |
| 1868 Register source(Register(variable->index())); | 1970 Register source(Register(variable->index())); |
| 1869 builder()->LoadAccumulatorWithRegister(source); | 1971 builder()->LoadAccumulatorWithRegister(source); |
| 1870 BuildHoleCheckForVariableLoad(variable); | 1972 BuildHoleCheckForVariableLoad(variable); |
| 1973 // this will generate a new register when within a RegisterResultScope | |
|
rmcilroy
2016/08/12 11:15:26
Thanks for updating this. How about:
We need to l
klaasb
2016/08/12 16:00:12
Done.
| |
| 1974 // which is needed when expressions assign to variables as side-effect | |
| 1871 execution_result()->SetResultInAccumulator(); | 1975 execution_result()->SetResultInAccumulator(); |
| 1872 break; | 1976 break; |
| 1873 } | 1977 } |
| 1874 case VariableLocation::PARAMETER: { | 1978 case VariableLocation::PARAMETER: { |
| 1875 // The parameter indices are shifted by 1 (receiver is variable | 1979 // The parameter indices are shifted by 1 (receiver is variable |
| 1876 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1980 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 1877 Register source = builder()->Parameter(variable->index() + 1); | 1981 Register source = builder()->Parameter(variable->index() + 1); |
| 1878 builder()->LoadAccumulatorWithRegister(source); | 1982 builder()->LoadAccumulatorWithRegister(source); |
| 1879 BuildHoleCheckForVariableLoad(variable); | 1983 BuildHoleCheckForVariableLoad(variable); |
| 1984 // this will generate a new register when within a RegisterResultScope | |
|
rmcilroy
2016/08/12 11:15:25
ditto
klaasb
2016/08/12 16:00:12
Done.
| |
| 1985 // which is needed when expressions assign to variables as side-effect | |
| 1880 execution_result()->SetResultInAccumulator(); | 1986 execution_result()->SetResultInAccumulator(); |
| 1881 break; | 1987 break; |
| 1882 } | 1988 } |
| 1883 case VariableLocation::GLOBAL: | 1989 case VariableLocation::GLOBAL: |
| 1884 case VariableLocation::UNALLOCATED: { | 1990 case VariableLocation::UNALLOCATED: { |
| 1885 builder()->LoadGlobal(feedback_index(slot), typeof_mode); | 1991 builder()->LoadGlobal(feedback_index(slot), typeof_mode); |
| 1886 execution_result()->SetResultInAccumulator(); | 1992 execution_result()->SetResultInAccumulator(); |
| 1887 break; | 1993 break; |
| 1888 } | 1994 } |
| 1889 case VariableLocation::CONTEXT: { | 1995 case VariableLocation::CONTEXT: { |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2729 VisitVariableLoadForAccumulatorValue( | 2835 VisitVariableLoadForAccumulatorValue( |
| 2730 proxy->var(), proxy->VariableFeedbackSlot(), INSIDE_TYPEOF); | 2836 proxy->var(), proxy->VariableFeedbackSlot(), INSIDE_TYPEOF); |
| 2731 } else { | 2837 } else { |
| 2732 VisitForAccumulatorValue(expr->expression()); | 2838 VisitForAccumulatorValue(expr->expression()); |
| 2733 } | 2839 } |
| 2734 builder()->TypeOf(); | 2840 builder()->TypeOf(); |
| 2735 execution_result()->SetResultInAccumulator(); | 2841 execution_result()->SetResultInAccumulator(); |
| 2736 } | 2842 } |
| 2737 | 2843 |
| 2738 void BytecodeGenerator::VisitNot(UnaryOperation* expr) { | 2844 void BytecodeGenerator::VisitNot(UnaryOperation* expr) { |
| 2739 VisitForAccumulatorValue(expr->expression()); | 2845 if (execution_result()->IsTest()) { |
|
rmcilroy
2016/08/12 11:15:26
Could you also add the IsEffect shortcut here (jus
klaasb
2016/08/12 16:00:12
Done.
| |
| 2740 builder()->LogicalNot(); | 2846 ControlResultScope* control_result = |
| 2741 execution_result()->SetResultInAccumulator(); | 2847 static_cast<ControlResultScope*>(execution_result()); |
|
rmcilroy
2016/08/12 11:15:26
Could you add an AsTest() function with DCHECKS to
klaasb
2016/08/12 16:00:12
Done.
| |
| 2848 VisitForControl(expr->expression(), control_result->ElseLabels(), | |
|
rmcilroy
2016/08/12 11:15:26
nit - comment that you are swapping the control fl
klaasb
2016/08/12 16:00:12
Done.
| |
| 2849 control_result->ThenLabels(), | |
| 2850 control_result->InvertedFallthrough()); | |
| 2851 control_result->SetNoResult(); | |
| 2852 } else { | |
| 2853 VisitForAccumulatorValue(expr->expression()); | |
| 2854 builder()->LogicalNot(); | |
| 2855 execution_result()->SetResultInAccumulator(); | |
| 2856 } | |
| 2742 } | 2857 } |
| 2743 | 2858 |
| 2744 void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 2859 void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 2745 switch (expr->op()) { | 2860 switch (expr->op()) { |
| 2746 case Token::Value::NOT: | 2861 case Token::Value::NOT: |
| 2747 VisitNot(expr); | 2862 VisitNot(expr); |
| 2748 break; | 2863 break; |
| 2749 case Token::Value::TYPEOF: | 2864 case Token::Value::TYPEOF: |
| 2750 VisitTypeOf(expr); | 2865 VisitTypeOf(expr); |
| 2751 break; | 2866 break; |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3010 | 3125 |
| 3011 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { | 3126 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { |
| 3012 VisitForEffect(binop->left()); | 3127 VisitForEffect(binop->left()); |
| 3013 Visit(binop->right()); | 3128 Visit(binop->right()); |
| 3014 } | 3129 } |
| 3015 | 3130 |
| 3016 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { | 3131 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { |
| 3017 Expression* left = binop->left(); | 3132 Expression* left = binop->left(); |
| 3018 Expression* right = binop->right(); | 3133 Expression* right = binop->right(); |
| 3019 | 3134 |
| 3020 // Short-circuit evaluation- If it is known that left is always true, | 3135 if (execution_result()->IsTest()) { |
| 3021 // no need to visit right | 3136 ControlResultScope* control_result = |
| 3022 if (left->ToBooleanIsTrue()) { | 3137 static_cast<ControlResultScope*>(execution_result()); |
| 3023 VisitForAccumulatorValue(left); | 3138 |
| 3139 if (left->ToBooleanIsTrue()) { | |
|
rmcilroy
2016/08/12 11:15:26
I think you could do:
if (left->ToBooleanIsTrue()
klaasb
2016/08/12 16:00:12
Done.
| |
| 3140 builder()->Jump(control_result->NewThenLabel()); | |
| 3141 } else { | |
| 3142 BytecodeLabels test_right; | |
| 3143 VisitForControl(left, control_result->ThenLabels(), &test_right, | |
| 3144 ControlFallthrough::ELSE); | |
| 3145 test_right.Bind(builder()); | |
| 3146 VisitForControl(right, control_result->ThenLabels(), | |
| 3147 control_result->ElseLabels(), | |
| 3148 control_result->Fallthrough()); | |
| 3149 } | |
| 3150 control_result->SetNoResult(); | |
| 3024 } else { | 3151 } else { |
| 3025 BytecodeLabel end_label; | 3152 // Short-circuit evaluation- If it is known that left is always true, |
| 3026 VisitForAccumulatorValue(left); | 3153 // no need to visit right |
|
rmcilroy
2016/08/12 11:15:26
Just remove this comment (ditto below)
klaasb
2016/08/12 16:00:13
Done.
| |
| 3027 builder()->JumpIfTrue(&end_label); | 3154 if (left->ToBooleanIsTrue()) { |
| 3028 VisitForAccumulatorValue(right); | 3155 VisitForAccumulatorValue(left); |
| 3029 builder()->Bind(&end_label); | 3156 } else { |
|
rmcilroy
2016/08/12 11:15:25
I know this isn't your code, but we should also be
klaasb
2016/08/12 16:00:12
Done.
| |
| 3157 BytecodeLabel end_label; | |
| 3158 VisitForAccumulatorValue(left); | |
| 3159 builder()->JumpIfTrue(&end_label); | |
| 3160 VisitForAccumulatorValue(right); | |
| 3161 builder()->Bind(&end_label); | |
| 3162 } | |
| 3163 execution_result()->SetResultInAccumulator(); | |
| 3030 } | 3164 } |
| 3031 execution_result()->SetResultInAccumulator(); | |
| 3032 } | 3165 } |
| 3033 | 3166 |
| 3034 void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { | 3167 void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { |
| 3035 Expression* left = binop->left(); | 3168 Expression* left = binop->left(); |
| 3036 Expression* right = binop->right(); | 3169 Expression* right = binop->right(); |
| 3037 | 3170 |
| 3038 // Short-circuit evaluation- If it is known that left is always false, | 3171 if (execution_result()->IsTest()) { |
| 3039 // no need to visit right | 3172 ControlResultScope* control_result = |
| 3040 if (left->ToBooleanIsFalse()) { | 3173 static_cast<ControlResultScope*>(execution_result()); |
| 3041 VisitForAccumulatorValue(left); | 3174 |
| 3175 if (left->ToBooleanIsFalse()) { | |
|
rmcilroy
2016/08/12 11:15:26
Same suggestion (for AND) as above for OR.
klaasb
2016/08/12 16:00:12
Done.
| |
| 3176 builder()->Jump(control_result->NewElseLabel()); | |
| 3177 } else { | |
| 3178 BytecodeLabels test_right; | |
| 3179 VisitForControl(left, &test_right, control_result->ElseLabels(), | |
| 3180 ControlFallthrough::THEN); | |
| 3181 test_right.Bind(builder()); | |
| 3182 VisitForControl(right, control_result->ThenLabels(), | |
| 3183 control_result->ElseLabels(), | |
| 3184 control_result->Fallthrough()); | |
| 3185 } | |
| 3186 control_result->SetNoResult(); | |
| 3042 } else { | 3187 } else { |
| 3043 BytecodeLabel end_label; | 3188 // Short-circuit evaluation- If it is known that left is always false, |
| 3044 VisitForAccumulatorValue(left); | 3189 // no need to visit right |
|
rmcilroy
2016/08/12 11:15:26
ditto
klaasb
2016/08/12 16:00:12
Done.
| |
| 3045 builder()->JumpIfFalse(&end_label); | 3190 if (left->ToBooleanIsFalse()) { |
|
rmcilroy
2016/08/12 11:15:25
Same suggestion as above.
klaasb
2016/08/12 16:00:12
Done.
| |
| 3046 VisitForAccumulatorValue(right); | 3191 VisitForAccumulatorValue(left); |
| 3047 builder()->Bind(&end_label); | 3192 } else { |
| 3193 BytecodeLabel end_label; | |
| 3194 VisitForAccumulatorValue(left); | |
| 3195 builder()->JumpIfFalse(&end_label); | |
| 3196 VisitForAccumulatorValue(right); | |
| 3197 builder()->Bind(&end_label); | |
| 3198 } | |
| 3199 execution_result()->SetResultInAccumulator(); | |
| 3048 } | 3200 } |
| 3049 execution_result()->SetResultInAccumulator(); | |
| 3050 } | 3201 } |
| 3051 | 3202 |
| 3052 void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { | 3203 void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { |
| 3053 Visit(expr->expression()); | 3204 Visit(expr->expression()); |
| 3054 } | 3205 } |
| 3055 | 3206 |
| 3056 void BytecodeGenerator::VisitNewLocalFunctionContext() { | 3207 void BytecodeGenerator::VisitNewLocalFunctionContext() { |
| 3057 AccumulatorResultScope accumulator_execution_result(this); | 3208 AccumulatorResultScope accumulator_execution_result(this); |
| 3058 Scope* scope = this->scope(); | 3209 Scope* scope = this->scope(); |
| 3059 | 3210 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3281 | 3432 |
| 3282 // Visits the expression |expr| and stores the expression result in | 3433 // Visits the expression |expr| and stores the expression result in |
| 3283 // |destination|. | 3434 // |destination|. |
| 3284 void BytecodeGenerator::VisitForRegisterValue(Expression* expr, | 3435 void BytecodeGenerator::VisitForRegisterValue(Expression* expr, |
| 3285 Register destination) { | 3436 Register destination) { |
| 3286 AccumulatorResultScope register_scope(this); | 3437 AccumulatorResultScope register_scope(this); |
| 3287 Visit(expr); | 3438 Visit(expr); |
| 3288 builder()->StoreAccumulatorInRegister(destination); | 3439 builder()->StoreAccumulatorInRegister(destination); |
| 3289 } | 3440 } |
| 3290 | 3441 |
| 3442 // Visits the expression |expr| for testing its boolean value and jumping to the | |
| 3443 // |then| or |other| label depending on value and short-circuit semantics | |
| 3444 void BytecodeGenerator::VisitForControl(Expression* expr, | |
| 3445 BytecodeLabels* then_labels, | |
| 3446 BytecodeLabels* else_labels, | |
| 3447 ControlFallthrough fallthrough) { | |
| 3448 bool has_result; | |
| 3449 { | |
| 3450 // to make sure that all temporary registers are returned before generating | |
|
rmcilroy
2016/08/12 11:15:26
/s/to/To
klaasb
2016/08/12 16:00:12
Done.
| |
| 3451 // jumps below, we assure that the result scope is deleted before | |
| 3452 // otherwise dead registers might be materialized | |
|
rmcilroy
2016/08/12 11:15:26
fullstop
klaasb
2016/08/12 16:00:11
Done.
| |
| 3453 ControlResultScope control_result(this, then_labels, else_labels, | |
| 3454 fallthrough); | |
| 3455 Visit(expr); | |
| 3456 has_result = control_result.HasResultValue(); | |
| 3457 } | |
| 3458 if (has_result) { | |
| 3459 switch (fallthrough) { | |
| 3460 case ControlFallthrough::THEN: | |
| 3461 builder()->JumpIfFalse(else_labels->New()); | |
| 3462 break; | |
| 3463 case ControlFallthrough::ELSE: | |
| 3464 builder()->JumpIfTrue(then_labels->New()); | |
| 3465 break; | |
| 3466 default: | |
|
rmcilroy
2016/08/12 11:15:26
Make this explicitly case ControlFallthrough::kNon
klaasb
2016/08/12 16:00:12
Done.
| |
| 3467 builder()->JumpIfTrue(then_labels->New()); | |
| 3468 builder()->Jump(else_labels->New()); | |
| 3469 } | |
| 3470 } | |
| 3471 } | |
| 3472 | |
| 3291 void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { | 3473 void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { |
| 3292 ContextScope context_scope(this, scope); | 3474 ContextScope context_scope(this, scope); |
| 3293 DCHECK(scope->declarations()->is_empty()); | 3475 DCHECK(scope->declarations()->is_empty()); |
| 3294 Visit(stmt); | 3476 Visit(stmt); |
| 3295 } | 3477 } |
| 3296 | 3478 |
| 3297 LanguageMode BytecodeGenerator::language_mode() const { | 3479 LanguageMode BytecodeGenerator::language_mode() const { |
| 3298 return execution_context()->scope()->language_mode(); | 3480 return execution_context()->scope()->language_mode(); |
| 3299 } | 3481 } |
| 3300 | 3482 |
| 3301 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3483 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 3302 return TypeFeedbackVector::GetIndex(slot); | 3484 return TypeFeedbackVector::GetIndex(slot); |
| 3303 } | 3485 } |
| 3304 | 3486 |
| 3305 } // namespace interpreter | 3487 } // namespace interpreter |
| 3306 } // namespace internal | 3488 } // namespace internal |
| 3307 } // namespace v8 | 3489 } // namespace v8 |
| OLD | NEW |