V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
deoptimizer-s390.cc
1 // Copyright 2014 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/assembler-inl.h"
6 #include "src/deoptimizer.h"
7 #include "src/register-configuration.h"
8 #include "src/safepoint-table.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 // LAY + LGHI/LHI + BRCL
14 const int Deoptimizer::table_entry_size_ = 16;
15 
16 #define __ masm()->
17 
18 // This code tries to be close to ia32 code so that any changes can be
19 // easily ported.
20 void Deoptimizer::TableEntryGenerator::Generate() {
21  GeneratePrologue();
22 
23  // Save all the registers onto the stack
24  const int kNumberOfRegisters = Register::kNumRegisters;
25 
26  RegList restored_regs = kJSCallerSaved | kCalleeSaved;
27 
28  const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
29  const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
30 
31  // Save all double registers before messing with them.
32  __ lay(sp, MemOperand(sp, -kDoubleRegsSize));
33  const RegisterConfiguration* config = RegisterConfiguration::Default();
34  for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
35  int code = config->GetAllocatableDoubleCode(i);
36  const DoubleRegister dreg = DoubleRegister::from_code(code);
37  int offset = code * kDoubleSize;
38  __ StoreDouble(dreg, MemOperand(sp, offset));
39  }
40  // Save all float registers before messing with them.
41  __ lay(sp, MemOperand(sp, -kFloatRegsSize));
42  for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
43  int code = config->GetAllocatableFloatCode(i);
44  const FloatRegister dreg = FloatRegister::from_code(code);
45  int offset = code * kFloatSize;
46  __ StoreFloat32(dreg, MemOperand(sp, offset));
47  }
48 
49  // Push all GPRs onto the stack
50  __ lay(sp, MemOperand(sp, -kNumberOfRegisters * kPointerSize));
51  __ StoreMultipleP(r0, sp, MemOperand(sp)); // Save all 16 registers
52 
53  __ mov(ip, Operand(ExternalReference::Create(
54  IsolateAddressId::kCEntryFPAddress, isolate())));
55  __ StoreP(fp, MemOperand(ip));
56 
57  const int kSavedRegistersAreaSize =
58  (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
59 
60  // Get the bailout id from the stack.
61  __ LoadP(r4, MemOperand(sp, kSavedRegistersAreaSize));
62 
63  // Cleanse the Return address for 31-bit
64  __ CleanseP(r14);
65 
66  // Get the address of the location in the code object (r5)(return
67  // address for lazy deoptimization) and compute the fp-to-sp delta in
68  // register r6.
69  __ LoadRR(r5, r14);
70  __ la(r6, MemOperand(sp, kSavedRegistersAreaSize + (1 * kPointerSize)));
71  __ SubP(r6, fp, r6);
72 
73  // Allocate a new deoptimizer object.
74  // Pass six arguments in r2 to r7.
75  __ PrepareCallCFunction(6, r7);
76  __ LoadImmP(r2, Operand::Zero());
77  Label context_check;
78  __ LoadP(r3, MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset));
79  __ JumpIfSmi(r3, &context_check);
80  __ LoadP(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
81  __ bind(&context_check);
82  __ LoadImmP(r3, Operand(static_cast<int>(deopt_kind())));
83  // r4: bailout id already loaded.
84  // r5: code address or 0 already loaded.
85  // r6: Fp-to-sp delta.
86  // Parm6: isolate is passed on the stack.
87  __ mov(r7, Operand(ExternalReference::isolate_address(isolate())));
88  __ StoreP(r7, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
89 
90  // Call Deoptimizer::New().
91  {
92  AllowExternalCallThatCantCauseGC scope(masm());
93  __ CallCFunction(ExternalReference::new_deoptimizer_function(), 6);
94  }
95 
96  // Preserve "deoptimizer" object in register r2 and get the input
97  // frame descriptor pointer to r3 (deoptimizer->input_);
98  __ LoadP(r3, MemOperand(r2, Deoptimizer::input_offset()));
99 
100  // Copy core registers into FrameDescription::registers_[kNumRegisters].
101  // DCHECK_EQ(Register::kNumRegisters, kNumberOfRegisters);
102  // __ mvc(MemOperand(r3, FrameDescription::registers_offset()),
103  // MemOperand(sp), kNumberOfRegisters * kPointerSize);
104  // Copy core registers into FrameDescription::registers_[kNumRegisters].
105  // TODO(john.yan): optimize the following code by using mvc instruction
106  DCHECK_EQ(Register::kNumRegisters, kNumberOfRegisters);
107  for (int i = 0; i < kNumberOfRegisters; i++) {
108  int offset = (i * kPointerSize) + FrameDescription::registers_offset();
109  __ LoadP(r4, MemOperand(sp, i * kPointerSize));
110  __ StoreP(r4, MemOperand(r3, offset));
111  }
112 
113  int double_regs_offset = FrameDescription::double_registers_offset();
114  // Copy double registers to
115  // double_registers_[DoubleRegister::kNumRegisters]
116  for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
117  int code = config->GetAllocatableDoubleCode(i);
118  int dst_offset = code * kDoubleSize + double_regs_offset;
119  int src_offset =
120  code * kDoubleSize + kNumberOfRegisters * kPointerSize + kFloatRegsSize;
121  // TODO(joransiu): MVC opportunity
122  __ LoadDouble(d0, MemOperand(sp, src_offset));
123  __ StoreDouble(d0, MemOperand(r3, dst_offset));
124  }
125 
126  int float_regs_offset = FrameDescription::float_registers_offset();
127  // Copy float registers to
128  // float_registers_[FloatRegister::kNumRegisters]
129  for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
130  int code = config->GetAllocatableFloatCode(i);
131  int dst_offset = code * kFloatSize + float_regs_offset;
132  int src_offset = code * kFloatSize + kNumberOfRegisters * kPointerSize;
133  // TODO(joransiu): MVC opportunity
134  __ LoadFloat32(d0, MemOperand(sp, src_offset));
135  __ StoreFloat32(d0, MemOperand(r3, dst_offset));
136  }
137  // Remove the bailout id and the saved registers from the stack.
138  __ la(sp, MemOperand(sp, kSavedRegistersAreaSize + (1 * kPointerSize)));
139 
140  // Compute a pointer to the unwinding limit in register r4; that is
141  // the first stack slot not part of the input frame.
142  __ LoadP(r4, MemOperand(r3, FrameDescription::frame_size_offset()));
143  __ AddP(r4, sp);
144 
145  // Unwind the stack down to - but not including - the unwinding
146  // limit and copy the contents of the activation frame to the input
147  // frame description.
148  __ la(r5, MemOperand(r3, FrameDescription::frame_content_offset()));
149  Label pop_loop;
150  Label pop_loop_header;
151  __ b(&pop_loop_header, Label::kNear);
152  __ bind(&pop_loop);
153  __ pop(r6);
154  __ StoreP(r6, MemOperand(r5, 0));
155  __ la(r5, MemOperand(r5, kPointerSize));
156  __ bind(&pop_loop_header);
157  __ CmpP(r4, sp);
158  __ bne(&pop_loop);
159 
160  // Compute the output frame in the deoptimizer.
161  __ push(r2); // Preserve deoptimizer object across call.
162  // r2: deoptimizer object; r3: scratch.
163  __ PrepareCallCFunction(1, r3);
164  // Call Deoptimizer::ComputeOutputFrames().
165  {
166  AllowExternalCallThatCantCauseGC scope(masm());
167  __ CallCFunction(ExternalReference::compute_output_frames_function(), 1);
168  }
169  __ pop(r2); // Restore deoptimizer object (class Deoptimizer).
170 
171  __ LoadP(sp, MemOperand(r2, Deoptimizer::caller_frame_top_offset()));
172 
173  // Replace the current (input) frame with the output frames.
174  Label outer_push_loop, inner_push_loop, outer_loop_header, inner_loop_header;
175  // Outer loop state: r6 = current "FrameDescription** output_",
176  // r3 = one past the last FrameDescription**.
177  __ LoadlW(r3, MemOperand(r2, Deoptimizer::output_count_offset()));
178  __ LoadP(r6, MemOperand(r2, Deoptimizer::output_offset())); // r6 is output_.
179  __ ShiftLeftP(r3, r3, Operand(kPointerSizeLog2));
180  __ AddP(r3, r6, r3);
181  __ b(&outer_loop_header, Label::kNear);
182 
183  __ bind(&outer_push_loop);
184  // Inner loop state: r4 = current FrameDescription*, r5 = loop index.
185  __ LoadP(r4, MemOperand(r6, 0)); // output_[ix]
186  __ LoadP(r5, MemOperand(r4, FrameDescription::frame_size_offset()));
187  __ b(&inner_loop_header, Label::kNear);
188 
189  __ bind(&inner_push_loop);
190  __ AddP(r5, Operand(-sizeof(intptr_t)));
191  __ AddP(r8, r4, r5);
192  __ LoadP(r8, MemOperand(r8, FrameDescription::frame_content_offset()));
193  __ push(r8);
194 
195  __ bind(&inner_loop_header);
196  __ CmpP(r5, Operand::Zero());
197  __ bne(&inner_push_loop); // test for gt?
198 
199  __ AddP(r6, r6, Operand(kPointerSize));
200  __ bind(&outer_loop_header);
201  __ CmpP(r6, r3);
202  __ blt(&outer_push_loop);
203 
204  __ LoadP(r3, MemOperand(r2, Deoptimizer::input_offset()));
205  for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
206  int code = config->GetAllocatableDoubleCode(i);
207  const DoubleRegister dreg = DoubleRegister::from_code(code);
208  int src_offset = code * kDoubleSize + double_regs_offset;
209  __ ld(dreg, MemOperand(r3, src_offset));
210  }
211 
212  // Push pc and continuation from the last output frame.
213  __ LoadP(r8, MemOperand(r4, FrameDescription::pc_offset()));
214  __ push(r8);
215  __ LoadP(r8, MemOperand(r4, FrameDescription::continuation_offset()));
216  __ push(r8);
217 
218  // Restore the registers from the last output frame.
219  __ LoadRR(r1, r4);
220  for (int i = kNumberOfRegisters - 1; i > 0; i--) {
221  int offset = (i * kPointerSize) + FrameDescription::registers_offset();
222  if ((restored_regs & (1 << i)) != 0) {
223  __ LoadP(ToRegister(i), MemOperand(r1, offset));
224  }
225  }
226 
227  __ pop(ip); // get continuation, leave pc on stack
228  __ pop(r14);
229  __ Jump(ip);
230  __ stop("Unreachable.");
231 }
232 
233 void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
234  // Create a sequence of deoptimization entries. Note that any
235  // registers may be still live.
236  Label done;
237  for (int i = 0; i < count(); i++) {
238  int start = masm()->pc_offset();
239  USE(start);
240  __ lay(sp, MemOperand(sp, -kPointerSize));
241  __ LoadImmP(ip, Operand(i));
242  __ b(&done);
243  int end = masm()->pc_offset();
244  USE(end);
245  DCHECK(masm()->pc_offset() - start == table_entry_size_);
246  }
247  __ bind(&done);
248  __ StoreP(ip, MemOperand(sp));
249 }
250 
251 bool Deoptimizer::PadTopOfStackRegister() { return false; }
252 
253 void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
254  SetFrameSlot(offset, value);
255 }
256 
257 void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
258  SetFrameSlot(offset, value);
259 }
260 
261 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
262  // No out-of-line constant pool support.
263  UNREACHABLE();
264 }
265 
266 #undef __
267 
268 } // namespace internal
269 } // namespace v8
Definition: libplatform.h:13