blob: 9d70c3236b82fc72710e85a2c8db647e579766a8 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Ben Murdoch8c569c42011-03-10 11:43:29 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_X64
Ben Murdochb8e0da22011-05-16 14:20:40 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/codegen.h"
8#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/full-codegen/full-codegen.h"
10#include "src/register-configuration.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/safepoint-table.h"
Ben Murdoch8c569c42011-03-10 11:43:29 +000012
Ben Murdochb0fe1622011-05-05 13:52:32 +010013namespace v8 {
14namespace internal {
Ben Murdoch8c569c42011-03-10 11:43:29 +000015
Ben Murdochb0fe1622011-05-05 13:52:32 +010016
Ben Murdoch69a99ed2011-11-30 16:03:39 +000017const int Deoptimizer::table_entry_size_ = 10;
Ben Murdochb0fe1622011-05-05 13:52:32 +010018
Steve Block1e0659c2011-05-24 12:43:12 +010019
20int Deoptimizer::patch_size() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021 return Assembler::kCallSequenceLength;
Steve Block44f0eee2011-05-26 01:26:41 +010022}
23
24
Emily Bernierd0a1eb72015-03-24 16:35:39 -040025void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
26 // Empty because there is no need for relocation information for the code
27 // patching in Deoptimizer::PatchCodeForDeoptimization below.
28}
29
30
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
Steve Block1e0659c2011-05-24 12:43:12 +010032 // Invalidate the relocation information, as it will become invalid by the
33 // code patching below, and is not needed any more.
34 code->InvalidateRelocation();
35
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 if (FLAG_zap_code_space) {
37 // Fail hard and early if we enter this code object again.
38 byte* pointer = code->FindCodeAgeSequence();
39 if (pointer != NULL) {
40 pointer += kNoCodeAgeSequenceLength;
41 } else {
42 pointer = code->instruction_start();
43 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044 CodePatcher patcher(isolate, pointer, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000045 patcher.masm()->int3();
46
47 DeoptimizationInputData* data =
48 DeoptimizationInputData::cast(code->deoptimization_data());
49 int osr_offset = data->OsrPcOffset()->value();
50 if (osr_offset > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051 CodePatcher osr_patcher(isolate, code->instruction_start() + osr_offset,
52 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053 osr_patcher.masm()->int3();
54 }
55 }
56
Ben Murdoch2b4ba112012-01-20 14:57:15 +000057 // For each LLazyBailout instruction insert a absolute call to the
Steve Block1e0659c2011-05-24 12:43:12 +010058 // corresponding deoptimization entry, or a short call to an absolute
59 // jump if space is short. The absolute jumps are put in a table just
60 // before the safepoint table (space was allocated there when the Code
61 // object was created, if necessary).
62
Ben Murdochb8a8cc12014-11-26 15:28:44 +000063 Address instruction_start = code->instruction_start();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000064#ifdef DEBUG
Ben Murdoch2b4ba112012-01-20 14:57:15 +000065 Address prev_call_address = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000066#endif
Ben Murdoch2b4ba112012-01-20 14:57:15 +000067 DeoptimizationInputData* deopt_data =
68 DeoptimizationInputData::cast(code->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000069 deopt_data->SetSharedFunctionInfo(Smi::FromInt(0));
70 // For each LLazyBailout instruction insert a call to the corresponding
71 // deoptimization entry.
Ben Murdoch2b4ba112012-01-20 14:57:15 +000072 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
73 if (deopt_data->Pc(i)->value() == -1) continue;
Steve Block1e0659c2011-05-24 12:43:12 +010074 // Position where Call will be patched in.
Ben Murdoch2b4ba112012-01-20 14:57:15 +000075 Address call_address = instruction_start + deopt_data->Pc(i)->value();
76 // There is room enough to write a long call instruction because we pad
77 // LLazyBailout instructions with nops if necessary.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078 CodePatcher patcher(isolate, call_address, Assembler::kCallSequenceLength);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 patcher.masm()->Call(GetDeoptimizationEntry(isolate, i, LAZY),
80 Assembler::RelocInfoNone());
81 DCHECK(prev_call_address == NULL ||
Ben Murdoch2b4ba112012-01-20 14:57:15 +000082 call_address >= prev_call_address + patch_size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 DCHECK(call_address + patch_size() <= code->instruction_end());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000084#ifdef DEBUG
Ben Murdoch2b4ba112012-01-20 14:57:15 +000085 prev_call_address = call_address;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000086#endif
Steve Block1e0659c2011-05-24 12:43:12 +010087 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010088}
89
90
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091void Deoptimizer::SetPlatformCompiledStubRegisters(
92 FrameDescription* output_frame, CodeStubDescriptor* descriptor) {
93 intptr_t handler =
94 reinterpret_cast<intptr_t>(descriptor->deoptimization_handler());
95 int params = descriptor->GetHandlerParameterCount();
96 output_frame->SetRegister(rax.code(), params);
97 output_frame->SetRegister(rbx.code(), handler);
98}
99
100
101void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 for (int i = 0; i < XMMRegister::kMaxNumRegisters; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 double double_value = input_->GetDoubleRegister(i);
104 output_frame->SetDoubleRegister(i, double_value);
105 }
106}
107
Steve Block1e0659c2011-05-24 12:43:12 +0100108#define __ masm()->
109
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110void Deoptimizer::TableEntryGenerator::Generate() {
Steve Block1e0659c2011-05-24 12:43:12 +0100111 GeneratePrologue();
Steve Block1e0659c2011-05-24 12:43:12 +0100112
113 // Save all general purpose registers before messing with them.
114 const int kNumberOfRegisters = Register::kNumRegisters;
115
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000116 const int kDoubleRegsSize = kDoubleSize * XMMRegister::kMaxNumRegisters;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 __ subp(rsp, Immediate(kDoubleRegsSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 const RegisterConfiguration* config =
120 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
121 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
122 int code = config->GetAllocatableDoubleCode(i);
123 XMMRegister xmm_reg = XMMRegister::from_code(code);
124 int offset = code * kDoubleSize;
125 __ Movsd(Operand(rsp, offset), xmm_reg);
Steve Block1e0659c2011-05-24 12:43:12 +0100126 }
127
128 // We push all registers onto the stack, even though we do not need
129 // to restore all later.
130 for (int i = 0; i < kNumberOfRegisters; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000131 Register r = Register::from_code(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 __ pushq(r);
Steve Block1e0659c2011-05-24 12:43:12 +0100133 }
134
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 const int kSavedRegistersAreaSize = kNumberOfRegisters * kRegisterSize +
Steve Block1e0659c2011-05-24 12:43:12 +0100136 kDoubleRegsSize;
137
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 __ Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
139
Steve Block1e0659c2011-05-24 12:43:12 +0100140 // We use this to keep the value of the fifth argument temporarily.
141 // Unfortunately we can't store it directly in r8 (used for passing
142 // this on linux), since it is another parameter passing register on windows.
143 Register arg5 = r11;
144
145 // Get the bailout id from the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 __ movp(arg_reg_3, Operand(rsp, kSavedRegistersAreaSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100147
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 // Get the address of the location in the code object
Steve Block1e0659c2011-05-24 12:43:12 +0100149 // and compute the fp-to-sp delta in register arg5.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 __ movp(arg_reg_4, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize));
151 __ leap(arg5, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize +
152 kPCOnStackSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100153
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 __ subp(arg5, rbp);
155 __ negp(arg5);
Steve Block1e0659c2011-05-24 12:43:12 +0100156
157 // Allocate a new deoptimizer object.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100158 __ PrepareCallCFunction(6);
Ben Murdochda12d292016-06-02 14:46:10 +0100159 __ movp(rax, Immediate(0));
160 Label context_check;
161 __ movp(rdi, Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset));
162 __ JumpIfSmi(rdi, &context_check);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochda12d292016-06-02 14:46:10 +0100164 __ bind(&context_check);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 __ movp(arg_reg_1, rax);
166 __ Set(arg_reg_2, type());
Steve Block1e0659c2011-05-24 12:43:12 +0100167 // Args 3 and 4 are already in the right registers.
168
Ben Murdoch8b112d22011-06-08 16:22:53 +0100169 // On windows put the arguments on the stack (PrepareCallCFunction
170 // has created space for this). On linux pass the arguments in r8 and r9.
Steve Block1e0659c2011-05-24 12:43:12 +0100171#ifdef _WIN64
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172 __ movq(Operand(rsp, 4 * kRegisterSize), arg5);
173 __ LoadAddress(arg5, ExternalReference::isolate_address(isolate()));
174 __ movq(Operand(rsp, 5 * kRegisterSize), arg5);
Steve Block1e0659c2011-05-24 12:43:12 +0100175#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 __ movp(r8, arg5);
177 __ LoadAddress(r9, ExternalReference::isolate_address(isolate()));
Steve Block1e0659c2011-05-24 12:43:12 +0100178#endif
179
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 { AllowExternalCallThatCantCauseGC scope(masm());
181 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100182 }
Steve Block1e0659c2011-05-24 12:43:12 +0100183 // Preserve deoptimizer object in register rax and get the input
184 // frame descriptor pointer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 __ movp(rbx, Operand(rax, Deoptimizer::input_offset()));
Steve Block1e0659c2011-05-24 12:43:12 +0100186
187 // Fill in the input registers.
188 for (int i = kNumberOfRegisters -1; i >= 0; i--) {
189 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 __ PopQuad(Operand(rbx, offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100191 }
192
193 // Fill in the double input registers.
194 int double_regs_offset = FrameDescription::double_registers_offset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
Steve Block1e0659c2011-05-24 12:43:12 +0100196 int dst_offset = i * kDoubleSize + double_regs_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 __ popq(Operand(rbx, dst_offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100198 }
199
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 // Remove the bailout id and return address from the stack.
201 __ addp(rsp, Immediate(1 * kRegisterSize + kPCOnStackSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100202
203 // Compute a pointer to the unwinding limit in register rcx; that is
204 // the first stack slot not part of the input frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000205 __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
206 __ addp(rcx, rsp);
Steve Block1e0659c2011-05-24 12:43:12 +0100207
208 // Unwind the stack down to - but not including - the unwinding
209 // limit and copy the contents of the activation frame to the input
210 // frame description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 __ leap(rdx, Operand(rbx, FrameDescription::frame_content_offset()));
212 Label pop_loop_header;
213 __ jmp(&pop_loop_header);
Steve Block1e0659c2011-05-24 12:43:12 +0100214 Label pop_loop;
215 __ bind(&pop_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 __ Pop(Operand(rdx, 0));
217 __ addp(rdx, Immediate(sizeof(intptr_t)));
218 __ bind(&pop_loop_header);
219 __ cmpp(rcx, rsp);
Steve Block1e0659c2011-05-24 12:43:12 +0100220 __ j(not_equal, &pop_loop);
221
222 // Compute the output frame in the deoptimizer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 __ pushq(rax);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100224 __ PrepareCallCFunction(2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 __ movp(arg_reg_1, rax);
226 __ LoadAddress(arg_reg_2, ExternalReference::isolate_address(isolate()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100227 {
228 AllowExternalCallThatCantCauseGC scope(masm());
229 __ CallCFunction(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230 ExternalReference::compute_output_frames_function(isolate()), 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100231 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 __ popq(rax);
Steve Block1e0659c2011-05-24 12:43:12 +0100233
Ben Murdochda12d292016-06-02 14:46:10 +0100234 __ movp(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
235
236 // Replace the current (input) frame with the output frames.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 Label outer_push_loop, inner_push_loop,
238 outer_loop_header, inner_loop_header;
Steve Block1e0659c2011-05-24 12:43:12 +0100239 // Outer loop state: rax = current FrameDescription**, rdx = one past the
240 // last FrameDescription**.
241 __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 __ movp(rax, Operand(rax, Deoptimizer::output_offset()));
243 __ leap(rdx, Operand(rax, rdx, times_pointer_size, 0));
244 __ jmp(&outer_loop_header);
Steve Block1e0659c2011-05-24 12:43:12 +0100245 __ bind(&outer_push_loop);
246 // Inner loop state: rbx = current FrameDescription*, rcx = loop index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 __ movp(rbx, Operand(rax, 0));
248 __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
249 __ jmp(&inner_loop_header);
Steve Block1e0659c2011-05-24 12:43:12 +0100250 __ bind(&inner_push_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 __ subp(rcx, Immediate(sizeof(intptr_t)));
252 __ Push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset()));
253 __ bind(&inner_loop_header);
254 __ testp(rcx, rcx);
Steve Block1e0659c2011-05-24 12:43:12 +0100255 __ j(not_zero, &inner_push_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000256 __ addp(rax, Immediate(kPointerSize));
257 __ bind(&outer_loop_header);
258 __ cmpp(rax, rdx);
Steve Block1e0659c2011-05-24 12:43:12 +0100259 __ j(below, &outer_push_loop);
260
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
262 int code = config->GetAllocatableDoubleCode(i);
263 XMMRegister xmm_reg = XMMRegister::from_code(code);
264 int src_offset = code * kDoubleSize + double_regs_offset;
265 __ Movsd(xmm_reg, Operand(rbx, src_offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100266 }
267
268 // Push state, pc, and continuation from the last output frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 __ Push(Operand(rbx, FrameDescription::state_offset()));
270 __ PushQuad(Operand(rbx, FrameDescription::pc_offset()));
271 __ PushQuad(Operand(rbx, FrameDescription::continuation_offset()));
Steve Block1e0659c2011-05-24 12:43:12 +0100272
273 // Push the registers from the last output frame.
274 for (int i = 0; i < kNumberOfRegisters; i++) {
275 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276 __ PushQuad(Operand(rbx, offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100277 }
278
279 // Restore the registers from the stack.
280 for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000281 Register r = Register::from_code(i);
Steve Block1e0659c2011-05-24 12:43:12 +0100282 // Do not restore rsp, simply pop the value into the next register
283 // and overwrite this afterwards.
284 if (r.is(rsp)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 DCHECK(i > 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000286 r = Register::from_code(i - 1);
Steve Block1e0659c2011-05-24 12:43:12 +0100287 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 __ popq(r);
Steve Block1e0659c2011-05-24 12:43:12 +0100289 }
290
291 // Set up the roots register.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100292 __ InitializeRootRegister();
Steve Block1e0659c2011-05-24 12:43:12 +0100293
294 // Return to the continuation point.
295 __ ret(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100296}
297
298
299void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
Steve Block1e0659c2011-05-24 12:43:12 +0100300 // Create a sequence of deoptimization entries.
301 Label done;
302 for (int i = 0; i < count(); i++) {
303 int start = masm()->pc_offset();
304 USE(start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 __ pushq_imm32(i);
Steve Block1e0659c2011-05-24 12:43:12 +0100306 __ jmp(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 DCHECK(masm()->pc_offset() - start == table_entry_size_);
Steve Block1e0659c2011-05-24 12:43:12 +0100308 }
309 __ bind(&done);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100310}
311
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312
313void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
314 if (kPCOnStackSize == 2 * kPointerSize) {
315 // Zero out the high-32 bit of PC for x32 port.
316 SetFrameSlot(offset + kPointerSize, 0);
317 }
318 SetFrameSlot(offset, value);
319}
320
321
322void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
323 if (kFPOnStackSize == 2 * kPointerSize) {
324 // Zero out the high-32 bit of FP for x32 port.
325 SetFrameSlot(offset + kPointerSize, 0);
326 }
327 SetFrameSlot(offset, value);
328}
329
330
331void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 // No embedded constant pool support.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333 UNREACHABLE();
334}
335
336
Steve Block1e0659c2011-05-24 12:43:12 +0100337#undef __
338
339
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000340} // namespace internal
341} // namespace v8
Ben Murdochb8e0da22011-05-16 14:20:40 +0100342
343#endif // V8_TARGET_ARCH_X64