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

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

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « src/x64/debug-x64.cc ('k') | src/x64/disasm-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 // Index of next deoptimization entry. If negative after calling 95 // Index of next deoptimization entry. If negative after calling
96 // FindNextIndex, there are no more, and Next will return an invalid 96 // FindNextIndex, there are no more, and Next will return an invalid
97 // SafepointEntry. 97 // SafepointEntry.
98 int index_; 98 int index_;
99 // Table length. 99 // Table length.
100 int limit_; 100 int limit_;
101 }; 101 };
102 102
103 103
104 void Deoptimizer::DeoptimizeFunction(JSFunction* function) { 104 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
105 HandleScope scope;
105 AssertNoAllocation no_allocation; 106 AssertNoAllocation no_allocation;
106 107
107 if (!function->IsOptimized()) return; 108 if (!function->IsOptimized()) return;
108 109
109 // Get the optimized code. 110 // Get the optimized code.
110 Code* code = function->code(); 111 Code* code = function->code();
111 112
112 // Invalidate the relocation information, as it will become invalid by the 113 // Invalidate the relocation information, as it will become invalid by the
113 // code patching below, and is not needed any more. 114 // code patching below, and is not needed any more.
114 code->InvalidateRelocation(); 115 code->InvalidateRelocation();
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 node->set_next(deoptimizing_code_list_); 190 node->set_next(deoptimizing_code_list_);
190 deoptimizing_code_list_ = node; 191 deoptimizing_code_list_ = node;
191 192
192 // Set the code for the function to non-optimized version. 193 // Set the code for the function to non-optimized version.
193 function->ReplaceCode(function->shared()->code()); 194 function->ReplaceCode(function->shared()->code());
194 195
195 if (FLAG_trace_deopt) { 196 if (FLAG_trace_deopt) {
196 PrintF("[forced deoptimization: "); 197 PrintF("[forced deoptimization: ");
197 function->PrintName(); 198 function->PrintName();
198 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); 199 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
200 #ifdef DEBUG
201 if (FLAG_print_code) {
202 code->PrintLn();
203 }
204 #endif
199 } 205 }
200 } 206 }
201 207
202 208
203 void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, 209 void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code,
204 Address pc_after, 210 Address pc_after,
205 Code* check_code, 211 Code* check_code,
206 Code* replacement_code) { 212 Code* replacement_code) {
207 Address call_target_address = pc_after - kIntSize; 213 Address call_target_address = pc_after - kIntSize;
208 ASSERT(check_code->entry() == 214 ASSERT(check_code->entry() ==
209 Assembler::target_address_at(call_target_address)); 215 Assembler::target_address_at(call_target_address));
210 // The stack check code matches the pattern: 216 // The stack check code matches the pattern:
211 // 217 //
212 // cmp rsp, <limit> 218 // cmp rsp, <limit>
213 // jae ok 219 // jae ok
214 // call <stack guard> 220 // call <stack guard>
215 // test rax, <loop nesting depth> 221 // test rax, <loop nesting depth>
216 // ok: ... 222 // ok: ...
217 // 223 //
218 // We will patch away the branch so the code is: 224 // We will patch away the branch so the code is:
219 // 225 //
220 // cmp rsp, <limit> ;; Not changed 226 // cmp rsp, <limit> ;; Not changed
221 // nop 227 // nop
222 // nop 228 // nop
223 // call <on-stack replacment> 229 // call <on-stack replacment>
224 // test rax, <loop nesting depth> 230 // test rax, <loop nesting depth>
225 // ok: 231 // ok:
226 // 232 //
227 ASSERT(*(call_target_address - 3) == 0x73 && // jae 233 ASSERT(*(call_target_address - 3) == 0x73 && // jae
228 *(call_target_address - 2) == 0x05 && // offset 234 *(call_target_address - 2) == 0x07 && // offset
229 *(call_target_address - 1) == 0xe8); // call 235 *(call_target_address - 1) == 0xe8); // call
230 *(call_target_address - 3) = 0x90; // nop 236 *(call_target_address - 3) = 0x90; // nop
231 *(call_target_address - 2) = 0x90; // nop 237 *(call_target_address - 2) = 0x90; // nop
232 Assembler::set_target_address_at(call_target_address, 238 Assembler::set_target_address_at(call_target_address,
233 replacement_code->entry()); 239 replacement_code->entry());
234 } 240 }
235 241
236 242
237 void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, 243 void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
238 Code* check_code, 244 Code* check_code,
239 Code* replacement_code) { 245 Code* replacement_code) {
240 Address call_target_address = pc_after - kIntSize; 246 Address call_target_address = pc_after - kIntSize;
241 ASSERT(replacement_code->entry() == 247 ASSERT(replacement_code->entry() ==
242 Assembler::target_address_at(call_target_address)); 248 Assembler::target_address_at(call_target_address));
243 // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to 249 // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to
244 // restore the conditional branch. 250 // restore the conditional branch.
245 ASSERT(*(call_target_address - 3) == 0x90 && // nop 251 ASSERT(*(call_target_address - 3) == 0x90 && // nop
246 *(call_target_address - 2) == 0x90 && // nop 252 *(call_target_address - 2) == 0x90 && // nop
247 *(call_target_address - 1) == 0xe8); // call 253 *(call_target_address - 1) == 0xe8); // call
248 *(call_target_address - 3) = 0x73; // jae 254 *(call_target_address - 3) = 0x73; // jae
249 *(call_target_address - 2) = 0x05; // offset 255 *(call_target_address - 2) = 0x07; // offset
250 Assembler::set_target_address_at(call_target_address, 256 Assembler::set_target_address_at(call_target_address,
251 check_code->entry()); 257 check_code->entry());
252 } 258 }
253 259
254 260
255 void Deoptimizer::DoComputeOsrOutputFrame() { 261 static int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) {
256 UNIMPLEMENTED(); 262 ByteArray* translations = data->TranslationByteArray();
263 int length = data->DeoptCount();
264 for (int i = 0; i < length; i++) {
265 if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) {
266 TranslationIterator it(translations, data->TranslationIndex(i)->value());
267 int value = it.Next();
268 ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
269 // Read the number of frames.
270 value = it.Next();
271 if (value == 1) return i;
272 }
273 }
274 UNREACHABLE();
275 return -1;
257 } 276 }
258 277
259 278
279 void Deoptimizer::DoComputeOsrOutputFrame() {
280 DeoptimizationInputData* data = DeoptimizationInputData::cast(
281 optimized_code_->deoptimization_data());
282 unsigned ast_id = data->OsrAstId()->value();
283 // TODO(kasperl): This should not be the bailout_id_. It should be
284 // the ast id. Confusing.
285 ASSERT(bailout_id_ == ast_id);
286
287 int bailout_id = LookupBailoutId(data, ast_id);
288 unsigned translation_index = data->TranslationIndex(bailout_id)->value();
289 ByteArray* translations = data->TranslationByteArray();
290
291 TranslationIterator iterator(translations, translation_index);
292 Translation::Opcode opcode =
293 static_cast<Translation::Opcode>(iterator.Next());
294 ASSERT(Translation::BEGIN == opcode);
295 USE(opcode);
296 int count = iterator.Next();
297 ASSERT(count == 1);
298 USE(count);
299
300 opcode = static_cast<Translation::Opcode>(iterator.Next());
301 USE(opcode);
302 ASSERT(Translation::FRAME == opcode);
303 unsigned node_id = iterator.Next();
304 USE(node_id);
305 ASSERT(node_id == ast_id);
306 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next()));
307 USE(function);
308 ASSERT(function == function_);
309 unsigned height = iterator.Next();
310 unsigned height_in_bytes = height * kPointerSize;
311 USE(height_in_bytes);
312
313 unsigned fixed_size = ComputeFixedSize(function_);
314 unsigned input_frame_size = static_cast<unsigned>(input_->GetFrameSize());
315 ASSERT(fixed_size + height_in_bytes == input_frame_size);
316
317 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
318 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
319 unsigned outgoing_size = outgoing_height * kPointerSize;
320 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
321 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call.
322
323 if (FLAG_trace_osr) {
324 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
325 reinterpret_cast<intptr_t>(function_));
326 function_->PrintName();
327 PrintF(" => node=%u, frame=%d->%d]\n",
328 ast_id,
329 input_frame_size,
330 output_frame_size);
331 }
332
333 // There's only one output frame in the OSR case.
334 output_count_ = 1;
335 output_ = new FrameDescription*[1];
336 output_[0] = new(output_frame_size) FrameDescription(
337 output_frame_size, function_);
338
339 // Clear the incoming parameters in the optimized frame to avoid
340 // confusing the garbage collector.
341 unsigned output_offset = output_frame_size - kPointerSize;
342 int parameter_count = function_->shared()->formal_parameter_count() + 1;
343 for (int i = 0; i < parameter_count; ++i) {
344 output_[0]->SetFrameSlot(output_offset, 0);
345 output_offset -= kPointerSize;
346 }
347
348 // Translate the incoming parameters. This may overwrite some of the
349 // incoming argument slots we've just cleared.
350 int input_offset = input_frame_size - kPointerSize;
351 bool ok = true;
352 int limit = input_offset - (parameter_count * kPointerSize);
353 while (ok && input_offset > limit) {
354 ok = DoOsrTranslateCommand(&iterator, &input_offset);
355 }
356
357 // There are no translation commands for the caller's pc and fp, the
358 // context, and the function. Set them up explicitly.
359 for (int i = 0; ok && i < 4; i++) {
360 intptr_t input_value = input_->GetFrameSlot(input_offset);
361 if (FLAG_trace_osr) {
362 PrintF(" [esp + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] (fixed part)\n",
363 output_offset,
364 input_value,
365 input_offset);
366 }
367 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
368 input_offset -= kPointerSize;
369 output_offset -= kPointerSize;
370 }
371
372 // Translate the rest of the frame.
373 while (ok && input_offset >= 0) {
374 ok = DoOsrTranslateCommand(&iterator, &input_offset);
375 }
376
377 // If translation of any command failed, continue using the input frame.
378 if (!ok) {
379 delete output_[0];
380 output_[0] = input_;
381 output_[0]->SetPc(reinterpret_cast<intptr_t>(from_));
382 } else {
383 // Setup the frame pointer and the context pointer.
384 output_[0]->SetRegister(rbp.code(), input_->GetRegister(rbp.code()));
385 output_[0]->SetRegister(rsi.code(), input_->GetRegister(rsi.code()));
386
387 unsigned pc_offset = data->OsrPcOffset()->value();
388 intptr_t pc = reinterpret_cast<intptr_t>(
389 optimized_code_->entry() + pc_offset);
390 output_[0]->SetPc(pc);
391 }
392 Code* continuation = Builtins::builtin(Builtins::NotifyOSR);
393 output_[0]->SetContinuation(
394 reinterpret_cast<intptr_t>(continuation->entry()));
395
396 if (FLAG_trace_osr) {
397 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
398 ok ? "finished" : "aborted",
399 reinterpret_cast<intptr_t>(function));
400 function->PrintName();
401 PrintF(" => pc=0x%0" V8PRIxPTR "]\n", output_[0]->GetPc());
402 }
403 }
404
405
260 void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, 406 void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
261 int frame_index) { 407 int frame_index) {
262 // Read the ast node id, function, and frame height for this output frame. 408 // Read the ast node id, function, and frame height for this output frame.
263 Translation::Opcode opcode = 409 Translation::Opcode opcode =
264 static_cast<Translation::Opcode>(iterator->Next()); 410 static_cast<Translation::Opcode>(iterator->Next());
265 USE(opcode); 411 USE(opcode);
266 ASSERT(Translation::FRAME == opcode); 412 ASSERT(Translation::FRAME == opcode);
267 int node_id = iterator->Next(); 413 int node_id = iterator->Next();
268 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 414 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
269 unsigned height = iterator->Next(); 415 unsigned height = iterator->Next();
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 intptr_t fp_value = top_address + output_offset; 498 intptr_t fp_value = top_address + output_offset;
353 ASSERT(!is_bottommost || input_->GetRegister(rbp.code()) == fp_value); 499 ASSERT(!is_bottommost || input_->GetRegister(rbp.code()) == fp_value);
354 output_frame->SetFp(fp_value); 500 output_frame->SetFp(fp_value);
355 if (is_topmost) output_frame->SetRegister(rbp.code(), fp_value); 501 if (is_topmost) output_frame->SetRegister(rbp.code(), fp_value);
356 if (FLAG_trace_deopt) { 502 if (FLAG_trace_deopt) {
357 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" 503 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
358 V8PRIxPTR " ; caller's fp\n", 504 V8PRIxPTR " ; caller's fp\n",
359 fp_value, output_offset, value); 505 fp_value, output_offset, value);
360 } 506 }
361 507
362 // The context can be gotten from the function so long as we don't 508 // For the bottommost output frame the context can be gotten from the input
363 // optimize functions that need local contexts. 509 // frame. For all subsequent output frames it can be gotten from the function
510 // so long as we don't inline functions that need local contexts.
364 output_offset -= kPointerSize; 511 output_offset -= kPointerSize;
365 input_offset -= kPointerSize; 512 input_offset -= kPointerSize;
366 value = reinterpret_cast<intptr_t>(function->context()); 513 if (is_bottommost) {
367 // The context for the bottommost output frame should also agree with the 514 value = input_->GetFrameSlot(input_offset);
368 // input frame. 515 } else {
369 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 516 value = reinterpret_cast<intptr_t>(function->context());
517 }
370 output_frame->SetFrameSlot(output_offset, value); 518 output_frame->SetFrameSlot(output_offset, value);
371 if (is_topmost) output_frame->SetRegister(rsi.code(), value); 519 if (is_topmost) output_frame->SetRegister(rsi.code(), value);
372 if (FLAG_trace_deopt) { 520 if (FLAG_trace_deopt) {
373 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" 521 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
374 V8PRIxPTR "; context\n", 522 V8PRIxPTR "; context\n",
375 top_address + output_offset, output_offset, value); 523 top_address + output_offset, output_offset, value);
376 } 524 }
377 525
378 // The function was mentioned explicitly in the BEGIN_FRAME. 526 // The function was mentioned explicitly in the BEGIN_FRAME.
379 output_offset -= kPointerSize; 527 output_offset -= kPointerSize;
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 // Allocate a new deoptimizer object. 640 // Allocate a new deoptimizer object.
493 __ PrepareCallCFunction(5); 641 __ PrepareCallCFunction(5);
494 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 642 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
495 __ movq(arg1, rax); 643 __ movq(arg1, rax);
496 __ movq(arg2, Immediate(type())); 644 __ movq(arg2, Immediate(type()));
497 // Args 3 and 4 are already in the right registers. 645 // Args 3 and 4 are already in the right registers.
498 646
499 // On windows put the argument on the stack (PrepareCallCFunction have 647 // On windows put the argument on the stack (PrepareCallCFunction have
500 // created space for this). On linux pass the argument in r8. 648 // created space for this). On linux pass the argument in r8.
501 #ifdef _WIN64 649 #ifdef _WIN64
502 __ movq(Operand(rsp, 0 * kPointerSize), arg5); 650 __ movq(Operand(rsp, 4 * kPointerSize), arg5);
503 #else 651 #else
504 __ movq(r8, arg5); 652 __ movq(r8, arg5);
505 #endif 653 #endif
506 654
507 __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5); 655 __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5);
508 // Preserve deoptimizer object in register rax and get the input 656 // Preserve deoptimizer object in register rax and get the input
509 // frame descriptor pointer. 657 // frame descriptor pointer.
510 __ movq(rbx, Operand(rax, Deoptimizer::input_offset())); 658 __ movq(rbx, Operand(rax, Deoptimizer::input_offset()));
511 659
512 // Fill in the input registers. 660 // Fill in the input registers.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 // and overwrite this afterwards. 749 // and overwrite this afterwards.
602 if (r.is(rsp)) { 750 if (r.is(rsp)) {
603 ASSERT(i > 0); 751 ASSERT(i > 0);
604 r = Register::toRegister(i - 1); 752 r = Register::toRegister(i - 1);
605 } 753 }
606 __ pop(r); 754 __ pop(r);
607 } 755 }
608 756
609 // Set up the roots register. 757 // Set up the roots register.
610 ExternalReference roots_address = ExternalReference::roots_address(); 758 ExternalReference roots_address = ExternalReference::roots_address();
611 __ movq(r13, roots_address); 759 __ InitializeRootRegister();
612 760 __ InitializeSmiConstantRegister();
613 __ movq(kSmiConstantRegister,
614 reinterpret_cast<uint64_t>(Smi::FromInt(kSmiConstantRegisterValue)),
615 RelocInfo::NONE);
616 761
617 // Return to the continuation point. 762 // Return to the continuation point.
618 __ ret(0); 763 __ ret(0);
619 } 764 }
620 765
621 766
622 void Deoptimizer::TableEntryGenerator::GeneratePrologue() { 767 void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
623 // Create a sequence of deoptimization entries. 768 // Create a sequence of deoptimization entries.
624 Label done; 769 Label done;
625 for (int i = 0; i < count(); i++) { 770 for (int i = 0; i < count(); i++) {
626 int start = masm()->pc_offset(); 771 int start = masm()->pc_offset();
627 USE(start); 772 USE(start);
628 __ push_imm32(i); 773 __ push_imm32(i);
629 __ jmp(&done); 774 __ jmp(&done);
630 ASSERT(masm()->pc_offset() - start == table_entry_size_); 775 ASSERT(masm()->pc_offset() - start == table_entry_size_);
631 } 776 }
632 __ bind(&done); 777 __ bind(&done);
633 } 778 }
634 779
635 #undef __ 780 #undef __
636 781
637 782
638 } } // namespace v8::internal 783 } } // namespace v8::internal
639 784
640 #endif // V8_TARGET_ARCH_X64 785 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/debug-x64.cc ('k') | src/x64/disasm-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698