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