1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/deoptimizer.h" 6 7 #include "src/accessors.h" 8 #include "src/ast/prettyprinter.h" 9 #include "src/codegen.h" 10 #include "src/disasm.h" 11 #include "src/frames-inl.h" 12 #include "src/full-codegen/full-codegen.h" 13 #include "src/global-handles.h" 14 #include "src/macro-assembler.h" 15 #include "src/profiler/cpu-profiler.h" 16 #include "src/v8.h" 17 18 19 namespace v8 { 20 namespace internal { 21 22 static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) { 23 return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(), 24 base::OS::CommitPageSize(), 25 #if defined(__native_client__) 26 // The Native Client port of V8 uses an interpreter, 27 // so code pages don't need PROT_EXEC. 28 NOT_EXECUTABLE, 29 #else 30 EXECUTABLE, 31 #endif 32 NULL); 33 } 34 35 36 DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator) 37 : allocator_(allocator), 38 deoptimized_frame_info_(NULL), 39 current_(NULL) { 40 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) { 41 deopt_entry_code_entries_[i] = -1; 42 deopt_entry_code_[i] = AllocateCodeChunk(allocator); 43 } 44 } 45 46 47 DeoptimizerData::~DeoptimizerData() { 48 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) { 49 allocator_->Free(deopt_entry_code_[i]); 50 deopt_entry_code_[i] = NULL; 51 } 52 } 53 54 55 void DeoptimizerData::Iterate(ObjectVisitor* v) { 56 if (deoptimized_frame_info_ != NULL) { 57 deoptimized_frame_info_->Iterate(v); 58 } 59 } 60 61 62 Code* Deoptimizer::FindDeoptimizingCode(Address addr) { 63 if (function_->IsHeapObject()) { 64 // Search all deoptimizing code in the native context of the function. 65 Context* native_context = function_->context()->native_context(); 66 Object* element = native_context->DeoptimizedCodeListHead(); 67 while (!element->IsUndefined()) { 68 Code* code = Code::cast(element); 69 CHECK(code->kind() == Code::OPTIMIZED_FUNCTION); 70 if (code->contains(addr)) return code; 71 element = code->next_code_link(); 72 } 73 } 74 return NULL; 75 } 76 77 78 // We rely on this function not causing a GC. It is called from generated code 79 // without having a real stack frame in place. 80 Deoptimizer* Deoptimizer::New(JSFunction* function, 81 BailoutType type, 82 unsigned bailout_id, 83 Address from, 84 int fp_to_sp_delta, 85 Isolate* isolate) { 86 Deoptimizer* deoptimizer = new Deoptimizer(isolate, 87 function, 88 type, 89 bailout_id, 90 from, 91 fp_to_sp_delta, 92 NULL); 93 CHECK(isolate->deoptimizer_data()->current_ == NULL); 94 isolate->deoptimizer_data()->current_ = deoptimizer; 95 return deoptimizer; 96 } 97 98 99 // No larger than 2K on all platforms 100 static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB; 101 102 103 size_t Deoptimizer::GetMaxDeoptTableSize() { 104 int entries_size = 105 Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_; 106 int commit_page_size = static_cast<int>(base::OS::CommitPageSize()); 107 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) / 108 commit_page_size) + 1; 109 return static_cast<size_t>(commit_page_size * page_count); 110 } 111 112 113 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { 114 Deoptimizer* result = isolate->deoptimizer_data()->current_; 115 CHECK_NOT_NULL(result); 116 result->DeleteFrameDescriptions(); 117 isolate->deoptimizer_data()->current_ = NULL; 118 return result; 119 } 120 121 122 int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) { 123 if (jsframe_index == 0) return 0; 124 125 int frame_index = 0; 126 while (jsframe_index >= 0) { 127 FrameDescription* frame = output_[frame_index]; 128 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) { 129 jsframe_index--; 130 } 131 frame_index++; 132 } 133 134 return frame_index - 1; 135 } 136 137 138 DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame( 139 JavaScriptFrame* frame, 140 int jsframe_index, 141 Isolate* isolate) { 142 CHECK(frame->is_optimized()); 143 CHECK(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL); 144 145 // Get the function and code from the frame. 146 JSFunction* function = frame->function(); 147 Code* code = frame->LookupCode(); 148 149 // Locate the deoptimization point in the code. As we are at a call the 150 // return address must be at a place in the code with deoptimization support. 151 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc()); 152 int deoptimization_index = safepoint_entry.deoptimization_index(); 153 CHECK_NE(deoptimization_index, Safepoint::kNoDeoptimizationIndex); 154 155 // Always use the actual stack slots when calculating the fp to sp 156 // delta adding two for the function and context. 157 unsigned stack_slots = code->stack_slots(); 158 unsigned arguments_stack_height = 159 Deoptimizer::ComputeOutgoingArgumentSize(code, deoptimization_index); 160 unsigned fp_to_sp_delta = (stack_slots * kPointerSize) + 161 StandardFrameConstants::kFixedFrameSizeFromFp + 162 arguments_stack_height; 163 164 Deoptimizer* deoptimizer = new Deoptimizer(isolate, 165 function, 166 Deoptimizer::DEBUGGER, 167 deoptimization_index, 168 frame->pc(), 169 fp_to_sp_delta, 170 code); 171 Address tos = frame->fp() - fp_to_sp_delta; 172 deoptimizer->FillInputFrame(tos, frame); 173 174 // Calculate the output frames. 175 Deoptimizer::ComputeOutputFrames(deoptimizer); 176 177 // Create the GC safe output frame information and register it for GC 178 // handling. 179 CHECK_LT(jsframe_index, deoptimizer->jsframe_count()); 180 181 // Convert JS frame index into frame index. 182 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index); 183 184 bool has_arguments_adaptor = 185 frame_index > 0 && 186 deoptimizer->output_[frame_index - 1]->GetFrameType() == 187 StackFrame::ARGUMENTS_ADAPTOR; 188 189 int construct_offset = has_arguments_adaptor ? 2 : 1; 190 bool has_construct_stub = 191 frame_index >= construct_offset && 192 deoptimizer->output_[frame_index - construct_offset]->GetFrameType() == 193 StackFrame::CONSTRUCT; 194 195 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer, 196 frame_index, 197 has_arguments_adaptor, 198 has_construct_stub); 199 isolate->deoptimizer_data()->deoptimized_frame_info_ = info; 200 201 // Done with the GC-unsafe frame descriptions. This re-enables allocation. 202 deoptimizer->DeleteFrameDescriptions(); 203 204 // Allocate a heap number for the doubles belonging to this frame. 205 deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame( 206 frame_index, info->parameters_count(), info->expression_count(), info); 207 208 // Finished using the deoptimizer instance. 209 delete deoptimizer; 210 211 return info; 212 } 213 214 215 void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info, 216 Isolate* isolate) { 217 CHECK_EQ(isolate->deoptimizer_data()->deoptimized_frame_info_, info); 218 delete info; 219 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL; 220 } 221 222 223 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, 224 int count, 225 BailoutType type) { 226 TableEntryGenerator generator(masm, type, count); 227 generator.Generate(); 228 } 229 230 231 void Deoptimizer::VisitAllOptimizedFunctionsForContext( 232 Context* context, OptimizedFunctionVisitor* visitor) { 233 DisallowHeapAllocation no_allocation; 234 235 CHECK(context->IsNativeContext()); 236 237 visitor->EnterContext(context); 238 239 // Visit the list of optimized functions, removing elements that 240 // no longer refer to optimized code. 241 JSFunction* prev = NULL; 242 Object* element = context->OptimizedFunctionsListHead(); 243 while (!element->IsUndefined()) { 244 JSFunction* function = JSFunction::cast(element); 245 Object* next = function->next_function_link(); 246 if (function->code()->kind() != Code::OPTIMIZED_FUNCTION || 247 (visitor->VisitFunction(function), 248 function->code()->kind() != Code::OPTIMIZED_FUNCTION)) { 249 // The function no longer refers to optimized code, or the visitor 250 // changed the code to which it refers to no longer be optimized code. 251 // Remove the function from this list. 252 if (prev != NULL) { 253 prev->set_next_function_link(next, UPDATE_WEAK_WRITE_BARRIER); 254 } else { 255 context->SetOptimizedFunctionsListHead(next); 256 } 257 // The visitor should not alter the link directly. 258 CHECK_EQ(function->next_function_link(), next); 259 // Set the next function link to undefined to indicate it is no longer 260 // in the optimized functions list. 261 function->set_next_function_link(context->GetHeap()->undefined_value(), 262 SKIP_WRITE_BARRIER); 263 } else { 264 // The visitor should not alter the link directly. 265 CHECK_EQ(function->next_function_link(), next); 266 // preserve this element. 267 prev = function; 268 } 269 element = next; 270 } 271 272 visitor->LeaveContext(context); 273 } 274 275 276 void Deoptimizer::VisitAllOptimizedFunctions( 277 Isolate* isolate, 278 OptimizedFunctionVisitor* visitor) { 279 DisallowHeapAllocation no_allocation; 280 281 // Run through the list of all native contexts. 282 Object* context = isolate->heap()->native_contexts_list(); 283 while (!context->IsUndefined()) { 284 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor); 285 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); 286 } 287 } 288 289 290 // Unlink functions referring to code marked for deoptimization, then move 291 // marked code from the optimized code list to the deoptimized code list, 292 // and patch code for lazy deopt. 293 void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) { 294 DisallowHeapAllocation no_allocation; 295 296 // A "closure" that unlinks optimized code that is going to be 297 // deoptimized from the functions that refer to it. 298 class SelectedCodeUnlinker: public OptimizedFunctionVisitor { 299 public: 300 virtual void EnterContext(Context* context) { } // Don't care. 301 virtual void LeaveContext(Context* context) { } // Don't care. 302 virtual void VisitFunction(JSFunction* function) { 303 Code* code = function->code(); 304 if (!code->marked_for_deoptimization()) return; 305 306 // Unlink this function and evict from optimized code map. 307 SharedFunctionInfo* shared = function->shared(); 308 function->set_code(shared->code()); 309 310 if (FLAG_trace_deopt) { 311 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer()); 312 PrintF(scope.file(), "[deoptimizer unlinked: "); 313 function->PrintName(scope.file()); 314 PrintF(scope.file(), 315 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); 316 } 317 } 318 }; 319 320 // Unlink all functions that refer to marked code. 321 SelectedCodeUnlinker unlinker; 322 VisitAllOptimizedFunctionsForContext(context, &unlinker); 323 324 Isolate* isolate = context->GetHeap()->isolate(); 325 #ifdef DEBUG 326 Code* topmost_optimized_code = NULL; 327 bool safe_to_deopt_topmost_optimized_code = false; 328 // Make sure all activations of optimized code can deopt at their current PC. 329 // The topmost optimized code has special handling because it cannot be 330 // deoptimized due to weak object dependency. 331 for (StackFrameIterator it(isolate, isolate->thread_local_top()); 332 !it.done(); it.Advance()) { 333 StackFrame::Type type = it.frame()->type(); 334 if (type == StackFrame::OPTIMIZED) { 335 Code* code = it.frame()->LookupCode(); 336 JSFunction* function = 337 static_cast<OptimizedFrame*>(it.frame())->function(); 338 if (FLAG_trace_deopt) { 339 CodeTracer::Scope scope(isolate->GetCodeTracer()); 340 PrintF(scope.file(), "[deoptimizer found activation of function: "); 341 function->PrintName(scope.file()); 342 PrintF(scope.file(), 343 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); 344 } 345 SafepointEntry safepoint = code->GetSafepointEntry(it.frame()->pc()); 346 int deopt_index = safepoint.deoptimization_index(); 347 // Turbofan deopt is checked when we are patching addresses on stack. 348 bool turbofanned = code->is_turbofanned() && 349 function->shared()->asm_function() && 350 !FLAG_turbo_asm_deoptimization; 351 bool safe_to_deopt = 352 deopt_index != Safepoint::kNoDeoptimizationIndex || turbofanned; 353 CHECK(topmost_optimized_code == NULL || safe_to_deopt || turbofanned); 354 if (topmost_optimized_code == NULL) { 355 topmost_optimized_code = code; 356 safe_to_deopt_topmost_optimized_code = safe_to_deopt; 357 } 358 } 359 } 360 #endif 361 362 // Move marked code from the optimized code list to the deoptimized 363 // code list, collecting them into a ZoneList. 364 Zone zone; 365 ZoneList<Code*> codes(10, &zone); 366 367 // Walk over all optimized code objects in this native context. 368 Code* prev = NULL; 369 Object* element = context->OptimizedCodeListHead(); 370 while (!element->IsUndefined()) { 371 Code* code = Code::cast(element); 372 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION); 373 Object* next = code->next_code_link(); 374 375 if (code->marked_for_deoptimization()) { 376 // Put the code into the list for later patching. 377 codes.Add(code, &zone); 378 379 if (prev != NULL) { 380 // Skip this code in the optimized code list. 381 prev->set_next_code_link(next); 382 } else { 383 // There was no previous node, the next node is the new head. 384 context->SetOptimizedCodeListHead(next); 385 } 386 387 // Move the code to the _deoptimized_ code list. 388 code->set_next_code_link(context->DeoptimizedCodeListHead()); 389 context->SetDeoptimizedCodeListHead(code); 390 } else { 391 // Not marked; preserve this element. 392 prev = code; 393 } 394 element = next; 395 } 396 397 // TODO(titzer): we need a handle scope only because of the macro assembler, 398 // which is only used in EnsureCodeForDeoptimizationEntry. 399 HandleScope scope(isolate); 400 401 // Now patch all the codes for deoptimization. 402 for (int i = 0; i < codes.length(); i++) { 403 #ifdef DEBUG 404 if (codes[i] == topmost_optimized_code) { 405 DCHECK(safe_to_deopt_topmost_optimized_code); 406 } 407 #endif 408 // It is finally time to die, code object. 409 410 // Remove the code from optimized code map. 411 DeoptimizationInputData* deopt_data = 412 DeoptimizationInputData::cast(codes[i]->deoptimization_data()); 413 SharedFunctionInfo* shared = 414 SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo()); 415 shared->EvictFromOptimizedCodeMap(codes[i], "deoptimized code"); 416 417 // Do platform-specific patching to force any activations to lazy deopt. 418 PatchCodeForDeoptimization(isolate, codes[i]); 419 420 // We might be in the middle of incremental marking with compaction. 421 // Tell collector to treat this code object in a special way and 422 // ignore all slots that might have been recorded on it. 423 isolate->heap()->mark_compact_collector()->InvalidateCode(codes[i]); 424 } 425 } 426 427 428 void Deoptimizer::DeoptimizeAll(Isolate* isolate) { 429 if (FLAG_trace_deopt) { 430 CodeTracer::Scope scope(isolate->GetCodeTracer()); 431 PrintF(scope.file(), "[deoptimize all code in all contexts]\n"); 432 } 433 DisallowHeapAllocation no_allocation; 434 // For all contexts, mark all code, then deoptimize. 435 Object* context = isolate->heap()->native_contexts_list(); 436 while (!context->IsUndefined()) { 437 Context* native_context = Context::cast(context); 438 MarkAllCodeForContext(native_context); 439 DeoptimizeMarkedCodeForContext(native_context); 440 context = native_context->get(Context::NEXT_CONTEXT_LINK); 441 } 442 } 443 444 445 void Deoptimizer::DeoptimizeMarkedCode(Isolate* isolate) { 446 if (FLAG_trace_deopt) { 447 CodeTracer::Scope scope(isolate->GetCodeTracer()); 448 PrintF(scope.file(), "[deoptimize marked code in all contexts]\n"); 449 } 450 DisallowHeapAllocation no_allocation; 451 // For all contexts, deoptimize code already marked. 452 Object* context = isolate->heap()->native_contexts_list(); 453 while (!context->IsUndefined()) { 454 Context* native_context = Context::cast(context); 455 DeoptimizeMarkedCodeForContext(native_context); 456 context = native_context->get(Context::NEXT_CONTEXT_LINK); 457 } 458 } 459 460 461 void Deoptimizer::MarkAllCodeForContext(Context* context) { 462 Object* element = context->OptimizedCodeListHead(); 463 while (!element->IsUndefined()) { 464 Code* code = Code::cast(element); 465 CHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION); 466 code->set_marked_for_deoptimization(true); 467 element = code->next_code_link(); 468 } 469 } 470 471 472 void Deoptimizer::DeoptimizeFunction(JSFunction* function) { 473 Code* code = function->code(); 474 if (code->kind() == Code::OPTIMIZED_FUNCTION) { 475 // Mark the code for deoptimization and unlink any functions that also 476 // refer to that code. The code cannot be shared across native contexts, 477 // so we only need to search one. 478 code->set_marked_for_deoptimization(true); 479 DeoptimizeMarkedCodeForContext(function->context()->native_context()); 480 } 481 } 482 483 484 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) { 485 deoptimizer->DoComputeOutputFrames(); 486 } 487 488 489 bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type, 490 StackFrame::Type frame_type) { 491 switch (deopt_type) { 492 case EAGER: 493 case SOFT: 494 case LAZY: 495 case DEBUGGER: 496 return (frame_type == StackFrame::STUB) 497 ? FLAG_trace_stub_failures 498 : FLAG_trace_deopt; 499 } 500 FATAL("Unsupported deopt type"); 501 return false; 502 } 503 504 505 const char* Deoptimizer::MessageFor(BailoutType type) { 506 switch (type) { 507 case EAGER: return "eager"; 508 case SOFT: return "soft"; 509 case LAZY: return "lazy"; 510 case DEBUGGER: return "debugger"; 511 } 512 FATAL("Unsupported deopt type"); 513 return NULL; 514 } 515 516 517 Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function, 518 BailoutType type, unsigned bailout_id, Address from, 519 int fp_to_sp_delta, Code* optimized_code) 520 : isolate_(isolate), 521 function_(function), 522 bailout_id_(bailout_id), 523 bailout_type_(type), 524 from_(from), 525 fp_to_sp_delta_(fp_to_sp_delta), 526 has_alignment_padding_(0), 527 input_(nullptr), 528 output_count_(0), 529 jsframe_count_(0), 530 output_(nullptr), 531 trace_scope_(nullptr) { 532 // For COMPILED_STUBs called from builtins, the function pointer is a SMI 533 // indicating an internal frame. 534 if (function->IsSmi()) { 535 function = nullptr; 536 } 537 DCHECK(from != nullptr); 538 if (function != nullptr && function->IsOptimized()) { 539 function->shared()->increment_deopt_count(); 540 if (bailout_type_ == Deoptimizer::SOFT) { 541 isolate->counters()->soft_deopts_executed()->Increment(); 542 // Soft deopts shouldn't count against the overall re-optimization count 543 // that can eventually lead to disabling optimization for a function. 544 int opt_count = function->shared()->opt_count(); 545 if (opt_count > 0) opt_count--; 546 function->shared()->set_opt_count(opt_count); 547 } 548 } 549 compiled_code_ = FindOptimizedCode(function, optimized_code); 550 #if DEBUG 551 DCHECK(compiled_code_ != NULL); 552 if (type == EAGER || type == SOFT || type == LAZY) { 553 DCHECK(compiled_code_->kind() != Code::FUNCTION); 554 } 555 #endif 556 557 StackFrame::Type frame_type = function == NULL 558 ? StackFrame::STUB 559 : StackFrame::JAVA_SCRIPT; 560 trace_scope_ = TraceEnabledFor(type, frame_type) ? 561 new CodeTracer::Scope(isolate->GetCodeTracer()) : NULL; 562 #ifdef DEBUG 563 CHECK(AllowHeapAllocation::IsAllowed()); 564 disallow_heap_allocation_ = new DisallowHeapAllocation(); 565 #endif // DEBUG 566 if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) { 567 PROFILE(isolate_, CodeDeoptEvent(compiled_code_, from_, fp_to_sp_delta_)); 568 } 569 unsigned size = ComputeInputFrameSize(); 570 input_ = new(size) FrameDescription(size, function); 571 input_->SetFrameType(frame_type); 572 } 573 574 575 Code* Deoptimizer::FindOptimizedCode(JSFunction* function, 576 Code* optimized_code) { 577 switch (bailout_type_) { 578 case Deoptimizer::SOFT: 579 case Deoptimizer::EAGER: 580 case Deoptimizer::LAZY: { 581 Code* compiled_code = FindDeoptimizingCode(from_); 582 return (compiled_code == NULL) 583 ? static_cast<Code*>(isolate_->FindCodeObject(from_)) 584 : compiled_code; 585 } 586 case Deoptimizer::DEBUGGER: 587 DCHECK(optimized_code->contains(from_)); 588 return optimized_code; 589 } 590 FATAL("Could not find code for optimized function"); 591 return NULL; 592 } 593 594 595 void Deoptimizer::PrintFunctionName() { 596 if (function_->IsJSFunction()) { 597 function_->ShortPrint(trace_scope_->file()); 598 } else { 599 PrintF(trace_scope_->file(), 600 "%s", Code::Kind2String(compiled_code_->kind())); 601 } 602 } 603 604 605 Deoptimizer::~Deoptimizer() { 606 DCHECK(input_ == NULL && output_ == NULL); 607 DCHECK(disallow_heap_allocation_ == NULL); 608 delete trace_scope_; 609 } 610 611 612 void Deoptimizer::DeleteFrameDescriptions() { 613 delete input_; 614 for (int i = 0; i < output_count_; ++i) { 615 if (output_[i] != input_) delete output_[i]; 616 } 617 delete[] output_; 618 input_ = NULL; 619 output_ = NULL; 620 #ifdef DEBUG 621 CHECK(!AllowHeapAllocation::IsAllowed()); 622 CHECK(disallow_heap_allocation_ != NULL); 623 delete disallow_heap_allocation_; 624 disallow_heap_allocation_ = NULL; 625 #endif // DEBUG 626 } 627 628 629 Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate, 630 int id, 631 BailoutType type, 632 GetEntryMode mode) { 633 CHECK_GE(id, 0); 634 if (id >= kMaxNumberOfEntries) return NULL; 635 if (mode == ENSURE_ENTRY_CODE) { 636 EnsureCodeForDeoptimizationEntry(isolate, type, id); 637 } else { 638 CHECK_EQ(mode, CALCULATE_ENTRY_ADDRESS); 639 } 640 DeoptimizerData* data = isolate->deoptimizer_data(); 641 CHECK_LT(type, kBailoutTypesWithCodeEntry); 642 MemoryChunk* base = data->deopt_entry_code_[type]; 643 return base->area_start() + (id * table_entry_size_); 644 } 645 646 647 int Deoptimizer::GetDeoptimizationId(Isolate* isolate, 648 Address addr, 649 BailoutType type) { 650 DeoptimizerData* data = isolate->deoptimizer_data(); 651 MemoryChunk* base = data->deopt_entry_code_[type]; 652 Address start = base->area_start(); 653 if (addr < start || 654 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) { 655 return kNotDeoptimizationEntry; 656 } 657 DCHECK_EQ(0, 658 static_cast<int>(addr - start) % table_entry_size_); 659 return static_cast<int>(addr - start) / table_entry_size_; 660 } 661 662 663 int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data, 664 BailoutId id, 665 SharedFunctionInfo* shared) { 666 // TODO(kasperl): For now, we do a simple linear search for the PC 667 // offset associated with the given node id. This should probably be 668 // changed to a binary search. 669 int length = data->DeoptPoints(); 670 for (int i = 0; i < length; i++) { 671 if (data->AstId(i) == id) { 672 return data->PcAndState(i)->value(); 673 } 674 } 675 OFStream os(stderr); 676 os << "[couldn't find pc offset for node=" << id.ToInt() << "]\n" 677 << "[method: " << shared->DebugName()->ToCString().get() << "]\n" 678 << "[source:\n" << SourceCodeOf(shared) << "\n]" << std::endl; 679 680 shared->GetHeap()->isolate()->PushStackTraceAndDie(0xfefefefe, data, shared, 681 0xfefefeff); 682 FATAL("unable to find pc offset during deoptimization"); 683 return -1; 684 } 685 686 687 int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) { 688 int length = 0; 689 // Count all entries in the deoptimizing code list of every context. 690 Object* context = isolate->heap()->native_contexts_list(); 691 while (!context->IsUndefined()) { 692 Context* native_context = Context::cast(context); 693 Object* element = native_context->DeoptimizedCodeListHead(); 694 while (!element->IsUndefined()) { 695 Code* code = Code::cast(element); 696 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); 697 length++; 698 element = code->next_code_link(); 699 } 700 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); 701 } 702 return length; 703 } 704 705 706 // We rely on this function not causing a GC. It is called from generated code 707 // without having a real stack frame in place. 708 void Deoptimizer::DoComputeOutputFrames() { 709 base::ElapsedTimer timer; 710 711 // Determine basic deoptimization information. The optimized frame is 712 // described by the input data. 713 DeoptimizationInputData* input_data = 714 DeoptimizationInputData::cast(compiled_code_->deoptimization_data()); 715 716 if (trace_scope_ != NULL) { 717 timer.Start(); 718 PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ", 719 MessageFor(bailout_type_)); 720 PrintFunctionName(); 721 PrintF(trace_scope_->file(), 722 " (opt #%d) @%d, FP to SP delta: %d]\n", 723 input_data->OptimizationId()->value(), 724 bailout_id_, 725 fp_to_sp_delta_); 726 if (bailout_type_ == EAGER || bailout_type_ == SOFT || 727 (compiled_code_->is_hydrogen_stub())) { 728 compiled_code_->PrintDeoptLocation(trace_scope_->file(), from_); 729 } 730 } 731 732 BailoutId node_id = input_data->AstId(bailout_id_); 733 ByteArray* translations = input_data->TranslationByteArray(); 734 unsigned translation_index = 735 input_data->TranslationIndex(bailout_id_)->value(); 736 737 TranslationIterator state_iterator(translations, translation_index); 738 translated_state_.Init( 739 input_->GetFramePointerAddress(), &state_iterator, 740 input_data->LiteralArray(), input_->GetRegisterValues(), 741 trace_scope_ == nullptr ? nullptr : trace_scope_->file()); 742 743 // Do the input frame to output frame(s) translation. 744 size_t count = translated_state_.frames().size(); 745 DCHECK(output_ == NULL); 746 output_ = new FrameDescription*[count]; 747 for (size_t i = 0; i < count; ++i) { 748 output_[i] = NULL; 749 } 750 output_count_ = static_cast<int>(count); 751 752 Register fp_reg = JavaScriptFrame::fp_register(); 753 stack_fp_ = reinterpret_cast<Address>( 754 input_->GetRegister(fp_reg.code()) + 755 has_alignment_padding_ * kPointerSize); 756 757 // Translate each output frame. 758 for (size_t i = 0; i < count; ++i) { 759 // Read the ast node id, function, and frame height for this output frame. 760 int frame_index = static_cast<int>(i); 761 switch (translated_state_.frames()[i].kind()) { 762 case TranslatedFrame::kFunction: 763 DoComputeJSFrame(frame_index); 764 jsframe_count_++; 765 break; 766 case TranslatedFrame::kInterpretedFunction: 767 DoComputeInterpretedFrame(frame_index); 768 jsframe_count_++; 769 break; 770 case TranslatedFrame::kArgumentsAdaptor: 771 DoComputeArgumentsAdaptorFrame(frame_index); 772 break; 773 case TranslatedFrame::kConstructStub: 774 DoComputeConstructStubFrame(frame_index); 775 break; 776 case TranslatedFrame::kGetter: 777 DoComputeAccessorStubFrame(frame_index, false); 778 break; 779 case TranslatedFrame::kSetter: 780 DoComputeAccessorStubFrame(frame_index, true); 781 break; 782 case TranslatedFrame::kCompiledStub: 783 DoComputeCompiledStubFrame(frame_index); 784 break; 785 case TranslatedFrame::kInvalid: 786 FATAL("invalid frame"); 787 break; 788 } 789 } 790 791 // Print some helpful diagnostic information. 792 if (trace_scope_ != NULL) { 793 double ms = timer.Elapsed().InMillisecondsF(); 794 int index = output_count_ - 1; // Index of the topmost frame. 795 PrintF(trace_scope_->file(), "[deoptimizing (%s): end ", 796 MessageFor(bailout_type_)); 797 PrintFunctionName(); 798 PrintF(trace_scope_->file(), 799 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s," 800 " took %0.3f ms]\n", 801 bailout_id_, 802 node_id.ToInt(), 803 output_[index]->GetPc(), 804 FullCodeGenerator::State2String( 805 static_cast<FullCodeGenerator::State>( 806 output_[index]->GetState()->value())), 807 has_alignment_padding_ ? "with padding" : "no padding", 808 ms); 809 } 810 } 811 812 813 void Deoptimizer::DoComputeJSFrame(int frame_index) { 814 TranslatedFrame* translated_frame = 815 &(translated_state_.frames()[frame_index]); 816 TranslatedFrame::iterator value_iterator = translated_frame->begin(); 817 int input_index = 0; 818 819 BailoutId node_id = translated_frame->node_id(); 820 unsigned height = 821 translated_frame->height() - 1; // Do not count the context. 822 unsigned height_in_bytes = height * kPointerSize; 823 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); 824 value_iterator++; 825 input_index++; 826 if (trace_scope_ != NULL) { 827 PrintF(trace_scope_->file(), " translating frame "); 828 function->PrintName(trace_scope_->file()); 829 PrintF(trace_scope_->file(), 830 " => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes); 831 } 832 833 // The 'fixed' part of the frame consists of the incoming parameters and 834 // the part described by JavaScriptFrameConstants. 835 unsigned fixed_frame_size = ComputeJavascriptFixedSize(function); 836 unsigned input_frame_size = input_->GetFrameSize(); 837 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 838 839 // Allocate and store the output frame description. 840 FrameDescription* output_frame = 841 new(output_frame_size) FrameDescription(output_frame_size, function); 842 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); 843 844 bool is_bottommost = (0 == frame_index); 845 bool is_topmost = (output_count_ - 1 == frame_index); 846 CHECK(frame_index >= 0 && frame_index < output_count_); 847 CHECK_NULL(output_[frame_index]); 848 output_[frame_index] = output_frame; 849 850 // The top address for the bottommost output frame can be computed from 851 // the input frame pointer and the output frame's height. For all 852 // subsequent output frames, it can be computed from the previous one's 853 // top address and the current frame's size. 854 Register fp_reg = JavaScriptFrame::fp_register(); 855 intptr_t top_address; 856 if (is_bottommost) { 857 // Determine whether the input frame contains alignment padding. 858 has_alignment_padding_ = 859 (!compiled_code_->is_turbofanned() && HasAlignmentPadding(function)) 860 ? 1 861 : 0; 862 // 2 = context and function in the frame. 863 // If the optimized frame had alignment padding, adjust the frame pointer 864 // to point to the new position of the old frame pointer after padding 865 // is removed. Subtract 2 * kPointerSize for the context and function slots. 866 top_address = input_->GetRegister(fp_reg.code()) - 867 StandardFrameConstants::kFixedFrameSizeFromFp - 868 height_in_bytes + has_alignment_padding_ * kPointerSize; 869 } else { 870 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 871 } 872 output_frame->SetTop(top_address); 873 874 // Compute the incoming parameter translation. 875 int parameter_count = 876 function->shared()->internal_formal_parameter_count() + 1; 877 unsigned output_offset = output_frame_size; 878 unsigned input_offset = input_frame_size; 879 for (int i = 0; i < parameter_count; ++i) { 880 output_offset -= kPointerSize; 881 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, 882 output_offset); 883 } 884 input_offset -= (parameter_count * kPointerSize); 885 886 // There are no translation commands for the caller's pc and fp, the 887 // context, and the function. Synthesize their values and set them up 888 // explicitly. 889 // 890 // The caller's pc for the bottommost output frame is the same as in the 891 // input frame. For all subsequent output frames, it can be read from the 892 // previous one. This frame's pc can be computed from the non-optimized 893 // function code and AST id of the bailout. 894 output_offset -= kPCOnStackSize; 895 input_offset -= kPCOnStackSize; 896 intptr_t value; 897 if (is_bottommost) { 898 value = input_->GetFrameSlot(input_offset); 899 } else { 900 value = output_[frame_index - 1]->GetPc(); 901 } 902 output_frame->SetCallerPc(output_offset, value); 903 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n"); 904 905 // The caller's frame pointer for the bottommost output frame is the same 906 // as in the input frame. For all subsequent output frames, it can be 907 // read from the previous one. Also compute and set this frame's frame 908 // pointer. 909 output_offset -= kFPOnStackSize; 910 input_offset -= kFPOnStackSize; 911 if (is_bottommost) { 912 value = input_->GetFrameSlot(input_offset); 913 } else { 914 value = output_[frame_index - 1]->GetFp(); 915 } 916 output_frame->SetCallerFp(output_offset, value); 917 intptr_t fp_value = top_address + output_offset; 918 DCHECK(!is_bottommost || (input_->GetRegister(fp_reg.code()) + 919 has_alignment_padding_ * kPointerSize) == fp_value); 920 output_frame->SetFp(fp_value); 921 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value); 922 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); 923 DCHECK(!is_bottommost || !has_alignment_padding_ || 924 (fp_value & kPointerSize) != 0); 925 926 if (FLAG_enable_embedded_constant_pool) { 927 // For the bottommost output frame the constant pool pointer can be gotten 928 // from the input frame. For subsequent output frames, it can be read from 929 // the previous frame. 930 output_offset -= kPointerSize; 931 input_offset -= kPointerSize; 932 if (is_bottommost) { 933 value = input_->GetFrameSlot(input_offset); 934 } else { 935 value = output_[frame_index - 1]->GetConstantPool(); 936 } 937 output_frame->SetCallerConstantPool(output_offset, value); 938 DebugPrintOutputSlot(value, frame_index, output_offset, 939 "caller's constant_pool\n"); 940 } 941 942 // For the bottommost output frame the context can be gotten from the input 943 // frame. For all subsequent output frames it can be gotten from the function 944 // so long as we don't inline functions that need local contexts. 945 Register context_reg = JavaScriptFrame::context_register(); 946 output_offset -= kPointerSize; 947 input_offset -= kPointerSize; 948 // Read the context from the translations. 949 Object* context = value_iterator->GetRawValue(); 950 if (context == isolate_->heap()->undefined_value()) { 951 // If the context was optimized away, just use the context from 952 // the activation. This should only apply to Crankshaft code. 953 CHECK(!compiled_code_->is_turbofanned()); 954 context = 955 is_bottommost 956 ? reinterpret_cast<Object*>(input_->GetFrameSlot(input_offset)) 957 : function->context(); 958 } 959 value = reinterpret_cast<intptr_t>(context); 960 output_frame->SetContext(value); 961 if (is_topmost) output_frame->SetRegister(context_reg.code(), value); 962 WriteValueToOutput(context, input_index, frame_index, output_offset, 963 "context "); 964 if (context == isolate_->heap()->arguments_marker()) { 965 Address output_address = 966 reinterpret_cast<Address>(output_[frame_index]->GetTop()) + 967 output_offset; 968 values_to_materialize_.push_back({output_address, value_iterator}); 969 } 970 value_iterator++; 971 input_index++; 972 973 // The function was mentioned explicitly in the BEGIN_FRAME. 974 output_offset -= kPointerSize; 975 input_offset -= kPointerSize; 976 value = reinterpret_cast<intptr_t>(function); 977 // The function for the bottommost output frame should also agree with the 978 // input frame. 979 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 980 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); 981 982 // Translate the rest of the frame. 983 for (unsigned i = 0; i < height; ++i) { 984 output_offset -= kPointerSize; 985 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, 986 output_offset); 987 } 988 CHECK_EQ(0u, output_offset); 989 990 // Compute this frame's PC, state, and continuation. 991 Code* non_optimized_code = function->shared()->code(); 992 FixedArray* raw_data = non_optimized_code->deoptimization_data(); 993 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); 994 Address start = non_optimized_code->instruction_start(); 995 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); 996 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); 997 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset); 998 output_frame->SetPc(pc_value); 999 1000 // Update constant pool. 1001 if (FLAG_enable_embedded_constant_pool) { 1002 intptr_t constant_pool_value = 1003 reinterpret_cast<intptr_t>(non_optimized_code->constant_pool()); 1004 output_frame->SetConstantPool(constant_pool_value); 1005 if (is_topmost) { 1006 Register constant_pool_reg = 1007 JavaScriptFrame::constant_pool_pointer_register(); 1008 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); 1009 } 1010 } 1011 1012 FullCodeGenerator::State state = 1013 FullCodeGenerator::StateField::decode(pc_and_state); 1014 output_frame->SetState(Smi::FromInt(state)); 1015 1016 // Set the continuation for the topmost frame. 1017 if (is_topmost && bailout_type_ != DEBUGGER) { 1018 Builtins* builtins = isolate_->builtins(); 1019 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); 1020 if (bailout_type_ == LAZY) { 1021 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); 1022 } else if (bailout_type_ == SOFT) { 1023 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); 1024 } else { 1025 CHECK_EQ(bailout_type_, EAGER); 1026 } 1027 output_frame->SetContinuation( 1028 reinterpret_cast<intptr_t>(continuation->entry())); 1029 } 1030 } 1031 1032 1033 void Deoptimizer::DoComputeInterpretedFrame(int frame_index) { 1034 TranslatedFrame* translated_frame = 1035 &(translated_state_.frames()[frame_index]); 1036 TranslatedFrame::iterator value_iterator = translated_frame->begin(); 1037 int input_index = 0; 1038 1039 BailoutId bytecode_offset = translated_frame->node_id(); 1040 unsigned height = translated_frame->height(); 1041 unsigned height_in_bytes = height * kPointerSize; 1042 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); 1043 value_iterator++; 1044 input_index++; 1045 if (trace_scope_ != NULL) { 1046 PrintF(trace_scope_->file(), " translating interpreted frame "); 1047 function->PrintName(trace_scope_->file()); 1048 PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d\n", 1049 bytecode_offset.ToInt(), height_in_bytes); 1050 } 1051 1052 // The 'fixed' part of the frame consists of the incoming parameters and 1053 // the part described by InterpreterFrameConstants. 1054 unsigned fixed_frame_size = ComputeInterpretedFixedSize(function); 1055 unsigned input_frame_size = input_->GetFrameSize(); 1056 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 1057 1058 // Allocate and store the output frame description. 1059 FrameDescription* output_frame = 1060 new (output_frame_size) FrameDescription(output_frame_size, function); 1061 output_frame->SetFrameType(StackFrame::INTERPRETED); 1062 1063 bool is_bottommost = (0 == frame_index); 1064 bool is_topmost = (output_count_ - 1 == frame_index); 1065 CHECK(frame_index >= 0 && frame_index < output_count_); 1066 CHECK_NULL(output_[frame_index]); 1067 output_[frame_index] = output_frame; 1068 1069 // The top address for the bottommost output frame can be computed from 1070 // the input frame pointer and the output frame's height. For all 1071 // subsequent output frames, it can be computed from the previous one's 1072 // top address and the current frame's size. 1073 Register fp_reg = InterpretedFrame::fp_register(); 1074 intptr_t top_address; 1075 if (is_bottommost) { 1076 // Subtract interpreter fixed frame size for the context function slots, 1077 // new,target and bytecode offset. 1078 top_address = input_->GetRegister(fp_reg.code()) - 1079 InterpreterFrameConstants::kFixedFrameSizeFromFp - 1080 height_in_bytes; 1081 } else { 1082 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 1083 } 1084 output_frame->SetTop(top_address); 1085 1086 // Compute the incoming parameter translation. 1087 int parameter_count = 1088 function->shared()->internal_formal_parameter_count() + 1; 1089 unsigned output_offset = output_frame_size; 1090 unsigned input_offset = input_frame_size; 1091 for (int i = 0; i < parameter_count; ++i) { 1092 output_offset -= kPointerSize; 1093 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, 1094 output_offset); 1095 } 1096 input_offset -= (parameter_count * kPointerSize); 1097 1098 // There are no translation commands for the caller's pc and fp, the 1099 // context, the function, new.target and the bytecode offset. Synthesize 1100 // their values and set them up 1101 // explicitly. 1102 // 1103 // The caller's pc for the bottommost output frame is the same as in the 1104 // input frame. For all subsequent output frames, it can be read from the 1105 // previous one. This frame's pc can be computed from the non-optimized 1106 // function code and AST id of the bailout. 1107 output_offset -= kPCOnStackSize; 1108 input_offset -= kPCOnStackSize; 1109 intptr_t value; 1110 if (is_bottommost) { 1111 value = input_->GetFrameSlot(input_offset); 1112 } else { 1113 value = output_[frame_index - 1]->GetPc(); 1114 } 1115 output_frame->SetCallerPc(output_offset, value); 1116 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n"); 1117 1118 // The caller's frame pointer for the bottommost output frame is the same 1119 // as in the input frame. For all subsequent output frames, it can be 1120 // read from the previous one. Also compute and set this frame's frame 1121 // pointer. 1122 output_offset -= kFPOnStackSize; 1123 input_offset -= kFPOnStackSize; 1124 if (is_bottommost) { 1125 value = input_->GetFrameSlot(input_offset); 1126 } else { 1127 value = output_[frame_index - 1]->GetFp(); 1128 } 1129 output_frame->SetCallerFp(output_offset, value); 1130 intptr_t fp_value = top_address + output_offset; 1131 DCHECK(!is_bottommost || 1132 (input_->GetRegister(fp_reg.code()) + 1133 has_alignment_padding_ * kPointerSize) == fp_value); 1134 output_frame->SetFp(fp_value); 1135 if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value); 1136 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); 1137 DCHECK(!is_bottommost || !has_alignment_padding_ || 1138 (fp_value & kPointerSize) != 0); 1139 1140 if (FLAG_enable_embedded_constant_pool) { 1141 // For the bottommost output frame the constant pool pointer can be gotten 1142 // from the input frame. For subsequent output frames, it can be read from 1143 // the previous frame. 1144 output_offset -= kPointerSize; 1145 input_offset -= kPointerSize; 1146 if (is_bottommost) { 1147 value = input_->GetFrameSlot(input_offset); 1148 } else { 1149 value = output_[frame_index - 1]->GetConstantPool(); 1150 } 1151 output_frame->SetCallerConstantPool(output_offset, value); 1152 DebugPrintOutputSlot(value, frame_index, output_offset, 1153 "caller's constant_pool\n"); 1154 } 1155 1156 // For the bottommost output frame the context can be gotten from the input 1157 // frame. For all subsequent output frames it can be gotten from the function 1158 // so long as we don't inline functions that need local contexts. 1159 Register context_reg = InterpretedFrame::context_register(); 1160 output_offset -= kPointerSize; 1161 input_offset -= kPointerSize; 1162 // Read the context from the translations. 1163 Object* context = value_iterator->GetRawValue(); 1164 // The context should not be a placeholder for a materialized object. 1165 CHECK(context != isolate_->heap()->arguments_marker()); 1166 value = reinterpret_cast<intptr_t>(context); 1167 output_frame->SetContext(value); 1168 if (is_topmost) output_frame->SetRegister(context_reg.code(), value); 1169 WriteValueToOutput(context, input_index, frame_index, output_offset, 1170 "context "); 1171 value_iterator++; 1172 input_index++; 1173 1174 // The function was mentioned explicitly in the BEGIN_FRAME. 1175 output_offset -= kPointerSize; 1176 input_offset -= kPointerSize; 1177 value = reinterpret_cast<intptr_t>(function); 1178 // The function for the bottommost output frame should also agree with the 1179 // input frame. 1180 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 1181 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); 1182 1183 // TODO(rmcilroy): Deal with new.target correctly - currently just set it to 1184 // undefined. 1185 output_offset -= kPointerSize; 1186 input_offset -= kPointerSize; 1187 Object* new_target = isolate_->heap()->undefined_value(); 1188 WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target "); 1189 1190 // The bytecode offset was mentioned explicitly in the BEGIN_FRAME. 1191 output_offset -= kPointerSize; 1192 input_offset -= kPointerSize; 1193 int raw_bytecode_offset = 1194 BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset.ToInt(); 1195 Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset); 1196 WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset, 1197 "bytecode offset "); 1198 1199 // Translate the rest of the interpreter registers in the frame. 1200 for (unsigned i = 0; i < height; ++i) { 1201 output_offset -= kPointerSize; 1202 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, 1203 output_offset); 1204 } 1205 CHECK_EQ(0u, output_offset); 1206 1207 // Set the accumulator register. 1208 output_frame->SetRegister( 1209 kInterpreterAccumulatorRegister.code(), 1210 reinterpret_cast<intptr_t>(value_iterator->GetRawValue())); 1211 value_iterator++; 1212 1213 Builtins* builtins = isolate_->builtins(); 1214 Code* trampoline = builtins->builtin(Builtins::kInterpreterEntryTrampoline); 1215 output_frame->SetPc(reinterpret_cast<intptr_t>(trampoline->entry())); 1216 output_frame->SetState(0); 1217 1218 // Update constant pool. 1219 if (FLAG_enable_embedded_constant_pool) { 1220 intptr_t constant_pool_value = 1221 reinterpret_cast<intptr_t>(trampoline->constant_pool()); 1222 output_frame->SetConstantPool(constant_pool_value); 1223 if (is_topmost) { 1224 Register constant_pool_reg = 1225 InterpretedFrame::constant_pool_pointer_register(); 1226 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); 1227 } 1228 } 1229 1230 // Set the continuation for the topmost frame. 1231 if (is_topmost && bailout_type_ != DEBUGGER) { 1232 Code* continuation = 1233 builtins->builtin(Builtins::kInterpreterNotifyDeoptimized); 1234 if (bailout_type_ == LAZY) { 1235 continuation = 1236 builtins->builtin(Builtins::kInterpreterNotifyLazyDeoptimized); 1237 } else if (bailout_type_ == SOFT) { 1238 continuation = 1239 builtins->builtin(Builtins::kInterpreterNotifySoftDeoptimized); 1240 } else { 1241 CHECK_EQ(bailout_type_, EAGER); 1242 } 1243 output_frame->SetContinuation( 1244 reinterpret_cast<intptr_t>(continuation->entry())); 1245 } 1246 } 1247 1248 1249 void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) { 1250 TranslatedFrame* translated_frame = 1251 &(translated_state_.frames()[frame_index]); 1252 TranslatedFrame::iterator value_iterator = translated_frame->begin(); 1253 int input_index = 0; 1254 1255 unsigned height = translated_frame->height(); 1256 unsigned height_in_bytes = height * kPointerSize; 1257 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); 1258 value_iterator++; 1259 input_index++; 1260 if (trace_scope_ != NULL) { 1261 PrintF(trace_scope_->file(), 1262 " translating arguments adaptor => height=%d\n", height_in_bytes); 1263 } 1264 1265 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize; 1266 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 1267 1268 // Allocate and store the output frame description. 1269 FrameDescription* output_frame = 1270 new(output_frame_size) FrameDescription(output_frame_size, function); 1271 output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR); 1272 1273 // Arguments adaptor can not be topmost or bottommost. 1274 CHECK(frame_index > 0 && frame_index < output_count_ - 1); 1275 CHECK(output_[frame_index] == NULL); 1276 output_[frame_index] = output_frame; 1277 1278 // The top address of the frame is computed from the previous 1279 // frame's top and this frame's size. 1280 intptr_t top_address; 1281 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 1282 output_frame->SetTop(top_address); 1283 1284 // Compute the incoming parameter translation. 1285 int parameter_count = height; 1286 unsigned output_offset = output_frame_size; 1287 for (int i = 0; i < parameter_count; ++i) { 1288 output_offset -= kPointerSize; 1289 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, 1290 output_offset); 1291 } 1292 1293 // Read caller's PC from the previous frame. 1294 output_offset -= kPCOnStackSize; 1295 intptr_t callers_pc = output_[frame_index - 1]->GetPc(); 1296 output_frame->SetCallerPc(output_offset, callers_pc); 1297 DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n"); 1298 1299 // Read caller's FP from the previous frame, and set this frame's FP. 1300 output_offset -= kFPOnStackSize; 1301 intptr_t value = output_[frame_index - 1]->GetFp(); 1302 output_frame->SetCallerFp(output_offset, value); 1303 intptr_t fp_value = top_address + output_offset; 1304 output_frame->SetFp(fp_value); 1305 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); 1306 1307 if (FLAG_enable_embedded_constant_pool) { 1308 // Read the caller's constant pool from the previous frame. 1309 output_offset -= kPointerSize; 1310 value = output_[frame_index - 1]->GetConstantPool(); 1311 output_frame->SetCallerConstantPool(output_offset, value); 1312 DebugPrintOutputSlot(value, frame_index, output_offset, 1313 "caller's constant_pool\n"); 1314 } 1315 1316 // A marker value is used in place of the context. 1317 output_offset -= kPointerSize; 1318 intptr_t context = reinterpret_cast<intptr_t>( 1319 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 1320 output_frame->SetFrameSlot(output_offset, context); 1321 DebugPrintOutputSlot(context, frame_index, output_offset, 1322 "context (adaptor sentinel)\n"); 1323 1324 // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME. 1325 output_offset -= kPointerSize; 1326 value = reinterpret_cast<intptr_t>(function); 1327 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); 1328 1329 // Number of incoming arguments. 1330 output_offset -= kPointerSize; 1331 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1)); 1332 output_frame->SetFrameSlot(output_offset, value); 1333 DebugPrintOutputSlot(value, frame_index, output_offset, "argc "); 1334 if (trace_scope_ != nullptr) { 1335 PrintF(trace_scope_->file(), "(%d)\n", height - 1); 1336 } 1337 1338 DCHECK(0 == output_offset); 1339 1340 Builtins* builtins = isolate_->builtins(); 1341 Code* adaptor_trampoline = 1342 builtins->builtin(Builtins::kArgumentsAdaptorTrampoline); 1343 intptr_t pc_value = reinterpret_cast<intptr_t>( 1344 adaptor_trampoline->instruction_start() + 1345 isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value()); 1346 output_frame->SetPc(pc_value); 1347 if (FLAG_enable_embedded_constant_pool) { 1348 intptr_t constant_pool_value = 1349 reinterpret_cast<intptr_t>(adaptor_trampoline->constant_pool()); 1350 output_frame->SetConstantPool(constant_pool_value); 1351 } 1352 } 1353 1354 1355 void Deoptimizer::DoComputeConstructStubFrame(int frame_index) { 1356 TranslatedFrame* translated_frame = 1357 &(translated_state_.frames()[frame_index]); 1358 TranslatedFrame::iterator value_iterator = translated_frame->begin(); 1359 int input_index = 0; 1360 1361 Builtins* builtins = isolate_->builtins(); 1362 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); 1363 unsigned height = translated_frame->height(); 1364 unsigned height_in_bytes = height * kPointerSize; 1365 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); 1366 value_iterator++; 1367 input_index++; 1368 if (trace_scope_ != NULL) { 1369 PrintF(trace_scope_->file(), 1370 " translating construct stub => height=%d\n", height_in_bytes); 1371 } 1372 1373 unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize; 1374 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 1375 1376 // Allocate and store the output frame description. 1377 FrameDescription* output_frame = 1378 new(output_frame_size) FrameDescription(output_frame_size, function); 1379 output_frame->SetFrameType(StackFrame::CONSTRUCT); 1380 1381 // Construct stub can not be topmost or bottommost. 1382 DCHECK(frame_index > 0 && frame_index < output_count_ - 1); 1383 DCHECK(output_[frame_index] == NULL); 1384 output_[frame_index] = output_frame; 1385 1386 // The top address of the frame is computed from the previous 1387 // frame's top and this frame's size. 1388 intptr_t top_address; 1389 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 1390 output_frame->SetTop(top_address); 1391 1392 // Compute the incoming parameter translation. 1393 int parameter_count = height; 1394 unsigned output_offset = output_frame_size; 1395 for (int i = 0; i < parameter_count; ++i) { 1396 output_offset -= kPointerSize; 1397 // The allocated receiver of a construct stub frame is passed as the 1398 // receiver parameter through the translation. It might be encoding 1399 // a captured object, override the slot address for a captured object. 1400 WriteTranslatedValueToOutput( 1401 &value_iterator, &input_index, frame_index, output_offset, nullptr, 1402 (i == 0) ? reinterpret_cast<Address>(top_address) : nullptr); 1403 } 1404 1405 // Read caller's PC from the previous frame. 1406 output_offset -= kPCOnStackSize; 1407 intptr_t callers_pc = output_[frame_index - 1]->GetPc(); 1408 output_frame->SetCallerPc(output_offset, callers_pc); 1409 DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n"); 1410 1411 // Read caller's FP from the previous frame, and set this frame's FP. 1412 output_offset -= kFPOnStackSize; 1413 intptr_t value = output_[frame_index - 1]->GetFp(); 1414 output_frame->SetCallerFp(output_offset, value); 1415 intptr_t fp_value = top_address + output_offset; 1416 output_frame->SetFp(fp_value); 1417 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); 1418 1419 if (FLAG_enable_embedded_constant_pool) { 1420 // Read the caller's constant pool from the previous frame. 1421 output_offset -= kPointerSize; 1422 value = output_[frame_index - 1]->GetConstantPool(); 1423 output_frame->SetCallerConstantPool(output_offset, value); 1424 DebugPrintOutputSlot(value, frame_index, output_offset, 1425 "caller's constant_pool\n"); 1426 } 1427 1428 // The context can be gotten from the previous frame. 1429 output_offset -= kPointerSize; 1430 value = output_[frame_index - 1]->GetContext(); 1431 output_frame->SetFrameSlot(output_offset, value); 1432 DebugPrintOutputSlot(value, frame_index, output_offset, "context\n"); 1433 1434 // A marker value is used in place of the function. 1435 output_offset -= kPointerSize; 1436 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT)); 1437 output_frame->SetFrameSlot(output_offset, value); 1438 DebugPrintOutputSlot(value, frame_index, output_offset, 1439 "function (construct sentinel)\n"); 1440 1441 // The output frame reflects a JSConstructStubGeneric frame. 1442 output_offset -= kPointerSize; 1443 value = reinterpret_cast<intptr_t>(construct_stub); 1444 output_frame->SetFrameSlot(output_offset, value); 1445 DebugPrintOutputSlot(value, frame_index, output_offset, "code object\n"); 1446 1447 // The allocation site. 1448 output_offset -= kPointerSize; 1449 value = reinterpret_cast<intptr_t>(isolate_->heap()->undefined_value()); 1450 output_frame->SetFrameSlot(output_offset, value); 1451 DebugPrintOutputSlot(value, frame_index, output_offset, "allocation site\n"); 1452 1453 // Number of incoming arguments. 1454 output_offset -= kPointerSize; 1455 value = reinterpret_cast<intptr_t>(Smi::FromInt(height - 1)); 1456 output_frame->SetFrameSlot(output_offset, value); 1457 DebugPrintOutputSlot(value, frame_index, output_offset, "argc "); 1458 if (trace_scope_ != nullptr) { 1459 PrintF(trace_scope_->file(), "(%d)\n", height - 1); 1460 } 1461 1462 // The newly allocated object was passed as receiver in the artificial 1463 // constructor stub environment created by HEnvironment::CopyForInlining(). 1464 output_offset -= kPointerSize; 1465 value = output_frame->GetFrameSlot(output_frame_size - kPointerSize); 1466 output_frame->SetFrameSlot(output_offset, value); 1467 DebugPrintOutputSlot(value, frame_index, output_offset, 1468 "allocated receiver\n"); 1469 1470 CHECK_EQ(0u, output_offset); 1471 1472 intptr_t pc = reinterpret_cast<intptr_t>( 1473 construct_stub->instruction_start() + 1474 isolate_->heap()->construct_stub_deopt_pc_offset()->value()); 1475 output_frame->SetPc(pc); 1476 if (FLAG_enable_embedded_constant_pool) { 1477 intptr_t constant_pool_value = 1478 reinterpret_cast<intptr_t>(construct_stub->constant_pool()); 1479 output_frame->SetConstantPool(constant_pool_value); 1480 } 1481 } 1482 1483 1484 void Deoptimizer::DoComputeAccessorStubFrame(int frame_index, 1485 bool is_setter_stub_frame) { 1486 TranslatedFrame* translated_frame = 1487 &(translated_state_.frames()[frame_index]); 1488 TranslatedFrame::iterator value_iterator = translated_frame->begin(); 1489 int input_index = 0; 1490 1491 JSFunction* accessor = JSFunction::cast(value_iterator->GetRawValue()); 1492 value_iterator++; 1493 input_index++; 1494 // The receiver (and the implicit return value, if any) are expected in 1495 // registers by the LoadIC/StoreIC, so they don't belong to the output stack 1496 // frame. This means that we have to use a height of 0. 1497 unsigned height = 0; 1498 unsigned height_in_bytes = height * kPointerSize; 1499 const char* kind = is_setter_stub_frame ? "setter" : "getter"; 1500 if (trace_scope_ != NULL) { 1501 PrintF(trace_scope_->file(), 1502 " translating %s stub => height=%u\n", kind, height_in_bytes); 1503 } 1504 1505 // We need 1 stack entry for the return address and enough entries for the 1506 // StackFrame::INTERNAL (FP, context, frame type, code object and constant 1507 // pool (if enabled)- see MacroAssembler::EnterFrame). 1508 // For a setter stub frame we need one additional entry for the implicit 1509 // return value, see StoreStubCompiler::CompileStoreViaSetter. 1510 unsigned fixed_frame_entries = 1511 (StandardFrameConstants::kFixedFrameSize / kPointerSize) + 1 + 1512 (is_setter_stub_frame ? 1 : 0); 1513 unsigned fixed_frame_size = fixed_frame_entries * kPointerSize; 1514 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 1515 1516 // Allocate and store the output frame description. 1517 FrameDescription* output_frame = 1518 new(output_frame_size) FrameDescription(output_frame_size, accessor); 1519 output_frame->SetFrameType(StackFrame::INTERNAL); 1520 1521 // A frame for an accessor stub can not be the topmost or bottommost one. 1522 CHECK(frame_index > 0 && frame_index < output_count_ - 1); 1523 CHECK_NULL(output_[frame_index]); 1524 output_[frame_index] = output_frame; 1525 1526 // The top address of the frame is computed from the previous frame's top and 1527 // this frame's size. 1528 intptr_t top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 1529 output_frame->SetTop(top_address); 1530 1531 unsigned output_offset = output_frame_size; 1532 1533 // Read caller's PC from the previous frame. 1534 output_offset -= kPCOnStackSize; 1535 intptr_t callers_pc = output_[frame_index - 1]->GetPc(); 1536 output_frame->SetCallerPc(output_offset, callers_pc); 1537 DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n"); 1538 1539 // Read caller's FP from the previous frame, and set this frame's FP. 1540 output_offset -= kFPOnStackSize; 1541 intptr_t value = output_[frame_index - 1]->GetFp(); 1542 output_frame->SetCallerFp(output_offset, value); 1543 intptr_t fp_value = top_address + output_offset; 1544 output_frame->SetFp(fp_value); 1545 DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); 1546 1547 if (FLAG_enable_embedded_constant_pool) { 1548 // Read the caller's constant pool from the previous frame. 1549 output_offset -= kPointerSize; 1550 value = output_[frame_index - 1]->GetConstantPool(); 1551 output_frame->SetCallerConstantPool(output_offset, value); 1552 DebugPrintOutputSlot(value, frame_index, output_offset, 1553 "caller's constant_pool\n"); 1554 } 1555 1556 // The context can be gotten from the previous frame. 1557 output_offset -= kPointerSize; 1558 value = output_[frame_index - 1]->GetContext(); 1559 output_frame->SetFrameSlot(output_offset, value); 1560 DebugPrintOutputSlot(value, frame_index, output_offset, "context\n"); 1561 1562 // A marker value is used in place of the function. 1563 output_offset -= kPointerSize; 1564 value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::INTERNAL)); 1565 output_frame->SetFrameSlot(output_offset, value); 1566 DebugPrintOutputSlot(value, frame_index, output_offset, "function "); 1567 if (trace_scope_ != nullptr) { 1568 PrintF(trace_scope_->file(), "(%s sentinel)\n", kind); 1569 } 1570 1571 // Get Code object from accessor stub. 1572 output_offset -= kPointerSize; 1573 Builtins::Name name = is_setter_stub_frame ? 1574 Builtins::kStoreIC_Setter_ForDeopt : 1575 Builtins::kLoadIC_Getter_ForDeopt; 1576 Code* accessor_stub = isolate_->builtins()->builtin(name); 1577 value = reinterpret_cast<intptr_t>(accessor_stub); 1578 output_frame->SetFrameSlot(output_offset, value); 1579 DebugPrintOutputSlot(value, frame_index, output_offset, "code object\n"); 1580 1581 // Skip receiver. 1582 value_iterator++; 1583 input_index++; 1584 1585 if (is_setter_stub_frame) { 1586 // The implicit return value was part of the artificial setter stub 1587 // environment. 1588 output_offset -= kPointerSize; 1589 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, 1590 output_offset); 1591 } 1592 1593 CHECK_EQ(0u, output_offset); 1594 1595 Smi* offset = is_setter_stub_frame ? 1596 isolate_->heap()->setter_stub_deopt_pc_offset() : 1597 isolate_->heap()->getter_stub_deopt_pc_offset(); 1598 intptr_t pc = reinterpret_cast<intptr_t>( 1599 accessor_stub->instruction_start() + offset->value()); 1600 output_frame->SetPc(pc); 1601 if (FLAG_enable_embedded_constant_pool) { 1602 intptr_t constant_pool_value = 1603 reinterpret_cast<intptr_t>(accessor_stub->constant_pool()); 1604 output_frame->SetConstantPool(constant_pool_value); 1605 } 1606 } 1607 1608 1609 void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) { 1610 // 1611 // FROM TO 1612 // | .... | | .... | 1613 // +-------------------------+ +-------------------------+ 1614 // | JSFunction continuation | | JSFunction continuation | 1615 // +-------------------------+ +-------------------------+ 1616 // | | saved frame (FP) | | saved frame (FP) | 1617 // | +=========================+<-fpreg +=========================+<-fpreg 1618 // | |constant pool (if ool_cp)| |constant pool (if ool_cp)| 1619 // | +-------------------------+ +-------------------------| 1620 // | | JSFunction context | | JSFunction context | 1621 // v +-------------------------+ +-------------------------| 1622 // | COMPILED_STUB marker | | STUB_FAILURE marker | 1623 // +-------------------------+ +-------------------------+ 1624 // | | | caller args.arguments_ | 1625 // | ... | +-------------------------+ 1626 // | | | caller args.length_ | 1627 // |-------------------------|<-spreg +-------------------------+ 1628 // | caller args pointer | 1629 // +-------------------------+ 1630 // | caller stack param 1 | 1631 // parameters in registers +-------------------------+ 1632 // and spilled to stack | .... | 1633 // +-------------------------+ 1634 // | caller stack param n | 1635 // +-------------------------+<-spreg 1636 // reg = number of parameters 1637 // reg = failure handler address 1638 // reg = saved frame 1639 // reg = JSFunction context 1640 // 1641 // Caller stack params contain the register parameters to the stub first, 1642 // and then, if the descriptor specifies a constant number of stack 1643 // parameters, the stack parameters as well. 1644 1645 TranslatedFrame* translated_frame = 1646 &(translated_state_.frames()[frame_index]); 1647 TranslatedFrame::iterator value_iterator = translated_frame->begin(); 1648 int input_index = 0; 1649 1650 CHECK(compiled_code_->is_hydrogen_stub()); 1651 int major_key = CodeStub::GetMajorKey(compiled_code_); 1652 CodeStubDescriptor descriptor(isolate_, compiled_code_->stub_key()); 1653 1654 // The output frame must have room for all pushed register parameters 1655 // and the standard stack frame slots. Include space for an argument 1656 // object to the callee and optionally the space to pass the argument 1657 // object to the stub failure handler. 1658 int param_count = descriptor.GetRegisterParameterCount(); 1659 int stack_param_count = descriptor.GetStackParameterCount(); 1660 CHECK_EQ(translated_frame->height(), param_count); 1661 CHECK_GE(param_count, 0); 1662 1663 int height_in_bytes = kPointerSize * (param_count + stack_param_count) + 1664 sizeof(Arguments) + kPointerSize; 1665 int fixed_frame_size = StandardFrameConstants::kFixedFrameSize; 1666 int input_frame_size = input_->GetFrameSize(); 1667 int output_frame_size = height_in_bytes + fixed_frame_size; 1668 if (trace_scope_ != NULL) { 1669 PrintF(trace_scope_->file(), 1670 " translating %s => StubFailureTrampolineStub, height=%d\n", 1671 CodeStub::MajorName(static_cast<CodeStub::Major>(major_key)), 1672 height_in_bytes); 1673 } 1674 1675 // The stub failure trampoline is a single frame. 1676 FrameDescription* output_frame = 1677 new(output_frame_size) FrameDescription(output_frame_size, NULL); 1678 output_frame->SetFrameType(StackFrame::STUB_FAILURE_TRAMPOLINE); 1679 CHECK_EQ(frame_index, 0); 1680 output_[frame_index] = output_frame; 1681 1682 // The top address for the output frame can be computed from the input 1683 // frame pointer and the output frame's height. Subtract space for the 1684 // context and function slots. 1685 Register fp_reg = StubFailureTrampolineFrame::fp_register(); 1686 intptr_t top_address = input_->GetRegister(fp_reg.code()) - 1687 StandardFrameConstants::kFixedFrameSizeFromFp - height_in_bytes; 1688 output_frame->SetTop(top_address); 1689 1690 // Read caller's PC (JSFunction continuation) from the input frame. 1691 unsigned input_frame_offset = input_frame_size - kPCOnStackSize; 1692 unsigned output_frame_offset = output_frame_size - kFPOnStackSize; 1693 intptr_t value = input_->GetFrameSlot(input_frame_offset); 1694 output_frame->SetCallerPc(output_frame_offset, value); 1695 DebugPrintOutputSlot(value, frame_index, output_frame_offset, 1696 "caller's pc\n"); 1697 1698 // Read caller's FP from the input frame, and set this frame's FP. 1699 input_frame_offset -= kFPOnStackSize; 1700 value = input_->GetFrameSlot(input_frame_offset); 1701 output_frame_offset -= kFPOnStackSize; 1702 output_frame->SetCallerFp(output_frame_offset, value); 1703 intptr_t frame_ptr = input_->GetRegister(fp_reg.code()); 1704 output_frame->SetRegister(fp_reg.code(), frame_ptr); 1705 output_frame->SetFp(frame_ptr); 1706 DebugPrintOutputSlot(value, frame_index, output_frame_offset, 1707 "caller's fp\n"); 1708 1709 if (FLAG_enable_embedded_constant_pool) { 1710 // Read the caller's constant pool from the input frame. 1711 input_frame_offset -= kPointerSize; 1712 value = input_->GetFrameSlot(input_frame_offset); 1713 output_frame_offset -= kPointerSize; 1714 output_frame->SetCallerConstantPool(output_frame_offset, value); 1715 DebugPrintOutputSlot(value, frame_index, output_frame_offset, 1716 "caller's constant_pool\n"); 1717 } 1718 1719 // The context can be gotten from the input frame. 1720 Register context_reg = StubFailureTrampolineFrame::context_register(); 1721 input_frame_offset -= kPointerSize; 1722 value = input_->GetFrameSlot(input_frame_offset); 1723 output_frame->SetRegister(context_reg.code(), value); 1724 output_frame_offset -= kPointerSize; 1725 output_frame->SetFrameSlot(output_frame_offset, value); 1726 CHECK(reinterpret_cast<Object*>(value)->IsContext()); 1727 DebugPrintOutputSlot(value, frame_index, output_frame_offset, "context\n"); 1728 1729 // A marker value is used in place of the function. 1730 output_frame_offset -= kPointerSize; 1731 value = reinterpret_cast<intptr_t>( 1732 Smi::FromInt(StackFrame::STUB_FAILURE_TRAMPOLINE)); 1733 output_frame->SetFrameSlot(output_frame_offset, value); 1734 DebugPrintOutputSlot(value, frame_index, output_frame_offset, 1735 "function (stub failure sentinel)\n"); 1736 1737 intptr_t caller_arg_count = stack_param_count; 1738 bool arg_count_known = !descriptor.stack_parameter_count().is_valid(); 1739 1740 // Build the Arguments object for the caller's parameters and a pointer to it. 1741 output_frame_offset -= kPointerSize; 1742 int args_arguments_offset = output_frame_offset; 1743 intptr_t the_hole = reinterpret_cast<intptr_t>( 1744 isolate_->heap()->the_hole_value()); 1745 if (arg_count_known) { 1746 value = frame_ptr + StandardFrameConstants::kCallerSPOffset + 1747 (caller_arg_count - 1) * kPointerSize; 1748 } else { 1749 value = the_hole; 1750 } 1751 1752 output_frame->SetFrameSlot(args_arguments_offset, value); 1753 DebugPrintOutputSlot( 1754 value, frame_index, args_arguments_offset, 1755 arg_count_known ? "args.arguments\n" : "args.arguments (the hole)\n"); 1756 1757 output_frame_offset -= kPointerSize; 1758 int length_frame_offset = output_frame_offset; 1759 value = arg_count_known ? caller_arg_count : the_hole; 1760 output_frame->SetFrameSlot(length_frame_offset, value); 1761 DebugPrintOutputSlot( 1762 value, frame_index, length_frame_offset, 1763 arg_count_known ? "args.length\n" : "args.length (the hole)\n"); 1764 1765 output_frame_offset -= kPointerSize; 1766 value = frame_ptr + StandardFrameConstants::kCallerSPOffset - 1767 (output_frame_size - output_frame_offset) + kPointerSize; 1768 output_frame->SetFrameSlot(output_frame_offset, value); 1769 DebugPrintOutputSlot(value, frame_index, output_frame_offset, "args*\n"); 1770 1771 // Copy the register parameters to the failure frame. 1772 int arguments_length_offset = -1; 1773 for (int i = 0; i < param_count; ++i) { 1774 output_frame_offset -= kPointerSize; 1775 WriteTranslatedValueToOutput(&value_iterator, &input_index, 0, 1776 output_frame_offset); 1777 1778 if (!arg_count_known && 1779 descriptor.GetRegisterParameter(i) 1780 .is(descriptor.stack_parameter_count())) { 1781 arguments_length_offset = output_frame_offset; 1782 } 1783 } 1784 1785 // Copy constant stack parameters to the failure frame. If the number of stack 1786 // parameters is not known in the descriptor, the arguments object is the way 1787 // to access them. 1788 for (int i = 0; i < stack_param_count; i++) { 1789 output_frame_offset -= kPointerSize; 1790 Object** stack_parameter = reinterpret_cast<Object**>( 1791 frame_ptr + StandardFrameConstants::kCallerSPOffset + 1792 (stack_param_count - i - 1) * kPointerSize); 1793 value = reinterpret_cast<intptr_t>(*stack_parameter); 1794 output_frame->SetFrameSlot(output_frame_offset, value); 1795 DebugPrintOutputSlot(value, frame_index, output_frame_offset, 1796 "stack parameter\n"); 1797 } 1798 1799 CHECK_EQ(0u, output_frame_offset); 1800 1801 if (!arg_count_known) { 1802 CHECK_GE(arguments_length_offset, 0); 1803 // We know it's a smi because 1) the code stub guarantees the stack 1804 // parameter count is in smi range, and 2) the DoTranslateCommand in the 1805 // parameter loop above translated that to a tagged value. 1806 Smi* smi_caller_arg_count = reinterpret_cast<Smi*>( 1807 output_frame->GetFrameSlot(arguments_length_offset)); 1808 caller_arg_count = smi_caller_arg_count->value(); 1809 output_frame->SetFrameSlot(length_frame_offset, caller_arg_count); 1810 DebugPrintOutputSlot(caller_arg_count, frame_index, length_frame_offset, 1811 "args.length\n"); 1812 value = frame_ptr + StandardFrameConstants::kCallerSPOffset + 1813 (caller_arg_count - 1) * kPointerSize; 1814 output_frame->SetFrameSlot(args_arguments_offset, value); 1815 DebugPrintOutputSlot(value, frame_index, args_arguments_offset, 1816 "args.arguments"); 1817 } 1818 1819 // Copy the double registers from the input into the output frame. 1820 CopyDoubleRegisters(output_frame); 1821 1822 // Fill registers containing handler and number of parameters. 1823 SetPlatformCompiledStubRegisters(output_frame, &descriptor); 1824 1825 // Compute this frame's PC, state, and continuation. 1826 Code* trampoline = NULL; 1827 StubFunctionMode function_mode = descriptor.function_mode(); 1828 StubFailureTrampolineStub(isolate_, function_mode) 1829 .FindCodeInCache(&trampoline); 1830 DCHECK(trampoline != NULL); 1831 output_frame->SetPc(reinterpret_cast<intptr_t>( 1832 trampoline->instruction_start())); 1833 if (FLAG_enable_embedded_constant_pool) { 1834 Register constant_pool_reg = 1835 StubFailureTrampolineFrame::constant_pool_pointer_register(); 1836 intptr_t constant_pool_value = 1837 reinterpret_cast<intptr_t>(trampoline->constant_pool()); 1838 output_frame->SetConstantPool(constant_pool_value); 1839 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); 1840 } 1841 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS)); 1842 Code* notify_failure = 1843 isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles); 1844 output_frame->SetContinuation( 1845 reinterpret_cast<intptr_t>(notify_failure->entry())); 1846 } 1847 1848 1849 void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { 1850 DCHECK_NE(DEBUGGER, bailout_type_); 1851 1852 // Walk to the last JavaScript output frame to find out if it has 1853 // adapted arguments. 1854 for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) { 1855 if (frame_index != 0) it->Advance(); 1856 } 1857 translated_state_.Prepare(it->frame()->has_adapted_arguments(), stack_fp_); 1858 1859 for (auto& materialization : values_to_materialize_) { 1860 Handle<Object> value = materialization.value_->GetValue(); 1861 1862 if (trace_scope_ != nullptr) { 1863 PrintF("Materialization [0x%08" V8PRIxPTR "] <- 0x%08" V8PRIxPTR " ; ", 1864 reinterpret_cast<intptr_t>(materialization.output_slot_address_), 1865 reinterpret_cast<intptr_t>(*value)); 1866 value->ShortPrint(trace_scope_->file()); 1867 PrintF(trace_scope_->file(), "\n"); 1868 } 1869 1870 *(reinterpret_cast<intptr_t*>(materialization.output_slot_address_)) = 1871 reinterpret_cast<intptr_t>(*value); 1872 } 1873 1874 isolate_->materialized_object_store()->Remove(stack_fp_); 1875 } 1876 1877 1878 void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame( 1879 int frame_index, int parameter_count, int expression_count, 1880 DeoptimizedFrameInfo* info) { 1881 CHECK_EQ(DEBUGGER, bailout_type_); 1882 1883 translated_state_.Prepare(false, nullptr); 1884 1885 TranslatedFrame* frame = &(translated_state_.frames()[frame_index]); 1886 CHECK(frame->kind() == TranslatedFrame::kFunction); 1887 int frame_arg_count = frame->shared_info()->internal_formal_parameter_count(); 1888 1889 // The height is #expressions + 1 for context. 1890 CHECK_EQ(expression_count + 1, frame->height()); 1891 TranslatedFrame* argument_frame = frame; 1892 if (frame_index > 0) { 1893 TranslatedFrame* previous_frame = 1894 &(translated_state_.frames()[frame_index - 1]); 1895 if (previous_frame->kind() == TranslatedFrame::kArgumentsAdaptor) { 1896 argument_frame = previous_frame; 1897 CHECK_EQ(parameter_count, argument_frame->height() - 1); 1898 } else { 1899 CHECK_EQ(frame_arg_count, parameter_count); 1900 } 1901 } else { 1902 CHECK_EQ(frame_arg_count, parameter_count); 1903 } 1904 1905 TranslatedFrame::iterator arg_iter = argument_frame->begin(); 1906 arg_iter++; // Skip the function. 1907 arg_iter++; // Skip the receiver. 1908 for (int i = 0; i < parameter_count; i++, arg_iter++) { 1909 if (!arg_iter->IsMaterializedObject()) { 1910 info->SetParameter(i, *(arg_iter->GetValue())); 1911 } 1912 } 1913 1914 TranslatedFrame::iterator iter = frame->begin(); 1915 // Skip the function, receiver, context and arguments. 1916 for (int i = 0; i < frame_arg_count + 3; i++, iter++) { 1917 } 1918 1919 for (int i = 0; i < expression_count; i++, iter++) { 1920 if (!iter->IsMaterializedObject()) { 1921 info->SetExpression(i, *(iter->GetValue())); 1922 } 1923 } 1924 } 1925 1926 1927 void Deoptimizer::WriteTranslatedValueToOutput( 1928 TranslatedFrame::iterator* iterator, int* input_index, int frame_index, 1929 unsigned output_offset, const char* debug_hint_string, 1930 Address output_address_for_materialization) { 1931 Object* value = (*iterator)->GetRawValue(); 1932 1933 WriteValueToOutput(value, *input_index, frame_index, output_offset, 1934 debug_hint_string); 1935 1936 if (value == isolate_->heap()->arguments_marker()) { 1937 Address output_address = 1938 reinterpret_cast<Address>(output_[frame_index]->GetTop()) + 1939 output_offset; 1940 if (output_address_for_materialization == nullptr) { 1941 output_address_for_materialization = output_address; 1942 } 1943 values_to_materialize_.push_back( 1944 {output_address_for_materialization, *iterator}); 1945 } 1946 1947 (*iterator)++; 1948 (*input_index)++; 1949 } 1950 1951 1952 void Deoptimizer::WriteValueToOutput(Object* value, int input_index, 1953 int frame_index, unsigned output_offset, 1954 const char* debug_hint_string) { 1955 output_[frame_index]->SetFrameSlot(output_offset, 1956 reinterpret_cast<intptr_t>(value)); 1957 1958 if (trace_scope_ != nullptr) { 1959 DebugPrintOutputSlot(reinterpret_cast<intptr_t>(value), frame_index, 1960 output_offset, debug_hint_string); 1961 value->ShortPrint(trace_scope_->file()); 1962 PrintF(trace_scope_->file(), " (input #%d)\n", input_index); 1963 } 1964 } 1965 1966 1967 void Deoptimizer::DebugPrintOutputSlot(intptr_t value, int frame_index, 1968 unsigned output_offset, 1969 const char* debug_hint_string) { 1970 if (trace_scope_ != nullptr) { 1971 Address output_address = 1972 reinterpret_cast<Address>(output_[frame_index]->GetTop()) + 1973 output_offset; 1974 PrintF(trace_scope_->file(), 1975 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s", 1976 reinterpret_cast<intptr_t>(output_address), output_offset, value, 1977 debug_hint_string == nullptr ? "" : debug_hint_string); 1978 } 1979 } 1980 1981 1982 unsigned Deoptimizer::ComputeInputFrameSize() const { 1983 unsigned fixed_size = ComputeJavascriptFixedSize(function_); 1984 // The fp-to-sp delta already takes the context, constant pool pointer and the 1985 // function into account so we have to avoid double counting them. 1986 unsigned result = fixed_size + fp_to_sp_delta_ - 1987 StandardFrameConstants::kFixedFrameSizeFromFp; 1988 if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) { 1989 unsigned stack_slots = compiled_code_->stack_slots(); 1990 unsigned outgoing_size = 1991 ComputeOutgoingArgumentSize(compiled_code_, bailout_id_); 1992 CHECK(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size); 1993 } 1994 return result; 1995 } 1996 1997 1998 unsigned Deoptimizer::ComputeJavascriptFixedSize(JSFunction* function) const { 1999 // The fixed part of the frame consists of the return address, frame 2000 // pointer, function, context, and all the incoming arguments. 2001 return ComputeIncomingArgumentSize(function) + 2002 StandardFrameConstants::kFixedFrameSize; 2003 } 2004 2005 2006 unsigned Deoptimizer::ComputeInterpretedFixedSize(JSFunction* function) const { 2007 // The fixed part of the frame consists of the return address, frame 2008 // pointer, function, context, new.target, bytecode offset and all the 2009 // incoming arguments. 2010 return ComputeIncomingArgumentSize(function) + 2011 InterpreterFrameConstants::kFixedFrameSize; 2012 } 2013 2014 2015 unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const { 2016 // The incoming arguments is the values for formal parameters and 2017 // the receiver. Every slot contains a pointer. 2018 if (function->IsSmi()) { 2019 CHECK_EQ(Smi::cast(function), Smi::FromInt(StackFrame::STUB)); 2020 return 0; 2021 } 2022 unsigned arguments = 2023 function->shared()->internal_formal_parameter_count() + 1; 2024 return arguments * kPointerSize; 2025 } 2026 2027 2028 // static 2029 unsigned Deoptimizer::ComputeOutgoingArgumentSize(Code* code, 2030 unsigned bailout_id) { 2031 DeoptimizationInputData* data = 2032 DeoptimizationInputData::cast(code->deoptimization_data()); 2033 unsigned height = data->ArgumentsStackHeight(bailout_id)->value(); 2034 return height * kPointerSize; 2035 } 2036 2037 2038 Object* Deoptimizer::ComputeLiteral(int index) const { 2039 DeoptimizationInputData* data = 2040 DeoptimizationInputData::cast(compiled_code_->deoptimization_data()); 2041 FixedArray* literals = data->LiteralArray(); 2042 return literals->get(index); 2043 } 2044 2045 2046 void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate, 2047 BailoutType type, 2048 int max_entry_id) { 2049 // We cannot run this if the serializer is enabled because this will 2050 // cause us to emit relocation information for the external 2051 // references. This is fine because the deoptimizer's code section 2052 // isn't meant to be serialized at all. 2053 CHECK(type == EAGER || type == SOFT || type == LAZY); 2054 DeoptimizerData* data = isolate->deoptimizer_data(); 2055 int entry_count = data->deopt_entry_code_entries_[type]; 2056 if (max_entry_id < entry_count) return; 2057 entry_count = Max(entry_count, Deoptimizer::kMinNumberOfEntries); 2058 while (max_entry_id >= entry_count) entry_count *= 2; 2059 CHECK(entry_count <= Deoptimizer::kMaxNumberOfEntries); 2060 2061 MacroAssembler masm(isolate, NULL, 16 * KB, CodeObjectRequired::kYes); 2062 masm.set_emit_debug_code(false); 2063 GenerateDeoptimizationEntries(&masm, entry_count, type); 2064 CodeDesc desc; 2065 masm.GetCode(&desc); 2066 DCHECK(!RelocInfo::RequiresRelocation(desc)); 2067 2068 MemoryChunk* chunk = data->deopt_entry_code_[type]; 2069 CHECK(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >= 2070 desc.instr_size); 2071 if (!chunk->CommitArea(desc.instr_size)) { 2072 V8::FatalProcessOutOfMemory( 2073 "Deoptimizer::EnsureCodeForDeoptimizationEntry"); 2074 } 2075 CopyBytes(chunk->area_start(), desc.buffer, 2076 static_cast<size_t>(desc.instr_size)); 2077 Assembler::FlushICache(isolate, chunk->area_start(), desc.instr_size); 2078 2079 data->deopt_entry_code_entries_[type] = entry_count; 2080 } 2081 2082 2083 FrameDescription::FrameDescription(uint32_t frame_size, 2084 JSFunction* function) 2085 : frame_size_(frame_size), 2086 function_(function), 2087 top_(kZapUint32), 2088 pc_(kZapUint32), 2089 fp_(kZapUint32), 2090 context_(kZapUint32), 2091 constant_pool_(kZapUint32) { 2092 // Zap all the registers. 2093 for (int r = 0; r < Register::kNumRegisters; r++) { 2094 // TODO(jbramley): It isn't safe to use kZapUint32 here. If the register 2095 // isn't used before the next safepoint, the GC will try to scan it as a 2096 // tagged value. kZapUint32 looks like a valid tagged pointer, but it isn't. 2097 SetRegister(r, kZapUint32); 2098 } 2099 2100 // Zap all the slots. 2101 for (unsigned o = 0; o < frame_size; o += kPointerSize) { 2102 SetFrameSlot(o, kZapUint32); 2103 } 2104 } 2105 2106 2107 int FrameDescription::ComputeFixedSize() { 2108 if (type_ == StackFrame::INTERPRETED) { 2109 return InterpreterFrameConstants::kFixedFrameSize + 2110 (ComputeParametersCount() + 1) * kPointerSize; 2111 } else { 2112 return StandardFrameConstants::kFixedFrameSize + 2113 (ComputeParametersCount() + 1) * kPointerSize; 2114 } 2115 } 2116 2117 2118 unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) { 2119 if (slot_index >= 0) { 2120 // Local or spill slots. Skip the fixed part of the frame 2121 // including all arguments. 2122 unsigned base = GetFrameSize() - ComputeFixedSize(); 2123 return base - ((slot_index + 1) * kPointerSize); 2124 } else { 2125 // Incoming parameter. 2126 int arg_size = (ComputeParametersCount() + 1) * kPointerSize; 2127 unsigned base = GetFrameSize() - arg_size; 2128 return base - ((slot_index + 1) * kPointerSize); 2129 } 2130 } 2131 2132 2133 int FrameDescription::ComputeParametersCount() { 2134 switch (type_) { 2135 case StackFrame::JAVA_SCRIPT: 2136 return function_->shared()->internal_formal_parameter_count(); 2137 case StackFrame::ARGUMENTS_ADAPTOR: { 2138 // Last slot contains number of incomming arguments as a smi. 2139 // Can't use GetExpression(0) because it would cause infinite recursion. 2140 return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value(); 2141 } 2142 case StackFrame::STUB: 2143 return -1; // Minus receiver. 2144 default: 2145 FATAL("Unexpected stack frame type"); 2146 return 0; 2147 } 2148 } 2149 2150 2151 Object* FrameDescription::GetParameter(int index) { 2152 CHECK_GE(index, 0); 2153 CHECK_LT(index, ComputeParametersCount()); 2154 // The slot indexes for incoming arguments are negative. 2155 unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount()); 2156 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset)); 2157 } 2158 2159 2160 unsigned FrameDescription::GetExpressionCount() { 2161 CHECK_EQ(StackFrame::JAVA_SCRIPT, type_); 2162 unsigned size = GetFrameSize() - ComputeFixedSize(); 2163 return size / kPointerSize; 2164 } 2165 2166 2167 Object* FrameDescription::GetExpression(int index) { 2168 DCHECK_EQ(StackFrame::JAVA_SCRIPT, type_); 2169 unsigned offset = GetOffsetFromSlotIndex(index); 2170 return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset)); 2171 } 2172 2173 2174 void TranslationBuffer::Add(int32_t value, Zone* zone) { 2175 // This wouldn't handle kMinInt correctly if it ever encountered it. 2176 DCHECK(value != kMinInt); 2177 // Encode the sign bit in the least significant bit. 2178 bool is_negative = (value < 0); 2179 uint32_t bits = ((is_negative ? -value : value) << 1) | 2180 static_cast<int32_t>(is_negative); 2181 // Encode the individual bytes using the least significant bit of 2182 // each byte to indicate whether or not more bytes follow. 2183 do { 2184 uint32_t next = bits >> 7; 2185 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone); 2186 bits = next; 2187 } while (bits != 0); 2188 } 2189 2190 2191 int32_t TranslationIterator::Next() { 2192 // Run through the bytes until we reach one with a least significant 2193 // bit of zero (marks the end). 2194 uint32_t bits = 0; 2195 for (int i = 0; true; i += 7) { 2196 DCHECK(HasNext()); 2197 uint8_t next = buffer_->get(index_++); 2198 bits |= (next >> 1) << i; 2199 if ((next & 1) == 0) break; 2200 } 2201 // The bits encode the sign in the least significant bit. 2202 bool is_negative = (bits & 1) == 1; 2203 int32_t result = bits >> 1; 2204 return is_negative ? -result : result; 2205 } 2206 2207 2208 Handle<ByteArray> TranslationBuffer::CreateByteArray(Factory* factory) { 2209 int length = contents_.length(); 2210 Handle<ByteArray> result = factory->NewByteArray(length, TENURED); 2211 MemCopy(result->GetDataStartAddress(), contents_.ToVector().start(), length); 2212 return result; 2213 } 2214 2215 2216 void Translation::BeginConstructStubFrame(int literal_id, unsigned height) { 2217 buffer_->Add(CONSTRUCT_STUB_FRAME, zone()); 2218 buffer_->Add(literal_id, zone()); 2219 buffer_->Add(height, zone()); 2220 } 2221 2222 2223 void Translation::BeginGetterStubFrame(int literal_id) { 2224 buffer_->Add(GETTER_STUB_FRAME, zone()); 2225 buffer_->Add(literal_id, zone()); 2226 } 2227 2228 2229 void Translation::BeginSetterStubFrame(int literal_id) { 2230 buffer_->Add(SETTER_STUB_FRAME, zone()); 2231 buffer_->Add(literal_id, zone()); 2232 } 2233 2234 2235 void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) { 2236 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone()); 2237 buffer_->Add(literal_id, zone()); 2238 buffer_->Add(height, zone()); 2239 } 2240 2241 2242 void Translation::BeginJSFrame(BailoutId node_id, 2243 int literal_id, 2244 unsigned height) { 2245 buffer_->Add(JS_FRAME, zone()); 2246 buffer_->Add(node_id.ToInt(), zone()); 2247 buffer_->Add(literal_id, zone()); 2248 buffer_->Add(height, zone()); 2249 } 2250 2251 2252 void Translation::BeginInterpretedFrame(BailoutId bytecode_offset, 2253 int literal_id, unsigned height) { 2254 buffer_->Add(INTERPRETED_FRAME, zone()); 2255 buffer_->Add(bytecode_offset.ToInt(), zone()); 2256 buffer_->Add(literal_id, zone()); 2257 buffer_->Add(height, zone()); 2258 } 2259 2260 2261 void Translation::BeginCompiledStubFrame(int height) { 2262 buffer_->Add(COMPILED_STUB_FRAME, zone()); 2263 buffer_->Add(height, zone()); 2264 } 2265 2266 2267 void Translation::BeginArgumentsObject(int args_length) { 2268 buffer_->Add(ARGUMENTS_OBJECT, zone()); 2269 buffer_->Add(args_length, zone()); 2270 } 2271 2272 2273 void Translation::BeginCapturedObject(int length) { 2274 buffer_->Add(CAPTURED_OBJECT, zone()); 2275 buffer_->Add(length, zone()); 2276 } 2277 2278 2279 void Translation::DuplicateObject(int object_index) { 2280 buffer_->Add(DUPLICATED_OBJECT, zone()); 2281 buffer_->Add(object_index, zone()); 2282 } 2283 2284 2285 void Translation::StoreRegister(Register reg) { 2286 buffer_->Add(REGISTER, zone()); 2287 buffer_->Add(reg.code(), zone()); 2288 } 2289 2290 2291 void Translation::StoreInt32Register(Register reg) { 2292 buffer_->Add(INT32_REGISTER, zone()); 2293 buffer_->Add(reg.code(), zone()); 2294 } 2295 2296 2297 void Translation::StoreUint32Register(Register reg) { 2298 buffer_->Add(UINT32_REGISTER, zone()); 2299 buffer_->Add(reg.code(), zone()); 2300 } 2301 2302 2303 void Translation::StoreBoolRegister(Register reg) { 2304 buffer_->Add(BOOL_REGISTER, zone()); 2305 buffer_->Add(reg.code(), zone()); 2306 } 2307 2308 2309 void Translation::StoreDoubleRegister(DoubleRegister reg) { 2310 buffer_->Add(DOUBLE_REGISTER, zone()); 2311 buffer_->Add(reg.code(), zone()); 2312 } 2313 2314 2315 void Translation::StoreStackSlot(int index) { 2316 buffer_->Add(STACK_SLOT, zone()); 2317 buffer_->Add(index, zone()); 2318 } 2319 2320 2321 void Translation::StoreInt32StackSlot(int index) { 2322 buffer_->Add(INT32_STACK_SLOT, zone()); 2323 buffer_->Add(index, zone()); 2324 } 2325 2326 2327 void Translation::StoreUint32StackSlot(int index) { 2328 buffer_->Add(UINT32_STACK_SLOT, zone()); 2329 buffer_->Add(index, zone()); 2330 } 2331 2332 2333 void Translation::StoreBoolStackSlot(int index) { 2334 buffer_->Add(BOOL_STACK_SLOT, zone()); 2335 buffer_->Add(index, zone()); 2336 } 2337 2338 2339 void Translation::StoreDoubleStackSlot(int index) { 2340 buffer_->Add(DOUBLE_STACK_SLOT, zone()); 2341 buffer_->Add(index, zone()); 2342 } 2343 2344 2345 void Translation::StoreLiteral(int literal_id) { 2346 buffer_->Add(LITERAL, zone()); 2347 buffer_->Add(literal_id, zone()); 2348 } 2349 2350 2351 void Translation::StoreArgumentsObject(bool args_known, 2352 int args_index, 2353 int args_length) { 2354 buffer_->Add(ARGUMENTS_OBJECT, zone()); 2355 buffer_->Add(args_known, zone()); 2356 buffer_->Add(args_index, zone()); 2357 buffer_->Add(args_length, zone()); 2358 } 2359 2360 2361 void Translation::StoreJSFrameFunction() { 2362 buffer_->Add(JS_FRAME_FUNCTION, zone()); 2363 } 2364 2365 2366 int Translation::NumberOfOperandsFor(Opcode opcode) { 2367 switch (opcode) { 2368 case JS_FRAME_FUNCTION: 2369 return 0; 2370 case GETTER_STUB_FRAME: 2371 case SETTER_STUB_FRAME: 2372 case DUPLICATED_OBJECT: 2373 case ARGUMENTS_OBJECT: 2374 case CAPTURED_OBJECT: 2375 case REGISTER: 2376 case INT32_REGISTER: 2377 case UINT32_REGISTER: 2378 case BOOL_REGISTER: 2379 case DOUBLE_REGISTER: 2380 case STACK_SLOT: 2381 case INT32_STACK_SLOT: 2382 case UINT32_STACK_SLOT: 2383 case BOOL_STACK_SLOT: 2384 case DOUBLE_STACK_SLOT: 2385 case LITERAL: 2386 case COMPILED_STUB_FRAME: 2387 return 1; 2388 case BEGIN: 2389 case ARGUMENTS_ADAPTOR_FRAME: 2390 case CONSTRUCT_STUB_FRAME: 2391 return 2; 2392 case JS_FRAME: 2393 case INTERPRETED_FRAME: 2394 return 3; 2395 } 2396 FATAL("Unexpected translation type"); 2397 return -1; 2398 } 2399 2400 2401 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 2402 2403 const char* Translation::StringFor(Opcode opcode) { 2404 #define TRANSLATION_OPCODE_CASE(item) case item: return #item; 2405 switch (opcode) { 2406 TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE) 2407 } 2408 #undef TRANSLATION_OPCODE_CASE 2409 UNREACHABLE(); 2410 return ""; 2411 } 2412 2413 #endif 2414 2415 2416 Handle<FixedArray> MaterializedObjectStore::Get(Address fp) { 2417 int index = StackIdToIndex(fp); 2418 if (index == -1) { 2419 return Handle<FixedArray>::null(); 2420 } 2421 Handle<FixedArray> array = GetStackEntries(); 2422 CHECK_GT(array->length(), index); 2423 return Handle<FixedArray>::cast(Handle<Object>(array->get(index), isolate())); 2424 } 2425 2426 2427 void MaterializedObjectStore::Set(Address fp, 2428 Handle<FixedArray> materialized_objects) { 2429 int index = StackIdToIndex(fp); 2430 if (index == -1) { 2431 index = frame_fps_.length(); 2432 frame_fps_.Add(fp); 2433 } 2434 2435 Handle<FixedArray> array = EnsureStackEntries(index + 1); 2436 array->set(index, *materialized_objects); 2437 } 2438 2439 2440 bool MaterializedObjectStore::Remove(Address fp) { 2441 int index = StackIdToIndex(fp); 2442 if (index == -1) { 2443 return false; 2444 } 2445 CHECK_GE(index, 0); 2446 2447 frame_fps_.Remove(index); 2448 FixedArray* array = isolate()->heap()->materialized_objects(); 2449 CHECK_LT(index, array->length()); 2450 for (int i = index; i < frame_fps_.length(); i++) { 2451 array->set(i, array->get(i + 1)); 2452 } 2453 array->set(frame_fps_.length(), isolate()->heap()->undefined_value()); 2454 return true; 2455 } 2456 2457 2458 int MaterializedObjectStore::StackIdToIndex(Address fp) { 2459 for (int i = 0; i < frame_fps_.length(); i++) { 2460 if (frame_fps_[i] == fp) { 2461 return i; 2462 } 2463 } 2464 return -1; 2465 } 2466 2467 2468 Handle<FixedArray> MaterializedObjectStore::GetStackEntries() { 2469 return Handle<FixedArray>(isolate()->heap()->materialized_objects()); 2470 } 2471 2472 2473 Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) { 2474 Handle<FixedArray> array = GetStackEntries(); 2475 if (array->length() >= length) { 2476 return array; 2477 } 2478 2479 int new_length = length > 10 ? length : 10; 2480 if (new_length < 2 * array->length()) { 2481 new_length = 2 * array->length(); 2482 } 2483 2484 Handle<FixedArray> new_array = 2485 isolate()->factory()->NewFixedArray(new_length, TENURED); 2486 for (int i = 0; i < array->length(); i++) { 2487 new_array->set(i, array->get(i)); 2488 } 2489 for (int i = array->length(); i < length; i++) { 2490 new_array->set(i, isolate()->heap()->undefined_value()); 2491 } 2492 isolate()->heap()->SetRootMaterializedObjects(*new_array); 2493 return new_array; 2494 } 2495 2496 2497 DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer, 2498 int frame_index, 2499 bool has_arguments_adaptor, 2500 bool has_construct_stub) { 2501 FrameDescription* output_frame = deoptimizer->output_[frame_index]; 2502 function_ = output_frame->GetFunction(); 2503 context_ = reinterpret_cast<Object*>(output_frame->GetContext()); 2504 has_construct_stub_ = has_construct_stub; 2505 expression_count_ = output_frame->GetExpressionCount(); 2506 expression_stack_ = new Object* [expression_count_]; 2507 // Get the source position using the unoptimized code. 2508 Address pc = reinterpret_cast<Address>(output_frame->GetPc()); 2509 Code* code = Code::cast(deoptimizer->isolate()->FindCodeObject(pc)); 2510 source_position_ = code->SourcePosition(pc); 2511 2512 for (int i = 0; i < expression_count_; i++) { 2513 Object* value = output_frame->GetExpression(i); 2514 // Replace materialization markers with the undefined value. 2515 if (value == deoptimizer->isolate()->heap()->arguments_marker()) { 2516 value = deoptimizer->isolate()->heap()->undefined_value(); 2517 } 2518 SetExpression(i, value); 2519 } 2520 2521 if (has_arguments_adaptor) { 2522 output_frame = deoptimizer->output_[frame_index - 1]; 2523 CHECK_EQ(output_frame->GetFrameType(), StackFrame::ARGUMENTS_ADAPTOR); 2524 } 2525 2526 parameters_count_ = output_frame->ComputeParametersCount(); 2527 parameters_ = new Object* [parameters_count_]; 2528 for (int i = 0; i < parameters_count_; i++) { 2529 Object* value = output_frame->GetParameter(i); 2530 // Replace materialization markers with the undefined value. 2531 if (value == deoptimizer->isolate()->heap()->arguments_marker()) { 2532 value = deoptimizer->isolate()->heap()->undefined_value(); 2533 } 2534 SetParameter(i, value); 2535 } 2536 } 2537 2538 2539 DeoptimizedFrameInfo::~DeoptimizedFrameInfo() { 2540 delete[] expression_stack_; 2541 delete[] parameters_; 2542 } 2543 2544 2545 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { 2546 v->VisitPointer(bit_cast<Object**>(&function_)); 2547 v->VisitPointer(&context_); 2548 v->VisitPointers(parameters_, parameters_ + parameters_count_); 2549 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); 2550 } 2551 2552 2553 const char* Deoptimizer::GetDeoptReason(DeoptReason deopt_reason) { 2554 DCHECK(deopt_reason < kLastDeoptReason); 2555 #define DEOPT_MESSAGES_TEXTS(C, T) T, 2556 static const char* deopt_messages_[] = { 2557 DEOPT_MESSAGES_LIST(DEOPT_MESSAGES_TEXTS)}; 2558 #undef DEOPT_MESSAGES_TEXTS 2559 return deopt_messages_[deopt_reason]; 2560 } 2561 2562 2563 Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, Address pc) { 2564 SourcePosition last_position = SourcePosition::Unknown(); 2565 Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason; 2566 int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) | 2567 RelocInfo::ModeMask(RelocInfo::POSITION); 2568 for (RelocIterator it(code, mask); !it.done(); it.next()) { 2569 RelocInfo* info = it.rinfo(); 2570 if (info->pc() >= pc) return DeoptInfo(last_position, NULL, last_reason); 2571 if (info->rmode() == RelocInfo::POSITION) { 2572 int raw_position = static_cast<int>(info->data()); 2573 last_position = raw_position ? SourcePosition::FromRaw(raw_position) 2574 : SourcePosition::Unknown(); 2575 } else if (info->rmode() == RelocInfo::DEOPT_REASON) { 2576 last_reason = static_cast<Deoptimizer::DeoptReason>(info->data()); 2577 } 2578 } 2579 return DeoptInfo(SourcePosition::Unknown(), NULL, Deoptimizer::kNoReason); 2580 } 2581 2582 2583 // static 2584 TranslatedValue TranslatedValue::NewArgumentsObject(TranslatedState* container, 2585 int length, 2586 int object_index) { 2587 TranslatedValue slot(container, kArgumentsObject); 2588 slot.materialization_info_ = {object_index, length}; 2589 return slot; 2590 } 2591 2592 2593 // static 2594 TranslatedValue TranslatedValue::NewDeferredObject(TranslatedState* container, 2595 int length, 2596 int object_index) { 2597 TranslatedValue slot(container, kCapturedObject); 2598 slot.materialization_info_ = {object_index, length}; 2599 return slot; 2600 } 2601 2602 2603 // static 2604 TranslatedValue TranslatedValue::NewDuplicateObject(TranslatedState* container, 2605 int id) { 2606 TranslatedValue slot(container, kDuplicatedObject); 2607 slot.materialization_info_ = {id, -1}; 2608 return slot; 2609 } 2610 2611 2612 // static 2613 TranslatedValue TranslatedValue::NewDouble(TranslatedState* container, 2614 double value) { 2615 TranslatedValue slot(container, kDouble); 2616 slot.double_value_ = value; 2617 return slot; 2618 } 2619 2620 2621 // static 2622 TranslatedValue TranslatedValue::NewInt32(TranslatedState* container, 2623 int32_t value) { 2624 TranslatedValue slot(container, kInt32); 2625 slot.int32_value_ = value; 2626 return slot; 2627 } 2628 2629 2630 // static 2631 TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container, 2632 uint32_t value) { 2633 TranslatedValue slot(container, kUInt32); 2634 slot.uint32_value_ = value; 2635 return slot; 2636 } 2637 2638 2639 // static 2640 TranslatedValue TranslatedValue::NewBool(TranslatedState* container, 2641 uint32_t value) { 2642 TranslatedValue slot(container, kBoolBit); 2643 slot.uint32_value_ = value; 2644 return slot; 2645 } 2646 2647 2648 // static 2649 TranslatedValue TranslatedValue::NewTagged(TranslatedState* container, 2650 Object* literal) { 2651 TranslatedValue slot(container, kTagged); 2652 slot.raw_literal_ = literal; 2653 return slot; 2654 } 2655 2656 2657 // static 2658 TranslatedValue TranslatedValue::NewInvalid(TranslatedState* container) { 2659 return TranslatedValue(container, kInvalid); 2660 } 2661 2662 2663 Isolate* TranslatedValue::isolate() const { return container_->isolate(); } 2664 2665 2666 Object* TranslatedValue::raw_literal() const { 2667 DCHECK_EQ(kTagged, kind()); 2668 return raw_literal_; 2669 } 2670 2671 2672 int32_t TranslatedValue::int32_value() const { 2673 DCHECK_EQ(kInt32, kind()); 2674 return int32_value_; 2675 } 2676 2677 2678 uint32_t TranslatedValue::uint32_value() const { 2679 DCHECK(kind() == kUInt32 || kind() == kBoolBit); 2680 return uint32_value_; 2681 } 2682 2683 2684 double TranslatedValue::double_value() const { 2685 DCHECK_EQ(kDouble, kind()); 2686 return double_value_; 2687 } 2688 2689 2690 int TranslatedValue::object_length() const { 2691 DCHECK(kind() == kArgumentsObject || kind() == kCapturedObject); 2692 return materialization_info_.length_; 2693 } 2694 2695 2696 int TranslatedValue::object_index() const { 2697 DCHECK(kind() == kArgumentsObject || kind() == kCapturedObject || 2698 kind() == kDuplicatedObject); 2699 return materialization_info_.id_; 2700 } 2701 2702 2703 Object* TranslatedValue::GetRawValue() const { 2704 // If we have a value, return it. 2705 Handle<Object> result_handle; 2706 if (value_.ToHandle(&result_handle)) { 2707 return *result_handle; 2708 } 2709 2710 // Otherwise, do a best effort to get the value without allocation. 2711 switch (kind()) { 2712 case kTagged: 2713 return raw_literal(); 2714 2715 case kInt32: { 2716 bool is_smi = Smi::IsValid(int32_value()); 2717 if (is_smi) { 2718 return Smi::FromInt(int32_value()); 2719 } 2720 break; 2721 } 2722 2723 case kUInt32: { 2724 bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue)); 2725 if (is_smi) { 2726 return Smi::FromInt(static_cast<int32_t>(uint32_value())); 2727 } 2728 break; 2729 } 2730 2731 case kBoolBit: { 2732 if (uint32_value() == 0) { 2733 return isolate()->heap()->false_value(); 2734 } else { 2735 CHECK_EQ(1U, uint32_value()); 2736 return isolate()->heap()->true_value(); 2737 } 2738 } 2739 2740 default: 2741 break; 2742 } 2743 2744 // If we could not get the value without allocation, return the arguments 2745 // marker. 2746 return isolate()->heap()->arguments_marker(); 2747 } 2748 2749 2750 Handle<Object> TranslatedValue::GetValue() { 2751 Handle<Object> result; 2752 // If we already have a value, then get it. 2753 if (value_.ToHandle(&result)) return result; 2754 2755 // Otherwise we have to materialize. 2756 switch (kind()) { 2757 case TranslatedValue::kTagged: 2758 case TranslatedValue::kInt32: 2759 case TranslatedValue::kUInt32: 2760 case TranslatedValue::kBoolBit: 2761 case TranslatedValue::kDouble: { 2762 MaterializeSimple(); 2763 return value_.ToHandleChecked(); 2764 } 2765 2766 case TranslatedValue::kArgumentsObject: 2767 case TranslatedValue::kCapturedObject: 2768 case TranslatedValue::kDuplicatedObject: 2769 return container_->MaterializeObjectAt(object_index()); 2770 2771 case TranslatedValue::kInvalid: 2772 FATAL("unexpected case"); 2773 return Handle<Object>::null(); 2774 } 2775 2776 FATAL("internal error: value missing"); 2777 return Handle<Object>::null(); 2778 } 2779 2780 2781 void TranslatedValue::MaterializeSimple() { 2782 // If we already have materialized, return. 2783 if (!value_.is_null()) return; 2784 2785 Object* raw_value = GetRawValue(); 2786 if (raw_value != isolate()->heap()->arguments_marker()) { 2787 // We can get the value without allocation, just return it here. 2788 value_ = Handle<Object>(raw_value, isolate()); 2789 return; 2790 } 2791 2792 switch (kind()) { 2793 case kInt32: { 2794 value_ = Handle<Object>(isolate()->factory()->NewNumber(int32_value())); 2795 return; 2796 } 2797 2798 case kUInt32: 2799 value_ = Handle<Object>(isolate()->factory()->NewNumber(uint32_value())); 2800 return; 2801 2802 case kDouble: 2803 value_ = Handle<Object>(isolate()->factory()->NewNumber(double_value())); 2804 return; 2805 2806 case kCapturedObject: 2807 case kDuplicatedObject: 2808 case kArgumentsObject: 2809 case kInvalid: 2810 case kTagged: 2811 case kBoolBit: 2812 FATAL("internal error: unexpected materialization."); 2813 break; 2814 } 2815 } 2816 2817 2818 bool TranslatedValue::IsMaterializedObject() const { 2819 switch (kind()) { 2820 case kCapturedObject: 2821 case kDuplicatedObject: 2822 case kArgumentsObject: 2823 return true; 2824 default: 2825 return false; 2826 } 2827 } 2828 2829 2830 int TranslatedValue::GetChildrenCount() const { 2831 if (kind() == kCapturedObject || kind() == kArgumentsObject) { 2832 return object_length(); 2833 } else { 2834 return 0; 2835 } 2836 } 2837 2838 2839 uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) { 2840 Address address = fp + slot_offset; 2841 #if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT 2842 return Memory::uint32_at(address + kIntSize); 2843 #else 2844 return Memory::uint32_at(address); 2845 #endif 2846 } 2847 2848 2849 void TranslatedValue::Handlify() { 2850 if (kind() == kTagged) { 2851 value_ = Handle<Object>(raw_literal(), isolate()); 2852 raw_literal_ = nullptr; 2853 } 2854 } 2855 2856 2857 TranslatedFrame TranslatedFrame::JSFrame(BailoutId node_id, 2858 SharedFunctionInfo* shared_info, 2859 int height) { 2860 TranslatedFrame frame(kFunction, shared_info->GetIsolate(), shared_info, 2861 height); 2862 frame.node_id_ = node_id; 2863 return frame; 2864 } 2865 2866 2867 TranslatedFrame TranslatedFrame::InterpretedFrame( 2868 BailoutId bytecode_offset, SharedFunctionInfo* shared_info, int height) { 2869 TranslatedFrame frame(kInterpretedFunction, shared_info->GetIsolate(), 2870 shared_info, height); 2871 frame.node_id_ = bytecode_offset; 2872 return frame; 2873 } 2874 2875 2876 TranslatedFrame TranslatedFrame::AccessorFrame( 2877 Kind kind, SharedFunctionInfo* shared_info) { 2878 DCHECK(kind == kSetter || kind == kGetter); 2879 return TranslatedFrame(kind, shared_info->GetIsolate(), shared_info); 2880 } 2881 2882 2883 TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame( 2884 SharedFunctionInfo* shared_info, int height) { 2885 return TranslatedFrame(kArgumentsAdaptor, shared_info->GetIsolate(), 2886 shared_info, height); 2887 } 2888 2889 2890 TranslatedFrame TranslatedFrame::ConstructStubFrame( 2891 SharedFunctionInfo* shared_info, int height) { 2892 return TranslatedFrame(kConstructStub, shared_info->GetIsolate(), shared_info, 2893 height); 2894 } 2895 2896 2897 int TranslatedFrame::GetValueCount() { 2898 switch (kind()) { 2899 case kFunction: { 2900 int parameter_count = 2901 raw_shared_info_->internal_formal_parameter_count() + 1; 2902 // + 1 for function. 2903 return height_ + parameter_count + 1; 2904 } 2905 2906 case kInterpretedFunction: { 2907 int parameter_count = 2908 raw_shared_info_->internal_formal_parameter_count() + 1; 2909 // + 3 for function, context and accumulator. 2910 return height_ + parameter_count + 3; 2911 } 2912 2913 case kGetter: 2914 return 2; // Function and receiver. 2915 2916 case kSetter: 2917 return 3; // Function, receiver and the value to set. 2918 2919 case kArgumentsAdaptor: 2920 case kConstructStub: 2921 return 1 + height_; 2922 2923 case kCompiledStub: 2924 return height_; 2925 2926 case kInvalid: 2927 UNREACHABLE(); 2928 break; 2929 } 2930 UNREACHABLE(); 2931 return -1; 2932 } 2933 2934 2935 void TranslatedFrame::Handlify() { 2936 if (raw_shared_info_ != nullptr) { 2937 shared_info_ = Handle<SharedFunctionInfo>(raw_shared_info_); 2938 raw_shared_info_ = nullptr; 2939 } 2940 for (auto& value : values_) { 2941 value.Handlify(); 2942 } 2943 } 2944 2945 2946 TranslatedFrame TranslatedState::CreateNextTranslatedFrame( 2947 TranslationIterator* iterator, FixedArray* literal_array, Address fp, 2948 FILE* trace_file) { 2949 Translation::Opcode opcode = 2950 static_cast<Translation::Opcode>(iterator->Next()); 2951 switch (opcode) { 2952 case Translation::JS_FRAME: { 2953 BailoutId node_id = BailoutId(iterator->Next()); 2954 SharedFunctionInfo* shared_info = 2955 SharedFunctionInfo::cast(literal_array->get(iterator->Next())); 2956 int height = iterator->Next(); 2957 if (trace_file != nullptr) { 2958 base::SmartArrayPointer<char> name = 2959 shared_info->DebugName()->ToCString(); 2960 PrintF(trace_file, " reading input frame %s", name.get()); 2961 int arg_count = shared_info->internal_formal_parameter_count() + 1; 2962 PrintF(trace_file, " => node=%d, args=%d, height=%d; inputs:\n", 2963 node_id.ToInt(), arg_count, height); 2964 } 2965 return TranslatedFrame::JSFrame(node_id, shared_info, height); 2966 } 2967 2968 case Translation::INTERPRETED_FRAME: { 2969 BailoutId bytecode_offset = BailoutId(iterator->Next()); 2970 SharedFunctionInfo* shared_info = 2971 SharedFunctionInfo::cast(literal_array->get(iterator->Next())); 2972 int height = iterator->Next(); 2973 if (trace_file != nullptr) { 2974 base::SmartArrayPointer<char> name = 2975 shared_info->DebugName()->ToCString(); 2976 PrintF(trace_file, " reading input frame %s", name.get()); 2977 int arg_count = shared_info->internal_formal_parameter_count() + 1; 2978 PrintF(trace_file, 2979 " => bytecode_offset=%d, args=%d, height=%d; inputs:\n", 2980 bytecode_offset.ToInt(), arg_count, height); 2981 } 2982 return TranslatedFrame::InterpretedFrame(bytecode_offset, shared_info, 2983 height); 2984 } 2985 2986 case Translation::ARGUMENTS_ADAPTOR_FRAME: { 2987 SharedFunctionInfo* shared_info = 2988 SharedFunctionInfo::cast(literal_array->get(iterator->Next())); 2989 int height = iterator->Next(); 2990 if (trace_file != nullptr) { 2991 base::SmartArrayPointer<char> name = 2992 shared_info->DebugName()->ToCString(); 2993 PrintF(trace_file, " reading arguments adaptor frame %s", name.get()); 2994 PrintF(trace_file, " => height=%d; inputs:\n", height); 2995 } 2996 return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height); 2997 } 2998 2999 case Translation::CONSTRUCT_STUB_FRAME: { 3000 SharedFunctionInfo* shared_info = 3001 SharedFunctionInfo::cast(literal_array->get(iterator->Next())); 3002 int height = iterator->Next(); 3003 if (trace_file != nullptr) { 3004 base::SmartArrayPointer<char> name = 3005 shared_info->DebugName()->ToCString(); 3006 PrintF(trace_file, " reading construct stub frame %s", name.get()); 3007 PrintF(trace_file, " => height=%d; inputs:\n", height); 3008 } 3009 return TranslatedFrame::ConstructStubFrame(shared_info, height); 3010 } 3011 3012 case Translation::GETTER_STUB_FRAME: { 3013 SharedFunctionInfo* shared_info = 3014 SharedFunctionInfo::cast(literal_array->get(iterator->Next())); 3015 if (trace_file != nullptr) { 3016 base::SmartArrayPointer<char> name = 3017 shared_info->DebugName()->ToCString(); 3018 PrintF(trace_file, " reading getter frame %s; inputs:\n", name.get()); 3019 } 3020 return TranslatedFrame::AccessorFrame(TranslatedFrame::kGetter, 3021 shared_info); 3022 } 3023 3024 case Translation::SETTER_STUB_FRAME: { 3025 SharedFunctionInfo* shared_info = 3026 SharedFunctionInfo::cast(literal_array->get(iterator->Next())); 3027 if (trace_file != nullptr) { 3028 base::SmartArrayPointer<char> name = 3029 shared_info->DebugName()->ToCString(); 3030 PrintF(trace_file, " reading setter frame %s; inputs:\n", name.get()); 3031 } 3032 return TranslatedFrame::AccessorFrame(TranslatedFrame::kSetter, 3033 shared_info); 3034 } 3035 3036 case Translation::COMPILED_STUB_FRAME: { 3037 int height = iterator->Next(); 3038 if (trace_file != nullptr) { 3039 PrintF(trace_file, 3040 " reading compiler stub frame => height=%d; inputs:\n", height); 3041 } 3042 return TranslatedFrame::CompiledStubFrame(height, 3043 literal_array->GetIsolate()); 3044 } 3045 3046 case Translation::BEGIN: 3047 case Translation::DUPLICATED_OBJECT: 3048 case Translation::ARGUMENTS_OBJECT: 3049 case Translation::CAPTURED_OBJECT: 3050 case Translation::REGISTER: 3051 case Translation::INT32_REGISTER: 3052 case Translation::UINT32_REGISTER: 3053 case Translation::BOOL_REGISTER: 3054 case Translation::DOUBLE_REGISTER: 3055 case Translation::STACK_SLOT: 3056 case Translation::INT32_STACK_SLOT: 3057 case Translation::UINT32_STACK_SLOT: 3058 case Translation::BOOL_STACK_SLOT: 3059 case Translation::DOUBLE_STACK_SLOT: 3060 case Translation::LITERAL: 3061 case Translation::JS_FRAME_FUNCTION: 3062 break; 3063 } 3064 FATAL("We should never get here - unexpected deopt info."); 3065 return TranslatedFrame::InvalidFrame(); 3066 } 3067 3068 3069 // static 3070 void TranslatedFrame::AdvanceIterator( 3071 std::deque<TranslatedValue>::iterator* iter) { 3072 int values_to_skip = 1; 3073 while (values_to_skip > 0) { 3074 // Consume the current element. 3075 values_to_skip--; 3076 // Add all the children. 3077 values_to_skip += (*iter)->GetChildrenCount(); 3078 3079 (*iter)++; 3080 } 3081 } 3082 3083 3084 // We can't intermix stack decoding and allocations because 3085 // deoptimization infrastracture is not GC safe. 3086 // Thus we build a temporary structure in malloced space. 3087 TranslatedValue TranslatedState::CreateNextTranslatedValue( 3088 int frame_index, int value_index, TranslationIterator* iterator, 3089 FixedArray* literal_array, Address fp, RegisterValues* registers, 3090 FILE* trace_file) { 3091 disasm::NameConverter converter; 3092 3093 Translation::Opcode opcode = 3094 static_cast<Translation::Opcode>(iterator->Next()); 3095 switch (opcode) { 3096 case Translation::BEGIN: 3097 case Translation::JS_FRAME: 3098 case Translation::INTERPRETED_FRAME: 3099 case Translation::ARGUMENTS_ADAPTOR_FRAME: 3100 case Translation::CONSTRUCT_STUB_FRAME: 3101 case Translation::GETTER_STUB_FRAME: 3102 case Translation::SETTER_STUB_FRAME: 3103 case Translation::COMPILED_STUB_FRAME: 3104 // Peeled off before getting here. 3105 break; 3106 3107 case Translation::DUPLICATED_OBJECT: { 3108 int object_id = iterator->Next(); 3109 if (trace_file != nullptr) { 3110 PrintF(trace_file, "duplicated object #%d", object_id); 3111 } 3112 object_positions_.push_back(object_positions_[object_id]); 3113 return TranslatedValue::NewDuplicateObject(this, object_id); 3114 } 3115 3116 case Translation::ARGUMENTS_OBJECT: { 3117 int arg_count = iterator->Next(); 3118 int object_index = static_cast<int>(object_positions_.size()); 3119 if (trace_file != nullptr) { 3120 PrintF(trace_file, "argumets object #%d (length = %d)", object_index, 3121 arg_count); 3122 } 3123 object_positions_.push_back({frame_index, value_index}); 3124 return TranslatedValue::NewArgumentsObject(this, arg_count, object_index); 3125 } 3126 3127 case Translation::CAPTURED_OBJECT: { 3128 int field_count = iterator->Next(); 3129 int object_index = static_cast<int>(object_positions_.size()); 3130 if (trace_file != nullptr) { 3131 PrintF(trace_file, "captured object #%d (length = %d)", object_index, 3132 field_count); 3133 } 3134 object_positions_.push_back({frame_index, value_index}); 3135 return TranslatedValue::NewDeferredObject(this, field_count, 3136 object_index); 3137 } 3138 3139 case Translation::REGISTER: { 3140 int input_reg = iterator->Next(); 3141 if (registers == nullptr) return TranslatedValue::NewInvalid(this); 3142 intptr_t value = registers->GetRegister(input_reg); 3143 if (trace_file != nullptr) { 3144 PrintF(trace_file, "0x%08" V8PRIxPTR " ; %s ", value, 3145 converter.NameOfCPURegister(input_reg)); 3146 reinterpret_cast<Object*>(value)->ShortPrint(trace_file); 3147 } 3148 return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value)); 3149 } 3150 3151 case Translation::INT32_REGISTER: { 3152 int input_reg = iterator->Next(); 3153 if (registers == nullptr) return TranslatedValue::NewInvalid(this); 3154 intptr_t value = registers->GetRegister(input_reg); 3155 if (trace_file != nullptr) { 3156 PrintF(trace_file, "%" V8PRIdPTR " ; %s ", value, 3157 converter.NameOfCPURegister(input_reg)); 3158 } 3159 return TranslatedValue::NewInt32(this, static_cast<int32_t>(value)); 3160 } 3161 3162 case Translation::UINT32_REGISTER: { 3163 int input_reg = iterator->Next(); 3164 if (registers == nullptr) return TranslatedValue::NewInvalid(this); 3165 intptr_t value = registers->GetRegister(input_reg); 3166 if (trace_file != nullptr) { 3167 PrintF(trace_file, "%" V8PRIuPTR " ; %s (uint)", value, 3168 converter.NameOfCPURegister(input_reg)); 3169 reinterpret_cast<Object*>(value)->ShortPrint(trace_file); 3170 } 3171 return TranslatedValue::NewUInt32(this, static_cast<uint32_t>(value)); 3172 } 3173 3174 case Translation::BOOL_REGISTER: { 3175 int input_reg = iterator->Next(); 3176 if (registers == nullptr) return TranslatedValue::NewInvalid(this); 3177 intptr_t value = registers->GetRegister(input_reg); 3178 if (trace_file != nullptr) { 3179 PrintF(trace_file, "%" V8PRIdPTR " ; %s (bool)", value, 3180 converter.NameOfCPURegister(input_reg)); 3181 } 3182 return TranslatedValue::NewBool(this, static_cast<uint32_t>(value)); 3183 } 3184 3185 case Translation::DOUBLE_REGISTER: { 3186 int input_reg = iterator->Next(); 3187 if (registers == nullptr) return TranslatedValue::NewInvalid(this); 3188 double value = registers->GetDoubleRegister(input_reg); 3189 if (trace_file != nullptr) { 3190 PrintF(trace_file, "%e ; %s (bool)", value, 3191 DoubleRegister::from_code(input_reg).ToString()); 3192 } 3193 return TranslatedValue::NewDouble(this, value); 3194 } 3195 3196 case Translation::STACK_SLOT: { 3197 int slot_offset = 3198 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next()); 3199 intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset)); 3200 if (trace_file != nullptr) { 3201 PrintF(trace_file, "0x%08" V8PRIxPTR " ; [fp %c %d] ", value, 3202 slot_offset < 0 ? '-' : '+', std::abs(slot_offset)); 3203 reinterpret_cast<Object*>(value)->ShortPrint(trace_file); 3204 } 3205 return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value)); 3206 } 3207 3208 case Translation::INT32_STACK_SLOT: { 3209 int slot_offset = 3210 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next()); 3211 uint32_t value = GetUInt32Slot(fp, slot_offset); 3212 if (trace_file != nullptr) { 3213 PrintF(trace_file, "%d ; (int) [fp %c %d] ", 3214 static_cast<int32_t>(value), slot_offset < 0 ? '-' : '+', 3215 std::abs(slot_offset)); 3216 } 3217 return TranslatedValue::NewInt32(this, value); 3218 } 3219 3220 case Translation::UINT32_STACK_SLOT: { 3221 int slot_offset = 3222 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next()); 3223 uint32_t value = GetUInt32Slot(fp, slot_offset); 3224 if (trace_file != nullptr) { 3225 PrintF(trace_file, "%u ; (uint) [fp %c %d] ", value, 3226 slot_offset < 0 ? '-' : '+', std::abs(slot_offset)); 3227 } 3228 return TranslatedValue::NewUInt32(this, value); 3229 } 3230 3231 case Translation::BOOL_STACK_SLOT: { 3232 int slot_offset = 3233 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next()); 3234 uint32_t value = GetUInt32Slot(fp, slot_offset); 3235 if (trace_file != nullptr) { 3236 PrintF(trace_file, "%u ; (bool) [fp %c %d] ", value, 3237 slot_offset < 0 ? '-' : '+', std::abs(slot_offset)); 3238 } 3239 return TranslatedValue::NewBool(this, value); 3240 } 3241 3242 case Translation::DOUBLE_STACK_SLOT: { 3243 int slot_offset = 3244 OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next()); 3245 double value = ReadDoubleValue(fp + slot_offset); 3246 if (trace_file != nullptr) { 3247 PrintF(trace_file, "%e ; (double) [fp %c %d] ", value, 3248 slot_offset < 0 ? '-' : '+', std::abs(slot_offset)); 3249 } 3250 return TranslatedValue::NewDouble(this, value); 3251 } 3252 3253 case Translation::LITERAL: { 3254 int literal_index = iterator->Next(); 3255 Object* value = literal_array->get(literal_index); 3256 if (trace_file != nullptr) { 3257 PrintF(trace_file, "0x%08" V8PRIxPTR " ; (literal %d) ", 3258 reinterpret_cast<intptr_t>(value), literal_index); 3259 reinterpret_cast<Object*>(value)->ShortPrint(trace_file); 3260 } 3261 3262 return TranslatedValue::NewTagged(this, value); 3263 } 3264 3265 case Translation::JS_FRAME_FUNCTION: { 3266 int slot_offset = JavaScriptFrameConstants::kFunctionOffset; 3267 intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset)); 3268 if (trace_file != nullptr) { 3269 PrintF(trace_file, "0x%08" V8PRIxPTR " ; (frame function) ", value); 3270 reinterpret_cast<Object*>(value)->ShortPrint(trace_file); 3271 } 3272 return TranslatedValue::NewTagged(this, reinterpret_cast<Object*>(value)); 3273 } 3274 } 3275 3276 FATAL("We should never get here - unexpected deopt info."); 3277 return TranslatedValue(nullptr, TranslatedValue::kInvalid); 3278 } 3279 3280 3281 TranslatedState::TranslatedState(JavaScriptFrame* frame) 3282 : isolate_(nullptr), 3283 stack_frame_pointer_(nullptr), 3284 has_adapted_arguments_(false) { 3285 int deopt_index = Safepoint::kNoDeoptimizationIndex; 3286 DeoptimizationInputData* data = 3287 static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index); 3288 TranslationIterator it(data->TranslationByteArray(), 3289 data->TranslationIndex(deopt_index)->value()); 3290 Init(frame->fp(), &it, data->LiteralArray(), nullptr /* registers */, 3291 nullptr /* trace file */); 3292 } 3293 3294 3295 TranslatedState::TranslatedState() 3296 : isolate_(nullptr), 3297 stack_frame_pointer_(nullptr), 3298 has_adapted_arguments_(false) {} 3299 3300 3301 void TranslatedState::Init(Address input_frame_pointer, 3302 TranslationIterator* iterator, 3303 FixedArray* literal_array, RegisterValues* registers, 3304 FILE* trace_file) { 3305 DCHECK(frames_.empty()); 3306 3307 isolate_ = literal_array->GetIsolate(); 3308 // Read out the 'header' translation. 3309 Translation::Opcode opcode = 3310 static_cast<Translation::Opcode>(iterator->Next()); 3311 CHECK(opcode == Translation::BEGIN); 3312 3313 int count = iterator->Next(); 3314 iterator->Next(); // Drop JS frames count. 3315 3316 frames_.reserve(count); 3317 3318 std::stack<int> nested_counts; 3319 3320 // Read the frames 3321 for (int i = 0; i < count; i++) { 3322 // Read the frame descriptor. 3323 frames_.push_back(CreateNextTranslatedFrame( 3324 iterator, literal_array, input_frame_pointer, trace_file)); 3325 TranslatedFrame& frame = frames_.back(); 3326 3327 // Read the values. 3328 int values_to_process = frame.GetValueCount(); 3329 while (values_to_process > 0 || !nested_counts.empty()) { 3330 if (trace_file != nullptr) { 3331 if (nested_counts.empty()) { 3332 // For top level values, print the value number. 3333 PrintF(trace_file, " %3i: ", 3334 frame.GetValueCount() - values_to_process); 3335 } else { 3336 // Take care of indenting for nested values. 3337 PrintF(trace_file, " "); 3338 for (size_t j = 0; j < nested_counts.size(); j++) { 3339 PrintF(trace_file, " "); 3340 } 3341 } 3342 } 3343 3344 TranslatedValue value = CreateNextTranslatedValue( 3345 i, static_cast<int>(frame.values_.size()), iterator, literal_array, 3346 input_frame_pointer, registers, trace_file); 3347 frame.Add(value); 3348 3349 if (trace_file != nullptr) { 3350 PrintF(trace_file, "\n"); 3351 } 3352 3353 // Update the value count and resolve the nesting. 3354 values_to_process--; 3355 int children_count = value.GetChildrenCount(); 3356 if (children_count > 0) { 3357 nested_counts.push(values_to_process); 3358 values_to_process = children_count; 3359 } else { 3360 while (values_to_process == 0 && !nested_counts.empty()) { 3361 values_to_process = nested_counts.top(); 3362 nested_counts.pop(); 3363 } 3364 } 3365 } 3366 } 3367 3368 CHECK(!iterator->HasNext() || 3369 static_cast<Translation::Opcode>(iterator->Next()) == 3370 Translation::BEGIN); 3371 } 3372 3373 3374 void TranslatedState::Prepare(bool has_adapted_arguments, 3375 Address stack_frame_pointer) { 3376 for (auto& frame : frames_) frame.Handlify(); 3377 3378 stack_frame_pointer_ = stack_frame_pointer; 3379 has_adapted_arguments_ = has_adapted_arguments; 3380 3381 UpdateFromPreviouslyMaterializedObjects(); 3382 } 3383 3384 3385 Handle<Object> TranslatedState::MaterializeAt(int frame_index, 3386 int* value_index) { 3387 TranslatedFrame* frame = &(frames_[frame_index]); 3388 DCHECK(static_cast<size_t>(*value_index) < frame->values_.size()); 3389 3390 TranslatedValue* slot = &(frame->values_[*value_index]); 3391 (*value_index)++; 3392 3393 switch (slot->kind()) { 3394 case TranslatedValue::kTagged: 3395 case TranslatedValue::kInt32: 3396 case TranslatedValue::kUInt32: 3397 case TranslatedValue::kBoolBit: 3398 case TranslatedValue::kDouble: { 3399 slot->MaterializeSimple(); 3400 Handle<Object> value = slot->GetValue(); 3401 if (value->IsMutableHeapNumber()) { 3402 HeapNumber::cast(*value)->set_map(isolate()->heap()->heap_number_map()); 3403 } 3404 return value; 3405 } 3406 3407 case TranslatedValue::kArgumentsObject: { 3408 int length = slot->GetChildrenCount(); 3409 Handle<JSObject> arguments; 3410 if (GetAdaptedArguments(&arguments, frame_index)) { 3411 // Store the materialized object and consume the nested values. 3412 for (int i = 0; i < length; ++i) { 3413 MaterializeAt(frame_index, value_index); 3414 } 3415 } else { 3416 Handle<JSFunction> function = 3417 Handle<JSFunction>::cast(frame->front().GetValue()); 3418 arguments = isolate_->factory()->NewArgumentsObject(function, length); 3419 Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length); 3420 DCHECK_EQ(array->length(), length); 3421 arguments->set_elements(*array); 3422 for (int i = 0; i < length; ++i) { 3423 Handle<Object> value = MaterializeAt(frame_index, value_index); 3424 array->set(i, *value); 3425 } 3426 } 3427 slot->value_ = arguments; 3428 return arguments; 3429 } 3430 case TranslatedValue::kCapturedObject: { 3431 int length = slot->GetChildrenCount(); 3432 3433 // The map must be a tagged object. 3434 CHECK(frame->values_[*value_index].kind() == TranslatedValue::kTagged); 3435 3436 Handle<Object> result; 3437 if (slot->value_.ToHandle(&result)) { 3438 // This has been previously materialized, return the previous value. 3439 // We still need to skip all the nested objects. 3440 for (int i = 0; i < length; i++) { 3441 MaterializeAt(frame_index, value_index); 3442 } 3443 3444 return result; 3445 } 3446 3447 Handle<Object> map_object = MaterializeAt(frame_index, value_index); 3448 Handle<Map> map = 3449 Map::GeneralizeAllFieldRepresentations(Handle<Map>::cast(map_object)); 3450 switch (map->instance_type()) { 3451 case MUTABLE_HEAP_NUMBER_TYPE: 3452 case HEAP_NUMBER_TYPE: { 3453 // Reuse the HeapNumber value directly as it is already properly 3454 // tagged and skip materializing the HeapNumber explicitly. 3455 Handle<Object> object = MaterializeAt(frame_index, value_index); 3456 slot->value_ = object; 3457 // On 32-bit architectures, there is an extra slot there because 3458 // the escape analysis calculates the number of slots as 3459 // object-size/pointer-size. To account for this, we read out 3460 // any extra slots. 3461 for (int i = 0; i < length - 2; i++) { 3462 MaterializeAt(frame_index, value_index); 3463 } 3464 return object; 3465 } 3466 case JS_OBJECT_TYPE: { 3467 Handle<JSObject> object = 3468 isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED); 3469 slot->value_ = object; 3470 Handle<Object> properties = MaterializeAt(frame_index, value_index); 3471 Handle<Object> elements = MaterializeAt(frame_index, value_index); 3472 object->set_properties(FixedArray::cast(*properties)); 3473 object->set_elements(FixedArrayBase::cast(*elements)); 3474 for (int i = 0; i < length - 3; ++i) { 3475 Handle<Object> value = MaterializeAt(frame_index, value_index); 3476 FieldIndex index = FieldIndex::ForPropertyIndex(object->map(), i); 3477 object->FastPropertyAtPut(index, *value); 3478 } 3479 return object; 3480 } 3481 case JS_ARRAY_TYPE: { 3482 Handle<JSArray> object = 3483 isolate_->factory()->NewJSArray(0, map->elements_kind()); 3484 slot->value_ = object; 3485 Handle<Object> properties = MaterializeAt(frame_index, value_index); 3486 Handle<Object> elements = MaterializeAt(frame_index, value_index); 3487 Handle<Object> length = MaterializeAt(frame_index, value_index); 3488 object->set_properties(FixedArray::cast(*properties)); 3489 object->set_elements(FixedArrayBase::cast(*elements)); 3490 object->set_length(*length); 3491 return object; 3492 } 3493 case FIXED_ARRAY_TYPE: { 3494 Handle<Object> lengthObject = MaterializeAt(frame_index, value_index); 3495 int32_t length = 0; 3496 CHECK(lengthObject->ToInt32(&length)); 3497 Handle<FixedArray> object = 3498 isolate_->factory()->NewFixedArray(length); 3499 // We need to set the map, because the fixed array we are 3500 // materializing could be a context or an arguments object, 3501 // in which case we must retain that information. 3502 object->set_map(*map); 3503 slot->value_ = object; 3504 for (int i = 0; i < length; ++i) { 3505 Handle<Object> value = MaterializeAt(frame_index, value_index); 3506 object->set(i, *value); 3507 } 3508 return object; 3509 } 3510 case FIXED_DOUBLE_ARRAY_TYPE: { 3511 DCHECK_EQ(*map, isolate_->heap()->fixed_double_array_map()); 3512 Handle<Object> lengthObject = MaterializeAt(frame_index, value_index); 3513 int32_t length = 0; 3514 CHECK(lengthObject->ToInt32(&length)); 3515 Handle<FixedArrayBase> object = 3516 isolate_->factory()->NewFixedDoubleArray(length); 3517 slot->value_ = object; 3518 if (length > 0) { 3519 Handle<FixedDoubleArray> double_array = 3520 Handle<FixedDoubleArray>::cast(object); 3521 for (int i = 0; i < length; ++i) { 3522 Handle<Object> value = MaterializeAt(frame_index, value_index); 3523 CHECK(value->IsNumber()); 3524 double_array->set(i, value->Number()); 3525 } 3526 } 3527 return object; 3528 } 3529 default: 3530 PrintF(stderr, "[couldn't handle instance type %d]\n", 3531 map->instance_type()); 3532 FATAL("unreachable"); 3533 return Handle<Object>::null(); 3534 } 3535 UNREACHABLE(); 3536 break; 3537 } 3538 3539 case TranslatedValue::kDuplicatedObject: { 3540 int object_index = slot->object_index(); 3541 TranslatedState::ObjectPosition pos = object_positions_[object_index]; 3542 3543 // Make sure the duplicate is refering to a previous object. 3544 DCHECK(pos.frame_index_ < frame_index || 3545 (pos.frame_index_ == frame_index && 3546 pos.value_index_ < *value_index - 1)); 3547 3548 Handle<Object> object = 3549 frames_[pos.frame_index_].values_[pos.value_index_].GetValue(); 3550 3551 // The object should have a (non-sentinel) value. 3552 DCHECK(!object.is_null() && 3553 !object.is_identical_to(isolate_->factory()->arguments_marker())); 3554 3555 slot->value_ = object; 3556 return object; 3557 } 3558 3559 case TranslatedValue::kInvalid: 3560 UNREACHABLE(); 3561 break; 3562 } 3563 3564 FATAL("We should never get here - unexpected deopt slot kind."); 3565 return Handle<Object>::null(); 3566 } 3567 3568 3569 Handle<Object> TranslatedState::MaterializeObjectAt(int object_index) { 3570 TranslatedState::ObjectPosition pos = object_positions_[object_index]; 3571 return MaterializeAt(pos.frame_index_, &(pos.value_index_)); 3572 } 3573 3574 3575 bool TranslatedState::GetAdaptedArguments(Handle<JSObject>* result, 3576 int frame_index) { 3577 if (frame_index == 0) { 3578 // Top level frame -> we need to go to the parent frame on the stack. 3579 if (!has_adapted_arguments_) return false; 3580 3581 // This is top level frame, so we need to go to the stack to get 3582 // this function's argument. (Note that this relies on not inlining 3583 // recursive functions!) 3584 Handle<JSFunction> function = 3585 Handle<JSFunction>::cast(frames_[frame_index].front().GetValue()); 3586 *result = Handle<JSObject>::cast(Accessors::FunctionGetArguments(function)); 3587 return true; 3588 } else { 3589 TranslatedFrame* previous_frame = &(frames_[frame_index]); 3590 if (previous_frame->kind() != TranslatedFrame::kArgumentsAdaptor) { 3591 return false; 3592 } 3593 // We get the adapted arguments from the parent translation. 3594 int length = previous_frame->height(); 3595 Handle<JSFunction> function = 3596 Handle<JSFunction>::cast(previous_frame->front().GetValue()); 3597 Handle<JSObject> arguments = 3598 isolate_->factory()->NewArgumentsObject(function, length); 3599 Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length); 3600 arguments->set_elements(*array); 3601 TranslatedFrame::iterator arg_iterator = previous_frame->begin(); 3602 arg_iterator++; // Skip function. 3603 for (int i = 0; i < length; ++i) { 3604 Handle<Object> value = arg_iterator->GetValue(); 3605 array->set(i, *value); 3606 arg_iterator++; 3607 } 3608 CHECK(arg_iterator == previous_frame->end()); 3609 *result = arguments; 3610 return true; 3611 } 3612 } 3613 3614 3615 TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex( 3616 int jsframe_index, int* args_count) { 3617 for (size_t i = 0; i < frames_.size(); i++) { 3618 if (frames_[i].kind() == TranslatedFrame::kFunction) { 3619 if (jsframe_index > 0) { 3620 jsframe_index--; 3621 } else { 3622 // We have the JS function frame, now check if it has arguments adaptor. 3623 if (i > 0 && 3624 frames_[i - 1].kind() == TranslatedFrame::kArgumentsAdaptor) { 3625 *args_count = frames_[i - 1].height(); 3626 return &(frames_[i - 1]); 3627 } 3628 *args_count = 3629 frames_[i].shared_info()->internal_formal_parameter_count() + 1; 3630 return &(frames_[i]); 3631 } 3632 } 3633 } 3634 return nullptr; 3635 } 3636 3637 3638 void TranslatedState::StoreMaterializedValuesAndDeopt() { 3639 MaterializedObjectStore* materialized_store = 3640 isolate_->materialized_object_store(); 3641 Handle<FixedArray> previously_materialized_objects = 3642 materialized_store->Get(stack_frame_pointer_); 3643 3644 Handle<Object> marker = isolate_->factory()->arguments_marker(); 3645 3646 int length = static_cast<int>(object_positions_.size()); 3647 bool new_store = false; 3648 if (previously_materialized_objects.is_null()) { 3649 previously_materialized_objects = 3650 isolate_->factory()->NewFixedArray(length); 3651 for (int i = 0; i < length; i++) { 3652 previously_materialized_objects->set(i, *marker); 3653 } 3654 new_store = true; 3655 } 3656 3657 DCHECK_EQ(length, previously_materialized_objects->length()); 3658 3659 bool value_changed = false; 3660 for (int i = 0; i < length; i++) { 3661 TranslatedState::ObjectPosition pos = object_positions_[i]; 3662 TranslatedValue* value_info = 3663 &(frames_[pos.frame_index_].values_[pos.value_index_]); 3664 3665 DCHECK(value_info->IsMaterializedObject()); 3666 3667 Handle<Object> value(value_info->GetRawValue(), isolate_); 3668 3669 if (!value.is_identical_to(marker)) { 3670 if (previously_materialized_objects->get(i) == *marker) { 3671 previously_materialized_objects->set(i, *value); 3672 value_changed = true; 3673 } else { 3674 DCHECK(previously_materialized_objects->get(i) == *value); 3675 } 3676 } 3677 } 3678 if (new_store && value_changed) { 3679 materialized_store->Set(stack_frame_pointer_, 3680 previously_materialized_objects); 3681 DCHECK_EQ(TranslatedFrame::kFunction, frames_[0].kind()); 3682 Object* const function = frames_[0].front().GetRawValue(); 3683 Deoptimizer::DeoptimizeFunction(JSFunction::cast(function)); 3684 } 3685 } 3686 3687 3688 void TranslatedState::UpdateFromPreviouslyMaterializedObjects() { 3689 MaterializedObjectStore* materialized_store = 3690 isolate_->materialized_object_store(); 3691 Handle<FixedArray> previously_materialized_objects = 3692 materialized_store->Get(stack_frame_pointer_); 3693 3694 // If we have no previously materialized objects, there is nothing to do. 3695 if (previously_materialized_objects.is_null()) return; 3696 3697 Handle<Object> marker = isolate_->factory()->arguments_marker(); 3698 3699 int length = static_cast<int>(object_positions_.size()); 3700 DCHECK_EQ(length, previously_materialized_objects->length()); 3701 3702 for (int i = 0; i < length; i++) { 3703 // For a previously materialized objects, inject their value into the 3704 // translated values. 3705 if (previously_materialized_objects->get(i) != *marker) { 3706 TranslatedState::ObjectPosition pos = object_positions_[i]; 3707 TranslatedValue* value_info = 3708 &(frames_[pos.frame_index_].values_[pos.value_index_]); 3709 DCHECK(value_info->IsMaterializedObject()); 3710 3711 value_info->value_ = 3712 Handle<Object>(previously_materialized_objects->get(i), isolate_); 3713 } 3714 } 3715 } 3716 3717 } // namespace internal 3718 } // namespace v8 3719