1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/compiler/x64/unwinding-info-writer-x64.h" 6 #include "src/compiler/instruction.h" 7 8 namespace v8 { 9 namespace internal { 10 namespace compiler { 11 12 void UnwindingInfoWriter::BeginInstructionBlock(int pc_offset, 13 const InstructionBlock* block) { 14 if (!enabled()) return; 15 16 block_will_exit_ = false; 17 18 DCHECK_LT(block->rpo_number().ToInt(), 19 static_cast<int>(block_initial_states_.size())); 20 const BlockInitialState* initial_state = 21 block_initial_states_[block->rpo_number().ToInt()]; 22 if (initial_state) { 23 if (!initial_state->register_.is(eh_frame_writer_.base_register()) && 24 initial_state->offset_ != eh_frame_writer_.base_offset()) { 25 eh_frame_writer_.AdvanceLocation(pc_offset); 26 eh_frame_writer_.SetBaseAddressRegisterAndOffset(initial_state->register_, 27 initial_state->offset_); 28 } else if (!initial_state->register_.is(eh_frame_writer_.base_register())) { 29 eh_frame_writer_.AdvanceLocation(pc_offset); 30 eh_frame_writer_.SetBaseAddressRegister(initial_state->register_); 31 } else if (initial_state->offset_ != eh_frame_writer_.base_offset()) { 32 eh_frame_writer_.AdvanceLocation(pc_offset); 33 eh_frame_writer_.SetBaseAddressOffset(initial_state->offset_); 34 } 35 36 tracking_fp_ = initial_state->tracking_fp_; 37 } else { 38 // The entry block always lacks an explicit initial state. 39 // The exit block may lack an explicit state, if it is only reached by 40 // the block ending in a ret. 41 // All the other blocks must have an explicit initial state. 42 DCHECK(block->predecessors().empty() || block->successors().empty()); 43 } 44 } 45 46 void UnwindingInfoWriter::EndInstructionBlock(const InstructionBlock* block) { 47 if (!enabled() || block_will_exit_) return; 48 49 for (const RpoNumber& successor : block->successors()) { 50 int successor_index = successor.ToInt(); 51 DCHECK_LT(successor_index, static_cast<int>(block_initial_states_.size())); 52 const BlockInitialState* existing_state = 53 block_initial_states_[successor_index]; 54 // If we already had an entry for this BB, check that the values are the 55 // same we are trying to insert. 56 if (existing_state) { 57 DCHECK(existing_state->register_.is(eh_frame_writer_.base_register())); 58 DCHECK_EQ(existing_state->offset_, eh_frame_writer_.base_offset()); 59 DCHECK_EQ(existing_state->tracking_fp_, tracking_fp_); 60 } else { 61 block_initial_states_[successor_index] = new (zone_) 62 BlockInitialState(eh_frame_writer_.base_register(), 63 eh_frame_writer_.base_offset(), tracking_fp_); 64 } 65 } 66 } 67 68 void UnwindingInfoWriter::MarkFrameConstructed(int pc_base) { 69 if (!enabled()) return; 70 71 // push rbp 72 eh_frame_writer_.AdvanceLocation(pc_base + 1); 73 eh_frame_writer_.IncreaseBaseAddressOffset(kInt64Size); 74 // <base address> points at the bottom of the current frame on x64 and 75 // <base register> is rsp, which points to the top of the frame by definition. 76 // Thus, the distance between <base address> and the top is -<base offset>. 77 int top_of_stack = -eh_frame_writer_.base_offset(); 78 eh_frame_writer_.RecordRegisterSavedToStack(rbp, top_of_stack); 79 80 // mov rbp, rsp 81 eh_frame_writer_.AdvanceLocation(pc_base + 4); 82 eh_frame_writer_.SetBaseAddressRegister(rbp); 83 84 tracking_fp_ = true; 85 } 86 87 void UnwindingInfoWriter::MarkFrameDeconstructed(int pc_base) { 88 if (!enabled()) return; 89 90 // mov rsp, rbp 91 eh_frame_writer_.AdvanceLocation(pc_base + 3); 92 eh_frame_writer_.SetBaseAddressRegister(rsp); 93 94 // pop rbp 95 eh_frame_writer_.AdvanceLocation(pc_base + 4); 96 eh_frame_writer_.IncreaseBaseAddressOffset(-kInt64Size); 97 98 tracking_fp_ = false; 99 } 100 101 } // namespace compiler 102 } // namespace internal 103 } // namespace v8 104