Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: src/arm/deoptimizer-arm.cc

Issue 6529055: [Isolates] Merge crankshaft (r5922 from bleeding_edge). (Closed)
Patch Set: Win32 port Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/arm/cpu-arm.cc ('k') | src/arm/frames-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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
35 namespace v8 {
36 namespace internal {
37
38 int Deoptimizer::table_entry_size_ = 16;
39
40 void 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);
58 int deoptimization_index = table.GetDeoptimizationIndex(i);
59 int gap_code_size = table.GetGapCodeSize(i);
60 // Check that we did not shoot past next safepoint.
61 // TODO(srdjan): How do we guarantee that safepoint code does not
62 // overlap other safepoint patching code?
63 CHECK(pc_offset >= last_pc_offset);
64 #ifdef DEBUG
65 // Destroy the code which is not supposed to be run again.
66 int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize;
67 CodePatcher destroyer(code->instruction_start() + last_pc_offset,
68 instructions);
69 for (int x = 0; x < instructions; x++) {
70 destroyer.masm()->bkpt(0);
71 }
72 #endif
73 last_pc_offset = pc_offset;
74 if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
75 const int kCallInstructionSizeInWords = 3;
76 CodePatcher patcher(code->instruction_start() + pc_offset + gap_code_size,
77 kCallInstructionSizeInWords);
78 Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
79 deoptimization_index, Deoptimizer::LAZY);
80 patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
81 last_pc_offset +=
82 gap_code_size + kCallInstructionSizeInWords * Assembler::kInstrSize;
83 }
84 }
85
86
87 #ifdef DEBUG
88 // Destroy the code which is not supposed to be run again.
89 int instructions =
90 (code->safepoint_table_start() - last_pc_offset) / Assembler::kInstrSize;
91 CodePatcher destroyer(code->instruction_start() + last_pc_offset,
92 instructions);
93 for (int x = 0; x < instructions; x++) {
94 destroyer.masm()->bkpt(0);
95 }
96 #endif
97
98 // Add the deoptimizing code to the list.
99 DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
100 DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
101 node->set_next(data->deoptimizing_code_list_);
102 data->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
115 void Deoptimizer::PatchStackCheckCode(RelocInfo* rinfo,
116 Code* replacement_code) {
117 UNIMPLEMENTED();
118 }
119
120
121 void Deoptimizer::RevertStackCheckCode(RelocInfo* rinfo, Code* check_code) {
122 UNIMPLEMENTED();
123 }
124
125
126 void 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.
133 void 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 uint32_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 unsigned 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<uint32_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
290 // Set the continuation for the topmost frame.
291 if (is_topmost) {
292 Builtins* builtins = isolate_->builtins();
293 Code* continuation = (bailout_type_ == EAGER)
294 ? builtins->builtin(Builtins::NotifyDeoptimized)
295 : builtins->builtin(Builtins::NotifyLazyDeoptimized);
296 output_frame->SetContinuation(
297 reinterpret_cast<uint32_t>(continuation->entry()));
298 }
299
300 if (output_count_ - 1 == frame_index) iterator->Done();
301 }
302
303
304 #define __ masm()->
305
306
307 // This code tries to be close to ia32 code so that any changes can be
308 // easily ported.
309 void Deoptimizer::EntryGenerator::Generate() {
310 GeneratePrologue();
311 // TOS: bailout-id; TOS+1: return address if not EAGER.
312 CpuFeatures::Scope scope(VFP3);
313 // Save all general purpose registers before messing with them.
314 const int kNumberOfRegisters = Register::kNumRegisters;
315
316 // Everything but pc, lr and ip which will be saved but not restored.
317 RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit();
318
319 const int kDoubleRegsSize =
320 kDoubleSize * DwVfpRegister::kNumAllocatableRegisters;
321
322 // Save all general purpose registers before messing with them.
323 __ sub(sp, sp, Operand(kDoubleRegsSize));
324 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) {
325 DwVfpRegister vfp_reg = DwVfpRegister::FromAllocationIndex(i);
326 int offset = i * kDoubleSize;
327 __ vstr(vfp_reg, sp, offset);
328 }
329
330 // Push all 16 registers (needed to populate FrameDescription::registers_).
331 __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
332
333 const int kSavedRegistersAreaSize =
334 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
335
336 // Get the bailout id from the stack.
337 __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize));
338
339 // Get the address of the location in the code object if possible (r3) (return
340 // address for lazy deoptimization) and compute the fp-to-sp delta in
341 // register r4.
342 if (type() == EAGER) {
343 __ mov(r3, Operand(0));
344 // Correct one word for bailout id.
345 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
346 } else {
347 __ mov(r3, lr);
348 // Correct two words for bailout id and return address.
349 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
350 }
351 __ sub(r4, fp, r4);
352
353 // Allocate a new deoptimizer object.
354 // Pass four arguments in r0 to r3 and fifth argument on stack.
355 __ PrepareCallCFunction(5, r5);
356 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
357 __ mov(r1, Operand(type())); // bailout type,
358 // r2: bailout id already loaded.
359 // r3: code address or 0 already loaded.
360 __ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta.
361 // Call Deoptimizer::New().
362 __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5);
363
364 // Preserve "deoptimizer" object in register r0 and get the input
365 // frame descriptor pointer to r1 (deoptimizer->input_);
366 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset()));
367
368
369 // Copy core registers into FrameDescription::registers_[kNumRegisters].
370 ASSERT(Register::kNumRegisters == kNumberOfRegisters);
371 for (int i = 0; i < kNumberOfRegisters; i++) {
372 int offset = (i * kIntSize) + FrameDescription::registers_offset();
373 __ ldr(r2, MemOperand(sp, i * kPointerSize));
374 __ str(r2, MemOperand(r1, offset));
375 }
376
377 // Copy VFP registers to
378 // double_registers_[DoubleRegister::kNumAllocatableRegisters]
379 int double_regs_offset = FrameDescription::double_registers_offset();
380 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) {
381 int dst_offset = i * kDoubleSize + double_regs_offset;
382 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
383 __ vldr(d0, sp, src_offset);
384 __ vstr(d0, r1, dst_offset);
385 }
386
387 // Remove the bailout id, eventually return address, and the saved registers
388 // from the stack.
389 if (type() == EAGER) {
390 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
391 } else {
392 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize)));
393 }
394
395 // Compute a pointer to the unwinding limit in register r2; that is
396 // the first stack slot not part of the input frame.
397 __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset()));
398 __ add(r2, r2, sp);
399
400 // Unwind the stack down to - but not including - the unwinding
401 // limit and copy the contents of the activation frame to the input
402 // frame description.
403 __ add(r3, r1, Operand(FrameDescription::frame_content_offset()));
404 Label pop_loop;
405 __ bind(&pop_loop);
406 __ pop(r4);
407 __ str(r4, MemOperand(r3, 0));
408 __ add(r3, r3, Operand(sizeof(uint32_t)));
409 __ cmp(r2, sp);
410 __ b(ne, &pop_loop);
411
412 // Compute the output frame in the deoptimizer.
413 __ push(r0); // Preserve deoptimizer object across call.
414 // r0: deoptimizer object; r1: scratch.
415 __ PrepareCallCFunction(1, r1);
416 // Call Deoptimizer::ComputeOutputFrames().
417 __ CallCFunction(ExternalReference::compute_output_frames_function(), 1);
418 __ pop(r0); // Restore deoptimizer object (class Deoptimizer).
419
420 // Replace the current (input) frame with the output frames.
421 Label outer_push_loop, inner_push_loop;
422 // Outer loop state: r0 = current "FrameDescription** output_",
423 // r1 = one past the last FrameDescription**.
424 __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset()));
425 __ ldr(r0, MemOperand(r0, Deoptimizer::output_offset())); // r0 is output_.
426 __ add(r1, r0, Operand(r1, LSL, 2));
427 __ bind(&outer_push_loop);
428 // Inner loop state: r2 = current FrameDescription*, r3 = loop index.
429 __ ldr(r2, MemOperand(r0, 0)); // output_[ix]
430 __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset()));
431 __ bind(&inner_push_loop);
432 __ sub(r3, r3, Operand(sizeof(uint32_t)));
433 // __ add(r6, r2, Operand(r3, LSL, 1));
434 __ add(r6, r2, Operand(r3));
435 __ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset()));
436 __ push(r7);
437 __ cmp(r3, Operand(0));
438 __ b(ne, &inner_push_loop); // test for gt?
439 __ add(r0, r0, Operand(kPointerSize));
440 __ cmp(r0, r1);
441 __ b(lt, &outer_push_loop);
442
443 // In case of OSR, we have to restore the XMM registers.
444 if (type() == OSR) {
445 UNIMPLEMENTED();
446 }
447
448 // Push state, pc, and continuation from the last output frame.
449 if (type() != OSR) {
450 __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
451 __ push(r6);
452 }
453
454 __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset()));
455 __ push(r6);
456 __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset()));
457 __ push(r6);
458
459 // Push the registers from the last output frame.
460 for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
461 int offset = (i * kIntSize) + FrameDescription::registers_offset();
462 __ ldr(r6, MemOperand(r2, offset));
463 __ push(r6);
464 }
465
466 // Restore the registers from the stack.
467 __ ldm(ia_w, sp, restored_regs); // all but pc registers.
468 __ pop(ip); // remove sp
469 __ pop(ip); // remove lr
470
471 // Set up the roots register.
472 ExternalReference roots_address = ExternalReference::roots_address();
473 __ mov(r10, Operand(roots_address));
474
475 __ pop(ip); // remove pc
476 __ pop(r7); // get continuation, leave pc on stack
477 __ pop(lr);
478 __ Jump(r7);
479 __ stop("Unreachable.");
480 }
481
482
483 void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
484 // Create a sequence of deoptimization entries. Note that any
485 // registers may be still live.
486 Label done;
487 for (int i = 0; i < count(); i++) {
488 int start = masm()->pc_offset();
489 USE(start);
490 if (type() == EAGER) {
491 __ nop();
492 } else {
493 // Emulate ia32 like call by pushing return address to stack.
494 __ push(lr);
495 }
496 __ mov(ip, Operand(i));
497 __ push(ip);
498 __ b(&done);
499 ASSERT(masm()->pc_offset() - start == table_entry_size_);
500 }
501 __ bind(&done);
502 }
503
504 #undef __
505
506 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/cpu-arm.cc ('k') | src/arm/frames-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698