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-array-builder.h" | 5 #include "src/interpreter/bytecode-array-builder.h" |
| 6 | 6 |
| 7 namespace v8 { | 7 namespace v8 { |
| 8 namespace internal { | 8 namespace internal { |
| 9 namespace interpreter { | 9 namespace interpreter { |
| 10 | 10 |
| 11 class BytecodeArrayBuilder::PreviousBytecodeHelper { | |
| 12 public: | |
| 13 explicit PreviousBytecodeHelper(const BytecodeArrayBuilder& array_builder) | |
| 14 : array_builder_(array_builder) {} | |
| 15 | |
| 16 Bytecode GetBytecode() const { | |
| 17 // Returns the previous bytecode in the same basicblock. If there is none it | |
| 18 // returns Bytecode::kLast. | |
| 19 if (!array_builder_.LastBytecodeInSameBlock()) { | |
| 20 return Bytecode::kLast; | |
|
rmcilroy
2015/12/07 11:56:03
Bytecode::kLast is the same as the last valid byte
| |
| 21 } | |
| 22 return Bytecodes::FromByte( | |
| 23 array_builder_.bytecodes()->at(array_builder_.last_bytecode_start_)); | |
| 24 } | |
| 25 | |
| 26 uint32_t GetOperand(int operand_index) const { | |
| 27 Bytecode bytecode = GetBytecode(); | |
| 28 DCHECK_GE(operand_index, 0); | |
| 29 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode)); | |
| 30 size_t operand_offset = | |
| 31 array_builder_.last_bytecode_start_ + | |
| 32 Bytecodes::GetOperandOffset(bytecode, operand_index); | |
| 33 OperandSize size = Bytecodes::GetOperandSize(bytecode, operand_index); | |
| 34 switch (size) { | |
| 35 default: | |
| 36 case OperandSize::kNone: | |
| 37 UNREACHABLE(); | |
| 38 case OperandSize::kByte: | |
| 39 return static_cast<uint32_t>( | |
| 40 array_builder_.bytecodes()->at(operand_offset)); | |
| 41 case OperandSize::kShort: | |
| 42 uint16_t operand = | |
| 43 (array_builder_.bytecodes()->at(operand_offset) << 8) + | |
| 44 array_builder_.bytecodes()->at(operand_offset + 1); | |
| 45 return static_cast<uint32_t>(operand); | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 Handle<Object> GetConstantForIndexOperand(int operand_index) const { | |
| 50 return array_builder_.constants_.at(GetOperand(operand_index)); | |
| 51 } | |
| 52 | |
| 53 private: | |
| 54 const BytecodeArrayBuilder& array_builder_; | |
| 55 }; | |
| 56 | |
| 57 | |
| 11 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) | 58 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) |
| 12 : isolate_(isolate), | 59 : isolate_(isolate), |
| 13 zone_(zone), | 60 zone_(zone), |
| 14 bytecodes_(zone), | 61 bytecodes_(zone), |
| 15 bytecode_generated_(false), | 62 bytecode_generated_(false), |
| 16 last_block_end_(0), | 63 last_block_end_(0), |
| 17 last_bytecode_start_(~0), | 64 last_bytecode_start_(~0), |
| 18 exit_seen_in_block_(false), | 65 exit_seen_in_block_(false), |
| 19 constants_map_(isolate->heap(), zone), | 66 constants_map_(isolate->heap(), zone), |
| 20 constants_(zone), | 67 constants_(zone), |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 270 return *this; | 317 return *this; |
| 271 } | 318 } |
| 272 | 319 |
| 273 | 320 |
| 274 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { | 321 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { |
| 275 Output(Bytecode::kLdaFalse); | 322 Output(Bytecode::kLdaFalse); |
| 276 return *this; | 323 return *this; |
| 277 } | 324 } |
| 278 | 325 |
| 279 | 326 |
| 327 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) { | |
| 328 if (value) { | |
| 329 LoadTrue(); | |
| 330 } else { | |
| 331 LoadFalse(); | |
| 332 } | |
| 333 return *this; | |
| 334 } | |
| 335 | |
| 336 | |
| 280 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( | 337 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( |
| 281 Register reg) { | 338 Register reg) { |
| 282 if (!IsRegisterInAccumulator(reg)) { | 339 if (!IsRegisterInAccumulator(reg)) { |
| 283 Output(Bytecode::kLdar, reg.ToOperand()); | 340 Output(Bytecode::kLdar, reg.ToOperand()); |
| 284 } | 341 } |
| 285 return *this; | 342 return *this; |
| 286 } | 343 } |
| 287 | 344 |
| 288 | 345 |
| 289 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( | 346 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 } | 573 } |
| 517 | 574 |
| 518 | 575 |
| 519 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { | 576 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { |
| 520 Output(Bytecode::kPopContext, context.ToOperand()); | 577 Output(Bytecode::kPopContext, context.ToOperand()); |
| 521 return *this; | 578 return *this; |
| 522 } | 579 } |
| 523 | 580 |
| 524 | 581 |
| 525 bool BytecodeArrayBuilder::NeedToBooleanCast() { | 582 bool BytecodeArrayBuilder::NeedToBooleanCast() { |
| 526 if (!LastBytecodeInSameBlock()) { | 583 PreviousBytecodeHelper previous_bytecode(*this); |
| 527 // If the previous bytecode was from a different block return false. | 584 switch (previous_bytecode.GetBytecode()) { |
| 528 return true; | |
| 529 } | |
| 530 | |
| 531 // If the previous bytecode puts a boolean in the accumulator return true. | |
| 532 switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) { | |
| 533 case Bytecode::kToBoolean: | 585 case Bytecode::kToBoolean: |
| 534 UNREACHABLE(); | 586 UNREACHABLE(); |
| 587 // If the previous bytecode puts a boolean in the accumulator return true. | |
| 535 case Bytecode::kLdaTrue: | 588 case Bytecode::kLdaTrue: |
| 536 case Bytecode::kLdaFalse: | 589 case Bytecode::kLdaFalse: |
| 537 case Bytecode::kLogicalNot: | 590 case Bytecode::kLogicalNot: |
| 538 case Bytecode::kTestEqual: | 591 case Bytecode::kTestEqual: |
| 539 case Bytecode::kTestNotEqual: | 592 case Bytecode::kTestNotEqual: |
| 540 case Bytecode::kTestEqualStrict: | 593 case Bytecode::kTestEqualStrict: |
| 541 case Bytecode::kTestNotEqualStrict: | 594 case Bytecode::kTestNotEqualStrict: |
| 542 case Bytecode::kTestLessThan: | 595 case Bytecode::kTestLessThan: |
| 543 case Bytecode::kTestLessThanOrEqual: | 596 case Bytecode::kTestLessThanOrEqual: |
| 544 case Bytecode::kTestGreaterThan: | 597 case Bytecode::kTestGreaterThan: |
| 545 case Bytecode::kTestGreaterThanOrEqual: | 598 case Bytecode::kTestGreaterThanOrEqual: |
| 546 case Bytecode::kTestInstanceOf: | 599 case Bytecode::kTestInstanceOf: |
| 547 case Bytecode::kTestIn: | 600 case Bytecode::kTestIn: |
| 548 case Bytecode::kForInDone: | 601 case Bytecode::kForInDone: |
| 549 return false; | 602 return false; |
| 603 // Also handles the case where the previous bytecode was in a different | |
| 604 // block. | |
| 550 default: | 605 default: |
| 551 return true; | 606 return true; |
| 552 } | 607 } |
| 553 } | 608 } |
| 554 | 609 |
| 555 | 610 |
| 556 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { | 611 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { |
| 612 PreviousBytecodeHelper previous_bytecode(*this); | |
| 557 // If the previous bytecode puts a boolean in the accumulator | 613 // If the previous bytecode puts a boolean in the accumulator |
| 558 // there is no need to emit an instruction. | 614 // there is no need to emit an instruction. |
| 559 if (NeedToBooleanCast()) { | 615 if (NeedToBooleanCast()) { |
| 560 Output(Bytecode::kToBoolean); | 616 switch (previous_bytecode.GetBytecode()) { |
|
rmcilroy
2015/12/07 11:56:03
Optional nit - It would be nice to have some tests
| |
| 617 // If the previous bytecode is a constant evaluate it and return false. | |
| 618 case Bytecode::kLdaZero: { | |
| 619 LoadFalse(); | |
| 620 break; | |
| 621 } | |
| 622 case Bytecode::kLdaSmi8: { | |
| 623 LoadBooleanConstant(previous_bytecode.GetOperand(0) != 0); | |
| 624 break; | |
| 625 } | |
| 626 case Bytecode::kLdaConstant: { | |
| 627 Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0); | |
| 628 LoadBooleanConstant(object->BooleanValue()); | |
| 629 break; | |
| 630 } | |
| 631 default: | |
| 632 Output(Bytecode::kToBoolean); | |
| 633 } | |
| 561 } | 634 } |
| 562 return *this; | 635 return *this; |
| 563 } | 636 } |
| 564 | 637 |
| 565 | 638 |
| 566 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { | 639 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { |
| 567 Output(Bytecode::kToObject); | 640 Output(Bytecode::kToObject); |
| 568 return *this; | 641 return *this; |
| 569 } | 642 } |
| 570 | 643 |
| 571 | 644 |
| 572 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { | 645 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { |
| 646 PreviousBytecodeHelper previous_bytecode(*this); | |
| 647 switch (previous_bytecode.GetBytecode()) { | |
| 648 case Bytecode::kLdaConstantWide: | |
| 649 case Bytecode::kLdaConstant: { | |
| 650 Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0); | |
| 651 if (object->IsName()) return *this; | |
| 652 break; | |
| 653 } | |
| 654 case Bytecode::kToName: | |
| 655 case Bytecode::kTypeOf: | |
| 656 return *this; | |
| 657 default: | |
| 658 break; | |
| 659 } | |
| 573 Output(Bytecode::kToName); | 660 Output(Bytecode::kToName); |
| 574 return *this; | 661 return *this; |
| 575 } | 662 } |
| 576 | 663 |
| 577 | 664 |
| 578 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { | 665 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { |
| 579 // TODO(rmcilroy): consider omitting if the preceeding bytecode always returns | 666 // TODO(rmcilroy): consider omitting if the preceeding bytecode always returns |
| 580 // a number. | 667 // a number. |
| 581 Output(Bytecode::kToNumber); | 668 Output(Bytecode::kToNumber); |
| 582 return *this; | 669 return *this; |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 995 } | 1082 } |
| 996 | 1083 |
| 997 | 1084 |
| 998 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { | 1085 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { |
| 999 return last_bytecode_start_ < bytecodes()->size() && | 1086 return last_bytecode_start_ < bytecodes()->size() && |
| 1000 last_bytecode_start_ >= last_block_end_; | 1087 last_bytecode_start_ >= last_block_end_; |
| 1001 } | 1088 } |
| 1002 | 1089 |
| 1003 | 1090 |
| 1004 bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { | 1091 bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { |
| 1005 if (!LastBytecodeInSameBlock()) return false; | 1092 PreviousBytecodeHelper previous_bytecode(*this); |
| 1006 Bytecode previous_bytecode = | 1093 if (previous_bytecode.GetBytecode() == Bytecode::kLdar || |
| 1007 Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_)); | 1094 previous_bytecode.GetBytecode() == Bytecode::kStar) { |
| 1008 if (previous_bytecode == Bytecode::kLdar || | 1095 if (reg == Register::FromOperand(previous_bytecode.GetOperand(0))) { |
| 1009 previous_bytecode == Bytecode::kStar) { | |
| 1010 size_t operand_offset = last_bytecode_start_ + | |
| 1011 Bytecodes::GetOperandOffset(previous_bytecode, 0); | |
| 1012 if (reg == Register::FromOperand(bytecodes()->at(operand_offset))) { | |
| 1013 return true; | 1096 return true; |
| 1014 } | 1097 } |
| 1015 } | 1098 } |
| 1016 return false; | 1099 return false; |
| 1017 } | 1100 } |
| 1018 | 1101 |
| 1019 | 1102 |
| 1020 // static | 1103 // static |
| 1021 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { | 1104 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { |
| 1022 switch (op) { | 1105 switch (op) { |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1341 DCHECK_GT(next_consecutive_count_, 0); | 1424 DCHECK_GT(next_consecutive_count_, 0); |
| 1342 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); | 1425 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); |
| 1343 allocated_.push_back(next_consecutive_register_); | 1426 allocated_.push_back(next_consecutive_register_); |
| 1344 next_consecutive_count_--; | 1427 next_consecutive_count_--; |
| 1345 return Register(next_consecutive_register_++); | 1428 return Register(next_consecutive_register_++); |
| 1346 } | 1429 } |
| 1347 | 1430 |
| 1348 } // namespace interpreter | 1431 } // namespace interpreter |
| 1349 } // namespace internal | 1432 } // namespace internal |
| 1350 } // namespace v8 | 1433 } // namespace v8 |
| OLD | NEW |