1 // Copyright 2021 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 #ifndef V8_DEOPTIMIZER_FRAME_DESCRIPTION_H_ 6 #define V8_DEOPTIMIZER_FRAME_DESCRIPTION_H_ 7 8 #include "src/codegen/register.h" 9 #include "src/execution/frame-constants.h" 10 #include "src/utils/boxed-float.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // Classes in this file describe the physical stack frame state. 16 // 17 // RegisterValues: stores gp and fp register values. Can be filled in either by 18 // the DeoptimizationEntry builtin (which fills in the input state of the 19 // optimized frame); or by the FrameWriter (fills in the output state of the 20 // interpreted frame). 21 // 22 // - FrameDescription: contains RegisterValues and other things. 23 24 class RegisterValues { 25 public: GetRegister(unsigned n)26 intptr_t GetRegister(unsigned n) const { 27 #if DEBUG 28 // This convoluted DCHECK is needed to work around a gcc problem that 29 // improperly detects an array bounds overflow in optimized debug builds 30 // when using a plain DCHECK. 31 if (n >= arraysize(registers_)) { 32 DCHECK(false); 33 return 0; 34 } 35 #endif 36 return registers_[n]; 37 } 38 39 Float32 GetFloatRegister(unsigned n) const; 40 GetDoubleRegister(unsigned n)41 Float64 GetDoubleRegister(unsigned n) const { 42 DCHECK(n < arraysize(double_registers_)); 43 return double_registers_[n]; 44 } 45 SetRegister(unsigned n,intptr_t value)46 void SetRegister(unsigned n, intptr_t value) { 47 DCHECK(n < arraysize(registers_)); 48 registers_[n] = value; 49 } 50 51 intptr_t registers_[Register::kNumRegisters]; 52 // Generated code writes directly into the following array, make sure the 53 // element size matches what the machine instructions expect. 54 static_assert(sizeof(Float64) == kDoubleSize, "size mismatch"); 55 Float64 double_registers_[DoubleRegister::kNumRegisters]; 56 }; 57 58 class FrameDescription { 59 public: FrameDescription(uint32_t frame_size,int parameter_count)60 FrameDescription(uint32_t frame_size, int parameter_count) 61 : frame_size_(frame_size), 62 parameter_count_(parameter_count), 63 top_(kZapUint32), 64 pc_(kZapUint32), 65 fp_(kZapUint32), 66 context_(kZapUint32), 67 constant_pool_(kZapUint32) { 68 // Zap all the registers. 69 for (int r = 0; r < Register::kNumRegisters; r++) { 70 // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register 71 // isn't used before the next safepoint, the GC will try to scan it as a 72 // tagged value. kZapUint32 looks like a valid tagged pointer, but it 73 // isn't. 74 #if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_ARM64) 75 // x18 is reserved as platform register on Windows arm64 platform 76 const int kPlatformRegister = 18; 77 if (r != kPlatformRegister) { 78 SetRegister(r, kZapUint32); 79 } 80 #else 81 SetRegister(r, kZapUint32); 82 #endif 83 } 84 85 // Zap all the slots. 86 for (unsigned o = 0; o < frame_size; o += kSystemPointerSize) { 87 SetFrameSlot(o, kZapUint32); 88 } 89 } 90 new(size_t size,uint32_t frame_size)91 void* operator new(size_t size, uint32_t frame_size) { 92 // Subtracts kSystemPointerSize, as the member frame_content_ already 93 // supplies the first element of the area to store the frame. 94 return base::Malloc(size + frame_size - kSystemPointerSize); 95 } 96 delete(void * pointer,uint32_t frame_size)97 void operator delete(void* pointer, uint32_t frame_size) { 98 base::Free(pointer); 99 } 100 delete(void * description)101 void operator delete(void* description) { base::Free(description); } 102 GetFrameSize()103 uint32_t GetFrameSize() const { 104 USE(frame_content_); 105 DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_); 106 return static_cast<uint32_t>(frame_size_); 107 } 108 GetFrameSlot(unsigned offset)109 intptr_t GetFrameSlot(unsigned offset) { 110 return *GetFrameSlotPointer(offset); 111 } 112 113 unsigned GetLastArgumentSlotOffset(bool pad_arguments = true) { 114 int parameter_slots = parameter_count(); 115 if (pad_arguments) { 116 parameter_slots = AddArgumentPaddingSlots(parameter_slots); 117 } 118 return GetFrameSize() - parameter_slots * kSystemPointerSize; 119 } 120 GetFramePointerAddress()121 Address GetFramePointerAddress() { 122 // We should not pad arguments in the bottom frame, since this 123 // already contain a padding if necessary and it might contain 124 // extra arguments (actual argument count > parameter count). 125 const bool pad_arguments_bottom_frame = false; 126 int fp_offset = GetLastArgumentSlotOffset(pad_arguments_bottom_frame) - 127 StandardFrameConstants::kCallerSPOffset; 128 return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset)); 129 } 130 GetRegisterValues()131 RegisterValues* GetRegisterValues() { return ®ister_values_; } 132 SetFrameSlot(unsigned offset,intptr_t value)133 void SetFrameSlot(unsigned offset, intptr_t value) { 134 *GetFrameSlotPointer(offset) = value; 135 } 136 137 void SetCallerPc(unsigned offset, intptr_t value); 138 139 void SetCallerFp(unsigned offset, intptr_t value); 140 141 void SetCallerConstantPool(unsigned offset, intptr_t value); 142 GetRegister(unsigned n)143 intptr_t GetRegister(unsigned n) const { 144 return register_values_.GetRegister(n); 145 } 146 GetDoubleRegister(unsigned n)147 Float64 GetDoubleRegister(unsigned n) const { 148 return register_values_.GetDoubleRegister(n); 149 } 150 SetRegister(unsigned n,intptr_t value)151 void SetRegister(unsigned n, intptr_t value) { 152 register_values_.SetRegister(n, value); 153 } 154 GetTop()155 intptr_t GetTop() const { return top_; } SetTop(intptr_t top)156 void SetTop(intptr_t top) { top_ = top; } 157 GetPc()158 intptr_t GetPc() const { return pc_; } 159 void SetPc(intptr_t pc); 160 GetFp()161 intptr_t GetFp() const { return fp_; } SetFp(intptr_t fp)162 void SetFp(intptr_t fp) { fp_ = fp; } 163 GetContext()164 intptr_t GetContext() const { return context_; } SetContext(intptr_t context)165 void SetContext(intptr_t context) { context_ = context; } 166 GetConstantPool()167 intptr_t GetConstantPool() const { return constant_pool_; } SetConstantPool(intptr_t constant_pool)168 void SetConstantPool(intptr_t constant_pool) { 169 constant_pool_ = constant_pool; 170 } 171 SetContinuation(intptr_t pc)172 void SetContinuation(intptr_t pc) { continuation_ = pc; } 173 174 // Argument count, including receiver. parameter_count()175 int parameter_count() { return parameter_count_; } 176 registers_offset()177 static int registers_offset() { 178 return offsetof(FrameDescription, register_values_.registers_); 179 } 180 double_registers_offset()181 static constexpr int double_registers_offset() { 182 return offsetof(FrameDescription, register_values_.double_registers_); 183 } 184 frame_size_offset()185 static int frame_size_offset() { 186 return offsetof(FrameDescription, frame_size_); 187 } 188 pc_offset()189 static int pc_offset() { return offsetof(FrameDescription, pc_); } 190 continuation_offset()191 static int continuation_offset() { 192 return offsetof(FrameDescription, continuation_); 193 } 194 frame_content_offset()195 static int frame_content_offset() { 196 return offsetof(FrameDescription, frame_content_); 197 } 198 199 private: 200 static const uint32_t kZapUint32 = 0xbeeddead; 201 202 // Frame_size_ must hold a uint32_t value. It is only a uintptr_t to 203 // keep the variable-size array frame_content_ of type intptr_t at 204 // the end of the structure aligned. 205 uintptr_t frame_size_; // Number of bytes. 206 int parameter_count_; 207 RegisterValues register_values_; 208 intptr_t top_; 209 intptr_t pc_; 210 intptr_t fp_; 211 intptr_t context_; 212 intptr_t constant_pool_; 213 214 // Continuation is the PC where the execution continues after 215 // deoptimizing. 216 intptr_t continuation_; 217 218 // This must be at the end of the object as the object is allocated larger 219 // than its definition indicates to extend this array. 220 intptr_t frame_content_[1]; 221 GetFrameSlotPointer(unsigned offset)222 intptr_t* GetFrameSlotPointer(unsigned offset) { 223 DCHECK(offset < frame_size_); 224 return reinterpret_cast<intptr_t*>(reinterpret_cast<Address>(this) + 225 frame_content_offset() + offset); 226 } 227 }; 228 229 } // namespace internal 230 } // namespace v8 231 232 #endif // V8_DEOPTIMIZER_FRAME_DESCRIPTION_H_ 233