1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "codegen.h" 31 #include "deoptimizer.h" 32 #include "full-codegen.h" 33 #include "safepoint-table.h" 34 35 namespace v8 { 36 namespace internal { 37 38 const int Deoptimizer::table_entry_size_ = 16; 39 40 41 int Deoptimizer::patch_size() { 42 const int kCallInstructionSizeInWords = 3; 43 return kCallInstructionSizeInWords * Assembler::kInstrSize; 44 } 45 46 47 void 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 111 static const int32_t kBranchBeforeStackCheck = 0x2a000001; 112 static const int32_t kBranchBeforeInterrupt = 0x5a000004; 113 114 115 void Deoptimizer::PatchStackCheckCodeAt(Code* unoptimized_code, 116 Address pc_after, 117 Code* check_code, 118 Code* replacement_code) { 119 const int kInstrSize = Assembler::kInstrSize; 120 // The call of the stack guard check has the following form: 121 // e1 5d 00 0c cmp sp, <limit> 122 // 2a 00 00 01 bcs ok 123 // e5 9f c? ?? ldr ip, [pc, <stack guard address>] 124 // e1 2f ff 3c blx ip 125 ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp); 126 ASSERT(Assembler::IsLdrPcImmediateOffset( 127 Assembler::instr_at(pc_after - 2 * kInstrSize))); 128 if (FLAG_count_based_interrupts) { 129 ASSERT_EQ(kBranchBeforeInterrupt, 130 Memory::int32_at(pc_after - 3 * kInstrSize)); 131 } else { 132 ASSERT_EQ(kBranchBeforeStackCheck, 133 Memory::int32_at(pc_after - 3 * kInstrSize)); 134 } 135 136 // We patch the code to the following form: 137 // e1 5d 00 0c cmp sp, <limit> 138 // e1 a0 00 00 mov r0, r0 (NOP) 139 // e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>] 140 // e1 2f ff 3c blx ip 141 // and overwrite the constant containing the 142 // address of the stack check stub. 143 144 // Replace conditional jump with NOP. 145 CodePatcher patcher(pc_after - 3 * kInstrSize, 1); 146 patcher.masm()->nop(); 147 148 // Replace the stack check address in the constant pool 149 // with the entry address of the replacement code. 150 uint32_t stack_check_address_offset = Memory::uint16_at(pc_after - 151 2 * kInstrSize) & 0xfff; 152 Address stack_check_address_pointer = pc_after + stack_check_address_offset; 153 ASSERT(Memory::uint32_at(stack_check_address_pointer) == 154 reinterpret_cast<uint32_t>(check_code->entry())); 155 Memory::uint32_at(stack_check_address_pointer) = 156 reinterpret_cast<uint32_t>(replacement_code->entry()); 157 158 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( 159 unoptimized_code, pc_after - 2 * kInstrSize, replacement_code); 160 } 161 162 163 void Deoptimizer::RevertStackCheckCodeAt(Code* unoptimized_code, 164 Address pc_after, 165 Code* check_code, 166 Code* replacement_code) { 167 const int kInstrSize = Assembler::kInstrSize; 168 ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp); 169 ASSERT(Assembler::IsLdrPcImmediateOffset( 170 Assembler::instr_at(pc_after - 2 * kInstrSize))); 171 172 // Replace NOP with conditional jump. 173 CodePatcher patcher(pc_after - 3 * kInstrSize, 1); 174 if (FLAG_count_based_interrupts) { 175 patcher.masm()->b(+16, pl); 176 ASSERT_EQ(kBranchBeforeInterrupt, 177 Memory::int32_at(pc_after - 3 * kInstrSize)); 178 } else { 179 patcher.masm()->b(+4, cs); 180 ASSERT_EQ(kBranchBeforeStackCheck, 181 Memory::int32_at(pc_after - 3 * kInstrSize)); 182 } 183 184 // Replace the stack check address in the constant pool 185 // with the entry address of the replacement code. 186 uint32_t stack_check_address_offset = Memory::uint16_at(pc_after - 187 2 * kInstrSize) & 0xfff; 188 Address stack_check_address_pointer = pc_after + stack_check_address_offset; 189 ASSERT(Memory::uint32_at(stack_check_address_pointer) == 190 reinterpret_cast<uint32_t>(replacement_code->entry())); 191 Memory::uint32_at(stack_check_address_pointer) = 192 reinterpret_cast<uint32_t>(check_code->entry()); 193 194 check_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( 195 unoptimized_code, pc_after - 2 * kInstrSize, check_code); 196 } 197 198 199 static 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 217 void 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 iterator.Skip(1); // Drop JS frame count. 233 ASSERT(count == 1); 234 USE(count); 235 236 opcode = static_cast<Translation::Opcode>(iterator.Next()); 237 USE(opcode); 238 ASSERT(Translation::JS_FRAME == opcode); 239 unsigned node_id = iterator.Next(); 240 USE(node_id); 241 ASSERT(node_id == ast_id); 242 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next())); 243 USE(function); 244 ASSERT(function == function_); 245 unsigned height = iterator.Next(); 246 unsigned height_in_bytes = height * kPointerSize; 247 USE(height_in_bytes); 248 249 unsigned fixed_size = ComputeFixedSize(function_); 250 unsigned input_frame_size = input_->GetFrameSize(); 251 ASSERT(fixed_size + height_in_bytes == input_frame_size); 252 253 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize; 254 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value(); 255 unsigned outgoing_size = outgoing_height * kPointerSize; 256 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size; 257 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call. 258 259 if (FLAG_trace_osr) { 260 PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ", 261 reinterpret_cast<intptr_t>(function_)); 262 function_->PrintName(); 263 PrintF(" => node=%u, frame=%d->%d]\n", 264 ast_id, 265 input_frame_size, 266 output_frame_size); 267 } 268 269 // There's only one output frame in the OSR case. 270 output_count_ = 1; 271 output_ = new FrameDescription*[1]; 272 output_[0] = new(output_frame_size) FrameDescription( 273 output_frame_size, function_); 274 output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT); 275 276 // Clear the incoming parameters in the optimized frame to avoid 277 // confusing the garbage collector. 278 unsigned output_offset = output_frame_size - kPointerSize; 279 int parameter_count = function_->shared()->formal_parameter_count() + 1; 280 for (int i = 0; i < parameter_count; ++i) { 281 output_[0]->SetFrameSlot(output_offset, 0); 282 output_offset -= kPointerSize; 283 } 284 285 // Translate the incoming parameters. This may overwrite some of the 286 // incoming argument slots we've just cleared. 287 int input_offset = input_frame_size - kPointerSize; 288 bool ok = true; 289 int limit = input_offset - (parameter_count * kPointerSize); 290 while (ok && input_offset > limit) { 291 ok = DoOsrTranslateCommand(&iterator, &input_offset); 292 } 293 294 // There are no translation commands for the caller's pc and fp, the 295 // context, and the function. Set them up explicitly. 296 for (int i = StandardFrameConstants::kCallerPCOffset; 297 ok && i >= StandardFrameConstants::kMarkerOffset; 298 i -= kPointerSize) { 299 uint32_t input_value = input_->GetFrameSlot(input_offset); 300 if (FLAG_trace_osr) { 301 const char* name = "UNKNOWN"; 302 switch (i) { 303 case StandardFrameConstants::kCallerPCOffset: 304 name = "caller's pc"; 305 break; 306 case StandardFrameConstants::kCallerFPOffset: 307 name = "fp"; 308 break; 309 case StandardFrameConstants::kContextOffset: 310 name = "context"; 311 break; 312 case StandardFrameConstants::kMarkerOffset: 313 name = "function"; 314 break; 315 } 316 PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n", 317 output_offset, 318 input_value, 319 input_offset, 320 name); 321 } 322 323 output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset)); 324 input_offset -= kPointerSize; 325 output_offset -= kPointerSize; 326 } 327 328 // Translate the rest of the frame. 329 while (ok && input_offset >= 0) { 330 ok = DoOsrTranslateCommand(&iterator, &input_offset); 331 } 332 333 // If translation of any command failed, continue using the input frame. 334 if (!ok) { 335 delete output_[0]; 336 output_[0] = input_; 337 output_[0]->SetPc(reinterpret_cast<uint32_t>(from_)); 338 } else { 339 // Set up the frame pointer and the context pointer. 340 output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code())); 341 output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code())); 342 343 unsigned pc_offset = data->OsrPcOffset()->value(); 344 uint32_t pc = reinterpret_cast<uint32_t>( 345 optimized_code_->entry() + pc_offset); 346 output_[0]->SetPc(pc); 347 } 348 Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR); 349 output_[0]->SetContinuation( 350 reinterpret_cast<uint32_t>(continuation->entry())); 351 352 if (FLAG_trace_osr) { 353 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ", 354 ok ? "finished" : "aborted", 355 reinterpret_cast<intptr_t>(function)); 356 function->PrintName(); 357 PrintF(" => pc=0x%0x]\n", output_[0]->GetPc()); 358 } 359 } 360 361 362 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, 363 int frame_index) { 364 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 365 unsigned height = iterator->Next(); 366 unsigned height_in_bytes = height * kPointerSize; 367 if (FLAG_trace_deopt) { 368 PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes); 369 } 370 371 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize; 372 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 373 374 // Allocate and store the output frame description. 375 FrameDescription* output_frame = 376 new(output_frame_size) FrameDescription(output_frame_size, function); 377 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR); 378 379 // Arguments adaptor can not be topmost or bottommost. 380 ASSERT(frame_index > 0 && frame_index < output_count_ - 1); 381 ASSERT(output_[frame_index] == NULL); 382 output_[frame_index] = output_frame; 383 384 // The top address of the frame is computed from the previous 385 // frame's top and this frame's size. 386 uint32_t top_address; 387 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 388 output_frame->SetTop(top_address); 389 390 // Compute the incoming parameter translation. 391 int parameter_count = height; 392 unsigned output_offset = output_frame_size; 393 for (int i = 0; i < parameter_count; ++i) { 394 output_offset -= kPointerSize; 395 DoTranslateCommand(iterator, frame_index, output_offset); 396 } 397 398 // Read caller's PC from the previous frame. 399 output_offset -= kPointerSize; 400 intptr_t callers_pc = output_[frame_index - 1]->GetPc(); 401 output_frame->SetFrameSlot(output_offset, callers_pc); 402 if (FLAG_trace_deopt) { 403 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n", 404 top_address + output_offset, output_offset, callers_pc); 405 } 406 407 // Read caller's FP from the previous frame, and set this frame's FP. 408 output_offset -= kPointerSize; 409 intptr_t value = output_[frame_index - 1]->GetFp(); 410 output_frame->SetFrameSlot(output_offset, value); 411 intptr_t fp_value = top_address + output_offset; 412 output_frame->SetFp(fp_value); 413 if (FLAG_trace_deopt) { 414 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n", 415 fp_value, output_offset, value); 416 } 417 418 // A marker value is used in place of the context. 419 output_offset -= kPointerSize; 420 intptr_t context = reinterpret_cast<intptr_t>( 421 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 422 output_frame->SetFrameSlot(output_offset, context); 423 if (FLAG_trace_deopt) { 424 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n", 425 top_address + output_offset, output_offset, context); 426 } 427 428 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME. 429 output_offset -= kPointerSize; 430 value = reinterpret_cast<intptr_t>(function); 431 output_frame->SetFrameSlot(output_offset, value); 432 if (FLAG_trace_deopt) { 433 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n", 434 top_address + output_offset, output_offset, value); 435 } 436 437 // Number of incoming arguments. 438 output_offset -= kPointerSize; 439 value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1)); 440 output_frame->SetFrameSlot(output_offset, value); 441 if (FLAG_trace_deopt) { 442 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n", 443 top_address + output_offset, output_offset, value, height - 1); 444 } 445 446 ASSERT(0 == output_offset); 447 448 Builtins* builtins = isolate_->builtins(); 449 Code* adaptor_trampoline = 450 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline); 451 uint32_t pc = reinterpret_cast<uint32_t>( 452 adaptor_trampoline->instruction_start() + 453 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value()); 454 output_frame->SetPc(pc); 455 } 456 457 458 void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator, 459 int frame_index) { 460 Builtins* builtins = isolate_->builtins(); 461 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); 462 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 463 unsigned height = iterator->Next(); 464 unsigned height_in_bytes = height * kPointerSize; 465 if (FLAG_trace_deopt) { 466 PrintF(" translating construct stub => height=%d\n", height_in_bytes); 467 } 468 469 unsigned fixed_frame_size = 8 * kPointerSize; 470 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 471 472 // Allocate and store the output frame description. 473 FrameDescription* output_frame = 474 new(output_frame_size) FrameDescription(output_frame_size, function); 475 output_frame->SetFrameType(StackFrame::CONSTRUCT); 476 477 // Construct stub can not be topmost or bottommost. 478 ASSERT(frame_index > 0 && frame_index < output_count_ - 1); 479 ASSERT(output_[frame_index] == NULL); 480 output_[frame_index] = output_frame; 481 482 // The top address of the frame is computed from the previous 483 // frame's top and this frame's size. 484 uint32_t top_address; 485 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 486 output_frame->SetTop(top_address); 487 488 // Compute the incoming parameter translation. 489 int parameter_count = height; 490 unsigned output_offset = output_frame_size; 491 for (int i = 0; i < parameter_count; ++i) { 492 output_offset -= kPointerSize; 493 DoTranslateCommand(iterator, frame_index, output_offset); 494 } 495 496 // Read caller's PC from the previous frame. 497 output_offset -= kPointerSize; 498 intptr_t callers_pc = output_[frame_index - 1]->GetPc(); 499 output_frame->SetFrameSlot(output_offset, callers_pc); 500 if (FLAG_trace_deopt) { 501 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n", 502 top_address + output_offset, output_offset, callers_pc); 503 } 504 505 // Read caller's FP from the previous frame, and set this frame's FP. 506 output_offset -= kPointerSize; 507 intptr_t value = output_[frame_index - 1]->GetFp(); 508 output_frame->SetFrameSlot(output_offset, value); 509 intptr_t fp_value = top_address + output_offset; 510 output_frame->SetFp(fp_value); 511 if (FLAG_trace_deopt) { 512 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n", 513 fp_value, output_offset, value); 514 } 515 516 // The context can be gotten from the previous frame. 517 output_offset -= kPointerSize; 518 value = output_[frame_index - 1]->GetContext(); 519 output_frame->SetFrameSlot(output_offset, value); 520 if (FLAG_trace_deopt) { 521 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n", 522 top_address + output_offset, output_offset, value); 523 } 524 525 // A marker value is used in place of the function. 526 output_offset -= kPointerSize; 527 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT)); 528 output_frame->SetFrameSlot(output_offset, value); 529 if (FLAG_trace_deopt) { 530 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function (construct sentinel)\n", 531 top_address + output_offset, output_offset, value); 532 } 533 534 // The output frame reflects a JSConstructStubGeneric frame. 535 output_offset -= kPointerSize; 536 value = reinterpret_cast<intptr_t>(construct_stub); 537 output_frame->SetFrameSlot(output_offset, value); 538 if (FLAG_trace_deopt) { 539 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; code object\n", 540 top_address + output_offset, output_offset, value); 541 } 542 543 // Number of incoming arguments. 544 output_offset -= kPointerSize; 545 value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1)); 546 output_frame->SetFrameSlot(output_offset, value); 547 if (FLAG_trace_deopt) { 548 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n", 549 top_address + output_offset, output_offset, value, height - 1); 550 } 551 552 // Constructor function being invoked by the stub. 553 output_offset -= kPointerSize; 554 value = reinterpret_cast<intptr_t>(function); 555 output_frame->SetFrameSlot(output_offset, value); 556 if (FLAG_trace_deopt) { 557 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; constructor function\n", 558 top_address + output_offset, output_offset, value); 559 } 560 561 // The newly allocated object was passed as receiver in the artificial 562 // constructor stub environment created by HEnvironment::CopyForInlining(). 563 output_offset -= kPointerSize; 564 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize); 565 output_frame->SetFrameSlot(output_offset, value); 566 if (FLAG_trace_deopt) { 567 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; allocated receiver\n", 568 top_address + output_offset, output_offset, value); 569 } 570 571 ASSERT(0 == output_offset); 572 573 uint32_t pc = reinterpret_cast<uint32_t>( 574 construct_stub->instruction_start() + 575 isolate_->heap()->construct_stub_deopt_pc_offset()->value()); 576 output_frame->SetPc(pc); 577 } 578 579 580 // This code is very similar to ia32 code, but relies on register names (fp, sp) 581 // and how the frame is laid out. 582 void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator, 583 int frame_index) { 584 // Read the ast node id, function, and frame height for this output frame. 585 int node_id = iterator->Next(); 586 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 587 unsigned height = iterator->Next(); 588 unsigned height_in_bytes = height * kPointerSize; 589 if (FLAG_trace_deopt) { 590 PrintF(" translating "); 591 function->PrintName(); 592 PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes); 593 } 594 595 // The 'fixed' part of the frame consists of the incoming parameters and 596 // the part described by JavaScriptFrameConstants. 597 unsigned fixed_frame_size = ComputeFixedSize(function); 598 unsigned input_frame_size = input_->GetFrameSize(); 599 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 600 601 // Allocate and store the output frame description. 602 FrameDescription* output_frame = 603 new(output_frame_size) FrameDescription(output_frame_size, function); 604 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); 605 606 bool is_bottommost = (0 == frame_index); 607 bool is_topmost = (output_count_ - 1 == frame_index); 608 ASSERT(frame_index >= 0 && frame_index < output_count_); 609 ASSERT(output_[frame_index] == NULL); 610 output_[frame_index] = output_frame; 611 612 // The top address for the bottommost output frame can be computed from 613 // the input frame pointer and the output frame's height. For all 614 // subsequent output frames, it can be computed from the previous one's 615 // top address and the current frame's size. 616 uint32_t top_address; 617 if (is_bottommost) { 618 // 2 = context and function in the frame. 619 top_address = 620 input_->GetRegister(fp.code()) - (2 * kPointerSize) - height_in_bytes; 621 } else { 622 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 623 } 624 output_frame->SetTop(top_address); 625 626 // Compute the incoming parameter translation. 627 int parameter_count = function->shared()->formal_parameter_count() + 1; 628 unsigned output_offset = output_frame_size; 629 unsigned input_offset = input_frame_size; 630 for (int i = 0; i < parameter_count; ++i) { 631 output_offset -= kPointerSize; 632 DoTranslateCommand(iterator, frame_index, output_offset); 633 } 634 input_offset -= (parameter_count * kPointerSize); 635 636 // There are no translation commands for the caller's pc and fp, the 637 // context, and the function. Synthesize their values and set them up 638 // explicitly. 639 // 640 // The caller's pc for the bottommost output frame is the same as in the 641 // input frame. For all subsequent output frames, it can be read from the 642 // previous one. This frame's pc can be computed from the non-optimized 643 // function code and AST id of the bailout. 644 output_offset -= kPointerSize; 645 input_offset -= kPointerSize; 646 intptr_t value; 647 if (is_bottommost) { 648 value = input_->GetFrameSlot(input_offset); 649 } else { 650 value = output_[frame_index - 1]->GetPc(); 651 } 652 output_frame->SetFrameSlot(output_offset, value); 653 if (FLAG_trace_deopt) { 654 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n", 655 top_address + output_offset, output_offset, value); 656 } 657 658 // The caller's frame pointer for the bottommost output frame is the same 659 // as in the input frame. For all subsequent output frames, it can be 660 // read from the previous one. Also compute and set this frame's frame 661 // pointer. 662 output_offset -= kPointerSize; 663 input_offset -= kPointerSize; 664 if (is_bottommost) { 665 value = input_->GetFrameSlot(input_offset); 666 } else { 667 value = output_[frame_index - 1]->GetFp(); 668 } 669 output_frame->SetFrameSlot(output_offset, value); 670 intptr_t fp_value = top_address + output_offset; 671 ASSERT(!is_bottommost || input_->GetRegister(fp.code()) == fp_value); 672 output_frame->SetFp(fp_value); 673 if (is_topmost) { 674 output_frame->SetRegister(fp.code(), fp_value); 675 } 676 if (FLAG_trace_deopt) { 677 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n", 678 fp_value, output_offset, value); 679 } 680 681 // For the bottommost output frame the context can be gotten from the input 682 // frame. For all subsequent output frames it can be gotten from the function 683 // so long as we don't inline functions that need local contexts. 684 output_offset -= kPointerSize; 685 input_offset -= kPointerSize; 686 if (is_bottommost) { 687 value = input_->GetFrameSlot(input_offset); 688 } else { 689 value = reinterpret_cast<intptr_t>(function->context()); 690 } 691 output_frame->SetFrameSlot(output_offset, value); 692 output_frame->SetContext(value); 693 if (is_topmost) output_frame->SetRegister(cp.code(), value); 694 if (FLAG_trace_deopt) { 695 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n", 696 top_address + output_offset, output_offset, value); 697 } 698 699 // The function was mentioned explicitly in the BEGIN_FRAME. 700 output_offset -= kPointerSize; 701 input_offset -= kPointerSize; 702 value = reinterpret_cast<uint32_t>(function); 703 // The function for the bottommost output frame should also agree with the 704 // input frame. 705 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 706 output_frame->SetFrameSlot(output_offset, value); 707 if (FLAG_trace_deopt) { 708 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n", 709 top_address + output_offset, output_offset, value); 710 } 711 712 // Translate the rest of the frame. 713 for (unsigned i = 0; i < height; ++i) { 714 output_offset -= kPointerSize; 715 DoTranslateCommand(iterator, frame_index, output_offset); 716 } 717 ASSERT(0 == output_offset); 718 719 // Compute this frame's PC, state, and continuation. 720 Code* non_optimized_code = function->shared()->code(); 721 FixedArray* raw_data = non_optimized_code->deoptimization_data(); 722 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); 723 Address start = non_optimized_code->instruction_start(); 724 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); 725 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); 726 uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset); 727 output_frame->SetPc(pc_value); 728 if (is_topmost) { 729 output_frame->SetRegister(pc.code(), pc_value); 730 } 731 732 FullCodeGenerator::State state = 733 FullCodeGenerator::StateField::decode(pc_and_state); 734 output_frame->SetState(Smi::FromInt(state)); 735 736 737 // Set the continuation for the topmost frame. 738 if (is_topmost && bailout_type_ != DEBUGGER) { 739 Builtins* builtins = isolate_->builtins(); 740 Code* continuation = (bailout_type_ == EAGER) 741 ? builtins->builtin(Builtins::kNotifyDeoptimized) 742 : builtins->builtin(Builtins::kNotifyLazyDeoptimized); 743 output_frame->SetContinuation( 744 reinterpret_cast<uint32_t>(continuation->entry())); 745 } 746 } 747 748 749 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { 750 // Set the register values. The values are not important as there are no 751 // callee saved registers in JavaScript frames, so all registers are 752 // spilled. Registers fp and sp are set to the correct values though. 753 754 for (int i = 0; i < Register::kNumRegisters; i++) { 755 input_->SetRegister(i, i * 4); 756 } 757 input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp())); 758 input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp())); 759 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) { 760 input_->SetDoubleRegister(i, 0.0); 761 } 762 763 // Fill the frame content from the actual data on the frame. 764 for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) { 765 input_->SetFrameSlot(i, Memory::uint32_at(tos + i)); 766 } 767 } 768 769 770 #define __ masm()-> 771 772 // This code tries to be close to ia32 code so that any changes can be 773 // easily ported. 774 void Deoptimizer::EntryGenerator::Generate() { 775 GeneratePrologue(); 776 777 Isolate* isolate = masm()->isolate(); 778 779 CpuFeatures::Scope scope(VFP3); 780 // Save all general purpose registers before messing with them. 781 const int kNumberOfRegisters = Register::kNumRegisters; 782 783 // Everything but pc, lr and ip which will be saved but not restored. 784 RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit(); 785 786 const int kDoubleRegsSize = 787 kDoubleSize * DwVfpRegister::kNumAllocatableRegisters; 788 789 // Save all VFP registers before messing with them. 790 DwVfpRegister first = DwVfpRegister::FromAllocationIndex(0); 791 DwVfpRegister last = 792 DwVfpRegister::FromAllocationIndex( 793 DwVfpRegister::kNumAllocatableRegisters - 1); 794 ASSERT(last.code() > first.code()); 795 ASSERT((last.code() - first.code()) == 796 (DwVfpRegister::kNumAllocatableRegisters - 1)); 797 #ifdef DEBUG 798 for (int i = 0; i <= (DwVfpRegister::kNumAllocatableRegisters - 1); i++) { 799 ASSERT((DwVfpRegister::FromAllocationIndex(i).code() <= last.code()) && 800 (DwVfpRegister::FromAllocationIndex(i).code() >= first.code())); 801 } 802 #endif 803 __ vstm(db_w, sp, first, last); 804 805 // Push all 16 registers (needed to populate FrameDescription::registers_). 806 // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps 807 // handle this a bit differently. 808 __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit()); 809 810 const int kSavedRegistersAreaSize = 811 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; 812 813 // Get the bailout id from the stack. 814 __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize)); 815 816 // Get the address of the location in the code object if possible (r3) (return 817 // address for lazy deoptimization) and compute the fp-to-sp delta in 818 // register r4. 819 if (type() == EAGER) { 820 __ mov(r3, Operand(0)); 821 // Correct one word for bailout id. 822 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 823 } else if (type() == OSR) { 824 __ mov(r3, lr); 825 // Correct one word for bailout id. 826 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 827 } else { 828 __ mov(r3, lr); 829 // Correct two words for bailout id and return address. 830 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize))); 831 } 832 __ sub(r4, fp, r4); 833 834 // Allocate a new deoptimizer object. 835 // Pass four arguments in r0 to r3 and fifth argument on stack. 836 __ PrepareCallCFunction(6, r5); 837 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 838 __ mov(r1, Operand(type())); // bailout type, 839 // r2: bailout id already loaded. 840 // r3: code address or 0 already loaded. 841 __ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta. 842 __ mov(r5, Operand(ExternalReference::isolate_address())); 843 __ str(r5, MemOperand(sp, 1 * kPointerSize)); // Isolate. 844 // Call Deoptimizer::New(). 845 { 846 AllowExternalCallThatCantCauseGC scope(masm()); 847 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6); 848 } 849 850 // Preserve "deoptimizer" object in register r0 and get the input 851 // frame descriptor pointer to r1 (deoptimizer->input_); 852 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset())); 853 854 // Copy core registers into FrameDescription::registers_[kNumRegisters]. 855 ASSERT(Register::kNumRegisters == kNumberOfRegisters); 856 for (int i = 0; i < kNumberOfRegisters; i++) { 857 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 858 __ ldr(r2, MemOperand(sp, i * kPointerSize)); 859 __ str(r2, MemOperand(r1, offset)); 860 } 861 862 // Copy VFP registers to 863 // double_registers_[DoubleRegister::kNumAllocatableRegisters] 864 int double_regs_offset = FrameDescription::double_registers_offset(); 865 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; ++i) { 866 int dst_offset = i * kDoubleSize + double_regs_offset; 867 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize; 868 __ vldr(d0, sp, src_offset); 869 __ vstr(d0, r1, dst_offset); 870 } 871 872 // Remove the bailout id, eventually return address, and the saved registers 873 // from the stack. 874 if (type() == EAGER || type() == OSR) { 875 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 876 } else { 877 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (2 * kPointerSize))); 878 } 879 880 // Compute a pointer to the unwinding limit in register r2; that is 881 // the first stack slot not part of the input frame. 882 __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset())); 883 __ add(r2, r2, sp); 884 885 // Unwind the stack down to - but not including - the unwinding 886 // limit and copy the contents of the activation frame to the input 887 // frame description. 888 __ add(r3, r1, Operand(FrameDescription::frame_content_offset())); 889 Label pop_loop; 890 __ bind(&pop_loop); 891 __ pop(r4); 892 __ str(r4, MemOperand(r3, 0)); 893 __ add(r3, r3, Operand(sizeof(uint32_t))); 894 __ cmp(r2, sp); 895 __ b(ne, &pop_loop); 896 897 // Compute the output frame in the deoptimizer. 898 __ push(r0); // Preserve deoptimizer object across call. 899 // r0: deoptimizer object; r1: scratch. 900 __ PrepareCallCFunction(1, r1); 901 // Call Deoptimizer::ComputeOutputFrames(). 902 { 903 AllowExternalCallThatCantCauseGC scope(masm()); 904 __ CallCFunction( 905 ExternalReference::compute_output_frames_function(isolate), 1); 906 } 907 __ pop(r0); // Restore deoptimizer object (class Deoptimizer). 908 909 // Replace the current (input) frame with the output frames. 910 Label outer_push_loop, inner_push_loop; 911 // Outer loop state: r0 = current "FrameDescription** output_", 912 // r1 = one past the last FrameDescription**. 913 __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset())); 914 __ ldr(r0, MemOperand(r0, Deoptimizer::output_offset())); // r0 is output_. 915 __ add(r1, r0, Operand(r1, LSL, 2)); 916 __ bind(&outer_push_loop); 917 // Inner loop state: r2 = current FrameDescription*, r3 = loop index. 918 __ ldr(r2, MemOperand(r0, 0)); // output_[ix] 919 __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset())); 920 __ bind(&inner_push_loop); 921 __ sub(r3, r3, Operand(sizeof(uint32_t))); 922 __ add(r6, r2, Operand(r3)); 923 __ ldr(r7, MemOperand(r6, FrameDescription::frame_content_offset())); 924 __ push(r7); 925 __ cmp(r3, Operand(0)); 926 __ b(ne, &inner_push_loop); // test for gt? 927 __ add(r0, r0, Operand(kPointerSize)); 928 __ cmp(r0, r1); 929 __ b(lt, &outer_push_loop); 930 931 // Push state, pc, and continuation from the last output frame. 932 if (type() != OSR) { 933 __ ldr(r6, MemOperand(r2, FrameDescription::state_offset())); 934 __ push(r6); 935 } 936 937 __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset())); 938 __ push(r6); 939 __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset())); 940 __ push(r6); 941 942 // Push the registers from the last output frame. 943 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 944 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 945 __ ldr(r6, MemOperand(r2, offset)); 946 __ push(r6); 947 } 948 949 // Restore the registers from the stack. 950 __ ldm(ia_w, sp, restored_regs); // all but pc registers. 951 __ pop(ip); // remove sp 952 __ pop(ip); // remove lr 953 954 __ InitializeRootRegister(); 955 956 __ pop(ip); // remove pc 957 __ pop(r7); // get continuation, leave pc on stack 958 __ pop(lr); 959 __ Jump(r7); 960 __ stop("Unreachable."); 961 } 962 963 964 void Deoptimizer::TableEntryGenerator::GeneratePrologue() { 965 // Create a sequence of deoptimization entries. Note that any 966 // registers may be still live. 967 Label done; 968 for (int i = 0; i < count(); i++) { 969 int start = masm()->pc_offset(); 970 USE(start); 971 if (type() == EAGER) { 972 __ nop(); 973 } else { 974 // Emulate ia32 like call by pushing return address to stack. 975 __ push(lr); 976 } 977 __ mov(ip, Operand(i)); 978 __ push(ip); 979 __ b(&done); 980 ASSERT(masm()->pc_offset() - start == table_entry_size_); 981 } 982 __ bind(&done); 983 } 984 985 #undef __ 986 987 } } // namespace v8::internal 988