deoptimizer-ia32.cc revision e0cee9b3ed82e2391fd85d118aeaa4ea361c687d
1// Copyright 2011 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#if defined(V8_TARGET_ARCH_IA32) 31 32#include "codegen.h" 33#include "deoptimizer.h" 34#include "full-codegen.h" 35#include "safepoint-table.h" 36 37namespace v8 { 38namespace internal { 39 40int Deoptimizer::table_entry_size_ = 10; 41 42 43int Deoptimizer::patch_size() { 44 return Assembler::kCallInstructionLength; 45} 46 47 48static void ZapCodeRange(Address start, Address end) { 49#ifdef DEBUG 50 ASSERT(start <= end); 51 int size = end - start; 52 CodePatcher destroyer(start, size); 53 while (size-- > 0) destroyer.masm()->int3(); 54#endif 55} 56 57 58void Deoptimizer::DeoptimizeFunction(JSFunction* function) { 59 AssertNoAllocation no_allocation; 60 61 if (!function->IsOptimized()) return; 62 63 // Get the optimized code. 64 Code* code = function->code(); 65 Address code_start_address = code->instruction_start(); 66 67 // We will overwrite the code's relocation info in-place. Relocation info 68 // is written backward. The relocation info is the payload of a byte 69 // array. Later on we will slide this to the start of the byte array and 70 // create a filler object in the remaining space. 71 ByteArray* reloc_info = code->relocation_info(); 72 Address reloc_end_address = reloc_info->address() + reloc_info->Size(); 73 RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address); 74 75 // For each return after a safepoint insert a call to the corresponding 76 // deoptimization entry. Since the call is a relative encoding, write new 77 // reloc info. We do not need any of the existing reloc info because the 78 // existing code will not be used again (we zap it in debug builds). 79 SafepointTable table(code); 80 Address prev_address = code_start_address; 81 for (unsigned i = 0; i < table.length(); ++i) { 82 Address curr_address = code_start_address + table.GetPcOffset(i); 83 ASSERT_GE(curr_address, prev_address); 84 ZapCodeRange(prev_address, curr_address); 85 86 SafepointEntry safepoint_entry = table.GetEntry(i); 87 int deoptimization_index = safepoint_entry.deoptimization_index(); 88 if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { 89 // The gap code is needed to get to the state expected at the bailout. 90 curr_address += safepoint_entry.gap_code_size(); 91 92 CodePatcher patcher(curr_address, patch_size()); 93 Address deopt_entry = GetDeoptimizationEntry(deoptimization_index, LAZY); 94 patcher.masm()->call(deopt_entry, RelocInfo::NONE); 95 96 // We use RUNTIME_ENTRY for deoptimization bailouts. 97 RelocInfo rinfo(curr_address + 1, // 1 after the call opcode. 98 RelocInfo::RUNTIME_ENTRY, 99 reinterpret_cast<intptr_t>(deopt_entry)); 100 reloc_info_writer.Write(&rinfo); 101 ASSERT_GE(reloc_info_writer.pos(), 102 reloc_info->address() + ByteArray::kHeaderSize); 103 curr_address += patch_size(); 104 } 105 prev_address = curr_address; 106 } 107 ZapCodeRange(prev_address, 108 code_start_address + code->safepoint_table_offset()); 109 110 // Move the relocation info to the beginning of the byte array. 111 int new_reloc_size = reloc_end_address - reloc_info_writer.pos(); 112 memmove(code->relocation_start(), reloc_info_writer.pos(), new_reloc_size); 113 114 // The relocation info is in place, update the size. 115 reloc_info->set_length(new_reloc_size); 116 117 // Handle the junk part after the new relocation info. We will create 118 // a non-live object in the extra space at the end of the former reloc info. 119 Address junk_address = reloc_info->address() + reloc_info->Size(); 120 ASSERT(junk_address <= reloc_end_address); 121 Heap::CreateFillerObjectAt(junk_address, reloc_end_address - junk_address); 122 123 // Add the deoptimizing code to the list. 124 DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); 125 node->set_next(deoptimizing_code_list_); 126 deoptimizing_code_list_ = node; 127 128 // Set the code for the function to non-optimized version. 129 function->ReplaceCode(function->shared()->code()); 130 131 if (FLAG_trace_deopt) { 132 PrintF("[forced deoptimization: "); 133 function->PrintName(); 134 PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function)); 135 } 136} 137 138 139void Deoptimizer::PatchStackCheckCodeAt(Address pc_after, 140 Code* check_code, 141 Code* replacement_code) { 142 Address call_target_address = pc_after - kIntSize; 143 ASSERT(check_code->entry() == 144 Assembler::target_address_at(call_target_address)); 145 // The stack check code matches the pattern: 146 // 147 // cmp esp, <limit> 148 // jae ok 149 // call <stack guard> 150 // test eax, <loop nesting depth> 151 // ok: ... 152 // 153 // We will patch away the branch so the code is: 154 // 155 // cmp esp, <limit> ;; Not changed 156 // nop 157 // nop 158 // call <on-stack replacment> 159 // test eax, <loop nesting depth> 160 // ok: 161 ASSERT(*(call_target_address - 3) == 0x73 && // jae 162 *(call_target_address - 2) == 0x07 && // offset 163 *(call_target_address - 1) == 0xe8); // call 164 *(call_target_address - 3) = 0x90; // nop 165 *(call_target_address - 2) = 0x90; // nop 166 Assembler::set_target_address_at(call_target_address, 167 replacement_code->entry()); 168} 169 170 171void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, 172 Code* check_code, 173 Code* replacement_code) { 174 Address call_target_address = pc_after - kIntSize; 175 ASSERT(replacement_code->entry() == 176 Assembler::target_address_at(call_target_address)); 177 // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to 178 // restore the conditional branch. 179 ASSERT(*(call_target_address - 3) == 0x90 && // nop 180 *(call_target_address - 2) == 0x90 && // nop 181 *(call_target_address - 1) == 0xe8); // call 182 *(call_target_address - 3) = 0x73; // jae 183 *(call_target_address - 2) = 0x07; // offset 184 Assembler::set_target_address_at(call_target_address, 185 check_code->entry()); 186} 187 188 189static int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) { 190 ByteArray* translations = data->TranslationByteArray(); 191 int length = data->DeoptCount(); 192 for (int i = 0; i < length; i++) { 193 if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) { 194 TranslationIterator it(translations, data->TranslationIndex(i)->value()); 195 int value = it.Next(); 196 ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value)); 197 // Read the number of frames. 198 value = it.Next(); 199 if (value == 1) return i; 200 } 201 } 202 UNREACHABLE(); 203 return -1; 204} 205 206 207void Deoptimizer::DoComputeOsrOutputFrame() { 208 DeoptimizationInputData* data = DeoptimizationInputData::cast( 209 optimized_code_->deoptimization_data()); 210 unsigned ast_id = data->OsrAstId()->value(); 211 // TODO(kasperl): This should not be the bailout_id_. It should be 212 // the ast id. Confusing. 213 ASSERT(bailout_id_ == ast_id); 214 215 int bailout_id = LookupBailoutId(data, ast_id); 216 unsigned translation_index = data->TranslationIndex(bailout_id)->value(); 217 ByteArray* translations = data->TranslationByteArray(); 218 219 TranslationIterator iterator(translations, translation_index); 220 Translation::Opcode opcode = 221 static_cast<Translation::Opcode>(iterator.Next()); 222 ASSERT(Translation::BEGIN == opcode); 223 USE(opcode); 224 int count = iterator.Next(); 225 ASSERT(count == 1); 226 USE(count); 227 228 opcode = static_cast<Translation::Opcode>(iterator.Next()); 229 USE(opcode); 230 ASSERT(Translation::FRAME == opcode); 231 unsigned node_id = iterator.Next(); 232 USE(node_id); 233 ASSERT(node_id == ast_id); 234 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next())); 235 USE(function); 236 ASSERT(function == function_); 237 unsigned height = iterator.Next(); 238 unsigned height_in_bytes = height * kPointerSize; 239 USE(height_in_bytes); 240 241 unsigned fixed_size = ComputeFixedSize(function_); 242 unsigned input_frame_size = input_->GetFrameSize(); 243 ASSERT(fixed_size + height_in_bytes == input_frame_size); 244 245 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize; 246 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value(); 247 unsigned outgoing_size = outgoing_height * kPointerSize; 248 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size; 249 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call. 250 251 if (FLAG_trace_osr) { 252 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ", 253 reinterpret_cast<intptr_t>(function_)); 254 function_->PrintName(); 255 PrintF(" => node=%u, frame=%d->%d]\n", 256 ast_id, 257 input_frame_size, 258 output_frame_size); 259 } 260 261 // There's only one output frame in the OSR case. 262 output_count_ = 1; 263 output_ = new FrameDescription*[1]; 264 output_[0] = new(output_frame_size) FrameDescription( 265 output_frame_size, function_); 266 267 // Clear the incoming parameters in the optimized frame to avoid 268 // confusing the garbage collector. 269 unsigned output_offset = output_frame_size - kPointerSize; 270 int parameter_count = function_->shared()->formal_parameter_count() + 1; 271 for (int i = 0; i < parameter_count; ++i) { 272 output_[0]->SetFrameSlot(output_offset, 0); 273 output_offset -= kPointerSize; 274 } 275 276 // Translate the incoming parameters. This may overwrite some of the 277 // incoming argument slots we've just cleared. 278 int input_offset = input_frame_size - kPointerSize; 279 bool ok = true; 280 int limit = input_offset - (parameter_count * kPointerSize); 281 while (ok && input_offset > limit) { 282 ok = DoOsrTranslateCommand(&iterator, &input_offset); 283 } 284 285 // There are no translation commands for the caller's pc and fp, the 286 // context, and the function. Set them up explicitly. 287 for (int i = 0; ok && i < 4; i++) { 288 uint32_t input_value = input_->GetFrameSlot(input_offset); 289 if (FLAG_trace_osr) { 290 PrintF(" [esp + %d] <- 0x%08x ; [esp + %d] (fixed part)\n", 291 output_offset, 292 input_value, 293 input_offset); 294 } 295 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset)); 296 input_offset -= kPointerSize; 297 output_offset -= kPointerSize; 298 } 299 300 // Translate the rest of the frame. 301 while (ok && input_offset >= 0) { 302 ok = DoOsrTranslateCommand(&iterator, &input_offset); 303 } 304 305 // If translation of any command failed, continue using the input frame. 306 if (!ok) { 307 delete output_[0]; 308 output_[0] = input_; 309 output_[0]->SetPc(reinterpret_cast<uint32_t>(from_)); 310 } else { 311 // Setup the frame pointer and the context pointer. 312 output_[0]->SetRegister(ebp.code(), input_->GetRegister(ebp.code())); 313 output_[0]->SetRegister(esi.code(), input_->GetRegister(esi.code())); 314 315 unsigned pc_offset = data->OsrPcOffset()->value(); 316 uint32_t pc = reinterpret_cast<uint32_t>( 317 optimized_code_->entry() + pc_offset); 318 output_[0]->SetPc(pc); 319 } 320 Code* continuation = Builtins::builtin(Builtins::NotifyOSR); 321 output_[0]->SetContinuation( 322 reinterpret_cast<uint32_t>(continuation->entry())); 323 324 if (FLAG_trace_osr) { 325 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ", 326 ok ? "finished" : "aborted", 327 reinterpret_cast<intptr_t>(function)); 328 function->PrintName(); 329 PrintF(" => pc=0x%0x]\n", output_[0]->GetPc()); 330 } 331} 332 333 334void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, 335 int frame_index) { 336 // Read the ast node id, function, and frame height for this output frame. 337 Translation::Opcode opcode = 338 static_cast<Translation::Opcode>(iterator->Next()); 339 USE(opcode); 340 ASSERT(Translation::FRAME == opcode); 341 int node_id = iterator->Next(); 342 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 343 unsigned height = iterator->Next(); 344 unsigned height_in_bytes = height * kPointerSize; 345 if (FLAG_trace_deopt) { 346 PrintF(" translating "); 347 function->PrintName(); 348 PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes); 349 } 350 351 // The 'fixed' part of the frame consists of the incoming parameters and 352 // the part described by JavaScriptFrameConstants. 353 unsigned fixed_frame_size = ComputeFixedSize(function); 354 unsigned input_frame_size = input_->GetFrameSize(); 355 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 356 357 // Allocate and store the output frame description. 358 FrameDescription* output_frame = 359 new(output_frame_size) FrameDescription(output_frame_size, function); 360 361 bool is_bottommost = (0 == frame_index); 362 bool is_topmost = (output_count_ - 1 == frame_index); 363 ASSERT(frame_index >= 0 && frame_index < output_count_); 364 ASSERT(output_[frame_index] == NULL); 365 output_[frame_index] = output_frame; 366 367 // The top address for the bottommost output frame can be computed from 368 // the input frame pointer and the output frame's height. For all 369 // subsequent output frames, it can be computed from the previous one's 370 // top address and the current frame's size. 371 uint32_t top_address; 372 if (is_bottommost) { 373 // 2 = context and function in the frame. 374 top_address = 375 input_->GetRegister(ebp.code()) - (2 * kPointerSize) - height_in_bytes; 376 } else { 377 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 378 } 379 output_frame->SetTop(top_address); 380 381 // Compute the incoming parameter translation. 382 int parameter_count = function->shared()->formal_parameter_count() + 1; 383 unsigned output_offset = output_frame_size; 384 unsigned input_offset = input_frame_size; 385 for (int i = 0; i < parameter_count; ++i) { 386 output_offset -= kPointerSize; 387 DoTranslateCommand(iterator, frame_index, output_offset); 388 } 389 input_offset -= (parameter_count * kPointerSize); 390 391 // There are no translation commands for the caller's pc and fp, the 392 // context, and the function. Synthesize their values and set them up 393 // explicitly. 394 // 395 // The caller's pc for the bottommost output frame is the same as in the 396 // input frame. For all subsequent output frames, it can be read from the 397 // previous one. This frame's pc can be computed from the non-optimized 398 // function code and AST id of the bailout. 399 output_offset -= kPointerSize; 400 input_offset -= kPointerSize; 401 intptr_t value; 402 if (is_bottommost) { 403 value = input_->GetFrameSlot(input_offset); 404 } else { 405 value = output_[frame_index - 1]->GetPc(); 406 } 407 output_frame->SetFrameSlot(output_offset, value); 408 if (FLAG_trace_deopt) { 409 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n", 410 top_address + output_offset, output_offset, value); 411 } 412 413 // The caller's frame pointer for the bottommost output frame is the same 414 // as in the input frame. For all subsequent output frames, it can be 415 // read from the previous one. Also compute and set this frame's frame 416 // pointer. 417 output_offset -= kPointerSize; 418 input_offset -= kPointerSize; 419 if (is_bottommost) { 420 value = input_->GetFrameSlot(input_offset); 421 } else { 422 value = output_[frame_index - 1]->GetFp(); 423 } 424 output_frame->SetFrameSlot(output_offset, value); 425 intptr_t fp_value = top_address + output_offset; 426 ASSERT(!is_bottommost || input_->GetRegister(ebp.code()) == fp_value); 427 output_frame->SetFp(fp_value); 428 if (is_topmost) output_frame->SetRegister(ebp.code(), fp_value); 429 if (FLAG_trace_deopt) { 430 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n", 431 fp_value, output_offset, value); 432 } 433 434 // For the bottommost output frame the context can be gotten from the input 435 // frame. For all subsequent output frames it can be gotten from the function 436 // so long as we don't inline functions that need local contexts. 437 output_offset -= kPointerSize; 438 input_offset -= kPointerSize; 439 if (is_bottommost) { 440 value = input_->GetFrameSlot(input_offset); 441 } else { 442 value = reinterpret_cast<uint32_t>(function->context()); 443 } 444 output_frame->SetFrameSlot(output_offset, value); 445 if (is_topmost) output_frame->SetRegister(esi.code(), value); 446 if (FLAG_trace_deopt) { 447 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n", 448 top_address + output_offset, output_offset, value); 449 } 450 451 // The function was mentioned explicitly in the BEGIN_FRAME. 452 output_offset -= kPointerSize; 453 input_offset -= kPointerSize; 454 value = reinterpret_cast<uint32_t>(function); 455 // The function for the bottommost output frame should also agree with the 456 // input frame. 457 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 458 output_frame->SetFrameSlot(output_offset, value); 459 if (FLAG_trace_deopt) { 460 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n", 461 top_address + output_offset, output_offset, value); 462 } 463 464 // Translate the rest of the frame. 465 for (unsigned i = 0; i < height; ++i) { 466 output_offset -= kPointerSize; 467 DoTranslateCommand(iterator, frame_index, output_offset); 468 } 469 ASSERT(0 == output_offset); 470 471 // Compute this frame's PC, state, and continuation. 472 Code* non_optimized_code = function->shared()->code(); 473 FixedArray* raw_data = non_optimized_code->deoptimization_data(); 474 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); 475 Address start = non_optimized_code->instruction_start(); 476 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); 477 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); 478 uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset); 479 output_frame->SetPc(pc_value); 480 481 FullCodeGenerator::State state = 482 FullCodeGenerator::StateField::decode(pc_and_state); 483 output_frame->SetState(Smi::FromInt(state)); 484 485 // Set the continuation for the topmost frame. 486 if (is_topmost) { 487 Code* continuation = (bailout_type_ == EAGER) 488 ? Builtins::builtin(Builtins::NotifyDeoptimized) 489 : Builtins::builtin(Builtins::NotifyLazyDeoptimized); 490 output_frame->SetContinuation( 491 reinterpret_cast<uint32_t>(continuation->entry())); 492 } 493 494 if (output_count_ - 1 == frame_index) iterator->Done(); 495} 496 497 498#define __ masm()-> 499 500void Deoptimizer::EntryGenerator::Generate() { 501 GeneratePrologue(); 502 CpuFeatures::Scope scope(SSE2); 503 504 // Save all general purpose registers before messing with them. 505 const int kNumberOfRegisters = Register::kNumRegisters; 506 507 const int kDoubleRegsSize = kDoubleSize * 508 XMMRegister::kNumAllocatableRegisters; 509 __ sub(Operand(esp), Immediate(kDoubleRegsSize)); 510 for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) { 511 XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i); 512 int offset = i * kDoubleSize; 513 __ movdbl(Operand(esp, offset), xmm_reg); 514 } 515 516 __ pushad(); 517 518 const int kSavedRegistersAreaSize = kNumberOfRegisters * kPointerSize + 519 kDoubleRegsSize; 520 521 // Get the bailout id from the stack. 522 __ mov(ebx, Operand(esp, kSavedRegistersAreaSize)); 523 524 // Get the address of the location in the code object if possible 525 // and compute the fp-to-sp delta in register edx. 526 if (type() == EAGER) { 527 __ Set(ecx, Immediate(0)); 528 __ lea(edx, Operand(esp, kSavedRegistersAreaSize + 1 * kPointerSize)); 529 } else { 530 __ mov(ecx, Operand(esp, kSavedRegistersAreaSize + 1 * kPointerSize)); 531 __ lea(edx, Operand(esp, kSavedRegistersAreaSize + 2 * kPointerSize)); 532 } 533 __ sub(edx, Operand(ebp)); 534 __ neg(edx); 535 536 // Allocate a new deoptimizer object. 537 __ PrepareCallCFunction(5, eax); 538 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 539 __ mov(Operand(esp, 0 * kPointerSize), eax); // Function. 540 __ mov(Operand(esp, 1 * kPointerSize), Immediate(type())); // Bailout type. 541 __ mov(Operand(esp, 2 * kPointerSize), ebx); // Bailout id. 542 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Code address or 0. 543 __ mov(Operand(esp, 4 * kPointerSize), edx); // Fp-to-sp delta. 544 __ CallCFunction(ExternalReference::new_deoptimizer_function(), 5); 545 546 // Preserve deoptimizer object in register eax and get the input 547 // frame descriptor pointer. 548 __ mov(ebx, Operand(eax, Deoptimizer::input_offset())); 549 550 // Fill in the input registers. 551 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 552 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 553 __ pop(Operand(ebx, offset)); 554 } 555 556 // Fill in the double input registers. 557 int double_regs_offset = FrameDescription::double_registers_offset(); 558 for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) { 559 int dst_offset = i * kDoubleSize + double_regs_offset; 560 int src_offset = i * kDoubleSize; 561 __ movdbl(xmm0, Operand(esp, src_offset)); 562 __ movdbl(Operand(ebx, dst_offset), xmm0); 563 } 564 565 // Remove the bailout id and the double registers from the stack. 566 if (type() == EAGER) { 567 __ add(Operand(esp), Immediate(kDoubleRegsSize + kPointerSize)); 568 } else { 569 __ add(Operand(esp), Immediate(kDoubleRegsSize + 2 * kPointerSize)); 570 } 571 572 // Compute a pointer to the unwinding limit in register ecx; that is 573 // the first stack slot not part of the input frame. 574 __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset())); 575 __ add(ecx, Operand(esp)); 576 577 // Unwind the stack down to - but not including - the unwinding 578 // limit and copy the contents of the activation frame to the input 579 // frame description. 580 __ lea(edx, Operand(ebx, FrameDescription::frame_content_offset())); 581 Label pop_loop; 582 __ bind(&pop_loop); 583 __ pop(Operand(edx, 0)); 584 __ add(Operand(edx), Immediate(sizeof(uint32_t))); 585 __ cmp(ecx, Operand(esp)); 586 __ j(not_equal, &pop_loop); 587 588 // Compute the output frame in the deoptimizer. 589 __ push(eax); 590 __ PrepareCallCFunction(1, ebx); 591 __ mov(Operand(esp, 0 * kPointerSize), eax); 592 __ CallCFunction(ExternalReference::compute_output_frames_function(), 1); 593 __ pop(eax); 594 595 // Replace the current frame with the output frames. 596 Label outer_push_loop, inner_push_loop; 597 // Outer loop state: eax = current FrameDescription**, edx = one past the 598 // last FrameDescription**. 599 __ mov(edx, Operand(eax, Deoptimizer::output_count_offset())); 600 __ mov(eax, Operand(eax, Deoptimizer::output_offset())); 601 __ lea(edx, Operand(eax, edx, times_4, 0)); 602 __ bind(&outer_push_loop); 603 // Inner loop state: ebx = current FrameDescription*, ecx = loop index. 604 __ mov(ebx, Operand(eax, 0)); 605 __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset())); 606 __ bind(&inner_push_loop); 607 __ sub(Operand(ecx), Immediate(sizeof(uint32_t))); 608 __ push(Operand(ebx, ecx, times_1, FrameDescription::frame_content_offset())); 609 __ test(ecx, Operand(ecx)); 610 __ j(not_zero, &inner_push_loop); 611 __ add(Operand(eax), Immediate(kPointerSize)); 612 __ cmp(eax, Operand(edx)); 613 __ j(below, &outer_push_loop); 614 615 // In case of OSR, we have to restore the XMM registers. 616 if (type() == OSR) { 617 for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) { 618 XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i); 619 int src_offset = i * kDoubleSize + double_regs_offset; 620 __ movdbl(xmm_reg, Operand(ebx, src_offset)); 621 } 622 } 623 624 // Push state, pc, and continuation from the last output frame. 625 if (type() != OSR) { 626 __ push(Operand(ebx, FrameDescription::state_offset())); 627 } 628 __ push(Operand(ebx, FrameDescription::pc_offset())); 629 __ push(Operand(ebx, FrameDescription::continuation_offset())); 630 631 632 // Push the registers from the last output frame. 633 for (int i = 0; i < kNumberOfRegisters; i++) { 634 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 635 __ push(Operand(ebx, offset)); 636 } 637 638 // Restore the registers from the stack. 639 __ popad(); 640 641 // Return to the continuation point. 642 __ ret(0); 643} 644 645 646void Deoptimizer::TableEntryGenerator::GeneratePrologue() { 647 // Create a sequence of deoptimization entries. 648 Label done; 649 for (int i = 0; i < count(); i++) { 650 int start = masm()->pc_offset(); 651 USE(start); 652 __ push_imm32(i); 653 __ jmp(&done); 654 ASSERT(masm()->pc_offset() - start == table_entry_size_); 655 } 656 __ bind(&done); 657} 658 659#undef __ 660 661 662} } // namespace v8::internal 663 664#endif // V8_TARGET_ARCH_IA32 665