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/compiler.h" | 7 #include "src/compiler.h" |
| 8 #include "src/interpreter/control-flow-builders.h" | 8 #include "src/interpreter/control-flow-builders.h" |
| 9 #include "src/objects.h" | 9 #include "src/objects.h" |
| 10 #include "src/parser.h" | 10 #include "src/parser.h" |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 set_result_identified(); | 290 set_result_identified(); |
| 291 } | 291 } |
| 292 | 292 |
| 293 Register ResultRegister() const { return result_register_; } | 293 Register ResultRegister() const { return result_register_; } |
| 294 | 294 |
| 295 private: | 295 private: |
| 296 Register result_register_; | 296 Register result_register_; |
| 297 }; | 297 }; |
| 298 | 298 |
| 299 | 299 |
| 300 BytecodeGenerator::AssignmentHazardHelper::AssignmentHazardHelper( | |
| 301 BytecodeGenerator* generator) | |
| 302 : generator_(generator), | |
| 303 alias_mappings_(generator->zone()), | |
| 304 aliased_locals_and_parameters_(generator->zone()), | |
| 305 execution_result_(nullptr), | |
| 306 scope_depth_(0) {} | |
| 307 | |
| 308 | |
| 309 void BytecodeGenerator::AssignmentHazardHelper::EnterScope() { | |
| 310 if (scope_depth_++ == 0) { | |
| 311 execution_result_ = generator_->execution_result(); | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 | |
| 316 void BytecodeGenerator::AssignmentHazardHelper::LeaveScope() { | |
|
rmcilroy
2015/11/12 12:49:15
DCHECK_GT(scope_depth, 0)
oth
2015/11/13 12:43:30
Done.
| |
| 317 if (--scope_depth_ == 0) { | |
| 318 RestoreAliasedLocalsAndParameters(); | |
|
rmcilroy
2015/11/12 12:49:15
DCHECK_EQ(execution_result_, generator_->execution
oth
2015/11/13 12:43:30
Good idea. Done.
| |
| 319 } | |
| 320 } | |
| 321 | |
| 322 | |
| 323 // Returns a register that a load instruction should use when | |
| 324 // loading from |reg|. This allows an alias for a modified version | |
| 325 // of |reg| to be used within a hazard regions. | |
| 326 MUST_USE_RESULT Register | |
| 327 BytecodeGenerator::AssignmentHazardHelper::GetRegisterForLoad(Register reg) { | |
| 328 if (scope_depth_ == 0) { | |
| 329 return reg; | |
| 330 } else { | |
| 331 // A load from |reg| is to be issued. The register is placed in | |
| 332 // the mappings table initially mapping to itself. Future stores | |
| 333 // will update the mapping with temporaries thus preserving the | |
| 334 // original register's value. | |
| 335 // | |
| 336 // NB This insert only updates the table if no mapping exists | |
| 337 // already (std::map::insert semantics). | |
| 338 auto insert_result = | |
| 339 alias_mappings_.insert(std::make_pair(reg.index(), reg.index())); | |
| 340 auto mapping = insert_result.first; | |
| 341 // Return the current alias for reg. | |
| 342 return Register(mapping->second); | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 | |
| 347 // Returns a register that a store instruction should use when | |
| 348 // loading from |reg|. This allows an alias for a modified version | |
| 349 // of |reg| to be used within hazard regions. | |
| 350 MUST_USE_RESULT Register | |
| 351 BytecodeGenerator::AssignmentHazardHelper::GetRegisterForStore(Register reg) { | |
| 352 if (scope_depth_ == 0 || | |
| 353 alias_mappings_.find(reg.index()) == alias_mappings_.end()) { | |
| 354 // If not in a hazard region or a load for this register has not | |
| 355 // occurred no mapping is necessary. | |
| 356 return reg; | |
| 357 } else { | |
| 358 // Storing to a register with 1 or more loads issued. The | |
| 359 // register is mapped to a temporary alias so we don't overwrite | |
| 360 // the lhs value, e.g. y = x + (x = 1); has a register for x on | |
| 361 // the lhs and needs a new register x' for the upcoming store on | |
| 362 // the rhs as the original x is an input to the add operation. | |
| 363 Register alias = execution_result_->NewRegister(); | |
| 364 alias_mappings_[reg.index()] = alias.index(); | |
| 365 if (generator_->builder()->RegisterIsParameterOrLocal(reg)) { | |
| 366 // Keep track of registers that need to be restored on exit | |
| 367 // from the assignment hazard region. | |
| 368 aliased_locals_and_parameters_.insert(reg.index()); | |
| 369 } | |
| 370 return alias; | |
| 371 } | |
| 372 } | |
| 373 | |
| 374 | |
| 375 void BytecodeGenerator::AssignmentHazardHelper:: | |
| 376 RestoreAliasedLocalsAndParameters() { | |
| 377 DCHECK(scope_depth_ == 0); | |
| 378 // Move temporary registers holding values for locals and | |
| 379 // parameters back into their local and parameter registers. | |
| 380 for (auto reg = aliased_locals_and_parameters_.begin(); | |
| 381 reg != aliased_locals_and_parameters_.end(); reg++) { | |
| 382 auto mapping = alias_mappings_.find(*reg); | |
| 383 if (mapping != alias_mappings_.end()) { | |
| 384 generator_->builder()->MoveRegister(Register(mapping->second), | |
| 385 Register(*reg)); | |
| 386 } | |
| 387 } | |
| 388 alias_mappings_.clear(); | |
| 389 aliased_locals_and_parameters_.clear(); | |
| 390 } | |
| 391 | |
| 392 | |
| 393 class BytecodeGenerator::AssignmentHazardScope final { | |
| 394 public: | |
| 395 explicit AssignmentHazardScope(BytecodeGenerator* generator) | |
| 396 : generator_(generator) { | |
| 397 generator_->assignment_hazard_helper()->EnterScope(); | |
| 398 } | |
| 399 | |
| 400 ~AssignmentHazardScope() { | |
| 401 generator_->assignment_hazard_helper()->LeaveScope(); | |
| 402 } | |
| 403 | |
| 404 private: | |
| 405 BytecodeGenerator* generator_; | |
| 406 | |
| 407 DISALLOW_COPY_AND_ASSIGN(AssignmentHazardScope); | |
| 408 }; | |
| 409 | |
| 410 | |
| 300 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) | 411 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
| 301 : isolate_(isolate), | 412 : isolate_(isolate), |
| 302 zone_(zone), | 413 zone_(zone), |
| 303 builder_(isolate, zone), | 414 builder_(isolate, zone), |
| 304 info_(nullptr), | 415 info_(nullptr), |
| 305 scope_(nullptr), | 416 scope_(nullptr), |
| 306 globals_(0, zone), | 417 globals_(0, zone), |
| 307 execution_control_(nullptr), | 418 execution_control_(nullptr), |
| 308 execution_context_(nullptr), | 419 execution_context_(nullptr), |
| 309 execution_result_(nullptr), | 420 execution_result_(nullptr), |
| 310 binary_expression_depth_(0), | 421 assignment_hazard_helper_(this) { |
| 311 binary_expression_hazard_set_(zone) { | |
| 312 InitializeAstVisitor(isolate); | 422 InitializeAstVisitor(isolate); |
| 313 } | 423 } |
| 314 | 424 |
| 315 | 425 |
| 316 BytecodeGenerator::~BytecodeGenerator() {} | |
| 317 | |
| 318 | |
| 319 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 426 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| 320 set_info(info); | 427 set_info(info); |
| 321 set_scope(info->scope()); | 428 set_scope(info->scope()); |
| 322 | 429 |
| 323 // Initialize the incoming context. | 430 // Initialize the incoming context. |
| 324 ContextScope incoming_context(this, scope(), false); | 431 ContextScope incoming_context(this, scope(), false); |
| 325 | 432 |
| 326 builder()->set_parameter_count(info->num_parameters_including_this()); | 433 builder()->set_parameter_count(info->num_parameters_including_this()); |
| 327 builder()->set_locals_count(scope()->num_stack_slots()); | 434 builder()->set_locals_count(scope()->num_stack_slots()); |
| 328 builder()->set_context_count(scope()->MaxNestedContextChainLength()); | 435 builder()->set_context_count(scope()->MaxNestedContextChainLength()); |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 builder()->LoadLiteral(Smi::FromInt(encoded_flags)); | 606 builder()->LoadLiteral(Smi::FromInt(encoded_flags)); |
| 500 builder()->StoreAccumulatorInRegister(flags); | 607 builder()->StoreAccumulatorInRegister(flags); |
| 501 DCHECK(flags.index() == pairs.index() + 1); | 608 DCHECK(flags.index() == pairs.index() + 1); |
| 502 | 609 |
| 503 builder()->CallRuntime(Runtime::kDeclareGlobals, pairs, 2); | 610 builder()->CallRuntime(Runtime::kDeclareGlobals, pairs, 2); |
| 504 globals()->clear(); | 611 globals()->clear(); |
| 505 } | 612 } |
| 506 | 613 |
| 507 | 614 |
| 508 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { | 615 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
| 509 // TODO(rmcilroy): Replace this with a StatementResultScope when it exists. | 616 EffectResultScope statement_result_scope(this); |
| 510 EffectResultScope effect_scope(this); | |
| 511 VisitForEffect(stmt->expression()); | 617 VisitForEffect(stmt->expression()); |
| 512 } | 618 } |
| 513 | 619 |
| 514 | 620 |
| 515 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { | 621 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
| 516 } | 622 } |
| 517 | 623 |
| 518 | 624 |
| 519 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { | 625 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { |
| 520 BytecodeLabel else_label, end_label; | 626 BytecodeLabel else_label, end_label; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 552 execution_control()->Continue(stmt->target()); | 658 execution_control()->Continue(stmt->target()); |
| 553 } | 659 } |
| 554 | 660 |
| 555 | 661 |
| 556 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 662 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
| 557 execution_control()->Break(stmt->target()); | 663 execution_control()->Break(stmt->target()); |
| 558 } | 664 } |
| 559 | 665 |
| 560 | 666 |
| 561 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 667 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| 562 EffectResultScope effect_scope(this); | 668 EffectResultScope statement_result_scope(this); |
| 563 VisitForAccumulatorValue(stmt->expression()); | 669 VisitForAccumulatorValue(stmt->expression()); |
| 564 builder()->Return(); | 670 builder()->Return(); |
| 565 } | 671 } |
| 566 | 672 |
| 567 | 673 |
| 568 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 674 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
| 569 UNIMPLEMENTED(); | 675 UNIMPLEMENTED(); |
| 570 } | 676 } |
| 571 | 677 |
| 572 | 678 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 621 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { | 727 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { |
| 622 // Handled entirely in VisitSwitchStatement. | 728 // Handled entirely in VisitSwitchStatement. |
| 623 UNREACHABLE(); | 729 UNREACHABLE(); |
| 624 } | 730 } |
| 625 | 731 |
| 626 | 732 |
| 627 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 733 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 628 LoopBuilder loop_builder(builder()); | 734 LoopBuilder loop_builder(builder()); |
| 629 ControlScopeForIteration execution_control(this, stmt, &loop_builder); | 735 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
| 630 BytecodeLabel body_label, condition_label, done_label; | 736 BytecodeLabel body_label, condition_label, done_label; |
| 631 | |
| 632 if (stmt->cond()->ToBooleanIsFalse()) { | 737 if (stmt->cond()->ToBooleanIsFalse()) { |
| 633 Visit(stmt->body()); | 738 Visit(stmt->body()); |
| 634 // Bind condition_label and done_label for processing continue and break. | 739 // Bind condition_label and done_label for processing continue and break. |
| 635 builder()->Bind(&condition_label); | 740 builder()->Bind(&condition_label); |
| 636 builder()->Bind(&done_label); | 741 builder()->Bind(&done_label); |
| 637 } else { | 742 } else { |
| 638 builder()->Bind(&body_label); | 743 builder()->Bind(&body_label); |
| 639 Visit(stmt->body()); | 744 Visit(stmt->body()); |
| 640 | 745 |
| 641 builder()->Bind(&condition_label); | 746 builder()->Bind(&condition_label); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 757 break; | 862 break; |
| 758 } | 863 } |
| 759 case NAMED_SUPER_PROPERTY: | 864 case NAMED_SUPER_PROPERTY: |
| 760 case KEYED_SUPER_PROPERTY: | 865 case KEYED_SUPER_PROPERTY: |
| 761 UNIMPLEMENTED(); | 866 UNIMPLEMENTED(); |
| 762 } | 867 } |
| 763 } | 868 } |
| 764 | 869 |
| 765 | 870 |
| 766 void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 871 void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 767 // TODO(oth): For now we need a parent scope for paths that end up | 872 EffectResultScope statement_result_scope(this); |
| 768 // in VisitLiteral which can allocate in the parent scope. A future | |
| 769 // CL in preparation will add a StatementResultScope that will | |
| 770 // remove the need for this EffectResultScope. | |
| 771 EffectResultScope result_scope(this); | |
| 772 | 873 |
| 773 if (stmt->subject()->IsNullLiteral() || | 874 if (stmt->subject()->IsNullLiteral() || |
| 774 stmt->subject()->IsUndefinedLiteral(isolate())) { | 875 stmt->subject()->IsUndefinedLiteral(isolate())) { |
| 775 // ForIn generates lots of code, skip if it wouldn't produce any effects. | 876 // ForIn generates lots of code, skip if it wouldn't produce any effects. |
| 776 return; | 877 return; |
| 777 } | 878 } |
| 778 | 879 |
| 779 LoopBuilder loop_builder(builder()); | 880 LoopBuilder loop_builder(builder()); |
| 780 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 881 ControlScopeForIteration control_scope(this, stmt, &loop_builder); |
| 781 | 882 |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1191 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 1292 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
| 1192 } | 1293 } |
| 1193 | 1294 |
| 1194 | 1295 |
| 1195 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 1296 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| 1196 FeedbackVectorSlot slot, | 1297 FeedbackVectorSlot slot, |
| 1197 TypeofMode typeof_mode) { | 1298 TypeofMode typeof_mode) { |
| 1198 switch (variable->location()) { | 1299 switch (variable->location()) { |
| 1199 case VariableLocation::LOCAL: { | 1300 case VariableLocation::LOCAL: { |
| 1200 Register source(Register(variable->index())); | 1301 Register source(Register(variable->index())); |
| 1302 source = assignment_hazard_helper()->GetRegisterForLoad(source); | |
| 1201 execution_result()->SetResultInRegister(source); | 1303 execution_result()->SetResultInRegister(source); |
| 1202 break; | 1304 break; |
| 1203 } | 1305 } |
| 1204 case VariableLocation::PARAMETER: { | 1306 case VariableLocation::PARAMETER: { |
| 1205 // The parameter indices are shifted by 1 (receiver is variable | 1307 // The parameter indices are shifted by 1 (receiver is variable |
| 1206 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1308 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 1207 Register source = builder()->Parameter(variable->index() + 1); | 1309 Register source = builder()->Parameter(variable->index() + 1); |
| 1310 source = assignment_hazard_helper()->GetRegisterForLoad(source); | |
| 1208 execution_result()->SetResultInRegister(source); | 1311 execution_result()->SetResultInRegister(source); |
| 1209 break; | 1312 break; |
| 1210 } | 1313 } |
| 1211 case VariableLocation::GLOBAL: | 1314 case VariableLocation::GLOBAL: |
| 1212 case VariableLocation::UNALLOCATED: { | 1315 case VariableLocation::UNALLOCATED: { |
| 1213 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); | 1316 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); |
| 1214 builder()->LoadGlobal(name_index, feedback_index(slot), language_mode(), | 1317 builder()->LoadGlobal(name_index, feedback_index(slot), language_mode(), |
| 1215 typeof_mode); | 1318 typeof_mode); |
| 1216 execution_result()->SetResultInAccumulator(); | 1319 execution_result()->SetResultInAccumulator(); |
| 1217 break; | 1320 break; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1262 return register_scope.ResultRegister(); | 1365 return register_scope.ResultRegister(); |
| 1263 } | 1366 } |
| 1264 | 1367 |
| 1265 | 1368 |
| 1266 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 1369 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
| 1267 FeedbackVectorSlot slot) { | 1370 FeedbackVectorSlot slot) { |
| 1268 switch (variable->location()) { | 1371 switch (variable->location()) { |
| 1269 case VariableLocation::LOCAL: { | 1372 case VariableLocation::LOCAL: { |
| 1270 // TODO(rmcilroy): support const mode initialization. | 1373 // TODO(rmcilroy): support const mode initialization. |
| 1271 Register destination(variable->index()); | 1374 Register destination(variable->index()); |
| 1375 destination = | |
| 1376 assignment_hazard_helper()->GetRegisterForStore(destination); | |
| 1272 builder()->StoreAccumulatorInRegister(destination); | 1377 builder()->StoreAccumulatorInRegister(destination); |
| 1273 RecordStoreToRegister(destination); | |
| 1274 break; | 1378 break; |
| 1275 } | 1379 } |
| 1276 case VariableLocation::PARAMETER: { | 1380 case VariableLocation::PARAMETER: { |
| 1277 // The parameter indices are shifted by 1 (receiver is variable | 1381 // The parameter indices are shifted by 1 (receiver is variable |
| 1278 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 1382 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 1279 Register destination(builder()->Parameter(variable->index() + 1)); | 1383 Register destination(builder()->Parameter(variable->index() + 1)); |
| 1384 destination = | |
| 1385 assignment_hazard_helper()->GetRegisterForStore(destination); | |
| 1386 | |
| 1280 builder()->StoreAccumulatorInRegister(destination); | 1387 builder()->StoreAccumulatorInRegister(destination); |
| 1281 RecordStoreToRegister(destination); | |
| 1282 break; | 1388 break; |
| 1283 } | 1389 } |
| 1284 case VariableLocation::GLOBAL: | 1390 case VariableLocation::GLOBAL: |
| 1285 case VariableLocation::UNALLOCATED: { | 1391 case VariableLocation::UNALLOCATED: { |
| 1286 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); | 1392 size_t name_index = builder()->GetConstantPoolEntry(variable->name()); |
| 1287 builder()->StoreGlobal(name_index, feedback_index(slot), language_mode()); | 1393 builder()->StoreGlobal(name_index, feedback_index(slot), language_mode()); |
| 1288 break; | 1394 break; |
| 1289 } | 1395 } |
| 1290 case VariableLocation::CONTEXT: { | 1396 case VariableLocation::CONTEXT: { |
| 1291 // TODO(rmcilroy): support const mode initialization. | 1397 // TODO(rmcilroy): support const mode initialization. |
| (...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1818 VisitLogicalAndExpression(binop); | 1924 VisitLogicalAndExpression(binop); |
| 1819 break; | 1925 break; |
| 1820 default: | 1926 default: |
| 1821 VisitArithmeticExpression(binop); | 1927 VisitArithmeticExpression(binop); |
| 1822 break; | 1928 break; |
| 1823 } | 1929 } |
| 1824 } | 1930 } |
| 1825 | 1931 |
| 1826 | 1932 |
| 1827 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 1933 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 1828 // TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression | 1934 // The evaluation of binary comparison expressions has an assignment |
| 1829 // once we have StatementScope that tracks hazardous loads/stores. | 1935 // hazard because the lhs may be a variable that evaluates to a |
| 1830 PrepareForBinaryExpression(); | 1936 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) |
| 1937 // To get a correct result the generator treats the inner assigment | |
| 1938 // as being made to a temporary x' that is spilled on exit of the | |
| 1939 // assignment hazard. | |
| 1940 AssignmentHazardScope assignment_hazard_scope(this); | |
| 1941 | |
| 1831 Register lhs = VisitForRegisterValue(expr->left()); | 1942 Register lhs = VisitForRegisterValue(expr->left()); |
| 1832 if (builder()->RegisterIsParameterOrLocal(lhs)) { | |
| 1833 // Result was returned in an existing local or parameter. See if | |
| 1834 // it needs to be moved to a temporary. | |
| 1835 // TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad(). | |
| 1836 lhs = LoadFromAliasedRegister(lhs); | |
| 1837 } | |
| 1838 VisitForAccumulatorValue(expr->right()); | 1943 VisitForAccumulatorValue(expr->right()); |
| 1839 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); | 1944 builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); |
| 1840 CompleteBinaryExpression(); | |
| 1841 execution_result()->SetResultInAccumulator(); | 1945 execution_result()->SetResultInAccumulator(); |
| 1842 } | 1946 } |
| 1843 | 1947 |
| 1844 | 1948 |
| 1845 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { | 1949 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
| 1846 // TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression | 1950 // The evaluation of binary arithmetic expressions has an assignment |
| 1847 // once we have StatementScope that tracks hazardous loads/stores. | 1951 // hazard because the lhs may be a variable that evaluates to a |
| 1848 PrepareForBinaryExpression(); | 1952 // local or parameter and the rhs may modify that, e.g. y = x + (x = 1) |
| 1953 // To get a correct result the generator treats the inner assigment | |
| 1954 // as being made to a temporary x' that is spilled on exit of the | |
| 1955 // assignment hazard. | |
| 1956 AssignmentHazardScope assignment_hazard_scope(this); | |
| 1957 | |
| 1849 Register lhs = VisitForRegisterValue(expr->left()); | 1958 Register lhs = VisitForRegisterValue(expr->left()); |
| 1850 if (builder()->RegisterIsParameterOrLocal(lhs)) { | |
| 1851 // Result was returned in an existing local or parameter. See if | |
| 1852 // it needs to be moved to a temporary. | |
| 1853 // TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad(). | |
| 1854 lhs = LoadFromAliasedRegister(lhs); | |
| 1855 } | |
| 1856 VisitForAccumulatorValue(expr->right()); | 1959 VisitForAccumulatorValue(expr->right()); |
| 1857 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); | 1960 builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); |
| 1858 CompleteBinaryExpression(); | |
| 1859 execution_result()->SetResultInAccumulator(); | 1961 execution_result()->SetResultInAccumulator(); |
| 1860 } | 1962 } |
| 1861 | 1963 |
| 1862 | 1964 |
| 1863 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } | 1965 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } |
| 1864 | 1966 |
| 1865 | 1967 |
| 1866 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { | 1968 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { |
| 1867 UNREACHABLE(); | 1969 UNREACHABLE(); |
| 1868 } | 1970 } |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2066 // Pass a SMI sentinel and let the runtime look up the empty function. | 2168 // Pass a SMI sentinel and let the runtime look up the empty function. |
| 2067 builder()->LoadLiteral(Smi::FromInt(0)); | 2169 builder()->LoadLiteral(Smi::FromInt(0)); |
| 2068 } else { | 2170 } else { |
| 2069 DCHECK(closure_scope->is_function_scope()); | 2171 DCHECK(closure_scope->is_function_scope()); |
| 2070 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | 2172 builder()->LoadAccumulatorWithRegister(Register::function_closure()); |
| 2071 } | 2173 } |
| 2072 execution_result()->SetResultInAccumulator(); | 2174 execution_result()->SetResultInAccumulator(); |
| 2073 } | 2175 } |
| 2074 | 2176 |
| 2075 | 2177 |
| 2076 void BytecodeGenerator::PrepareForBinaryExpression() { | |
| 2077 if (binary_expression_depth_++ == 0) { | |
| 2078 binary_expression_hazard_set_.clear(); | |
| 2079 } | |
| 2080 } | |
| 2081 | |
| 2082 | |
| 2083 // Visits the expression |expr| and places the result in the accumulator. | 2178 // Visits the expression |expr| and places the result in the accumulator. |
| 2084 void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { | 2179 void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { |
| 2085 AccumulatorResultScope accumulator_scope(this); | 2180 AccumulatorResultScope accumulator_scope(this); |
| 2086 Visit(expr); | 2181 Visit(expr); |
| 2087 } | 2182 } |
| 2088 | 2183 |
| 2089 | 2184 |
| 2090 // Visits the expression |expr| and discards the result. | 2185 // Visits the expression |expr| and discards the result. |
| 2091 void BytecodeGenerator::VisitForEffect(Expression* expr) { | 2186 void BytecodeGenerator::VisitForEffect(Expression* expr) { |
| 2092 EffectResultScope effect_scope(this); | 2187 EffectResultScope effect_scope(this); |
| 2093 Visit(expr); | 2188 Visit(expr); |
| 2094 } | 2189 } |
| 2095 | 2190 |
| 2096 | 2191 |
| 2097 // Visits the expression |expr| and returns the register containing | 2192 // Visits the expression |expr| and returns the register containing |
| 2098 // the expression result. | 2193 // the expression result. |
| 2099 Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { | 2194 Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { |
| 2100 RegisterResultScope register_scope(this); | 2195 RegisterResultScope register_scope(this); |
| 2101 Visit(expr); | 2196 Visit(expr); |
| 2102 return register_scope.ResultRegister(); | 2197 return register_scope.ResultRegister(); |
| 2103 } | 2198 } |
| 2104 | 2199 |
| 2105 | 2200 |
| 2106 Register BytecodeGenerator::LoadFromAliasedRegister(Register reg) { | |
| 2107 // TODO(oth): Follow on CL to load from re-map here. | |
| 2108 DCHECK(builder()->RegisterIsParameterOrLocal(reg)); | |
| 2109 if (binary_expression_depth_ > 0) { | |
| 2110 binary_expression_hazard_set_.insert(reg.index()); | |
| 2111 } | |
| 2112 return reg; | |
| 2113 } | |
| 2114 | |
| 2115 | |
| 2116 void BytecodeGenerator::RecordStoreToRegister(Register reg) { | |
| 2117 DCHECK(builder()->RegisterIsParameterOrLocal(reg)); | |
| 2118 if (binary_expression_depth_ > 0) { | |
| 2119 // TODO(oth): a store to a register that's be loaded needs to be | |
| 2120 // remapped. | |
| 2121 DCHECK(binary_expression_hazard_set_.find(reg.index()) == | |
| 2122 binary_expression_hazard_set_.end()); | |
| 2123 } | |
| 2124 } | |
| 2125 | |
| 2126 | |
| 2127 void BytecodeGenerator::CompleteBinaryExpression() { | |
| 2128 DCHECK(binary_expression_depth_ > 0); | |
| 2129 binary_expression_depth_ -= 1; | |
| 2130 // TODO(oth): spill remapped registers into origins. | |
| 2131 // TODO(oth): make statement/top-level. | |
| 2132 } | |
| 2133 | |
| 2134 | |
| 2135 Register BytecodeGenerator::NextContextRegister() const { | 2201 Register BytecodeGenerator::NextContextRegister() const { |
| 2136 if (execution_context() == nullptr) { | 2202 if (execution_context() == nullptr) { |
| 2137 // Return the incoming function context for the outermost execution context. | 2203 // Return the incoming function context for the outermost execution context. |
| 2138 return Register::function_context(); | 2204 return Register::function_context(); |
| 2139 } | 2205 } |
| 2140 Register previous = execution_context()->reg(); | 2206 Register previous = execution_context()->reg(); |
| 2141 if (previous == Register::function_context()) { | 2207 if (previous == Register::function_context()) { |
| 2142 // If the previous context was the incoming function context, then the next | 2208 // If the previous context was the incoming function context, then the next |
| 2143 // context register is the first local context register. | 2209 // context register is the first local context register. |
| 2144 return builder_.first_context_register(); | 2210 return builder_.first_context_register(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 2160 } | 2226 } |
| 2161 | 2227 |
| 2162 | 2228 |
| 2163 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2229 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 2164 return info()->feedback_vector()->GetIndex(slot); | 2230 return info()->feedback_vector()->GetIndex(slot); |
| 2165 } | 2231 } |
| 2166 | 2232 |
| 2167 } // namespace interpreter | 2233 } // namespace interpreter |
| 2168 } // namespace internal | 2234 } // namespace internal |
| 2169 } // namespace v8 | 2235 } // namespace v8 |
| OLD | NEW |