• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &register_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