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