| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 #include "vm/deopt_instructions.h" | 5 #include "vm/deopt_instructions.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 #include "vm/code_patcher.h" | 8 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" |
| 9 #include "vm/intermediate_language.h" | 10 #include "vm/intermediate_language.h" |
| 10 #include "vm/locations.h" | 11 #include "vm/locations.h" |
| 11 #include "vm/parser.h" | 12 #include "vm/parser.h" |
| 12 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
| 13 #include "vm/thread.h" | 14 #include "vm/thread.h" |
| 14 | 15 |
| 15 namespace dart { | 16 namespace dart { |
| 16 | 17 |
| 17 DEFINE_FLAG(bool, compress_deopt_info, true, | 18 DEFINE_FLAG(bool, compress_deopt_info, true, |
| 18 "Compress the size of the deoptimization info for optimized code."); | 19 "Compress the size of the deoptimization info for optimized code."); |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 } | 371 } |
| 371 | 372 |
| 372 virtual DeoptInstr::Kind kind() const { return kRetAddress; } | 373 virtual DeoptInstr::Kind kind() const { return kRetAddress; } |
| 373 | 374 |
| 374 virtual const char* ArgumentsToCString() const { | 375 virtual const char* ArgumentsToCString() const { |
| 375 return Thread::Current()->zone()->PrintToString( | 376 return Thread::Current()->zone()->PrintToString( |
| 376 "%" Pd ", %" Pd "", object_table_index_, deopt_id_); | 377 "%" Pd ", %" Pd "", object_table_index_, deopt_id_); |
| 377 } | 378 } |
| 378 | 379 |
| 379 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) { | 380 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) { |
| 380 Code& code = Code::Handle(deopt_context->zone()); | 381 *dest_addr = Smi::RawValue(0); |
| 381 code ^= deopt_context->ObjectAt(object_table_index_); | 382 deopt_context->DeferRetAddrMaterialization( |
| 382 ASSERT(!code.IsNull()); | 383 object_table_index_, deopt_id_, dest_addr); |
| 383 uword continue_at_pc = code.GetPcForDeoptId(deopt_id_, | |
| 384 RawPcDescriptors::kDeopt); | |
| 385 ASSERT(continue_at_pc != 0); | |
| 386 *dest_addr = continue_at_pc; | |
| 387 | |
| 388 uword pc = code.GetPcForDeoptId(deopt_id_, RawPcDescriptors::kIcCall); | |
| 389 if (pc != 0) { | |
| 390 // If the deoptimization happened at an IC call, update the IC data | |
| 391 // to avoid repeated deoptimization at the same site next time around. | |
| 392 ICData& ic_data = ICData::Handle(); | |
| 393 CodePatcher::GetInstanceCallAt(pc, code, &ic_data); | |
| 394 if (!ic_data.IsNull()) { | |
| 395 ic_data.AddDeoptReason(deopt_context->deopt_reason()); | |
| 396 } | |
| 397 } else { | |
| 398 const Function& function = Function::Handle(code.function()); | |
| 399 if (deopt_context->HasDeoptFlag(ICData::kHoisted)) { | |
| 400 // Prevent excessive deoptimization. | |
| 401 function.set_allows_hoisting_check_class(false); | |
| 402 } | |
| 403 | |
| 404 if (deopt_context->HasDeoptFlag(ICData::kGeneralized)) { | |
| 405 function.set_allows_bounds_check_generalization(false); | |
| 406 } | |
| 407 } | |
| 408 } | 384 } |
| 409 | 385 |
| 410 intptr_t object_table_index() const { return object_table_index_; } | 386 intptr_t object_table_index() const { return object_table_index_; } |
| 411 intptr_t deopt_id() const { return deopt_id_; } | 387 intptr_t deopt_id() const { return deopt_id_; } |
| 412 | 388 |
| 413 private: | 389 private: |
| 414 static const intptr_t kFieldWidth = kBitsPerWord / 2; | 390 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
| 415 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | 391 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; |
| 416 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | 392 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
| 417 | 393 |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 | 610 |
| 635 virtual intptr_t source_index() const { return object_table_index_; } | 611 virtual intptr_t source_index() const { return object_table_index_; } |
| 636 virtual DeoptInstr::Kind kind() const { return kPcMarker; } | 612 virtual DeoptInstr::Kind kind() const { return kPcMarker; } |
| 637 | 613 |
| 638 virtual const char* ArgumentsToCString() const { | 614 virtual const char* ArgumentsToCString() const { |
| 639 return Thread::Current()->zone()->PrintToString( | 615 return Thread::Current()->zone()->PrintToString( |
| 640 "%" Pd "", object_table_index_); | 616 "%" Pd "", object_table_index_); |
| 641 } | 617 } |
| 642 | 618 |
| 643 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) { | 619 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) { |
| 644 Code& code = Code::Handle(deopt_context->zone()); | 620 *dest_addr = Smi::RawValue(0); |
| 645 code ^= deopt_context->ObjectAt(object_table_index_); | 621 deopt_context->DeferPcMarkerMaterialization( |
| 646 if (code.IsNull()) { | 622 object_table_index_, dest_addr); |
| 647 // Callee's PC marker is not used (pc of Deoptimize stub). Set to 0. | |
| 648 *dest_addr = 0; | |
| 649 return; | |
| 650 } | |
| 651 const Function& function = | |
| 652 Function::Handle(deopt_context->zone(), code.function()); | |
| 653 ASSERT(function.HasCode()); | |
| 654 const intptr_t pc_marker = | |
| 655 code.EntryPoint() + Assembler::EntryPointToPcMarkerOffset(); | |
| 656 *dest_addr = pc_marker; | |
| 657 // Increment the deoptimization counter. This effectively increments each | |
| 658 // function occurring in the optimized frame. | |
| 659 function.set_deoptimization_counter(function.deoptimization_counter() + 1); | |
| 660 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) { | |
| 661 OS::PrintErr("Deoptimizing %s (count %d)\n", | |
| 662 function.ToFullyQualifiedCString(), | |
| 663 function.deoptimization_counter()); | |
| 664 } | |
| 665 // Clear invocation counter so that hopefully the function gets reoptimized | |
| 666 // only after more feedback has been collected. | |
| 667 function.set_usage_counter(0); | |
| 668 if (function.HasOptimizedCode()) { | |
| 669 function.SwitchToUnoptimizedCode(); | |
| 670 } | |
| 671 } | 623 } |
| 672 | 624 |
| 673 private: | 625 private: |
| 674 intptr_t object_table_index_; | 626 intptr_t object_table_index_; |
| 675 | 627 |
| 676 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); | 628 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr); |
| 677 }; | 629 }; |
| 678 | 630 |
| 679 | 631 |
| 680 // Deoptimization instruction creating a pool pointer for the code of | 632 // Deoptimization instruction creating a pool pointer for the code of |
| 681 // function at 'object_table_index'. | 633 // function at 'object_table_index'. |
| 682 class DeoptPpInstr : public DeoptInstr { | 634 class DeoptPpInstr : public DeoptInstr { |
| 683 public: | 635 public: |
| 684 explicit DeoptPpInstr(intptr_t object_table_index) | 636 explicit DeoptPpInstr(intptr_t object_table_index) |
| 685 : object_table_index_(object_table_index) { | 637 : object_table_index_(object_table_index) { |
| 686 ASSERT(object_table_index >= 0); | 638 ASSERT(object_table_index >= 0); |
| 687 } | 639 } |
| 688 | 640 |
| 689 virtual intptr_t source_index() const { return object_table_index_; } | 641 virtual intptr_t source_index() const { return object_table_index_; } |
| 690 virtual DeoptInstr::Kind kind() const { return kPp; } | 642 virtual DeoptInstr::Kind kind() const { return kPp; } |
| 691 | 643 |
| 692 virtual const char* ArgumentsToCString() const { | 644 virtual const char* ArgumentsToCString() const { |
| 693 return Thread::Current()->zone()->PrintToString( | 645 return Thread::Current()->zone()->PrintToString( |
| 694 "%" Pd "", object_table_index_); | 646 "%" Pd "", object_table_index_); |
| 695 } | 647 } |
| 696 | 648 |
| 697 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) { | 649 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) { |
| 698 Code& code = Code::Handle(deopt_context->zone()); | 650 *dest_addr = Smi::RawValue(0); |
| 699 code ^= deopt_context->ObjectAt(object_table_index_); | 651 deopt_context->DeferPpMaterialization(object_table_index_, |
| 700 ASSERT(!code.IsNull()); | 652 reinterpret_cast<RawObject**>(dest_addr)); |
| 701 const intptr_t pp = reinterpret_cast<intptr_t>(code.ObjectPool()); | |
| 702 *dest_addr = pp; | |
| 703 } | 653 } |
| 704 | 654 |
| 705 private: | 655 private: |
| 706 intptr_t object_table_index_; | 656 intptr_t object_table_index_; |
| 707 | 657 |
| 708 DISALLOW_COPY_AND_ASSIGN(DeoptPpInstr); | 658 DISALLOW_COPY_AND_ASSIGN(DeoptPpInstr); |
| 709 }; | 659 }; |
| 710 | 660 |
| 711 | 661 |
| 712 // Deoptimization instruction copying the caller saved FP from optimized frame. | 662 // Deoptimization instruction copying the caller saved FP from optimized frame. |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 uword DeoptInstr::GetRetAddress(DeoptInstr* instr, | 833 uword DeoptInstr::GetRetAddress(DeoptInstr* instr, |
| 884 const Array& object_table, | 834 const Array& object_table, |
| 885 Code* code) { | 835 Code* code) { |
| 886 ASSERT(instr->kind() == kRetAddress); | 836 ASSERT(instr->kind() == kRetAddress); |
| 887 DeoptRetAddressInstr* ret_address_instr = | 837 DeoptRetAddressInstr* ret_address_instr = |
| 888 static_cast<DeoptRetAddressInstr*>(instr); | 838 static_cast<DeoptRetAddressInstr*>(instr); |
| 889 // The following assert may trigger when displaying a backtrace | 839 // The following assert may trigger when displaying a backtrace |
| 890 // from the simulator. | 840 // from the simulator. |
| 891 ASSERT(Isolate::IsDeoptAfter(ret_address_instr->deopt_id())); | 841 ASSERT(Isolate::IsDeoptAfter(ret_address_instr->deopt_id())); |
| 892 ASSERT(!object_table.IsNull()); | 842 ASSERT(!object_table.IsNull()); |
| 843 Function& function = Function::Handle(); |
| 844 function ^= object_table.At(ret_address_instr->object_table_index()); |
| 893 ASSERT(code != NULL); | 845 ASSERT(code != NULL); |
| 894 *code ^= object_table.At(ret_address_instr->object_table_index()); | 846 Compiler::EnsureUnoptimizedCode(Thread::Current(), function); |
| 847 *code ^= function.unoptimized_code(); |
| 895 ASSERT(!code->IsNull()); | 848 ASSERT(!code->IsNull()); |
| 896 uword res = code->GetPcForDeoptId(ret_address_instr->deopt_id(), | 849 uword res = code->GetPcForDeoptId(ret_address_instr->deopt_id(), |
| 897 RawPcDescriptors::kDeopt); | 850 RawPcDescriptors::kDeopt); |
| 898 ASSERT(res != 0); | 851 ASSERT(res != 0); |
| 899 return res; | 852 return res; |
| 900 } | 853 } |
| 901 | 854 |
| 902 | 855 |
| 903 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t source_index) { | 856 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t source_index) { |
| 904 Kind kind = static_cast<Kind>(kind_as_int); | 857 Kind kind = static_cast<Kind>(kind_as_int); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 return FpuRegisterSource(FpuRegisterSource::kRegister, loc.fpu_reg()); | 1029 return FpuRegisterSource(FpuRegisterSource::kRegister, loc.fpu_reg()); |
| 1077 } else { | 1030 } else { |
| 1078 ASSERT((stack_slot_kind == Location::kQuadStackSlot) || | 1031 ASSERT((stack_slot_kind == Location::kQuadStackSlot) || |
| 1079 (stack_slot_kind == Location::kDoubleStackSlot)); | 1032 (stack_slot_kind == Location::kDoubleStackSlot)); |
| 1080 ASSERT(loc.kind() == stack_slot_kind); | 1033 ASSERT(loc.kind() == stack_slot_kind); |
| 1081 return FpuRegisterSource( | 1034 return FpuRegisterSource( |
| 1082 FpuRegisterSource::kStackSlot, CalculateStackIndex(loc)); | 1035 FpuRegisterSource::kStackSlot, CalculateStackIndex(loc)); |
| 1083 } | 1036 } |
| 1084 } | 1037 } |
| 1085 | 1038 |
| 1086 void DeoptInfoBuilder::AddReturnAddress(const Code& code, | 1039 void DeoptInfoBuilder::AddReturnAddress(const Function& function, |
| 1087 intptr_t deopt_id, | 1040 intptr_t deopt_id, |
| 1088 intptr_t dest_index) { | 1041 intptr_t dest_index) { |
| 1089 // Check that deopt_id exists. | 1042 const intptr_t object_table_index = FindOrAddObjectInTable(function); |
| 1090 // TODO(vegorov): verify after deoptimization targets as well. | |
| 1091 #ifdef DEBUG | |
| 1092 ASSERT(Isolate::IsDeoptAfter(deopt_id) || | |
| 1093 (code.GetPcForDeoptId(deopt_id, RawPcDescriptors::kDeopt) != 0)); | |
| 1094 #endif | |
| 1095 const intptr_t object_table_index = FindOrAddObjectInTable(code); | |
| 1096 ASSERT(dest_index == FrameSize()); | 1043 ASSERT(dest_index == FrameSize()); |
| 1097 instructions_.Add( | 1044 instructions_.Add( |
| 1098 new(zone()) DeoptRetAddressInstr(object_table_index, deopt_id)); | 1045 new(zone()) DeoptRetAddressInstr(object_table_index, deopt_id)); |
| 1099 } | 1046 } |
| 1100 | 1047 |
| 1101 | 1048 |
| 1102 void DeoptInfoBuilder::AddPcMarker(const Code& code, | 1049 void DeoptInfoBuilder::AddPcMarker(const Function& function, |
| 1103 intptr_t dest_index) { | 1050 intptr_t dest_index) { |
| 1104 intptr_t object_table_index = FindOrAddObjectInTable(code); | 1051 intptr_t object_table_index = FindOrAddObjectInTable(function); |
| 1105 ASSERT(dest_index == FrameSize()); | 1052 ASSERT(dest_index == FrameSize()); |
| 1106 instructions_.Add(new(zone()) DeoptPcMarkerInstr(object_table_index)); | 1053 instructions_.Add(new(zone()) DeoptPcMarkerInstr(object_table_index)); |
| 1107 } | 1054 } |
| 1108 | 1055 |
| 1109 | 1056 |
| 1110 void DeoptInfoBuilder::AddPp(const Code& code, | 1057 void DeoptInfoBuilder::AddPp(const Function& function, |
| 1111 intptr_t dest_index) { | 1058 intptr_t dest_index) { |
| 1112 intptr_t object_table_index = FindOrAddObjectInTable(code); | 1059 intptr_t object_table_index = FindOrAddObjectInTable(function); |
| 1113 ASSERT(dest_index == FrameSize()); | 1060 ASSERT(dest_index == FrameSize()); |
| 1114 instructions_.Add(new(zone()) DeoptPpInstr(object_table_index)); | 1061 instructions_.Add(new(zone()) DeoptPpInstr(object_table_index)); |
| 1115 } | 1062 } |
| 1116 | 1063 |
| 1117 | 1064 |
| 1118 void DeoptInfoBuilder::AddCopy(Value* value, | 1065 void DeoptInfoBuilder::AddCopy(Value* value, |
| 1119 const Location& source_loc, | 1066 const Location& source_loc, |
| 1120 const intptr_t dest_index) { | 1067 const intptr_t dest_index) { |
| 1121 DeoptInstr* deopt_instr = NULL; | 1068 DeoptInstr* deopt_instr = NULL; |
| 1122 if (source_loc.IsConstant()) { | 1069 if (source_loc.IsConstant()) { |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1354 Smi* offset, | 1301 Smi* offset, |
| 1355 DeoptInfo* info, | 1302 DeoptInfo* info, |
| 1356 Smi* reason) { | 1303 Smi* reason) { |
| 1357 intptr_t i = index * kEntrySize; | 1304 intptr_t i = index * kEntrySize; |
| 1358 *offset ^= table.At(i); | 1305 *offset ^= table.At(i); |
| 1359 *info ^= table.At(i + 1); | 1306 *info ^= table.At(i + 1); |
| 1360 *reason ^= table.At(i + 2); | 1307 *reason ^= table.At(i + 2); |
| 1361 } | 1308 } |
| 1362 | 1309 |
| 1363 } // namespace dart | 1310 } // namespace dart |
| OLD | NEW |