1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "deoptimizer.h"
32 #include "full-codegen.h"
33 #include "safepoint-table.h"
38 const int Deoptimizer::table_entry_size_ = 12;
41 int Deoptimizer::patch_size() {
42 const int kCallInstructionSizeInWords = 3;
43 return kCallInstructionSizeInWords * Assembler::kInstrSize;
47 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
48 Address code_start_address = code->instruction_start();
49 // Invalidate the relocation information, as it will become invalid by the
50 // code patching below, and is not needed any more.
51 code->InvalidateRelocation();
53 if (FLAG_zap_code_space) {
54 // Fail hard and early if we enter this code object again.
55 byte* pointer = code->FindCodeAgeSequence();
56 if (pointer != NULL) {
57 pointer += kNoCodeAgeSequenceLength * Assembler::kInstrSize;
59 pointer = code->instruction_start();
61 CodePatcher patcher(pointer, 1);
62 patcher.masm()->bkpt(0);
64 DeoptimizationInputData* data =
65 DeoptimizationInputData::cast(code->deoptimization_data());
66 int osr_offset = data->OsrPcOffset()->value();
68 CodePatcher osr_patcher(code->instruction_start() + osr_offset, 1);
69 osr_patcher.masm()->bkpt(0);
73 DeoptimizationInputData* deopt_data =
74 DeoptimizationInputData::cast(code->deoptimization_data());
75 SharedFunctionInfo* shared =
76 SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
77 shared->EvictFromOptimizedCodeMap(code, "deoptimized code");
79 Address prev_call_address = NULL;
81 // For each LLazyBailout instruction insert a call to the corresponding
82 // deoptimization entry.
83 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
84 if (deopt_data->Pc(i)->value() == -1) continue;
85 Address call_address = code_start_address + deopt_data->Pc(i)->value();
86 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY);
87 // We need calls to have a predictable size in the unoptimized code, but
88 // this is optimized code, so we don't have to have a predictable size.
89 int call_size_in_bytes =
90 MacroAssembler::CallSizeNotPredictableCodeSize(deopt_entry,
92 int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
93 ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
94 ASSERT(call_size_in_bytes <= patch_size());
95 CodePatcher patcher(call_address, call_size_in_words);
96 patcher.masm()->Call(deopt_entry, RelocInfo::NONE32);
97 ASSERT(prev_call_address == NULL ||
98 call_address >= prev_call_address + patch_size());
99 ASSERT(call_address + patch_size() <= code->instruction_end());
101 prev_call_address = call_address;
107 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
108 // Set the register values. The values are not important as there are no
109 // callee saved registers in JavaScript frames, so all registers are
110 // spilled. Registers fp and sp are set to the correct values though.
112 for (int i = 0; i < Register::kNumRegisters; i++) {
113 input_->SetRegister(i, i * 4);
115 input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp()));
116 input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
117 for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
118 input_->SetDoubleRegister(i, 0.0);
121 // Fill the frame content from the actual data on the frame.
122 for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
123 input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
128 void Deoptimizer::SetPlatformCompiledStubRegisters(
129 FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) {
130 ApiFunction function(descriptor->deoptimization_handler_);
131 ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
132 intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
133 int params = descriptor->GetHandlerParameterCount();
134 output_frame->SetRegister(r0.code(), params);
135 output_frame->SetRegister(r1.code(), handler);
139 void Deoptimizer::CopySIMD128Registers(FrameDescription* output_frame) {
140 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
141 double double_value = input_->GetDoubleRegister(i);
142 output_frame->SetDoubleRegister(i, double_value);
147 bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
148 // There is no dynamic alignment padding on ARM in the input frame.
153 Code* Deoptimizer::NotifyStubFailureBuiltin() {
154 return isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles);
160 // This code tries to be close to ia32 code so that any changes can be
162 void Deoptimizer::EntryGenerator::Generate() {
165 // Save all general purpose registers before messing with them.
166 const int kNumberOfRegisters = Register::kNumRegisters;
168 // Everything but pc, lr and ip which will be saved but not restored.
169 RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit();
171 const int kDoubleRegsSize =
172 kDoubleSize * DwVfpRegister::kMaxNumAllocatableRegisters;
174 // Save all allocatable VFP registers before messing with them.
175 ASSERT(kDoubleRegZero.code() == 14);
176 ASSERT(kScratchDoubleReg.code() == 15);
178 // Check CPU flags for number of registers, setting the Z condition flag.
179 __ CheckFor32DRegs(ip);
181 // Push registers d0-d13, and possibly d16-d31, on the stack.
182 // If d16-d31 are not pushed, decrease the stack pointer instead.
183 __ vstm(db_w, sp, d16, d31, ne);
184 __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
185 __ vstm(db_w, sp, d0, d13);
187 // Push all 16 registers (needed to populate FrameDescription::registers_).
188 // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps
189 // handle this a bit differently.
190 __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
192 const int kSavedRegistersAreaSize =
193 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
195 // Get the bailout id from the stack.
196 __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize));
198 // Get the address of the location in the code object (r3) (return
199 // address for lazy deoptimization) and compute the fp-to-sp delta in
202 // Correct one word for bailout id.
203 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
206 // Allocate a new deoptimizer object.
207 // Pass four arguments in r0 to r3 and fifth argument on stack.
208 __ PrepareCallCFunction(6, r5);
209 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
210 __ mov(r1, Operand(type())); // bailout type,
211 // r2: bailout id already loaded.
212 // r3: code address or 0 already loaded.
213 __ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta.
214 __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
215 __ str(r5, MemOperand(sp, 1 * kPointerSize)); // Isolate.
216 // Call Deoptimizer::New().
218 AllowExternalCallThatCantCauseGC scope(masm());
219 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
222 // Preserve "deoptimizer" object in register r0 and get the input
223 // frame descriptor pointer to r1 (deoptimizer->input_);
224 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
226 // Copy core registers into FrameDescription::registers_[kNumRegisters].
227 ASSERT(Register::kNumRegisters == kNumberOfRegisters);
228 for (int i = 0; i < kNumberOfRegisters; i++) {
229 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
230 __ ldr(r2, MemOperand(sp, i * kPointerSize));
231 __ str(r2, MemOperand(r1, offset));
234 // Copy VFP registers to
235 // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
236 int double_regs_offset = FrameDescription::simd128_registers_offset();
237 for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
238 int dst_offset = i * kDoubleSize + double_regs_offset;
239 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
240 __ vldr(d0, sp, src_offset);
241 __ vstr(d0, r1, dst_offset);
244 // Remove the bailout id and the saved registers from the stack.
245 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
247 // Compute a pointer to the unwinding limit in register r2; that is
248 // the first stack slot not part of the input frame.
249 __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset()));
252 // Unwind the stack down to - but not including - the unwinding
253 // limit and copy the contents of the activation frame to the input
254 // frame description.
255 __ add(r3, r1, Operand(FrameDescription::frame_content_offset()));
257 Label pop_loop_header;
258 __ b(&pop_loop_header);
261 __ str(r4, MemOperand(r3, 0));
262 __ add(r3, r3, Operand(sizeof(uint32_t)));
263 __ bind(&pop_loop_header);
267 // Compute the output frame in the deoptimizer.
268 __ push(r0); // Preserve deoptimizer object across call.
269 // r0: deoptimizer object; r1: scratch.
270 __ PrepareCallCFunction(1, r1);
271 // Call Deoptimizer::ComputeOutputFrames().
273 AllowExternalCallThatCantCauseGC scope(masm());
275 ExternalReference::compute_output_frames_function(isolate()), 1);
277 __ pop(r0); // Restore deoptimizer object (class Deoptimizer).
279 // Replace the current (input) frame with the output frames.
280 Label outer_push_loop, inner_push_loop,
281 outer_loop_header, inner_loop_header;
282 // Outer loop state: r4 = current "FrameDescription** output_",
283 // r1 = one past the last FrameDescription**.
284 __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset()));
285 __ ldr(r4, MemOperand(r0, Deoptimizer::output_offset())); // r4 is output_.
286 __ add(r1, r4, Operand(r1, LSL, 2));
287 __ jmp(&outer_loop_header);
288 __ bind(&outer_push_loop);
289 // Inner loop state: r2 = current FrameDescription*, r3 = loop index.
290 __ ldr(r2, MemOperand(r4, 0)); // output_[ix]
291 __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset()));
292 __ jmp(&inner_loop_header);
293 __ bind(&inner_push_loop);
294 __ sub(r3, r3, Operand(sizeof(uint32_t)));
295 __ add(r6, r2, Operand(r3));
296 __ ldr(r6, MemOperand(r6, FrameDescription::frame_content_offset()));
298 __ bind(&inner_loop_header);
299 __ cmp(r3, Operand::Zero());
300 __ b(ne, &inner_push_loop); // test for gt?
301 __ add(r4, r4, Operand(kPointerSize));
302 __ bind(&outer_loop_header);
304 __ b(lt, &outer_push_loop);
306 // Check CPU flags for number of registers, setting the Z condition flag.
307 __ CheckFor32DRegs(ip);
309 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
310 int src_offset = FrameDescription::simd128_registers_offset();
311 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) {
312 if (i == kDoubleRegZero.code()) continue;
313 if (i == kScratchDoubleReg.code()) continue;
315 const DwVfpRegister reg = DwVfpRegister::from_code(i);
316 __ vldr(reg, r1, src_offset, i < 16 ? al : ne);
317 src_offset += kDoubleSize;
320 // Push state, pc, and continuation from the last output frame.
321 __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
323 __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset()));
325 __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset()));
328 // Push the registers from the last output frame.
329 for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
330 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
331 __ ldr(r6, MemOperand(r2, offset));
335 // Restore the registers from the stack.
336 __ ldm(ia_w, sp, restored_regs); // all but pc registers.
337 __ pop(ip); // remove sp
338 __ pop(ip); // remove lr
340 __ InitializeRootRegister();
342 __ pop(ip); // remove pc
343 __ pop(ip); // get continuation, leave pc on stack
346 __ stop("Unreachable.");
350 void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
351 // Create a sequence of deoptimization entries.
352 // Note that registers are still live when jumping to an entry.
354 for (int i = 0; i < count(); i++) {
355 int start = masm()->pc_offset();
357 __ mov(ip, Operand(i));
360 ASSERT(masm()->pc_offset() - start == table_entry_size_);
366 void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
367 SetFrameSlot(offset, value);
371 void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
372 SetFrameSlot(offset, value);
376 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
377 ASSERT(FLAG_enable_ool_constant_pool);
378 SetFrameSlot(offset, value);
382 double FrameDescription::GetDoubleRegister(unsigned n) const {
383 ASSERT(n < 2 * ARRAY_SIZE(simd128_registers_));
384 return simd128_registers_[n / 2].d[n % 2];
388 void FrameDescription::SetDoubleRegister(unsigned n, double value) {
389 ASSERT(n < 2 * ARRAY_SIZE(simd128_registers_));
390 simd128_registers_[n / 2].d[n % 2] = value;
396 } } // namespace v8::internal