deoptimizer-arm.cc revision 42effa50d92d47f80404ee63808dbde9921e6202
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#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 40 41int Deoptimizer::patch_size() { 42 const int kCallInstructionSizeInWords = 3; 43 return kCallInstructionSizeInWords * Assembler::kInstrSize; 44} 45 46 47void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) { 48 // Nothing to do. No new relocation information is written for lazy 49 // deoptimization on ARM. 50} 51 52 53void Deoptimizer::DeoptimizeFunction(JSFunction* function) { 54 HandleScope scope; 55 AssertNoAllocation no_allocation; 56 57 if (!function->IsOptimized()) return; 58 59 // Get the optimized code. 60 Code* code = function->code(); 61 62 // Invalidate the relocation information, as it will become invalid by the 63 // code patching below, and is not needed any more. 64 code->InvalidateRelocation(); 65 66 // For each return after a safepoint insert an absolute call to the 67 // corresponding deoptimization entry. 68 unsigned last_pc_offset = 0; 69 SafepointTable table(function->code()); 70 for (unsigned i = 0; i < table.length(); i++) { 71 unsigned pc_offset = table.GetPcOffset(i); 72 SafepointEntry safepoint_entry = table.GetEntry(i); 73 int deoptimization_index = safepoint_entry.deoptimization_index(); 74 int gap_code_size = safepoint_entry.gap_code_size(); 75 // Check that we did not shoot past next safepoint. 76 CHECK(pc_offset >= last_pc_offset); 77#ifdef DEBUG 78 // Destroy the code which is not supposed to be run again. 79 int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize; 80 CodePatcher destroyer(code->instruction_start() + last_pc_offset, 81 instructions); 82 for (int x = 0; x < instructions; x++) { 83 destroyer.masm()->bkpt(0); 84 } 85#endif 86 last_pc_offset = pc_offset; 87 if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { 88 Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry( 89 deoptimization_index, Deoptimizer::LAZY); 90 last_pc_offset += gap_code_size; 91 int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry, 92 RelocInfo::NONE); 93 int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; 94 ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0); 95 ASSERT(call_size_in_bytes <= patch_size()); 96 CodePatcher patcher(code->instruction_start() + last_pc_offset, 97 call_size_in_words); 98 patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE); 99 last_pc_offset += call_size_in_bytes; 100 } 101 } 102 103 104#ifdef DEBUG 105 // Destroy the code which is not supposed to be run again. 106 int instructions = 107 (code->safepoint_table_offset() - last_pc_offset) / Assembler::kInstrSize; 108 CodePatcher destroyer(code->instruction_start() + last_pc_offset, 109 instructions); 110 for (int x = 0; x < instructions; x++) { 111 destroyer.masm()->bkpt(0); 112 } 113#endif 114 115 // Add the deoptimizing code to the list. 116 DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); 117 DeoptimizerData* data = code->GetIsolate()->deoptimizer_data(); 118 node->set_next(data->deoptimizing_code_list_); 119 data->deoptimizing_code_list_ = node; 120 121 // Set the code for the function to non-optimized version. 122 function->ReplaceCode(function->shared()->code()); 123 124 if (FLAG_trace_deopt) { 125 PrintF("[forced deoptimization: "); 126 function->PrintName(); 127 PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function)); 128#ifdef DEBUG 129 if (FLAG_print_code) { 130 code->PrintLn(); 131 } 132#endif 133 } 134} 135 136 137void Deoptimizer::PatchStackCheckCodeAt(Address pc_after, 138 Code* check_code, 139 Code* replacement_code) { 140 const int kInstrSize = Assembler::kInstrSize; 141 // The call of the stack guard check has the following form: 142 // e1 5d 00 0c cmp sp, <limit> 143 // 2a 00 00 01 bcs ok 144 // e5 9f c? ?? ldr ip, [pc, <stack guard address>] 145 // e1 2f ff 3c blx ip 146 ASSERT(Memory::int32_at(pc_after - kInstrSize) == 147 (al | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | ip.code())); 148 ASSERT(Assembler::IsLdrPcImmediateOffset( 149 Assembler::instr_at(pc_after - 2 * kInstrSize))); 150 151 // We patch the code to the following form: 152 // e1 5d 00 0c cmp sp, <limit> 153 // e1 a0 00 00 mov r0, r0 (NOP) 154 // e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>] 155 // e1 2f ff 3c blx ip 156 // and overwrite the constant containing the 157 // address of the stack check stub. 158 159 // Replace conditional jump with NOP. 160 CodePatcher patcher(pc_after - 3 * kInstrSize, 1); 161 patcher.masm()->nop(); 162 163 // Replace the stack check address in the constant pool 164 // with the entry address of the replacement code. 165 uint32_t stack_check_address_offset = Memory::uint16_at(pc_after - 166 2 * kInstrSize) & 0xfff; 167 Address stack_check_address_pointer = pc_after + stack_check_address_offset; 168 ASSERT(Memory::uint32_at(stack_check_address_pointer) == 169 reinterpret_cast<uint32_t>(check_code->entry())); 170 Memory::uint32_at(stack_check_address_pointer) = 171 reinterpret_cast<uint32_t>(replacement_code->entry()); 172} 173 174 175void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, 176 Code* check_code, 177 Code* replacement_code) { 178 const int kInstrSize = Assembler::kInstrSize; 179 ASSERT(Memory::uint32_at(pc_after - kInstrSize) == 0xe12fff3c); 180 ASSERT(Memory::uint8_at(pc_after - kInstrSize - 1) == 0xe5); 181 ASSERT(Memory::uint8_at(pc_after - kInstrSize - 2) == 0x9f); 182 183 // Replace NOP with conditional jump. 184 CodePatcher patcher(pc_after - 3 * kInstrSize, 1); 185 patcher.masm()->b(+4, cs); 186 187 // Replace the stack check address in the constant pool 188 // with the entry address of the replacement code. 189 uint32_t stack_check_address_offset = Memory::uint16_at(pc_after - 190 2 * kInstrSize) & 0xfff; 191 Address stack_check_address_pointer = pc_after + stack_check_address_offset; 192 ASSERT(Memory::uint32_at(stack_check_address_pointer) == 193 reinterpret_cast<uint32_t>(replacement_code->entry())); 194 Memory::uint32_at(stack_check_address_pointer) = 195 reinterpret_cast<uint32_t>(check_code->entry()); 196} 197 198 199static int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) { 200 ByteArray* translations = data->TranslationByteArray(); 201 int length = data->DeoptCount(); 202 for (int i = 0; i < length; i++) { 203 if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) { 204 TranslationIterator it(translations, data->TranslationIndex(i)->value()); 205 int value = it.Next(); 206 ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value)); 207 // Read the number of frames. 208 value = it.Next(); 209 if (value == 1) return i; 210 } 211 } 212 UNREACHABLE(); 213 return -1; 214} 215 216 217void Deoptimizer::DoComputeOsrOutputFrame() { 218 DeoptimizationInputData* data = DeoptimizationInputData::cast( 219 optimized_code_->deoptimization_data()); 220 unsigned ast_id = data->OsrAstId()->value(); 221 222 int bailout_id = LookupBailoutId(data, ast_id); 223 unsigned translation_index = data->TranslationIndex(bailout_id)->value(); 224 ByteArray* translations = data->TranslationByteArray(); 225 226 TranslationIterator iterator(translations, translation_index); 227 Translation::Opcode opcode = 228 static_cast<Translation::Opcode>(iterator.Next()); 229 ASSERT(Translation::BEGIN == opcode); 230 USE(opcode); 231 int count = iterator.Next(); 232 ASSERT(count == 1); 233 USE(count); 234 235 opcode = static_cast<Translation::Opcode>(iterator.Next()); 236 USE(opcode); 237 ASSERT(Translation::FRAME == opcode); 238 unsigned node_id = iterator.Next(); 239 USE(node_id); 240 ASSERT(node_id == ast_id); 241 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next())); 242 USE(function); 243 ASSERT(function == function_); 244 unsigned height = iterator.Next(); 245 unsigned height_in_bytes = height * kPointerSize; 246 USE(height_in_bytes); 247 248 unsigned fixed_size = ComputeFixedSize(function_); 249 unsigned input_frame_size = input_->GetFrameSize(); 250 ASSERT(fixed_size + height_in_bytes == input_frame_size); 251 252 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize; 253 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value(); 254 unsigned outgoing_size = outgoing_height * kPointerSize; 255 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size; 256 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call. 257 258 if (FLAG_trace_osr) { 259 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ", 260 reinterpret_cast<intptr_t>(function_)); 261 function_->PrintName(); 262 PrintF(" => node=%u, frame=%d->%d]\n", 263 ast_id, 264 input_frame_size, 265 output_frame_size); 266 } 267 268 // There's only one output frame in the OSR case. 269 output_count_ = 1; 270 output_ = new FrameDescription*[1]; 271 output_[0] = new(output_frame_size) FrameDescription( 272 output_frame_size, function_); 273 274 // Clear the incoming parameters in the optimized frame to avoid 275 // confusing the garbage collector. 276 unsigned output_offset = output_frame_size - kPointerSize; 277 int parameter_count = function_->shared()->formal_parameter_count() + 1; 278 for (int i = 0; i < parameter_count; ++i) { 279 output_[0]->SetFrameSlot(output_offset, 0); 280 output_offset -= kPointerSize; 281 } 282 283 // Translate the incoming parameters. This may overwrite some of the 284 // incoming argument slots we've just cleared. 285 int input_offset = input_frame_size - kPointerSize; 286 bool ok = true; 287 int limit = input_offset - (parameter_count * kPointerSize); 288 while (ok && input_offset > limit) { 289 ok = DoOsrTranslateCommand(&iterator, &input_offset); 290 } 291 292 // There are no translation commands for the caller's pc and fp, the 293 // context, and the function. Set them up explicitly. 294 for (int i = StandardFrameConstants::kCallerPCOffset; 295 ok && i >= StandardFrameConstants::kMarkerOffset; 296 i -= kPointerSize) { 297 uint32_t input_value = input_->GetFrameSlot(input_offset); 298 if (FLAG_trace_osr) { 299 const char* name = "UNKNOWN"; 300 switch (i) { 301 case StandardFrameConstants::kCallerPCOffset: 302 name = "caller's pc"; 303 break; 304 case StandardFrameConstants::kCallerFPOffset: 305 name = "fp"; 306 break; 307 case StandardFrameConstants::kContextOffset: 308 name = "context"; 309 break; 310 case StandardFrameConstants::kMarkerOffset: 311 name = "function"; 312 break; 313 } 314 PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n", 315 output_offset, 316 input_value, 317 input_offset, 318 name); 319 } 320 321 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset)); 322 input_offset -= kPointerSize; 323 output_offset -= kPointerSize; 324 } 325 326 // Translate the rest of the frame. 327 while (ok && input_offset >= 0) { 328 ok = DoOsrTranslateCommand(&iterator, &input_offset); 329 } 330 331 // If translation of any command failed, continue using the input frame. 332 if (!ok) { 333 delete output_[0]; 334 output_[0] = input_; 335 output_[0]->SetPc(reinterpret_cast<uint32_t>(from_)); 336 } else { 337 // Setup the frame pointer and the context pointer. 338 output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code())); 339 output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code())); 340 341 unsigned pc_offset = data->OsrPcOffset()->value(); 342 uint32_t pc = reinterpret_cast<uint32_t>( 343 optimized_code_->entry() + pc_offset); 344 output_[0]->SetPc(pc); 345 } 346 Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR); 347 output_[0]->SetContinuation( 348 reinterpret_cast<uint32_t>(continuation->entry())); 349 350 if (FLAG_trace_osr) { 351 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ", 352 ok ? "finished" : "aborted", 353 reinterpret_cast<intptr_t>(function)); 354 function->PrintName(); 355 PrintF(" => pc=0x%0x]\n", output_[0]->GetPc()); 356 } 357} 358 359 360// This code is very similar to ia32 code, but relies on register names (fp, sp) 361// and how the frame is laid out. 362void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, 363 int frame_index) { 364 // Read the ast node id, function, and frame height for this output frame. 365 Translation::Opcode opcode = 366 static_cast<Translation::Opcode>(iterator->Next()); 367 USE(opcode); 368 ASSERT(Translation::FRAME == opcode); 369 int node_id = iterator->Next(); 370 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 371 unsigned height = iterator->Next(); 372 unsigned height_in_bytes = height * kPointerSize; 373 if (FLAG_trace_deopt) { 374 PrintF(" translating "); 375 function->PrintName(); 376 PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes); 377 } 378 379 // The 'fixed' part of the frame consists of the incoming parameters and 380 // the part described by JavaScriptFrameConstants. 381 unsigned fixed_frame_size = ComputeFixedSize(function); 382 unsigned input_frame_size = input_->GetFrameSize(); 383 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 384 385 // Allocate and store the output frame description. 386 FrameDescription* output_frame = 387 new(output_frame_size) FrameDescription(output_frame_size, function); 388 389 bool is_bottommost = (0 == frame_index); 390 bool is_topmost = (output_count_ - 1 == frame_index); 391 ASSERT(frame_index >= 0 && frame_index < output_count_); 392 ASSERT(output_[frame_index] == NULL); 393 output_[frame_index] = output_frame; 394 395 // The top address for the bottommost output frame can be computed from 396 // the input frame pointer and the output frame's height. For all 397 // subsequent output frames, it can be computed from the previous one's 398 // top address and the current frame's size. 399 uint32_t top_address; 400 if (is_bottommost) { 401 // 2 = context and function in the frame. 402 top_address = 403 input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes; 404 } else { 405 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 406 } 407 output_frame->SetTop(top_address); 408 409 // Compute the incoming parameter translation. 410 int parameter_count = function->shared()->formal_parameter_count() + 1; 411 unsigned output_offset = output_frame_size; 412 unsigned input_offset = input_frame_size; 413 for (int i = 0; i < parameter_count; ++i) { 414 output_offset -= kPointerSize; 415 DoTranslateCommand(iterator, frame_index, output_offset); 416 } 417 input_offset -= (parameter_count * kPointerSize); 418 419 // There are no translation commands for the caller's pc and fp, the 420 // context, and the function. Synthesize their values and set them up 421 // explicitly. 422 // 423 // The caller's pc for the bottommost output frame is the same as in the 424 // input frame. For all subsequent output frames, it can be read from the 425 // previous one. This frame's pc can be computed from the non-optimized 426 // function code and AST id of the bailout. 427 output_offset -= kPointerSize; 428 input_offset -= kPointerSize; 429 intptr_t value; 430 if (is_bottommost) { 431 value = input_->GetFrameSlot(input_offset); 432 } else { 433 value = output_[frame_index - 1]->GetPc(); 434 } 435 output_frame->SetFrameSlot(output_offset, value); 436 if (FLAG_trace_deopt) { 437 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n", 438 top_address + output_offset, output_offset, value); 439 } 440 441 // The caller's frame pointer for the bottommost output frame is the same 442 // as in the input frame. For all subsequent output frames, it can be 443 // read from the previous one. Also compute and set this frame's frame 444 // pointer. 445 output_offset -= kPointerSize; 446 input_offset -= kPointerSize; 447 if (is_bottommost) { 448 value = input_->GetFrameSlot(input_offset); 449 } else { 450 value = output_[frame_index - 1]->GetFp(); 451 } 452 output_frame->SetFrameSlot(output_offset, value); 453 intptr_t fp_value = top_address + output_offset; 454 ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value); 455 output_frame->SetFp(fp_value); 456 if (is_topmost) { 457 output_frame->SetRegister(fp.code(), fp_value); 458 } 459 if (FLAG_trace_deopt) { 460 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n", 461 fp_value, output_offset, value); 462 } 463 464 // For the bottommost output frame the context can be gotten from the input 465 // frame. For all subsequent output frames it can be gotten from the function 466 // so long as we don't inline functions that need local contexts. 467 output_offset -= kPointerSize; 468 input_offset -= kPointerSize; 469 if (is_bottommost) { 470 value = input_->GetFrameSlot(input_offset); 471 } else { 472 value = reinterpret_cast<intptr_t>(function->context()); 473 } 474 output_frame->SetFrameSlot(output_offset, value); 475 if (is_topmost) { 476 output_frame->SetRegister(cp.code(), value); 477 } 478 if (FLAG_trace_deopt) { 479 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n", 480 top_address + output_offset, output_offset, value); 481 } 482 483 // The function was mentioned explicitly in the BEGIN_FRAME. 484 output_offset -= kPointerSize; 485 input_offset -= kPointerSize; 486 value = reinterpret_cast<uint32_t>(function); 487 // The function for the bottommost output frame should also agree with the 488 // input frame. 489 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 490 output_frame->SetFrameSlot(output_offset, value); 491 if (FLAG_trace_deopt) { 492 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n", 493 top_address + output_offset, output_offset, value); 494 } 495 496 // Translate the rest of the frame. 497 for (unsigned i = 0; i < height; ++i) { 498 output_offset -= kPointerSize; 499 DoTranslateCommand(iterator, frame_index, output_offset); 500 } 501 ASSERT(0 == output_offset); 502 503 // Compute this frame's PC, state, and continuation. 504 Code* non_optimized_code = function->shared()->code(); 505 FixedArray* raw_data = non_optimized_code->deoptimization_data(); 506 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); 507 Address start = non_optimized_code->instruction_start(); 508 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); 509 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); 510 uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset); 511 output_frame->SetPc(pc_value); 512 if (is_topmost) { 513 output_frame->SetRegister(pc.code(), pc_value); 514 } 515 516 FullCodeGenerator::State state = 517 FullCodeGenerator::StateField::decode(pc_and_state); 518 output_frame->SetState(Smi::FromInt(state)); 519 520 521 // Set the continuation for the topmost frame. 522 if (is_topmost) { 523 Builtins* builtins = isolate_->builtins(); 524 Code* continuation = (bailout_type_ == EAGER) 525 ? builtins->builtin(Builtins::kNotifyDeoptimized) 526 : builtins->builtin(Builtins::kNotifyLazyDeoptimized); 527 output_frame->SetContinuation( 528 reinterpret_cast<uint32_t>(continuation->entry())); 529 } 530 531 if (output_count_ - 1 == frame_index) iterator->Done(); 532} 533 534 535#define __ masm()-> 536 537 538// This code tries to be close to ia32 code so that any changes can be 539// easily ported. 540void Deoptimizer::EntryGenerator::Generate() { 541 GeneratePrologue(); 542 543 Isolate* isolate = masm()->isolate(); 544 545 CpuFeatures::Scope scope(VFP3); 546 // Save all general purpose registers before messing with them. 547 const int kNumberOfRegisters = Register::kNumRegisters; 548 549 // Everything but pc, lr and ip which will be saved but not restored. 550 RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit(); 551 552 const int kDoubleRegsSize = 553 kDoubleSize * DwVfpRegister::kNumAllocatableRegisters; 554 555 // Save all general purpose registers before messing with them. 556 __ sub(sp, sp, Operand(kDoubleRegsSize)); 557 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) { 558 DwVfpRegister vfp_reg = DwVfpRegister::FromAllocationIndex(i); 559 int offset = i * kDoubleSize; 560 __ vstr(vfp_reg, sp, offset); 561 } 562 563 // Push all 16 registers (needed to populate FrameDescription::registers_). 564 __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit()); 565 566 const int kSavedRegistersAreaSize = 567 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; 568 569 // Get the bailout id from the stack. 570 __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize)); 571 572 // Get the address of the location in the code object if possible (r3) (return 573 // address for lazy deoptimization) and compute the fp-to-sp delta in 574 // register r4. 575 if (type() == EAGER) { 576 __ mov(r3, Operand(0)); 577 // Correct one word for bailout id. 578 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 579 } else if (type() == OSR) { 580 __ mov(r3, lr); 581 // Correct one word for bailout id. 582 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 583 } else { 584 __ mov(r3, lr); 585 // Correct two words for bailout id and return address. 586 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize))); 587 } 588 __ sub(r4, fp, r4); 589 590 // Allocate a new deoptimizer object. 591 // Pass four arguments in r0 to r3 and fifth argument on stack. 592 __ PrepareCallCFunction(6, r5); 593 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 594 __ mov(r1, Operand(type())); // bailout type, 595 // r2: bailout id already loaded. 596 // r3: code address or 0 already loaded. 597 __ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta. 598 __ mov(r5, Operand(ExternalReference::isolate_address())); 599 __ str(r5, MemOperand(sp, 1 * kPointerSize)); // Isolate. 600 // Call Deoptimizer::New(). 601 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6); 602 603 // Preserve "deoptimizer" object in register r0 and get the input 604 // frame descriptor pointer to r1 (deoptimizer->input_); 605 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset())); 606 607 // Copy core registers into FrameDescription::registers_[kNumRegisters]. 608 ASSERT(Register::kNumRegisters == kNumberOfRegisters); 609 for (int i = 0; i < kNumberOfRegisters; i++) { 610 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 611 __ ldr(r2, MemOperand(sp, i * kPointerSize)); 612 __ str(r2, MemOperand(r1, offset)); 613 } 614 615 // Copy VFP registers to 616 // double_registers_[DoubleRegister::kNumAllocatableRegisters] 617 int double_regs_offset = FrameDescription::double_registers_offset(); 618 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) { 619 int dst_offset = i * kDoubleSize + double_regs_offset; 620 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize; 621 __ vldr(d0, sp, src_offset); 622 __ vstr(d0, r1, dst_offset); 623 } 624 625 // Remove the bailout id, eventually return address, and the saved registers 626 // from the stack. 627 if (type() == EAGER || type() == OSR) { 628 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 629 } else { 630 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize))); 631 } 632 633 // Compute a pointer to the unwinding limit in register r2; that is 634 // the first stack slot not part of the input frame. 635 __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset())); 636 __ add(r2, r2, sp); 637 638 // Unwind the stack down to - but not including - the unwinding 639 // limit and copy the contents of the activation frame to the input 640 // frame description. 641 __ add(r3, r1, Operand(FrameDescription::frame_content_offset())); 642 Label pop_loop; 643 __ bind(&pop_loop); 644 __ pop(r4); 645 __ str(r4, MemOperand(r3, 0)); 646 __ add(r3, r3, Operand(sizeof(uint32_t))); 647 __ cmp(r2, sp); 648 __ b(ne, &pop_loop); 649 650 // Compute the output frame in the deoptimizer. 651 __ push(r0); // Preserve deoptimizer object across call. 652 // r0: deoptimizer object; r1: scratch. 653 __ PrepareCallCFunction(1, r1); 654 // Call Deoptimizer::ComputeOutputFrames(). 655 __ CallCFunction( 656 ExternalReference::compute_output_frames_function(isolate), 1); 657 __ pop(r0); // Restore deoptimizer object (class Deoptimizer). 658 659 // Replace the current (input) frame with the output frames. 660 Label outer_push_loop, inner_push_loop; 661 // Outer loop state: r0 = current "FrameDescription** output_", 662 // r1 = one past the last FrameDescription**. 663 __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset())); 664 __ ldr(r0, MemOperand(r0, Deoptimizer::output_offset())); // r0 is output_. 665 __ add(r1, r0, Operand(r1, LSL, 2)); 666 __ bind(&outer_push_loop); 667 // Inner loop state: r2 = current FrameDescription*, r3 = loop index. 668 __ ldr(r2, MemOperand(r0, 0)); // output_[ix] 669 __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset())); 670 __ bind(&inner_push_loop); 671 __ sub(r3, r3, Operand(sizeof(uint32_t))); 672 // __ add(r6, r2, Operand(r3, LSL, 1)); 673 __ add(r6, r2, Operand(r3)); 674 __ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset())); 675 __ push(r7); 676 __ cmp(r3, Operand(0)); 677 __ b(ne, &inner_push_loop); // test for gt? 678 __ add(r0, r0, Operand(kPointerSize)); 679 __ cmp(r0, r1); 680 __ b(lt, &outer_push_loop); 681 682 // Push state, pc, and continuation from the last output frame. 683 if (type() != OSR) { 684 __ ldr(r6, MemOperand(r2, FrameDescription::state_offset())); 685 __ push(r6); 686 } 687 688 __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset())); 689 __ push(r6); 690 __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset())); 691 __ push(r6); 692 693 // Push the registers from the last output frame. 694 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 695 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 696 __ ldr(r6, MemOperand(r2, offset)); 697 __ push(r6); 698 } 699 700 // Restore the registers from the stack. 701 __ ldm(ia_w, sp, restored_regs); // all but pc registers. 702 __ pop(ip); // remove sp 703 __ pop(ip); // remove lr 704 705 // Set up the roots register. 706 ExternalReference roots_address = ExternalReference::roots_address(isolate); 707 __ mov(r10, Operand(roots_address)); 708 709 __ pop(ip); // remove pc 710 __ pop(r7); // get continuation, leave pc on stack 711 __ pop(lr); 712 __ Jump(r7); 713 __ stop("Unreachable."); 714} 715 716 717void Deoptimizer::TableEntryGenerator::GeneratePrologue() { 718 // Create a sequence of deoptimization entries. Note that any 719 // registers may be still live. 720 Label done; 721 for (int i = 0; i < count(); i++) { 722 int start = masm()->pc_offset(); 723 USE(start); 724 if (type() == EAGER) { 725 __ nop(); 726 } else { 727 // Emulate ia32 like call by pushing return address to stack. 728 __ push(lr); 729 } 730 __ mov(ip, Operand(i)); 731 __ push(ip); 732 __ b(&done); 733 ASSERT(masm()->pc_offset() - start == table_entry_size_); 734 } 735 __ bind(&done); 736} 737 738#undef __ 739 740} } // namespace v8::internal 741