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