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