| 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/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 #include "vm/locations.h" | 10 #include "vm/locations.h" |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 } | 236 } |
| 237 | 237 |
| 238 private: | 238 private: |
| 239 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. | 239 const intptr_t stack_slot_index_; // First argument is 0, always >= 0. |
| 240 | 240 |
| 241 DISALLOW_COPY_AND_ASSIGN(DeoptUint32x4StackSlotInstr); | 241 DISALLOW_COPY_AND_ASSIGN(DeoptUint32x4StackSlotInstr); |
| 242 }; | 242 }; |
| 243 | 243 |
| 244 | 244 |
| 245 // Deoptimization instruction creating return address using function and | 245 // Deoptimization instruction creating return address using function and |
| 246 // deopt-id stored at 'object_table_index'. Uses the deopt-after | 246 // deopt-id stored at 'object_table_index'. |
| 247 // continuation point. | 247 class DeoptRetAddressInstr : public DeoptInstr { |
| 248 class DeoptRetAfterAddressInstr : public DeoptInstr { | |
| 249 public: | 248 public: |
| 250 DeoptRetAfterAddressInstr(intptr_t object_table_index, intptr_t deopt_id) | 249 DeoptRetAddressInstr(intptr_t object_table_index, intptr_t deopt_id) |
| 251 : object_table_index_(object_table_index), deopt_id_(deopt_id) { | 250 : object_table_index_(object_table_index), deopt_id_(deopt_id) { |
| 252 ASSERT(object_table_index >= 0); | 251 ASSERT(object_table_index >= 0); |
| 253 ASSERT(deopt_id >= 0); | 252 ASSERT(deopt_id >= 0); |
| 254 } | 253 } |
| 255 | 254 |
| 256 explicit DeoptRetAfterAddressInstr(intptr_t from_index) | 255 explicit DeoptRetAddressInstr(intptr_t from_index) |
| 257 : object_table_index_(ObjectTableIndex::decode(from_index)), | 256 : object_table_index_(ObjectTableIndex::decode(from_index)), |
| 258 deopt_id_(DeoptId::decode(from_index)) { | 257 deopt_id_(DeoptId::decode(from_index)) { |
| 259 } | 258 } |
| 260 | 259 |
| 261 virtual intptr_t from_index() const { | 260 virtual intptr_t from_index() const { |
| 262 return ObjectTableIndex::encode(object_table_index_) | | 261 return ObjectTableIndex::encode(object_table_index_) | |
| 263 DeoptId::encode(deopt_id_); | 262 DeoptId::encode(deopt_id_); |
| 264 } | 263 } |
| 265 virtual DeoptInstr::Kind kind() const { return kRetAfterAddress; } | 264 |
| 265 virtual DeoptInstr::Kind kind() const { return kRetAddress; } |
| 266 | 266 |
| 267 virtual const char* ToCString() const { | 267 virtual const char* ToCString() const { |
| 268 const char* format = "ret aft oti:%"Pd"(%"Pd")"; | 268 return Isolate::Current()->current_zone()->PrintToString( |
| 269 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); | 269 "ret oti:%"Pd"(%"Pd")", object_table_index_, deopt_id_); |
| 270 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | |
| 271 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); | |
| 272 return chars; | |
| 273 } | 270 } |
| 274 | 271 |
| 275 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | 272 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { |
| 276 Function& function = Function::Handle(deopt_context->isolate()); | |
| 277 function ^= deopt_context->ObjectAt(object_table_index_); | |
| 278 const Code& code = | |
| 279 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); | |
| 280 ASSERT(!code.IsNull()); | |
| 281 uword continue_at_pc = code.GetDeoptAfterPcAtDeoptId(deopt_id_); | |
| 282 ASSERT(continue_at_pc != 0); | |
| 283 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | |
| 284 *to_addr = continue_at_pc; | |
| 285 } | |
| 286 | |
| 287 intptr_t object_table_index() const { return object_table_index_; } | |
| 288 intptr_t deopt_id() const { return deopt_id_; } | |
| 289 | |
| 290 private: | |
| 291 static const intptr_t kFieldWidth = kBitsPerWord / 2; | |
| 292 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | |
| 293 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | |
| 294 | |
| 295 const intptr_t object_table_index_; | |
| 296 const intptr_t deopt_id_; | |
| 297 | |
| 298 DISALLOW_COPY_AND_ASSIGN(DeoptRetAfterAddressInstr); | |
| 299 }; | |
| 300 | |
| 301 | |
| 302 // Deoptimization instruction creating return address using function and | |
| 303 // deopt-id stored at 'object_table_index'. Uses the deopt-before | |
| 304 // continuation point. | |
| 305 class DeoptRetBeforeAddressInstr : public DeoptInstr { | |
| 306 public: | |
| 307 DeoptRetBeforeAddressInstr(intptr_t object_table_index, intptr_t deopt_id) | |
| 308 : object_table_index_(object_table_index), deopt_id_(deopt_id) { | |
| 309 ASSERT(object_table_index >= 0); | |
| 310 ASSERT(deopt_id >= 0); | |
| 311 } | |
| 312 | |
| 313 explicit DeoptRetBeforeAddressInstr(intptr_t from_index) | |
| 314 : object_table_index_(ObjectTableIndex::decode(from_index)), | |
| 315 deopt_id_(DeoptId::decode(from_index)) { | |
| 316 } | |
| 317 | |
| 318 virtual intptr_t from_index() const { | |
| 319 return ObjectTableIndex::encode(object_table_index_) | | |
| 320 DeoptId::encode(deopt_id_); | |
| 321 } | |
| 322 virtual DeoptInstr::Kind kind() const { return kRetBeforeAddress; } | |
| 323 | |
| 324 virtual const char* ToCString() const { | |
| 325 const char* format = "ret bef oti:%"Pd"(%"Pd")"; | |
| 326 intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_, deopt_id_); | |
| 327 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | |
| 328 OS::SNPrint(chars, len + 1, format, object_table_index_, deopt_id_); | |
| 329 return chars; | |
| 330 } | |
| 331 | |
| 332 void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) { | |
| 333 Function& function = Function::Handle(deopt_context->isolate()); | 273 Function& function = Function::Handle(deopt_context->isolate()); |
| 334 function ^= deopt_context->ObjectAt(object_table_index_); | 274 function ^= deopt_context->ObjectAt(object_table_index_); |
| 335 const Code& code = | 275 const Code& code = |
| 336 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); | 276 Code::Handle(deopt_context->isolate(), function.unoptimized_code()); |
| 337 ASSERT(!code.IsNull()); | 277 ASSERT(!code.IsNull()); |
| 338 uword continue_at_pc = code.GetDeoptBeforePcAtDeoptId(deopt_id_); | 278 uword continue_at_pc = code.GetPcForDeoptId(deopt_id_, |
| 279 PcDescriptors::kDeopt); |
| 339 ASSERT(continue_at_pc != 0); | 280 ASSERT(continue_at_pc != 0); |
| 340 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); | 281 intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index); |
| 341 *to_addr = continue_at_pc; | 282 *to_addr = continue_at_pc; |
| 342 | 283 |
| 343 uword pc = code.GetPcForDeoptId(deopt_id_, PcDescriptors::kIcCall); | 284 uword pc = code.GetPcForDeoptId(deopt_id_, PcDescriptors::kIcCall); |
| 344 if (pc != 0) { | 285 if (pc != 0) { |
| 345 // If the deoptimization happened at an IC call, update the IC data | 286 // If the deoptimization happened at an IC call, update the IC data |
| 346 // to avoid repeated deoptimization at the same site next time around. | 287 // to avoid repeated deoptimization at the same site next time around. |
| 347 ICData& ic_data = ICData::Handle(); | 288 ICData& ic_data = ICData::Handle(); |
| 348 CodePatcher::GetInstanceCallAt(pc, code, &ic_data, NULL); | 289 CodePatcher::GetInstanceCallAt(pc, code, &ic_data, NULL); |
| 349 if (!ic_data.IsNull()) { | 290 if (!ic_data.IsNull()) { |
| 350 ic_data.set_deopt_reason(deopt_context->deopt_reason()); | 291 ic_data.set_deopt_reason(deopt_context->deopt_reason()); |
| 351 } | 292 } |
| 352 } | 293 } |
| 353 } | 294 } |
| 354 | 295 |
| 296 intptr_t object_table_index() const { return object_table_index_; } |
| 297 intptr_t deopt_id() const { return deopt_id_; } |
| 298 |
| 355 private: | 299 private: |
| 356 static const intptr_t kFieldWidth = kBitsPerWord / 2; | 300 static const intptr_t kFieldWidth = kBitsPerWord / 2; |
| 357 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; | 301 class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { }; |
| 358 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; | 302 class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { }; |
| 359 | 303 |
| 360 const intptr_t object_table_index_; | 304 const intptr_t object_table_index_; |
| 361 const intptr_t deopt_id_; | 305 const intptr_t deopt_id_; |
| 362 | 306 |
| 363 DISALLOW_COPY_AND_ASSIGN(DeoptRetBeforeAddressInstr); | 307 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddressInstr); |
| 364 }; | 308 }; |
| 365 | 309 |
| 366 | 310 |
| 367 // Deoptimization instruction moving a constant stored at 'object_table_index'. | 311 // Deoptimization instruction moving a constant stored at 'object_table_index'. |
| 368 class DeoptConstantInstr : public DeoptInstr { | 312 class DeoptConstantInstr : public DeoptInstr { |
| 369 public: | 313 public: |
| 370 explicit DeoptConstantInstr(intptr_t object_table_index) | 314 explicit DeoptConstantInstr(intptr_t object_table_index) |
| 371 : object_table_index_(object_table_index) { | 315 : object_table_index_(object_table_index) { |
| 372 ASSERT(object_table_index >= 0); | 316 ASSERT(object_table_index >= 0); |
| 373 } | 317 } |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 DISALLOW_COPY_AND_ASSIGN(DeoptSuffixInstr); | 650 DISALLOW_COPY_AND_ASSIGN(DeoptSuffixInstr); |
| 707 }; | 651 }; |
| 708 | 652 |
| 709 | 653 |
| 710 intptr_t DeoptInstr::DecodeSuffix(intptr_t from_index, intptr_t* info_number) { | 654 intptr_t DeoptInstr::DecodeSuffix(intptr_t from_index, intptr_t* info_number) { |
| 711 *info_number = DeoptSuffixInstr::InfoNumber::decode(from_index); | 655 *info_number = DeoptSuffixInstr::InfoNumber::decode(from_index); |
| 712 return DeoptSuffixInstr::SuffixLength::decode(from_index); | 656 return DeoptSuffixInstr::SuffixLength::decode(from_index); |
| 713 } | 657 } |
| 714 | 658 |
| 715 | 659 |
| 716 uword DeoptInstr::GetRetAfterAddress(DeoptInstr* instr, | 660 uword DeoptInstr::GetRetAddress(DeoptInstr* instr, |
| 717 const Array& object_table, | 661 const Array& object_table, |
| 718 Function* func) { | 662 Function* func) { |
| 719 ASSERT(instr->kind() == kRetAfterAddress); | 663 ASSERT(instr->kind() == kRetAddress); |
| 720 DeoptRetAfterAddressInstr* ret_after_instr = | 664 DeoptRetAddressInstr* ret_address_instr = |
| 721 static_cast<DeoptRetAfterAddressInstr*>(instr); | 665 static_cast<DeoptRetAddressInstr*>(instr); |
| 666 ASSERT(Isolate::IsDeoptAfter(ret_address_instr->deopt_id())); |
| 722 ASSERT(!object_table.IsNull()); | 667 ASSERT(!object_table.IsNull()); |
| 723 ASSERT(func != NULL); | 668 ASSERT(func != NULL); |
| 724 *func ^= object_table.At(ret_after_instr->object_table_index()); | 669 *func ^= object_table.At(ret_address_instr->object_table_index()); |
| 725 const Code& code = Code::Handle(func->unoptimized_code()); | 670 const Code& code = Code::Handle(func->unoptimized_code()); |
| 726 ASSERT(!code.IsNull()); | 671 ASSERT(!code.IsNull()); |
| 727 uword res = code.GetDeoptAfterPcAtDeoptId(ret_after_instr->deopt_id()); | 672 uword res = code.GetPcForDeoptId(ret_address_instr->deopt_id(), |
| 673 PcDescriptors::kDeopt); |
| 728 ASSERT(res != 0); | 674 ASSERT(res != 0); |
| 729 return res; | 675 return res; |
| 730 } | 676 } |
| 731 | 677 |
| 732 | 678 |
| 733 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { | 679 DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t from_index) { |
| 734 Kind kind = static_cast<Kind>(kind_as_int); | 680 Kind kind = static_cast<Kind>(kind_as_int); |
| 735 switch (kind) { | 681 switch (kind) { |
| 736 case kStackSlot: return new DeoptStackSlotInstr(from_index); | 682 case kStackSlot: return new DeoptStackSlotInstr(from_index); |
| 737 case kDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index); | 683 case kDoubleStackSlot: return new DeoptDoubleStackSlotInstr(from_index); |
| 738 case kInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index); | 684 case kInt64StackSlot: return new DeoptInt64StackSlotInstr(from_index); |
| 739 case kFloat32x4StackSlot: | 685 case kFloat32x4StackSlot: |
| 740 return new DeoptFloat32x4StackSlotInstr(from_index); | 686 return new DeoptFloat32x4StackSlotInstr(from_index); |
| 741 case kUint32x4StackSlot: | 687 case kUint32x4StackSlot: |
| 742 return new DeoptUint32x4StackSlotInstr(from_index); | 688 return new DeoptUint32x4StackSlotInstr(from_index); |
| 743 case kRetAfterAddress: return new DeoptRetAfterAddressInstr(from_index); | 689 case kRetAddress: return new DeoptRetAddressInstr(from_index); |
| 744 case kRetBeforeAddress: return new DeoptRetBeforeAddressInstr(from_index); | |
| 745 case kConstant: return new DeoptConstantInstr(from_index); | 690 case kConstant: return new DeoptConstantInstr(from_index); |
| 746 case kRegister: return new DeoptRegisterInstr(from_index); | 691 case kRegister: return new DeoptRegisterInstr(from_index); |
| 747 case kFpuRegister: return new DeoptFpuRegisterInstr(from_index); | 692 case kFpuRegister: return new DeoptFpuRegisterInstr(from_index); |
| 748 case kInt64FpuRegister: return new DeoptInt64FpuRegisterInstr(from_index); | 693 case kInt64FpuRegister: return new DeoptInt64FpuRegisterInstr(from_index); |
| 749 case kFloat32x4FpuRegister: | 694 case kFloat32x4FpuRegister: |
| 750 return new DeoptFloat32x4FpuRegisterInstr(from_index); | 695 return new DeoptFloat32x4FpuRegisterInstr(from_index); |
| 751 case kUint32x4FpuRegister: | 696 case kUint32x4FpuRegister: |
| 752 return new DeoptUint32x4FpuRegisterInstr(from_index); | 697 return new DeoptUint32x4FpuRegisterInstr(from_index); |
| 753 case kPcMarker: return new DeoptPcMarkerInstr(from_index); | 698 case kPcMarker: return new DeoptPcMarkerInstr(from_index); |
| 754 case kCallerFp: return new DeoptCallerFpInstr(); | 699 case kCallerFp: return new DeoptCallerFpInstr(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 return i; | 752 return i; |
| 808 } | 753 } |
| 809 } | 754 } |
| 810 // Add object. | 755 // Add object. |
| 811 const intptr_t result = object_table_.Length(); | 756 const intptr_t result = object_table_.Length(); |
| 812 object_table_.Add(obj); | 757 object_table_.Add(obj); |
| 813 return result; | 758 return result; |
| 814 } | 759 } |
| 815 | 760 |
| 816 | 761 |
| 817 void DeoptInfoBuilder::AddReturnAddressBefore(const Function& function, | 762 void DeoptInfoBuilder::AddReturnAddress(const Function& function, |
| 818 intptr_t deopt_id, | 763 intptr_t deopt_id, |
| 819 intptr_t to_index) { | 764 intptr_t to_index) { |
| 820 // Check that deopt_id exists. | 765 // Check that deopt_id exists. |
| 821 ASSERT(Code::Handle(function.unoptimized_code()). | 766 // TODO(vegorov): verify after deoptimization targets as well. |
| 822 GetDeoptBeforePcAtDeoptId(deopt_id) != 0); | 767 #ifdef DEBUG |
| 768 const Code& code = Code::Handle(function.unoptimized_code()); |
| 769 ASSERT(Isolate::IsDeoptAfter(deopt_id) || |
| 770 (code.GetPcForDeoptId(deopt_id, PcDescriptors::kDeopt) != 0)); |
| 771 #endif |
| 823 const intptr_t object_table_index = FindOrAddObjectInTable(function); | 772 const intptr_t object_table_index = FindOrAddObjectInTable(function); |
| 824 ASSERT(to_index == instructions_.length()); | 773 ASSERT(to_index == instructions_.length()); |
| 825 instructions_.Add(new DeoptRetBeforeAddressInstr(object_table_index, | 774 instructions_.Add(new DeoptRetAddressInstr(object_table_index, deopt_id)); |
| 826 deopt_id)); | |
| 827 } | 775 } |
| 828 | 776 |
| 829 | 777 |
| 830 void DeoptInfoBuilder::AddReturnAddressAfter(const Function& function, | |
| 831 intptr_t deopt_id, | |
| 832 intptr_t to_index) { | |
| 833 const intptr_t object_table_index = FindOrAddObjectInTable(function); | |
| 834 ASSERT(to_index == instructions_.length()); | |
| 835 instructions_.Add(new DeoptRetAfterAddressInstr(object_table_index, | |
| 836 deopt_id)); | |
| 837 } | |
| 838 | |
| 839 | |
| 840 void DeoptInfoBuilder::AddPcMarker(const Function& function, | 778 void DeoptInfoBuilder::AddPcMarker(const Function& function, |
| 841 intptr_t to_index) { | 779 intptr_t to_index) { |
| 842 // Function object was already added by AddReturnAddress, find it. | 780 // Function object was already added by AddReturnAddress, find it. |
| 843 intptr_t from_index = FindOrAddObjectInTable(function); | 781 intptr_t from_index = FindOrAddObjectInTable(function); |
| 844 ASSERT(to_index == instructions_.length()); | 782 ASSERT(to_index == instructions_.length()); |
| 845 instructions_.Add(new DeoptPcMarkerInstr(from_index)); | 783 instructions_.Add(new DeoptPcMarkerInstr(from_index)); |
| 846 } | 784 } |
| 847 | 785 |
| 848 | 786 |
| 849 void DeoptInfoBuilder::AddCopy(const Location& from_loc, | 787 void DeoptInfoBuilder::AddCopy(const Location& from_loc, |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 Smi* offset, | 910 Smi* offset, |
| 973 DeoptInfo* info, | 911 DeoptInfo* info, |
| 974 Smi* reason) { | 912 Smi* reason) { |
| 975 intptr_t i = index * kEntrySize; | 913 intptr_t i = index * kEntrySize; |
| 976 *offset ^= table.At(i); | 914 *offset ^= table.At(i); |
| 977 *info ^= table.At(i + 1); | 915 *info ^= table.At(i + 1); |
| 978 *reason ^= table.At(i + 2); | 916 *reason ^= table.At(i + 2); |
| 979 } | 917 } |
| 980 | 918 |
| 981 } // namespace dart | 919 } // namespace dart |
| OLD | NEW |