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.
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"
20 static MemoryChunk* AllocateCodeChunk(MemoryAllocator* allocator) {
21 return allocator->AllocateChunk(Deoptimizer::GetMaxDeoptTableSize(),
23 #if defined(__native_client__)
24 // The Native Client port of V8 uses an interpreter,
25 // so code pages don't need PROT_EXEC.
34 DeoptimizerData::DeoptimizerData(MemoryAllocator* allocator)
35 : allocator_(allocator),
36 deoptimized_frame_info_(NULL),
38 for (int i = 0; i < Deoptimizer::kBailoutTypesWithCodeEntry; ++i) {
39 deopt_entry_code_entries_[i] = -1;
40 deopt_entry_code_[i] = AllocateCodeChunk(allocator);
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;
53 void DeoptimizerData::Iterate(ObjectVisitor* v) {
54 if (deoptimized_frame_info_ != NULL) {
55 deoptimized_frame_info_->Iterate(v);
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();
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,
84 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
91 CHECK(isolate->deoptimizer_data()->current_ == NULL);
92 isolate->deoptimizer_data()->current_ = deoptimizer;
97 // No larger than 2K on all platforms
98 static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
101 size_t Deoptimizer::GetMaxDeoptTableSize() {
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);
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;
120 int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) {
121 if (jsframe_index == 0) return 0;
124 while (jsframe_index >= 0) {
125 FrameDescription* frame = output_[frame_index];
126 if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) {
132 return frame_index - 1;
136 DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
137 JavaScriptFrame* frame,
140 CHECK(frame->is_optimized());
141 CHECK(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL);
143 // Get the function and code from the frame.
144 JSFunction* function = frame->function();
145 Code* code = frame->LookupCode();
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);
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;
159 Deoptimizer* deoptimizer = new Deoptimizer(isolate,
161 Deoptimizer::DEBUGGER,
162 deoptimization_index,
166 Address tos = frame->fp() - fp_to_sp_delta;
167 deoptimizer->FillInputFrame(tos, frame);
169 // Calculate the output frames.
170 Deoptimizer::ComputeOutputFrames(deoptimizer);
172 // Create the GC safe output frame information and register it for GC
174 CHECK_LT(jsframe_index, deoptimizer->jsframe_count());
176 // Convert JS frame index into frame index.
177 int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index);
179 bool has_arguments_adaptor =
181 deoptimizer->output_[frame_index - 1]->GetFrameType() ==
182 StackFrame::ARGUMENTS_ADAPTOR;
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;
190 DeoptimizedFrameInfo* info = new DeoptimizedFrameInfo(deoptimizer,
192 has_arguments_adaptor,
194 isolate->deoptimizer_data()->deoptimized_frame_info_ = info;
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];
201 uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize;
202 Address parameters_top = reinterpret_cast<Address>(
203 parameters_frame->GetTop() + (parameters_frame->GetFrameSize() -
206 uint32_t expressions_size = info->expression_count() * kPointerSize;
207 Address expressions_top = reinterpret_cast<Address>(
208 deoptimizer->output_[frame_index]->GetTop());
210 // Done with the GC-unsafe frame descriptions. This re-enables allocation.
211 deoptimizer->DeleteFrameDescriptions();
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);
217 // Finished using the deoptimizer instance.
224 void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
226 CHECK_EQ(isolate->deoptimizer_data()->deoptimized_frame_info_, info);
228 isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL;
232 void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
235 TableEntryGenerator generator(masm, type, count);
236 generator.Generate();
240 void Deoptimizer::VisitAllOptimizedFunctionsForContext(
241 Context* context, OptimizedFunctionVisitor* visitor) {
242 DisallowHeapAllocation no_allocation;
244 CHECK(context->IsNativeContext());
246 visitor->EnterContext(context);
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.
262 prev->set_next_function_link(next);
264 context->SetOptimizedFunctionsListHead(next);
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());
272 // The visitor should not alter the link directly.
273 CHECK_EQ(function->next_function_link(), next);
274 // preserve this element.
280 visitor->LeaveContext(context);
284 void Deoptimizer::VisitAllOptimizedFunctions(
286 OptimizedFunctionVisitor* visitor) {
287 DisallowHeapAllocation no_allocation;
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);
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;
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 {
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;
314 // Unlink this function and evict from optimized code map.
315 SharedFunctionInfo* shared = function->shared();
316 function->set_code(shared->code());
318 if (FLAG_trace_deopt) {
319 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
320 PrintF(scope.file(), "[deoptimizer unlinked: ");
321 function->PrintName(scope.file());
323 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
328 // Unlink all functions that refer to marked code.
329 SelectedCodeUnlinker unlinker;
330 VisitAllOptimizedFunctionsForContext(context, &unlinker);
332 Isolate* isolate = context->GetHeap()->isolate();
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());
351 " / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
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;
365 // Move marked code from the optimized code list to the deoptimized
366 // code list, collecting them into a ZoneList.
368 ZoneList<Code*> codes(10, &zone);
370 // Walk over all optimized code objects in this native context.
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);
382 // Skip this code in the optimized code list.
383 prev->set_next_code_link(next);
385 // There was no previous node, the next node is the new head.
386 context->SetOptimizedCodeListHead(next);
389 // Move the code to the _deoptimized_ code list.
390 code->set_next_code_link(context->DeoptimizedCodeListHead());
391 context->SetDeoptimizedCodeListHead(code);
393 // Not marked; preserve this element.
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);
403 // Now patch all the codes for deoptimization.
404 for (int i = 0; i < codes.length(); i++) {
406 if (codes[i] == topmost_optimized_code) {
407 ASSERT(safe_to_deopt_topmost_optimized_code);
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]);
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]);
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");
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);
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");
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);
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));
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);
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();
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());
498 void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
499 deoptimizer->DoComputeOutputFrames();
503 bool Deoptimizer::TraceEnabledFor(BailoutType deopt_type,
504 StackFrame::Type frame_type) {
505 switch (deopt_type) {
510 return (frame_type == StackFrame::STUB)
511 ? FLAG_trace_stub_failures
514 FATAL("Unsupported deopt type");
519 const char* Deoptimizer::MessageFor(BailoutType type) {
521 case EAGER: return "eager";
522 case SOFT: return "soft";
523 case LAZY: return "lazy";
524 case DEBUGGER: return "debugger";
526 FATAL("Unsupported deopt type");
531 Deoptimizer::Deoptimizer(Isolate* isolate,
532 JSFunction* function,
537 Code* optimized_code)
540 bailout_id_(bailout_id),
543 fp_to_sp_delta_(fp_to_sp_delta),
544 has_alignment_padding_(0),
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),
560 // For COMPILED_STUBs called from builtins, the function pointer is a SMI
561 // indicating an internal frame.
562 if (function->IsSmi()) {
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);
577 compiled_code_ = FindOptimizedCode(function, optimized_code);
580 ASSERT(compiled_code_ != NULL);
581 if (type == EAGER || type == SOFT || type == LAZY) {
582 ASSERT(compiled_code_->kind() != Code::FUNCTION);
586 StackFrame::Type frame_type = function == NULL
588 : StackFrame::JAVA_SCRIPT;
589 trace_scope_ = TraceEnabledFor(type, frame_type) ?
590 new CodeTracer::Scope(isolate->GetCodeTracer()) : NULL;
592 CHECK(AllowHeapAllocation::IsAllowed());
593 disallow_heap_allocation_ = new DisallowHeapAllocation();
595 unsigned size = ComputeInputFrameSize();
596 input_ = new(size) FrameDescription(size, function);
597 input_->SetFrameType(frame_type);
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_))
612 case Deoptimizer::DEBUGGER:
613 ASSERT(optimized_code->contains(from_));
614 return optimized_code;
616 FATAL("Could not find code for optimized function");
621 void Deoptimizer::PrintFunctionName() {
622 if (function_->IsJSFunction()) {
623 function_->PrintName(trace_scope_->file());
625 PrintF(trace_scope_->file(),
626 "%s", Code::Kind2String(compiled_code_->kind()));
631 Deoptimizer::~Deoptimizer() {
632 ASSERT(input_ == NULL && output_ == NULL);
633 ASSERT(disallow_heap_allocation_ == NULL);
638 void Deoptimizer::DeleteFrameDescriptions() {
640 for (int i = 0; i < output_count_; ++i) {
641 if (output_[i] != input_) delete output_[i];
647 CHECK(!AllowHeapAllocation::IsAllowed());
648 CHECK(disallow_heap_allocation_ != NULL);
649 delete disallow_heap_allocation_;
650 disallow_heap_allocation_ = NULL;
655 Address Deoptimizer::GetDeoptimizationEntry(Isolate* isolate,
660 if (id >= kMaxNumberOfEntries) return NULL;
661 if (mode == ENSURE_ENTRY_CODE) {
662 EnsureCodeForDeoptimizationEntry(isolate, type, id);
664 CHECK_EQ(mode, CALCULATE_ENTRY_ADDRESS);
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_);
673 int Deoptimizer::GetDeoptimizationId(Isolate* isolate,
676 DeoptimizerData* data = isolate->deoptimizer_data();
677 MemoryChunk* base = data->deopt_entry_code_[type];
678 Address start = base->area_start();
681 addr >= start + (kMaxNumberOfEntries * table_entry_size_)) {
682 return kNotDeoptimizationEntry;
685 static_cast<int>(addr - start) % table_entry_size_);
686 return static_cast<int>(addr - start) / table_entry_size_;
690 int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
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();
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());
710 FATAL("unable to find pc offset during deoptimization");
715 int Deoptimizer::GetDeoptimizedCodeCount(Isolate* isolate) {
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);
726 element = code->next_code_link();
728 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
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_));
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());
749 if (trace_scope_ != NULL) {
751 PrintF(trace_scope_->file(),
752 "[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ",
753 MessageFor(bailout_type_),
754 reinterpret_cast<intptr_t>(function_));
756 PrintF(trace_scope_->file(),
757 " (opt #%d) @%d, FP to SP delta: %d]\n",
758 input_data->OptimizationId()->value(),
761 if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
762 compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
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();
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);
777 // Read the number of output frames and allocate an array for their
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) {
786 output_count_ = count;
788 Register fp_reg = JavaScriptFrame::fp_register();
789 stack_fp_ = reinterpret_cast<Address>(
790 input_->GetRegister(fp_reg.code()) +
791 has_alignment_padding_ * kPointerSize);
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());
799 case Translation::JS_FRAME:
800 DoComputeJSFrame(&iterator, i);
803 case Translation::ARGUMENTS_ADAPTOR_FRAME:
804 DoComputeArgumentsAdaptorFrame(&iterator, i);
806 case Translation::CONSTRUCT_STUB_FRAME:
807 DoComputeConstructStubFrame(&iterator, i);
809 case Translation::GETTER_STUB_FRAME:
810 DoComputeAccessorStubFrame(&iterator, i, false);
812 case Translation::SETTER_STUB_FRAME:
813 DoComputeAccessorStubFrame(&iterator, i, true);
815 case Translation::COMPILED_STUB_FRAME:
816 DoComputeCompiledStubFrame(&iterator, i);
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:
830 FATAL("Unsupported translation");
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));
845 PrintF(trace_scope_->file(),
846 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
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",
860 void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
862 BailoutId node_id = BailoutId(iterator->Next());
863 JSFunction* function;
864 if (frame_index != 0) {
865 function = JSFunction::cast(ComputeLiteral(iterator->Next()));
867 int closure_id = iterator->Next();
869 CHECK_EQ(Translation::kSelfLiteralId, closure_id);
870 function = function_;
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);
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;
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);
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;
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;
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;
915 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
917 output_frame->SetTop(top_address);
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);
927 input_offset -= (parameter_count * kPointerSize);
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
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;
941 value = input_->GetFrameSlot(input_offset);
943 value = output_[frame_index - 1]->GetPc();
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);
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
957 output_offset -= kFPOnStackSize;
958 input_offset -= kFPOnStackSize;
960 value = input_->GetFrameSlot(input_offset);
962 value = output_[frame_index - 1]->GetFp();
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);
976 ASSERT(!is_bottommost || !has_alignment_padding_ ||
977 (fp_value & kPointerSize) != 0);
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;
986 value = input_->GetFrameSlot(input_offset);
988 value = output_[frame_index - 1]->GetConstantPool();
990 output_frame->SetCallerConstantPool(output_offset, value);
992 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
993 V8PRIxPTR "; caller's constant_pool\n",
994 top_address + output_offset, output_offset, value);
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);
1007 value = reinterpret_cast<intptr_t>(function->context());
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);
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
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);
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);
1039 CHECK_EQ(0, output_offset);
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);
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);
1057 Register constant_pool_reg =
1058 JavaScriptFrame::constant_pool_pointer_register();
1059 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
1063 FullCodeGenerator::State state =
1064 FullCodeGenerator::StateField::decode(pc_and_state);
1065 output_frame->SetState(Smi::FromInt(state));
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);
1076 CHECK_EQ(bailout_type_, EAGER);
1078 output_frame->SetContinuation(
1079 reinterpret_cast<intptr_t>(continuation->entry()));
1084 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
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);
1094 unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
1095 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
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);
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;
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);
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);
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);
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);
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);
1151 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1152 V8PRIxPTR "; caller's constant_pool\n",
1153 top_address + output_offset, output_offset, value);
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);
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);
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);
1191 ASSERT(0 == output_offset);
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);
1208 void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
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);
1220 unsigned fixed_frame_size = ConstructFrameConstants::kFrameSize;
1221 unsigned output_frame_size = height_in_bytes + fixed_frame_size;
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);
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;
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);
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);
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);
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);
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);
1285 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1286 V8PRIxPTR " ; caller's constant pool\n",
1287 top_address + output_offset, output_offset, value);
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);
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);
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);
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);
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);
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);
1361 CHECK_EQ(0, output_offset);
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);
1375 void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
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);
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;
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);
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;
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);
1416 unsigned output_offset = output_frame_size;
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
1426 top_address + output_offset, output_offset, callers_pc);
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
1439 fp_value, output_offset, value);
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);
1448 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
1449 V8PRIxPTR " ; caller's constant pool\n",
1450 top_address + output_offset, output_offset, value);
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
1462 top_address + output_offset, output_offset, value);
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);
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
1488 top_address + output_offset, output_offset, value);
1492 DoTranslateObjectAndSkip(iterator);
1494 if (is_setter_stub_frame) {
1495 // The implicit return value was part of the artificial setter stub
1497 output_offset -= kPointerSize;
1498 DoTranslateCommand(iterator, frame_index, output_offset);
1501 CHECK_EQ(output_offset, 0);
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);
1517 void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
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
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);
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),
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;
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);
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);
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);
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);
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);
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);
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);
1656 intptr_t caller_arg_count = 0;
1657 bool arg_count_known = !descriptor->stack_parameter_count_.is_valid();
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;
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)");
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)");
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);
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);
1709 if (!arg_count_known && descriptor->IsParameterCountRegister(i)) {
1710 arguments_length_offset = output_frame_offset;
1714 CHECK_EQ(output_frame_offset, 0);
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,
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,
1744 // Copy the double registers from the input into the output frame.
1745 CopyDoubleRegisters(output_frame);
1747 // Fill registers containing handler and number of parameters.
1748 SetPlatformCompiledStubRegisters(output_frame, descriptor);
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);
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()));
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();
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();
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);
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_));
1824 materialized_objects_->Add(object);
1826 materialization_value_index_ += kDoubleSize / kPointerSize - 1;
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_));
1836 materialized_objects_->Add(object);
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);
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_));
1856 materialized_objects_->Add(object);
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);
1868 "[couldn't handle instance type %d]\n", map->instance_type());
1869 FATAL("Unsupported instance type");
1873 return materialized_objects_->at(object_index);
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();
1887 void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
1888 ASSERT_NE(DEBUGGER, bailout_type_);
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();
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());
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_));
1910 // Play it safe and clear all unhandlified values before we continue.
1911 deferred_objects_tagged_values_.Clear();
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),
1926 Memory::Object_at(d.destination()) = *num;
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),
1941 ASSERT(values.at(d.destination())->IsTheHole());
1942 values.Set(d.destination(), num);
1945 // Play it safe and clear all object double values before we continue.
1946 deferred_objects_double_values_.Clear();
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;
1954 while (materialization_object_index_ < deferred_objects_.length()) {
1955 int object_index = materialization_object_index_;
1956 ObjectMaterializationDescriptor descriptor =
1957 deferred_objects_.at(object_index);
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;
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()));
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()));
1979 object->ShortPrint(trace_scope_->file());
1980 PrintF(trace_scope_->file(), "\n");
1984 CHECK_EQ(materialization_object_index_, materialized_objects_->length());
1985 CHECK_EQ(materialization_value_index_, materialized_values_->length());
1988 if (prev_materialized_count_ > 0) {
1989 materialized_store->Remove(stack_fp_);
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];
2006 // Check of the heap number to materialize actually belong to the frame
2008 Address slot = d.destination();
2009 if (parameters_top <= slot && slot < parameters_bottom) {
2010 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
2012 int index = (info->parameters_count() - 1) -
2013 static_cast<int>(slot - parameters_top) / kPointerSize;
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),
2025 info->SetParameter(index, *num);
2026 } else if (expressions_top <= slot && slot < expressions_bottom) {
2027 Handle<Object> num = isolate_->factory()->NewNumber(d.value());
2029 int index = info->expression_count() - 1 -
2030 static_cast<int>(slot - expressions_top) / kPointerSize;
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),
2042 info->SetExpression(index, *num);
2048 static const char* TraceValueType(bool is_smi) {
2053 return "heap number";
2057 void Deoptimizer::DoTranslateObjectAndSkip(TranslationIterator* iterator) {
2058 Translation::Opcode opcode =
2059 static_cast<Translation::Opcode>(iterator->Next());
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");
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));
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);
2094 AddObjectDuplication(0, object_index);
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);
2108 AddObjectStart(0, length, is_args);
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);
2120 FATAL("Unexpected translation opcode");
2124 void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
2127 disasm::NameConverter converter;
2128 Address object_slot = deferred_objects_[object_index].slot_address();
2130 Translation::Opcode opcode =
2131 static_cast<Translation::Opcode>(iterator->Next());
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");
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),
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(),
2160 AddObjectTaggedValue(input_value);
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),
2173 PrintF(trace_scope_->file(),
2174 "%" V8PRIdPTR " ; %s (%s)\n", value,
2175 converter.NameOfCPURegister(input_reg),
2176 TraceValueType(is_smi));
2179 intptr_t tagged_value =
2180 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2181 AddObjectTaggedValue(tagged_value);
2183 double double_value = static_cast<double>(static_cast<int32_t>(value));
2184 AddObjectDoubleValue(double_value);
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),
2198 PrintF(trace_scope_->file(),
2199 "%" V8PRIdPTR " ; uint %s (%s)\n", value,
2200 converter.NameOfCPURegister(input_reg),
2201 TraceValueType(is_smi));
2204 intptr_t tagged_value =
2205 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2206 AddObjectTaggedValue(tagged_value);
2208 double double_value = static_cast<double>(static_cast<uint32_t>(value));
2209 AddObjectDoubleValue(double_value);
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),
2222 PrintF(trace_scope_->file(),
2224 DoubleRegister::AllocationIndexToString(input_reg));
2226 AddObjectDoubleValue(value);
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),
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(),
2246 AddObjectTaggedValue(input_value);
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),
2260 PrintF(trace_scope_->file(),
2261 "%" V8PRIdPTR " ; [sp + %d] (%s)\n",
2262 value, input_offset, TraceValueType(is_smi));
2265 intptr_t tagged_value =
2266 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2267 AddObjectTaggedValue(tagged_value);
2269 double double_value = static_cast<double>(static_cast<int32_t>(value));
2270 AddObjectDoubleValue(double_value);
2275 case Translation::UINT32_STACK_SLOT: {
2276 int input_slot_index = iterator->Next();
2277 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
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),
2286 PrintF(trace_scope_->file(),
2287 "%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
2288 value, input_offset, TraceValueType(is_smi));
2291 intptr_t tagged_value =
2292 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
2293 AddObjectTaggedValue(tagged_value);
2295 double double_value = static_cast<double>(static_cast<uint32_t>(value));
2296 AddObjectDoubleValue(double_value);
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),
2310 PrintF(trace_scope_->file(),
2311 "%e ; [sp + %d]\n", value, input_offset);
2313 AddObjectDoubleValue(value);
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),
2324 literal->ShortPrint(trace_scope_->file());
2325 PrintF(trace_scope_->file(),
2328 intptr_t value = reinterpret_cast<intptr_t>(literal);
2329 AddObjectTaggedValue(value);
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),
2340 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2341 PrintF(trace_scope_->file(),
2342 " ; duplicate of object #%d\n", object_index);
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);
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),
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);
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);
2382 FATAL("Unexpected translation opcode");
2386 void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
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));
2393 Translation::Opcode opcode =
2394 static_cast<Translation::Opcode>(iterator->Next());
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");
2407 case Translation::REGISTER: {
2408 int input_reg = iterator->Next();
2409 intptr_t input_value = input_->GetRegister(input_reg);
2410 if (trace_scope_ != NULL) {
2412 trace_scope_->file(),
2413 " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
2414 output_[frame_index]->GetTop() + output_offset,
2417 converter.NameOfCPURegister(input_reg));
2418 reinterpret_cast<Object*>(input_value)->ShortPrint(
2419 trace_scope_->file());
2420 PrintF(trace_scope_->file(), "\n");
2422 output_[frame_index]->SetFrameSlot(output_offset, input_value);
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) {
2432 trace_scope_->file(),
2433 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
2434 output_[frame_index]->GetTop() + output_offset,
2437 converter.NameOfCPURegister(input_reg),
2438 TraceValueType(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);
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);
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) {
2460 trace_scope_->file(),
2461 " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
2462 " ; uint %s (%s)\n",
2463 output_[frame_index]->GetTop() + output_offset,
2466 converter.NameOfCPURegister(input_reg),
2467 TraceValueType(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);
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);
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,
2492 DoubleRegister::AllocationIndexToString(input_reg));
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);
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] ",
2514 reinterpret_cast<Object*>(input_value)->ShortPrint(
2515 trace_scope_->file());
2516 PrintF(trace_scope_->file(), "\n");
2518 output_[frame_index]->SetFrameSlot(output_offset, input_value);
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",
2536 TraceValueType(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);
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);
2552 case Translation::UINT32_STACK_SLOT: {
2553 int input_slot_index = iterator->Next();
2554 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
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",
2567 TraceValueType(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);
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);
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,
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);
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,
2609 literal->ShortPrint(trace_scope_->file());
2610 PrintF(trace_scope_->file(), " ; literal\n");
2612 intptr_t value = reinterpret_cast<intptr_t>(literal);
2613 output_[frame_index]->SetFrameSlot(output_offset, value);
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,
2624 isolate_->heap()->arguments_marker()->ShortPrint(trace_scope_->file());
2625 PrintF(trace_scope_->file(),
2626 " ; duplicate of object #%d\n", object_index);
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,
2634 output_[frame_index]->SetFrameSlot(output_offset, value);
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,
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);
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,
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);
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);
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;
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));
2700 unsigned arguments = function->shared()->formal_parameter_count() + 1;
2701 return arguments * kPointerSize;
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;
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);
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);
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);
2735 void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
2736 deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
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);
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);
2755 void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate,
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);
2770 MacroAssembler masm(isolate, NULL, 16 * KB);
2771 masm.set_emit_debug_code(false);
2772 GenerateDeoptimizationEntries(&masm, entry_count, type);
2774 masm.GetCode(&desc);
2775 ASSERT(!RelocInfo::RequiresRelocation(desc));
2777 MemoryChunk* chunk = data->deopt_entry_code_[type];
2778 CHECK(static_cast<int>(Deoptimizer::GetMaxDeoptTableSize()) >=
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);
2785 data->deopt_entry_code_entries_[type] = entry_count;
2789 FrameDescription::FrameDescription(uint32_t frame_size,
2790 JSFunction* function)
2791 : frame_size_(frame_size),
2792 function_(function),
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);
2806 // Zap all the slots.
2807 for (unsigned o = 0; o < frame_size; o += kPointerSize) {
2808 SetFrameSlot(o, kZapUint32);
2813 int FrameDescription::ComputeFixedSize() {
2814 return StandardFrameConstants::kFixedFrameSize +
2815 (ComputeParametersCount() + 1) * kPointerSize;
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);
2826 // Incoming parameter.
2827 int arg_size = (ComputeParametersCount() + 1) * kPointerSize;
2828 unsigned base = GetFrameSize() - arg_size;
2829 return base - ((slot_index + 1) * kPointerSize);
2834 int FrameDescription::ComputeParametersCount() {
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();
2843 case StackFrame::STUB:
2844 return -1; // Minus receiver.
2846 FATAL("Unexpected stack frame type");
2852 Object* FrameDescription::GetParameter(int index) {
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));
2861 unsigned FrameDescription::GetExpressionCount() {
2862 CHECK_EQ(StackFrame::JAVA_SCRIPT, type_);
2863 unsigned size = GetFrameSize() - ComputeFixedSize();
2864 return size / kPointerSize;
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));
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.
2883 uint32_t next = bits >> 7;
2884 contents_.Add(((bits << 1) & 0xFF) | (next != 0), zone);
2886 } while (bits != 0);
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).
2894 for (int i = 0; true; i += 7) {
2896 uint8_t next = buffer_->get(index_++);
2897 bits |= (next >> 1) << i;
2898 if ((next & 1) == 0) break;
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;
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);
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());
2922 void Translation::BeginGetterStubFrame(int literal_id) {
2923 buffer_->Add(GETTER_STUB_FRAME, zone());
2924 buffer_->Add(literal_id, zone());
2928 void Translation::BeginSetterStubFrame(int literal_id) {
2929 buffer_->Add(SETTER_STUB_FRAME, zone());
2930 buffer_->Add(literal_id, zone());
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());
2941 void Translation::BeginJSFrame(BailoutId node_id,
2944 buffer_->Add(JS_FRAME, zone());
2945 buffer_->Add(node_id.ToInt(), zone());
2946 buffer_->Add(literal_id, zone());
2947 buffer_->Add(height, zone());
2951 void Translation::BeginCompiledStubFrame() {
2952 buffer_->Add(COMPILED_STUB_FRAME, zone());
2956 void Translation::BeginArgumentsObject(int args_length) {
2957 buffer_->Add(ARGUMENTS_OBJECT, zone());
2958 buffer_->Add(args_length, zone());
2962 void Translation::BeginCapturedObject(int length) {
2963 buffer_->Add(CAPTURED_OBJECT, zone());
2964 buffer_->Add(length, zone());
2968 void Translation::DuplicateObject(int object_index) {
2969 buffer_->Add(DUPLICATED_OBJECT, zone());
2970 buffer_->Add(object_index, zone());
2974 void Translation::StoreRegister(Register reg) {
2975 buffer_->Add(REGISTER, zone());
2976 buffer_->Add(reg.code(), zone());
2980 void Translation::StoreInt32Register(Register reg) {
2981 buffer_->Add(INT32_REGISTER, zone());
2982 buffer_->Add(reg.code(), zone());
2986 void Translation::StoreUint32Register(Register reg) {
2987 buffer_->Add(UINT32_REGISTER, zone());
2988 buffer_->Add(reg.code(), zone());
2992 void Translation::StoreDoubleRegister(DoubleRegister reg) {
2993 buffer_->Add(DOUBLE_REGISTER, zone());
2994 buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
2998 void Translation::StoreStackSlot(int index) {
2999 buffer_->Add(STACK_SLOT, zone());
3000 buffer_->Add(index, zone());
3004 void Translation::StoreInt32StackSlot(int index) {
3005 buffer_->Add(INT32_STACK_SLOT, zone());
3006 buffer_->Add(index, zone());
3010 void Translation::StoreUint32StackSlot(int index) {
3011 buffer_->Add(UINT32_STACK_SLOT, zone());
3012 buffer_->Add(index, zone());
3016 void Translation::StoreDoubleStackSlot(int index) {
3017 buffer_->Add(DOUBLE_STACK_SLOT, zone());
3018 buffer_->Add(index, zone());
3022 void Translation::StoreLiteral(int literal_id) {
3023 buffer_->Add(LITERAL, zone());
3024 buffer_->Add(literal_id, zone());
3028 void Translation::StoreArgumentsObject(bool args_known,
3031 buffer_->Add(ARGUMENTS_OBJECT, zone());
3032 buffer_->Add(args_known, zone());
3033 buffer_->Add(args_index, zone());
3034 buffer_->Add(args_length, zone());
3038 int Translation::NumberOfOperandsFor(Opcode opcode) {
3040 case GETTER_STUB_FRAME:
3041 case SETTER_STUB_FRAME:
3042 case DUPLICATED_OBJECT:
3043 case ARGUMENTS_OBJECT:
3044 case CAPTURED_OBJECT:
3046 case INT32_REGISTER:
3047 case UINT32_REGISTER:
3048 case DOUBLE_REGISTER:
3050 case INT32_STACK_SLOT:
3051 case UINT32_STACK_SLOT:
3052 case DOUBLE_STACK_SLOT:
3054 case COMPILED_STUB_FRAME:
3057 case ARGUMENTS_ADAPTOR_FRAME:
3058 case CONSTRUCT_STUB_FRAME:
3063 FATAL("Unexpected translation type");
3068 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
3070 const char* Translation::StringFor(Opcode opcode) {
3071 #define TRANSLATION_OPCODE_CASE(item) case item: return #item;
3073 TRANSLATION_OPCODE_LIST(TRANSLATION_OPCODE_CASE)
3075 #undef TRANSLATION_OPCODE_CASE
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) {
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.
3101 case Translation::DUPLICATED_OBJECT: {
3102 return SlotRef::NewDuplicateObject(iterator->Next());
3105 case Translation::ARGUMENTS_OBJECT:
3106 return SlotRef::NewArgumentsObject(iterator->Next());
3108 case Translation::CAPTURED_OBJECT: {
3109 return SlotRef::NewDeferredObject(iterator->Next());
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.
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);
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);
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);
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);
3145 case Translation::LITERAL: {
3146 int literal_index = iterator->Next();
3147 return SlotRef(data->GetIsolate(),
3148 data->LiteralArray()->get(literal_index));
3151 case Translation::COMPILED_STUB_FRAME:
3156 FATAL("We should never get here - unexpected deopt info.");
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;
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.
3176 stack_frame_id_ = frame->fp();
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);
3190 it.Skip(1); // literal id
3191 int height = it.Next();
3193 // Skip the translation command for the receiver.
3194 it.Skip(Translation::NumberOfOperandsFor(
3195 static_cast<Translation::Opcode>(it.Next())));
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;
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));
3209 // Skip the translation command for the receiver.
3210 it.Skip(Translation::NumberOfOperandsFor(
3211 static_cast<Translation::Opcode>(it.Next())));
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;
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));
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
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;
3246 // Skip over operands to advance to the next opcode.
3247 it.Skip(Translation::NumberOfOperandsFor(opcode));
3251 List<JSFunction*> functions(2);
3252 frame->GetFunctions(&functions);
3253 Deoptimizer::DeoptimizeFunction(functions[0]);
3258 Handle<Object> SlotRef::GetValue(Isolate* isolate) {
3259 switch (representation_) {
3261 return Handle<Object>(Memory::Object_at(addr_), isolate);
3264 int value = Memory::int32_at(addr_);
3265 if (Smi::IsValid(value)) {
3266 return Handle<Object>(Smi::FromInt(value), isolate);
3268 return isolate->factory()->NewNumberFromInt(value);
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);
3277 return isolate->factory()->NewNumber(static_cast<double>(value));
3282 double value = read_double_value(addr_);
3283 return isolate->factory()->NewNumber(value);
3290 FATAL("We should never get here - unexpected deopt info.");
3291 return Handle<Object>::null();
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();
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);
3309 CHECK_EQ(current_slot_, first_slot_index_);
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);
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_];
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();
3330 // Put the nested deferred/duplicate objects into our materialization
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),
3338 materialized_objects_.Add(nested_object);
3342 return return_value;
3346 Handle<Object> SlotRefValueBuilder::GetNext(Isolate* isolate, int lvl) {
3347 SlotRef& slot = slot_refs_[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);
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);
3367 return isolate->factory()->undefined_value();
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);
3374 int object_index = materialized_objects_.length();
3375 if (object_index < prev_materialized_count_) {
3376 return GetPreviouslyMaterialized(isolate, length);
3379 Handle<Object> map_object = slot_refs_[current_slot_].GetValue(isolate);
3380 Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
3381 Handle<Map>::cast(map_object));
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
3395 for (int i = 0; i < length - 2; i++) {
3396 GetNext(isolate, lvl + 1);
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);
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);
3429 "[couldn't handle instance type %d]\n", map->instance_type());
3437 case SlotRef::DUPLICATE_OBJECT: {
3438 int object_index = slot.DuplicateObjectId();
3439 Handle<Object> object = materialized_objects_[object_index];
3440 materialized_objects_.Add(object);
3448 FATAL("We should never get here - unexpected deopt slot kind.");
3449 return Handle<Object>::null();
3453 void SlotRefValueBuilder::Finish(Isolate* isolate) {
3454 // We should have processed all the slots
3455 CHECK_EQ(slot_refs_.length(), current_slot_);
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)));
3465 isolate->materialized_object_store()->Set(stack_frame_id_, array);
3470 Handle<FixedArray> MaterializedObjectStore::Get(Address fp) {
3471 int index = StackIdToIndex(fp);
3473 return Handle<FixedArray>::null();
3475 Handle<FixedArray> array = GetStackEntries();
3476 CHECK_GT(array->length(), index);
3477 return Handle<FixedArray>::cast(Handle<Object>(array->get(index),
3482 void MaterializedObjectStore::Set(Address fp,
3483 Handle<FixedArray> materialized_objects) {
3484 int index = StackIdToIndex(fp);
3486 index = frame_fps_.length();
3490 Handle<FixedArray> array = EnsureStackEntries(index + 1);
3491 array->set(index, *materialized_objects);
3495 void MaterializedObjectStore::Remove(Address fp) {
3496 int index = StackIdToIndex(fp);
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));
3505 array->set(frame_fps_.length(), isolate()->heap()->undefined_value());
3509 int MaterializedObjectStore::StackIdToIndex(Address fp) {
3510 for (int i = 0; i < frame_fps_.length(); i++) {
3511 if (frame_fps_[i] == fp) {
3519 Handle<FixedArray> MaterializedObjectStore::GetStackEntries() {
3520 return Handle<FixedArray>(isolate()->heap()->materialized_objects());
3524 Handle<FixedArray> MaterializedObjectStore::EnsureStackEntries(int length) {
3525 Handle<FixedArray> array = GetStackEntries();
3526 if (array->length() >= length) {
3530 int new_length = length > 10 ? length : 10;
3531 if (new_length < 2 * array->length()) {
3532 new_length = 2 * array->length();
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));
3540 for (int i = array->length(); i < length; i++) {
3541 new_array->set(i, isolate()->heap()->undefined_value());
3543 isolate()->heap()->public_set_materialized_objects(*new_array);
3548 DeoptimizedFrameInfo::DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
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);
3562 for (int i = 0; i < expression_count_; i++) {
3563 SetExpression(i, output_frame->GetExpression(i));
3566 if (has_arguments_adaptor) {
3567 output_frame = deoptimizer->output_[frame_index - 1];
3568 CHECK_EQ(output_frame->GetFrameType(), StackFrame::ARGUMENTS_ADAPTOR);
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));
3579 DeoptimizedFrameInfo::~DeoptimizedFrameInfo() {
3580 delete[] expression_stack_;
3581 delete[] parameters_;
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_);
3591 } } // namespace v8::internal