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