blob: 8a53d1cbd6475a338dc2523adf9b1c0b3b0b2682 [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 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
4// met:
5//
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.
15//
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.
27
28#include "v8.h"
29
30#include "codegen.h"
31#include "deoptimizer.h"
32#include "full-codegen.h"
33#include "safepoint-table.h"
34
35namespace v8 {
36namespace internal {
37
38int Deoptimizer::table_entry_size_ = 16;
39
40void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
41 AssertNoAllocation no_allocation;
42
43 if (!function->IsOptimized()) return;
44
45 // Get the optimized code.
46 Code* code = function->code();
47
48 // Invalidate the relocation information, as it will become invalid by the
49 // code patching below, and is not needed any more.
50 code->InvalidateRelocation();
51
52 // For each return after a safepoint insert an absolute call to the
53 // corresponding deoptimization entry.
54 unsigned last_pc_offset = 0;
55 SafepointTable table(function->code());
56 for (unsigned i = 0; i < table.length(); i++) {
57 unsigned pc_offset = table.GetPcOffset(i);
Ben Murdochb8e0da22011-05-16 14:20:40 +010058 SafepointEntry safepoint_entry = table.GetEntry(i);
59 int deoptimization_index = safepoint_entry.deoptimization_index();
60 int gap_code_size = safepoint_entry.gap_code_size();
Ben Murdochb0fe1622011-05-05 13:52:32 +010061 // Check that we did not shoot past next safepoint.
62 // TODO(srdjan): How do we guarantee that safepoint code does not
63 // overlap other safepoint patching code?
64 CHECK(pc_offset >= last_pc_offset);
65#ifdef DEBUG
66 // Destroy the code which is not supposed to be run again.
67 int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize;
68 CodePatcher destroyer(code->instruction_start() + last_pc_offset,
69 instructions);
70 for (int x = 0; x < instructions; x++) {
71 destroyer.masm()->bkpt(0);
72 }
73#endif
74 last_pc_offset = pc_offset;
75 if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
76 const int kCallInstructionSizeInWords = 3;
77 CodePatcher patcher(code->instruction_start() + pc_offset + gap_code_size,
78 kCallInstructionSizeInWords);
79 Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
80 deoptimization_index, Deoptimizer::LAZY);
81 patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
82 last_pc_offset +=
83 gap_code_size + kCallInstructionSizeInWords * Assembler::kInstrSize;
84 }
85 }
86
87
88#ifdef DEBUG
89 // Destroy the code which is not supposed to be run again.
90 int instructions =
91 (code->safepoint_table_start() - last_pc_offset) / Assembler::kInstrSize;
92 CodePatcher destroyer(code->instruction_start() + last_pc_offset,
93 instructions);
94 for (int x = 0; x < instructions; x++) {
95 destroyer.masm()->bkpt(0);
96 }
97#endif
98
99 // Add the deoptimizing code to the list.
100 DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
101 node->set_next(deoptimizing_code_list_);
102 deoptimizing_code_list_ = node;
103
104 // Set the code for the function to non-optimized version.
105 function->ReplaceCode(function->shared()->code());
106
107 if (FLAG_trace_deopt) {
108 PrintF("[forced deoptimization: ");
109 function->PrintName();
110 PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
111 }
112}
113
114
115void Deoptimizer::PatchStackCheckCode(RelocInfo* rinfo,
116 Code* replacement_code) {
117 UNIMPLEMENTED();
118}
119
120
121void Deoptimizer::RevertStackCheckCode(RelocInfo* rinfo, Code* check_code) {
122 UNIMPLEMENTED();
123}
124
125
126void Deoptimizer::DoComputeOsrOutputFrame() {
127 UNIMPLEMENTED();
128}
129
130
131// This code is very similar to ia32 code, but relies on register names (fp, sp)
132// and how the frame is laid out.
133void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
134 int frame_index) {
135 // Read the ast node id, function, and frame height for this output frame.
136 Translation::Opcode opcode =
137 static_cast<Translation::Opcode>(iterator->Next());
138 USE(opcode);
139 ASSERT(Translation::FRAME == opcode);
140 int node_id = iterator->Next();
141 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
142 unsigned height = iterator->Next();
143 unsigned height_in_bytes = height * kPointerSize;
144 if (FLAG_trace_deopt) {
145 PrintF(" translating ");
146 function->PrintName();
147 PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes);
148 }
149
150 // The 'fixed' part of the frame consists of the incoming parameters and
151 // the part described by JavaScriptFrameConstants.
152 unsigned fixed_frame_size = ComputeFixedSize(function);
153 unsigned input_frame_size = input_->GetFrameSize();
154 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
155
156 // Allocate and store the output frame description.
157 FrameDescription* output_frame =
158 new(output_frame_size) FrameDescription(output_frame_size, function);
159
160 bool is_bottommost = (0 == frame_index);
161 bool is_topmost = (output_count_ - 1 == frame_index);
162 ASSERT(frame_index >= 0 && frame_index < output_count_);
163 ASSERT(output_[frame_index] == NULL);
164 output_[frame_index] = output_frame;
165
166 // The top address for the bottommost output frame can be computed from
167 // the input frame pointer and the output frame's height. For all
168 // subsequent output frames, it can be computed from the previous one's
169 // top address and the current frame's size.
170 uint32_t top_address;
171 if (is_bottommost) {
172 // 2 = context and function in the frame.
173 top_address =
174 input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes;
175 } else {
176 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
177 }
178 output_frame->SetTop(top_address);
179
180 // Compute the incoming parameter translation.
181 int parameter_count = function->shared()->formal_parameter_count() + 1;
182 unsigned output_offset = output_frame_size;
183 unsigned input_offset = input_frame_size;
184 for (int i = 0; i < parameter_count; ++i) {
185 output_offset -= kPointerSize;
186 DoTranslateCommand(iterator, frame_index, output_offset);
187 }
188 input_offset -= (parameter_count * kPointerSize);
189
190 // There are no translation commands for the caller's pc and fp, the
191 // context, and the function. Synthesize their values and set them up
192 // explicitly.
193 //
194 // The caller's pc for the bottommost output frame is the same as in the
195 // input frame. For all subsequent output frames, it can be read from the
196 // previous one. This frame's pc can be computed from the non-optimized
197 // function code and AST id of the bailout.
198 output_offset -= kPointerSize;
199 input_offset -= kPointerSize;
200 intptr_t value;
201 if (is_bottommost) {
202 value = input_->GetFrameSlot(input_offset);
203 } else {
204 value = output_[frame_index - 1]->GetPc();
205 }
206 output_frame->SetFrameSlot(output_offset, value);
207 if (FLAG_trace_deopt) {
208 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
209 top_address + output_offset, output_offset, value);
210 }
211
212 // The caller's frame pointer for the bottommost output frame is the same
213 // as in the input frame. For all subsequent output frames, it can be
214 // read from the previous one. Also compute and set this frame's frame
215 // pointer.
216 output_offset -= kPointerSize;
217 input_offset -= kPointerSize;
218 if (is_bottommost) {
219 value = input_->GetFrameSlot(input_offset);
220 } else {
221 value = output_[frame_index - 1]->GetFp();
222 }
223 output_frame->SetFrameSlot(output_offset, value);
224 intptr_t fp_value = top_address + output_offset;
225 ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value);
226 output_frame->SetFp(fp_value);
227 if (is_topmost) {
228 output_frame->SetRegister(fp.code(), fp_value);
229 }
230 if (FLAG_trace_deopt) {
231 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
232 fp_value, output_offset, value);
233 }
234
235 // The context can be gotten from the function so long as we don't
236 // optimize functions that need local contexts.
237 output_offset -= kPointerSize;
238 input_offset -= kPointerSize;
239 value = reinterpret_cast<intptr_t>(function->context());
240 // The context for the bottommost output frame should also agree with the
241 // input frame.
242 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
243 output_frame->SetFrameSlot(output_offset, value);
244 if (is_topmost) {
245 output_frame->SetRegister(cp.code(), value);
246 }
247 if (FLAG_trace_deopt) {
248 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
249 top_address + output_offset, output_offset, value);
250 }
251
252 // The function was mentioned explicitly in the BEGIN_FRAME.
253 output_offset -= kPointerSize;
254 input_offset -= kPointerSize;
255 value = reinterpret_cast<uint32_t>(function);
256 // The function for the bottommost output frame should also agree with the
257 // input frame.
258 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
259 output_frame->SetFrameSlot(output_offset, value);
260 if (FLAG_trace_deopt) {
261 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
262 top_address + output_offset, output_offset, value);
263 }
264
265 // Translate the rest of the frame.
266 for (unsigned i = 0; i < height; ++i) {
267 output_offset -= kPointerSize;
268 DoTranslateCommand(iterator, frame_index, output_offset);
269 }
270 ASSERT(0 == output_offset);
271
272 // Compute this frame's PC, state, and continuation.
273 Code* non_optimized_code = function->shared()->code();
274 FixedArray* raw_data = non_optimized_code->deoptimization_data();
275 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
276 Address start = non_optimized_code->instruction_start();
277 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
278 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
279 uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
280 output_frame->SetPc(pc_value);
281 if (is_topmost) {
282 output_frame->SetRegister(pc.code(), pc_value);
283 }
284
285 FullCodeGenerator::State state =
286 FullCodeGenerator::StateField::decode(pc_and_state);
287 output_frame->SetState(Smi::FromInt(state));
288
289 // Set the continuation for the topmost frame.
290 if (is_topmost) {
291 Code* continuation = (bailout_type_ == EAGER)
292 ? Builtins::builtin(Builtins::NotifyDeoptimized)
293 : Builtins::builtin(Builtins::NotifyLazyDeoptimized);
294 output_frame->SetContinuation(
295 reinterpret_cast<uint32_t>(continuation->entry()));
296 }
297
298 if (output_count_ - 1 == frame_index) iterator->Done();
299}
300
301
302#define __ masm()->
303
304
305// This code tries to be close to ia32 code so that any changes can be
306// easily ported.
307void Deoptimizer::EntryGenerator::Generate() {
308 GeneratePrologue();
309 // TOS: bailout-id; TOS+1: return address if not EAGER.
310 CpuFeatures::Scope scope(VFP3);
311 // Save all general purpose registers before messing with them.
312 const int kNumberOfRegisters = Register::kNumRegisters;
313
314 // Everything but pc, lr and ip which will be saved but not restored.
315 RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit();
316
317 const int kDoubleRegsSize =
318 kDoubleSize * DwVfpRegister::kNumAllocatableRegisters;
319
320 // Save all general purpose registers before messing with them.
321 __ sub(sp, sp, Operand(kDoubleRegsSize));
322 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) {
323 DwVfpRegister vfp_reg = DwVfpRegister::FromAllocationIndex(i);
324 int offset = i * kDoubleSize;
325 __ vstr(vfp_reg, sp, offset);
326 }
327
328 // Push all 16 registers (needed to populate FrameDescription::registers_).
329 __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
330
331 const int kSavedRegistersAreaSize =
332 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
333
334 // Get the bailout id from the stack.
335 __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize));
336
337 // Get the address of the location in the code object if possible (r3) (return
338 // address for lazy deoptimization) and compute the fp-to-sp delta in
339 // register r4.
340 if (type() == EAGER) {
341 __ mov(r3, Operand(0));
342 // Correct one word for bailout id.
343 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
344 } else {
345 __ mov(r3, lr);
346 // Correct two words for bailout id and return address.
347 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
348 }
349 __ sub(r4, fp, r4);
350
351 // Allocate a new deoptimizer object.
352 // Pass four arguments in r0 to r3 and fifth argument on stack.
353 __ PrepareCallCFunction(5, r5);
354 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
355 __ mov(r1, Operand(type())); // bailout type,
356 // r2: bailout id already loaded.
357 // r3: code address or 0 already loaded.
358 __ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta.
359 // Call Deoptimizer::New().
360 __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5);
361
362 // Preserve "deoptimizer" object in register r0 and get the input
363 // frame descriptor pointer to r1 (deoptimizer->input_);
364 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
365
366
367 // Copy core registers into FrameDescription::registers_[kNumRegisters].
368 ASSERT(Register::kNumRegisters == kNumberOfRegisters);
369 for (int i = 0; i < kNumberOfRegisters; i++) {
370 int offset = (i * kIntSize) + FrameDescription::registers_offset();
371 __ ldr(r2, MemOperand(sp, i * kPointerSize));
372 __ str(r2, MemOperand(r1, offset));
373 }
374
375 // Copy VFP registers to
376 // double_registers_[DoubleRegister::kNumAllocatableRegisters]
377 int double_regs_offset = FrameDescription::double_registers_offset();
378 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) {
379 int dst_offset = i * kDoubleSize + double_regs_offset;
380 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
381 __ vldr(d0, sp, src_offset);
382 __ vstr(d0, r1, dst_offset);
383 }
384
385 // Remove the bailout id, eventually return address, and the saved registers
386 // from the stack.
387 if (type() == EAGER) {
388 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
389 } else {
390 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
391 }
392
393 // Compute a pointer to the unwinding limit in register r2; that is
394 // the first stack slot not part of the input frame.
395 __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset()));
396 __ add(r2, r2, sp);
397
398 // Unwind the stack down to - but not including - the unwinding
399 // limit and copy the contents of the activation frame to the input
400 // frame description.
401 __ add(r3, r1, Operand(FrameDescription::frame_content_offset()));
402 Label pop_loop;
403 __ bind(&pop_loop);
404 __ pop(r4);
405 __ str(r4, MemOperand(r3, 0));
406 __ add(r3, r3, Operand(sizeof(uint32_t)));
407 __ cmp(r2, sp);
408 __ b(ne, &pop_loop);
409
410 // Compute the output frame in the deoptimizer.
411 __ push(r0); // Preserve deoptimizer object across call.
412 // r0: deoptimizer object; r1: scratch.
413 __ PrepareCallCFunction(1, r1);
414 // Call Deoptimizer::ComputeOutputFrames().
415 __ CallCFunction(ExternalReference::compute_output_frames_function(), 1);
416 __ pop(r0); // Restore deoptimizer object (class Deoptimizer).
417
418 // Replace the current (input) frame with the output frames.
419 Label outer_push_loop, inner_push_loop;
420 // Outer loop state: r0 = current "FrameDescription** output_",
421 // r1 = one past the last FrameDescription**.
422 __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset()));
423 __ ldr(r0, MemOperand(r0, Deoptimizer::output_offset())); // r0 is output_.
424 __ add(r1, r0, Operand(r1, LSL, 2));
425 __ bind(&outer_push_loop);
426 // Inner loop state: r2 = current FrameDescription*, r3 = loop index.
427 __ ldr(r2, MemOperand(r0, 0)); // output_[ix]
428 __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset()));
429 __ bind(&inner_push_loop);
430 __ sub(r3, r3, Operand(sizeof(uint32_t)));
431 // __ add(r6, r2, Operand(r3, LSL, 1));
432 __ add(r6, r2, Operand(r3));
433 __ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset()));
434 __ push(r7);
435 __ cmp(r3, Operand(0));
436 __ b(ne, &inner_push_loop); // test for gt?
437 __ add(r0, r0, Operand(kPointerSize));
438 __ cmp(r0, r1);
439 __ b(lt, &outer_push_loop);
440
441 // In case of OSR, we have to restore the XMM registers.
442 if (type() == OSR) {
443 UNIMPLEMENTED();
444 }
445
446 // Push state, pc, and continuation from the last output frame.
447 if (type() != OSR) {
448 __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
449 __ push(r6);
450 }
451
452 __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset()));
453 __ push(r6);
454 __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset()));
455 __ push(r6);
456
457 // Push the registers from the last output frame.
458 for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
459 int offset = (i * kIntSize) + FrameDescription::registers_offset();
460 __ ldr(r6, MemOperand(r2, offset));
461 __ push(r6);
462 }
463
464 // Restore the registers from the stack.
465 __ ldm(ia_w, sp, restored_regs); // all but pc registers.
466 __ pop(ip); // remove sp
467 __ pop(ip); // remove lr
468
469 // Set up the roots register.
470 ExternalReference roots_address = ExternalReference::roots_address();
471 __ mov(r10, Operand(roots_address));
472
473 __ pop(ip); // remove pc
474 __ pop(r7); // get continuation, leave pc on stack
475 __ pop(lr);
476 __ Jump(r7);
477 __ stop("Unreachable.");
478}
479
480
481void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
482 // Create a sequence of deoptimization entries. Note that any
483 // registers may be still live.
484 Label done;
485 for (int i = 0; i < count(); i++) {
486 int start = masm()->pc_offset();
487 USE(start);
488 if (type() == EAGER) {
489 __ nop();
490 } else {
491 // Emulate ia32 like call by pushing return address to stack.
492 __ push(lr);
493 }
494 __ mov(ip, Operand(i));
495 __ push(ip);
496 __ b(&done);
497 ASSERT(masm()->pc_offset() - start == table_entry_size_);
498 }
499 __ bind(&done);
500}
501
502#undef __
503
504} } // namespace v8::internal