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; |
| 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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 } | 563 } |
507 | 564 |
508 | 565 |
509 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { | 566 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { |
510 Output(Bytecode::kPopContext, context.ToOperand()); | 567 Output(Bytecode::kPopContext, context.ToOperand()); |
511 return *this; | 568 return *this; |
512 } | 569 } |
513 | 570 |
514 | 571 |
515 bool BytecodeArrayBuilder::NeedToBooleanCast() { | 572 bool BytecodeArrayBuilder::NeedToBooleanCast() { |
516 if (!LastBytecodeInSameBlock()) { | 573 PreviousBytecodeHelper previous_bytecode(*this); |
517 // If the previous bytecode was from a different block return false. | 574 switch (previous_bytecode.GetBytecode()) { |
518 return true; | |
519 } | |
520 | |
521 // If the previous bytecode puts a boolean in the accumulator return true. | |
522 switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) { | |
523 case Bytecode::kToBoolean: | 575 case Bytecode::kToBoolean: |
524 UNREACHABLE(); | 576 UNREACHABLE(); |
| 577 // If the previous bytecode puts a boolean in the accumulator return true. |
525 case Bytecode::kLdaTrue: | 578 case Bytecode::kLdaTrue: |
526 case Bytecode::kLdaFalse: | 579 case Bytecode::kLdaFalse: |
527 case Bytecode::kLogicalNot: | 580 case Bytecode::kLogicalNot: |
528 case Bytecode::kTestEqual: | 581 case Bytecode::kTestEqual: |
529 case Bytecode::kTestNotEqual: | 582 case Bytecode::kTestNotEqual: |
530 case Bytecode::kTestEqualStrict: | 583 case Bytecode::kTestEqualStrict: |
531 case Bytecode::kTestNotEqualStrict: | 584 case Bytecode::kTestNotEqualStrict: |
532 case Bytecode::kTestLessThan: | 585 case Bytecode::kTestLessThan: |
533 case Bytecode::kTestLessThanOrEqual: | 586 case Bytecode::kTestLessThanOrEqual: |
534 case Bytecode::kTestGreaterThan: | 587 case Bytecode::kTestGreaterThan: |
535 case Bytecode::kTestGreaterThanOrEqual: | 588 case Bytecode::kTestGreaterThanOrEqual: |
536 case Bytecode::kTestInstanceOf: | 589 case Bytecode::kTestInstanceOf: |
537 case Bytecode::kTestIn: | 590 case Bytecode::kTestIn: |
538 case Bytecode::kForInDone: | 591 case Bytecode::kForInDone: |
539 return false; | 592 return false; |
| 593 // Also handles the case where the previous bytecode was in a different |
| 594 // block. |
540 default: | 595 default: |
541 return true; | 596 return true; |
542 } | 597 } |
543 } | 598 } |
544 | 599 |
545 | 600 |
546 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { | 601 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { |
| 602 PreviousBytecodeHelper previous_bytecode(*this); |
547 // If the previous bytecode puts a boolean in the accumulator | 603 // If the previous bytecode puts a boolean in the accumulator |
548 // there is no need to emit an instruction. | 604 // there is no need to emit an instruction. |
549 if (NeedToBooleanCast()) { | 605 if (NeedToBooleanCast()) { |
550 Output(Bytecode::kToBoolean); | 606 switch (previous_bytecode.GetBytecode()) { |
| 607 // If the previous bytecode is a constant evaluate it and return false. |
| 608 case Bytecode::kLdaZero: { |
| 609 LoadFalse(); |
| 610 break; |
| 611 } |
| 612 case Bytecode::kLdaSmi8: { |
| 613 LoadBooleanConstant(previous_bytecode.GetOperand(0) != 0); |
| 614 break; |
| 615 } |
| 616 case Bytecode::kLdaConstant: { |
| 617 Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0); |
| 618 LoadBooleanConstant(object->BooleanValue()); |
| 619 break; |
| 620 } |
| 621 default: |
| 622 Output(Bytecode::kToBoolean); |
| 623 } |
551 } | 624 } |
552 return *this; | 625 return *this; |
553 } | 626 } |
554 | 627 |
555 | 628 |
556 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { | 629 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToJSObject() { |
557 Output(Bytecode::kToObject); | 630 Output(Bytecode::kToObject); |
558 return *this; | 631 return *this; |
559 } | 632 } |
560 | 633 |
561 | 634 |
562 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { | 635 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { |
| 636 PreviousBytecodeHelper previous_bytecode(*this); |
| 637 switch (previous_bytecode.GetBytecode()) { |
| 638 case Bytecode::kLdaConstantWide: |
| 639 case Bytecode::kLdaConstant: { |
| 640 Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0); |
| 641 if (object->IsName()) return *this; |
| 642 break; |
| 643 } |
| 644 case Bytecode::kToName: |
| 645 case Bytecode::kTypeOf: |
| 646 return *this; |
| 647 default: |
| 648 break; |
| 649 } |
563 Output(Bytecode::kToName); | 650 Output(Bytecode::kToName); |
564 return *this; | 651 return *this; |
565 } | 652 } |
566 | 653 |
567 | 654 |
568 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { | 655 BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() { |
569 // TODO(rmcilroy): consider omitting if the preceeding bytecode always returns | 656 // TODO(rmcilroy): consider omitting if the preceeding bytecode always returns |
570 // a number. | 657 // a number. |
571 Output(Bytecode::kToNumber); | 658 Output(Bytecode::kToNumber); |
572 return *this; | 659 return *this; |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
984 } | 1071 } |
985 | 1072 |
986 | 1073 |
987 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { | 1074 bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const { |
988 return last_bytecode_start_ < bytecodes()->size() && | 1075 return last_bytecode_start_ < bytecodes()->size() && |
989 last_bytecode_start_ >= last_block_end_; | 1076 last_bytecode_start_ >= last_block_end_; |
990 } | 1077 } |
991 | 1078 |
992 | 1079 |
993 bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { | 1080 bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { |
994 if (!LastBytecodeInSameBlock()) return false; | 1081 PreviousBytecodeHelper previous_bytecode(*this); |
995 Bytecode previous_bytecode = | 1082 if (previous_bytecode.GetBytecode() == Bytecode::kLdar || |
996 Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_)); | 1083 previous_bytecode.GetBytecode() == Bytecode::kStar) { |
997 if (previous_bytecode == Bytecode::kLdar || | 1084 if (reg == Register::FromOperand(previous_bytecode.GetOperand(0))) { |
998 previous_bytecode == Bytecode::kStar) { | |
999 size_t operand_offset = last_bytecode_start_ + | |
1000 Bytecodes::GetOperandOffset(previous_bytecode, 0); | |
1001 if (reg == Register::FromOperand(bytecodes()->at(operand_offset))) { | |
1002 return true; | 1085 return true; |
1003 } | 1086 } |
1004 } | 1087 } |
1005 return false; | 1088 return false; |
1006 } | 1089 } |
1007 | 1090 |
1008 | 1091 |
1009 // static | 1092 // static |
1010 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { | 1093 Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { |
1011 switch (op) { | 1094 switch (op) { |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1330 DCHECK_GT(next_consecutive_count_, 0); | 1413 DCHECK_GT(next_consecutive_count_, 0); |
1331 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); | 1414 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); |
1332 allocated_.push_back(next_consecutive_register_); | 1415 allocated_.push_back(next_consecutive_register_); |
1333 next_consecutive_count_--; | 1416 next_consecutive_count_--; |
1334 return Register(next_consecutive_register_++); | 1417 return Register(next_consecutive_register_++); |
1335 } | 1418 } |
1336 | 1419 |
1337 } // namespace interpreter | 1420 } // namespace interpreter |
1338 } // namespace internal | 1421 } // namespace internal |
1339 } // namespace v8 | 1422 } // namespace v8 |
OLD | NEW |