blob: 35da7a2c00c6030f1c71f6813afb34c205a38a06 [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 Murdoch61f157c2016-09-16 13:49:30 +0100119 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
121 int code = config->GetAllocatableDoubleCode(i);
122 XMMRegister xmm_reg = XMMRegister::from_code(code);
123 int offset = code * kDoubleSize;
124 __ Movsd(Operand(rsp, offset), xmm_reg);
Steve Block1e0659c2011-05-24 12:43:12 +0100125 }
126
127 // We push all registers onto the stack, even though we do not need
128 // to restore all later.
129 for (int i = 0; i < kNumberOfRegisters; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000130 Register r = Register::from_code(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 __ pushq(r);
Steve Block1e0659c2011-05-24 12:43:12 +0100132 }
133
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 const int kSavedRegistersAreaSize = kNumberOfRegisters * kRegisterSize +
Steve Block1e0659c2011-05-24 12:43:12 +0100135 kDoubleRegsSize;
136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 __ Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
138
Steve Block1e0659c2011-05-24 12:43:12 +0100139 // We use this to keep the value of the fifth argument temporarily.
140 // Unfortunately we can't store it directly in r8 (used for passing
141 // this on linux), since it is another parameter passing register on windows.
142 Register arg5 = r11;
143
144 // Get the bailout id from the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 __ movp(arg_reg_3, Operand(rsp, kSavedRegistersAreaSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100146
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 // Get the address of the location in the code object
Steve Block1e0659c2011-05-24 12:43:12 +0100148 // and compute the fp-to-sp delta in register arg5.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149 __ movp(arg_reg_4, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize));
150 __ leap(arg5, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize +
151 kPCOnStackSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100152
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000153 __ subp(arg5, rbp);
154 __ negp(arg5);
Steve Block1e0659c2011-05-24 12:43:12 +0100155
156 // Allocate a new deoptimizer object.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100157 __ PrepareCallCFunction(6);
Ben Murdochda12d292016-06-02 14:46:10 +0100158 __ movp(rax, Immediate(0));
159 Label context_check;
160 __ movp(rdi, Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset));
161 __ JumpIfSmi(rdi, &context_check);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000162 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochda12d292016-06-02 14:46:10 +0100163 __ bind(&context_check);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 __ movp(arg_reg_1, rax);
165 __ Set(arg_reg_2, type());
Steve Block1e0659c2011-05-24 12:43:12 +0100166 // Args 3 and 4 are already in the right registers.
167
Ben Murdoch8b112d22011-06-08 16:22:53 +0100168 // On windows put the arguments on the stack (PrepareCallCFunction
169 // has created space for this). On linux pass the arguments in r8 and r9.
Steve Block1e0659c2011-05-24 12:43:12 +0100170#ifdef _WIN64
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 __ movq(Operand(rsp, 4 * kRegisterSize), arg5);
172 __ LoadAddress(arg5, ExternalReference::isolate_address(isolate()));
173 __ movq(Operand(rsp, 5 * kRegisterSize), arg5);
Steve Block1e0659c2011-05-24 12:43:12 +0100174#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000175 __ movp(r8, arg5);
176 __ LoadAddress(r9, ExternalReference::isolate_address(isolate()));
Steve Block1e0659c2011-05-24 12:43:12 +0100177#endif
178
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 { AllowExternalCallThatCantCauseGC scope(masm());
180 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100181 }
Steve Block1e0659c2011-05-24 12:43:12 +0100182 // Preserve deoptimizer object in register rax and get the input
183 // frame descriptor pointer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 __ movp(rbx, Operand(rax, Deoptimizer::input_offset()));
Steve Block1e0659c2011-05-24 12:43:12 +0100185
186 // Fill in the input registers.
187 for (int i = kNumberOfRegisters -1; i >= 0; i--) {
188 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 __ PopQuad(Operand(rbx, offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100190 }
191
192 // Fill in the double input registers.
193 int double_regs_offset = FrameDescription::double_registers_offset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
Steve Block1e0659c2011-05-24 12:43:12 +0100195 int dst_offset = i * kDoubleSize + double_regs_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 __ popq(Operand(rbx, dst_offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100197 }
198
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 // Remove the bailout id and return address from the stack.
200 __ addp(rsp, Immediate(1 * kRegisterSize + kPCOnStackSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100201
202 // Compute a pointer to the unwinding limit in register rcx; that is
203 // the first stack slot not part of the input frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
205 __ addp(rcx, rsp);
Steve Block1e0659c2011-05-24 12:43:12 +0100206
207 // Unwind the stack down to - but not including - the unwinding
208 // limit and copy the contents of the activation frame to the input
209 // frame description.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 __ leap(rdx, Operand(rbx, FrameDescription::frame_content_offset()));
211 Label pop_loop_header;
212 __ jmp(&pop_loop_header);
Steve Block1e0659c2011-05-24 12:43:12 +0100213 Label pop_loop;
214 __ bind(&pop_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 __ Pop(Operand(rdx, 0));
216 __ addp(rdx, Immediate(sizeof(intptr_t)));
217 __ bind(&pop_loop_header);
218 __ cmpp(rcx, rsp);
Steve Block1e0659c2011-05-24 12:43:12 +0100219 __ j(not_equal, &pop_loop);
220
221 // Compute the output frame in the deoptimizer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 __ pushq(rax);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100223 __ PrepareCallCFunction(2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 __ movp(arg_reg_1, rax);
225 __ LoadAddress(arg_reg_2, ExternalReference::isolate_address(isolate()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100226 {
227 AllowExternalCallThatCantCauseGC scope(masm());
228 __ CallCFunction(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229 ExternalReference::compute_output_frames_function(isolate()), 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 __ popq(rax);
Steve Block1e0659c2011-05-24 12:43:12 +0100232
Ben Murdochda12d292016-06-02 14:46:10 +0100233 __ movp(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
234
235 // Replace the current (input) frame with the output frames.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 Label outer_push_loop, inner_push_loop,
237 outer_loop_header, inner_loop_header;
Steve Block1e0659c2011-05-24 12:43:12 +0100238 // Outer loop state: rax = current FrameDescription**, rdx = one past the
239 // last FrameDescription**.
240 __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241 __ movp(rax, Operand(rax, Deoptimizer::output_offset()));
242 __ leap(rdx, Operand(rax, rdx, times_pointer_size, 0));
243 __ jmp(&outer_loop_header);
Steve Block1e0659c2011-05-24 12:43:12 +0100244 __ bind(&outer_push_loop);
245 // Inner loop state: rbx = current FrameDescription*, rcx = loop index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 __ movp(rbx, Operand(rax, 0));
247 __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
248 __ jmp(&inner_loop_header);
Steve Block1e0659c2011-05-24 12:43:12 +0100249 __ bind(&inner_push_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 __ subp(rcx, Immediate(sizeof(intptr_t)));
251 __ Push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset()));
252 __ bind(&inner_loop_header);
253 __ testp(rcx, rcx);
Steve Block1e0659c2011-05-24 12:43:12 +0100254 __ j(not_zero, &inner_push_loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 __ addp(rax, Immediate(kPointerSize));
256 __ bind(&outer_loop_header);
257 __ cmpp(rax, rdx);
Steve Block1e0659c2011-05-24 12:43:12 +0100258 __ j(below, &outer_push_loop);
259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
261 int code = config->GetAllocatableDoubleCode(i);
262 XMMRegister xmm_reg = XMMRegister::from_code(code);
263 int src_offset = code * kDoubleSize + double_regs_offset;
264 __ Movsd(xmm_reg, Operand(rbx, src_offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100265 }
266
267 // Push state, pc, and continuation from the last output frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268 __ Push(Operand(rbx, FrameDescription::state_offset()));
269 __ PushQuad(Operand(rbx, FrameDescription::pc_offset()));
270 __ PushQuad(Operand(rbx, FrameDescription::continuation_offset()));
Steve Block1e0659c2011-05-24 12:43:12 +0100271
272 // Push the registers from the last output frame.
273 for (int i = 0; i < kNumberOfRegisters; i++) {
274 int offset = (i * kPointerSize) + FrameDescription::registers_offset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275 __ PushQuad(Operand(rbx, offset));
Steve Block1e0659c2011-05-24 12:43:12 +0100276 }
277
278 // Restore the registers from the stack.
279 for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000280 Register r = Register::from_code(i);
Steve Block1e0659c2011-05-24 12:43:12 +0100281 // Do not restore rsp, simply pop the value into the next register
282 // and overwrite this afterwards.
283 if (r.is(rsp)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284 DCHECK(i > 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000285 r = Register::from_code(i - 1);
Steve Block1e0659c2011-05-24 12:43:12 +0100286 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 __ popq(r);
Steve Block1e0659c2011-05-24 12:43:12 +0100288 }
289
290 // Set up the roots register.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100291 __ InitializeRootRegister();
Steve Block1e0659c2011-05-24 12:43:12 +0100292
293 // Return to the continuation point.
294 __ ret(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100295}
296
297
298void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
Steve Block1e0659c2011-05-24 12:43:12 +0100299 // Create a sequence of deoptimization entries.
300 Label done;
301 for (int i = 0; i < count(); i++) {
302 int start = masm()->pc_offset();
303 USE(start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 __ pushq_imm32(i);
Steve Block1e0659c2011-05-24 12:43:12 +0100305 __ jmp(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 DCHECK(masm()->pc_offset() - start == table_entry_size_);
Steve Block1e0659c2011-05-24 12:43:12 +0100307 }
308 __ bind(&done);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309}
310
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311
312void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
313 if (kPCOnStackSize == 2 * kPointerSize) {
314 // Zero out the high-32 bit of PC for x32 port.
315 SetFrameSlot(offset + kPointerSize, 0);
316 }
317 SetFrameSlot(offset, value);
318}
319
320
321void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
322 if (kFPOnStackSize == 2 * kPointerSize) {
323 // Zero out the high-32 bit of FP for x32 port.
324 SetFrameSlot(offset + kPointerSize, 0);
325 }
326 SetFrameSlot(offset, value);
327}
328
329
330void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 // No embedded constant pool support.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 UNREACHABLE();
333}
334
335
Steve Block1e0659c2011-05-24 12:43:12 +0100336#undef __
337
338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339} // namespace internal
340} // namespace v8
Ben Murdochb8e0da22011-05-16 14:20:40 +0100341
342#endif // V8_TARGET_ARCH_X64