• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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/translated-state.h"
6 
7 #include <iomanip>
8 
9 #include "src/base/memory.h"
10 #include "src/deoptimizer/deoptimizer.h"
11 #include "src/deoptimizer/materialized-object-store.h"
12 #include "src/deoptimizer/translation-opcode.h"
13 #include "src/diagnostics/disasm.h"
14 #include "src/execution/frames.h"
15 #include "src/execution/isolate.h"
16 #include "src/numbers/conversions.h"
17 #include "src/objects/arguments.h"
18 #include "src/objects/heap-number-inl.h"
19 #include "src/objects/oddball.h"
20 
21 // Has to be the last include (doesn't have include guards)
22 #include "src/objects/object-macros.h"
23 
24 namespace v8 {
25 
26 using base::Memory;
27 using base::ReadUnalignedValue;
28 
29 namespace internal {
30 
TranslationArrayPrintSingleFrame(std::ostream & os,TranslationArray translation_array,int translation_index,DeoptimizationLiteralArray literal_array)31 void TranslationArrayPrintSingleFrame(
32     std::ostream& os, TranslationArray translation_array, int translation_index,
33     DeoptimizationLiteralArray literal_array) {
34   DisallowGarbageCollection gc_oh_noes;
35   TranslationArrayIterator iterator(translation_array, translation_index);
36   disasm::NameConverter converter;
37 
38   TranslationOpcode opcode = TranslationOpcodeFromInt(iterator.Next());
39   DCHECK(TranslationOpcode::BEGIN == opcode);
40   int frame_count = iterator.Next();
41   int jsframe_count = iterator.Next();
42   int update_feedback_count = iterator.Next();
43   os << "  " << TranslationOpcodeToString(opcode)
44      << " {frame count=" << frame_count << ", js frame count=" << jsframe_count
45      << ", update_feedback_count=" << update_feedback_count << "}\n";
46 
47   while (iterator.HasNext()) {
48     opcode = TranslationOpcodeFromInt(iterator.Next());
49     if (opcode == TranslationOpcode::BEGIN) break;
50 
51     os << std::setw(31) << "    " << TranslationOpcodeToString(opcode) << " ";
52 
53     switch (opcode) {
54       case TranslationOpcode::BEGIN:
55         UNREACHABLE();
56 
57       case TranslationOpcode::INTERPRETED_FRAME: {
58         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 5);
59         int bytecode_offset = iterator.Next();
60         int shared_info_id = iterator.Next();
61         unsigned height = iterator.Next();
62         int return_value_offset = iterator.Next();
63         int return_value_count = iterator.Next();
64         Object shared_info = literal_array.get(shared_info_id);
65         os << "{bytecode_offset=" << bytecode_offset << ", function="
66            << SharedFunctionInfo::cast(shared_info).DebugNameCStr().get()
67            << ", height=" << height << ", retval=@" << return_value_offset
68            << "(#" << return_value_count << ")}";
69         break;
70       }
71 
72       case TranslationOpcode::CONSTRUCT_STUB_FRAME: {
73         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 3);
74         int bailout_id = iterator.Next();
75         int shared_info_id = iterator.Next();
76         Object shared_info = literal_array.get(shared_info_id);
77         unsigned height = iterator.Next();
78         os << "{bailout_id=" << bailout_id << ", function="
79            << SharedFunctionInfo::cast(shared_info).DebugNameCStr().get()
80            << ", height=" << height << "}";
81         break;
82       }
83 
84       case TranslationOpcode::BUILTIN_CONTINUATION_FRAME:
85       case TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
86       case TranslationOpcode::
87           JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
88         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 3);
89         int bailout_id = iterator.Next();
90         int shared_info_id = iterator.Next();
91         Object shared_info = literal_array.get(shared_info_id);
92         unsigned height = iterator.Next();
93         os << "{bailout_id=" << bailout_id << ", function="
94            << SharedFunctionInfo::cast(shared_info).DebugNameCStr().get()
95            << ", height=" << height << "}";
96         break;
97       }
98 
99 #if V8_ENABLE_WEBASSEMBLY
100       case TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME: {
101         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 4);
102         int bailout_id = iterator.Next();
103         int shared_info_id = iterator.Next();
104         Object shared_info = literal_array.get(shared_info_id);
105         unsigned height = iterator.Next();
106         int wasm_return_type = iterator.Next();
107         os << "{bailout_id=" << bailout_id << ", function="
108            << SharedFunctionInfo::cast(shared_info).DebugNameCStr().get()
109            << ", height=" << height << ", wasm_return_type=" << wasm_return_type
110            << "}";
111         break;
112       }
113 #endif  // V8_ENABLE_WEBASSEMBLY
114 
115       case TranslationOpcode::ARGUMENTS_ADAPTOR_FRAME: {
116         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 2);
117         int shared_info_id = iterator.Next();
118         Object shared_info = literal_array.get(shared_info_id);
119         unsigned height = iterator.Next();
120         os << "{function="
121            << SharedFunctionInfo::cast(shared_info).DebugNameCStr().get()
122            << ", height=" << height << "}";
123         break;
124       }
125 
126       case TranslationOpcode::REGISTER: {
127         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
128         int reg_code = iterator.Next();
129         os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
130         break;
131       }
132 
133       case TranslationOpcode::INT32_REGISTER: {
134         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
135         int reg_code = iterator.Next();
136         os << "{input=" << converter.NameOfCPURegister(reg_code) << " (int32)}";
137         break;
138       }
139 
140       case TranslationOpcode::INT64_REGISTER: {
141         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
142         int reg_code = iterator.Next();
143         os << "{input=" << converter.NameOfCPURegister(reg_code) << " (int64)}";
144         break;
145       }
146 
147       case TranslationOpcode::UINT32_REGISTER: {
148         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
149         int reg_code = iterator.Next();
150         os << "{input=" << converter.NameOfCPURegister(reg_code)
151            << " (uint32)}";
152         break;
153       }
154 
155       case TranslationOpcode::BOOL_REGISTER: {
156         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
157         int reg_code = iterator.Next();
158         os << "{input=" << converter.NameOfCPURegister(reg_code) << " (bool)}";
159         break;
160       }
161 
162       case TranslationOpcode::FLOAT_REGISTER: {
163         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
164         int reg_code = iterator.Next();
165         os << "{input=" << FloatRegister::from_code(reg_code) << "}";
166         break;
167       }
168 
169       case TranslationOpcode::DOUBLE_REGISTER: {
170         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
171         int reg_code = iterator.Next();
172         os << "{input=" << DoubleRegister::from_code(reg_code) << "}";
173         break;
174       }
175 
176       case TranslationOpcode::STACK_SLOT: {
177         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
178         int input_slot_index = iterator.Next();
179         os << "{input=" << input_slot_index << "}";
180         break;
181       }
182 
183       case TranslationOpcode::INT32_STACK_SLOT: {
184         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
185         int input_slot_index = iterator.Next();
186         os << "{input=" << input_slot_index << " (int32)}";
187         break;
188       }
189 
190       case TranslationOpcode::INT64_STACK_SLOT: {
191         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
192         int input_slot_index = iterator.Next();
193         os << "{input=" << input_slot_index << " (int64)}";
194         break;
195       }
196 
197       case TranslationOpcode::UINT32_STACK_SLOT: {
198         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
199         int input_slot_index = iterator.Next();
200         os << "{input=" << input_slot_index << " (uint32)}";
201         break;
202       }
203 
204       case TranslationOpcode::BOOL_STACK_SLOT: {
205         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
206         int input_slot_index = iterator.Next();
207         os << "{input=" << input_slot_index << " (bool)}";
208         break;
209       }
210 
211       case TranslationOpcode::FLOAT_STACK_SLOT:
212       case TranslationOpcode::DOUBLE_STACK_SLOT: {
213         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
214         int input_slot_index = iterator.Next();
215         os << "{input=" << input_slot_index << "}";
216         break;
217       }
218 
219       case TranslationOpcode::LITERAL: {
220         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
221         int literal_index = iterator.Next();
222         Object literal_value = literal_array.get(literal_index);
223         os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
224            << ")}";
225         break;
226       }
227 
228       case TranslationOpcode::DUPLICATED_OBJECT: {
229         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
230         int object_index = iterator.Next();
231         os << "{object_index=" << object_index << "}";
232         break;
233       }
234 
235       case TranslationOpcode::ARGUMENTS_ELEMENTS: {
236         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
237         CreateArgumentsType arguments_type =
238             static_cast<CreateArgumentsType>(iterator.Next());
239         os << "{arguments_type=" << arguments_type << "}";
240         break;
241       }
242       case TranslationOpcode::ARGUMENTS_LENGTH: {
243         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 0);
244         os << "{arguments_length}";
245         break;
246       }
247 
248       case TranslationOpcode::CAPTURED_OBJECT: {
249         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
250         int args_length = iterator.Next();
251         os << "{length=" << args_length << "}";
252         break;
253       }
254 
255       case TranslationOpcode::UPDATE_FEEDBACK: {
256         DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 2);
257         int literal_index = iterator.Next();
258         FeedbackSlot slot(iterator.Next());
259         os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
260            << "}}";
261         break;
262       }
263     }
264     os << "\n";
265   }
266 }
267 
268 // static
NewDeferredObject(TranslatedState * container,int length,int object_index)269 TranslatedValue TranslatedValue::NewDeferredObject(TranslatedState* container,
270                                                    int length,
271                                                    int object_index) {
272   TranslatedValue slot(container, kCapturedObject);
273   slot.materialization_info_ = {object_index, length};
274   return slot;
275 }
276 
277 // static
NewDuplicateObject(TranslatedState * container,int id)278 TranslatedValue TranslatedValue::NewDuplicateObject(TranslatedState* container,
279                                                     int id) {
280   TranslatedValue slot(container, kDuplicatedObject);
281   slot.materialization_info_ = {id, -1};
282   return slot;
283 }
284 
285 // static
NewFloat(TranslatedState * container,Float32 value)286 TranslatedValue TranslatedValue::NewFloat(TranslatedState* container,
287                                           Float32 value) {
288   TranslatedValue slot(container, kFloat);
289   slot.float_value_ = value;
290   return slot;
291 }
292 
293 // static
NewDouble(TranslatedState * container,Float64 value)294 TranslatedValue TranslatedValue::NewDouble(TranslatedState* container,
295                                            Float64 value) {
296   TranslatedValue slot(container, kDouble);
297   slot.double_value_ = value;
298   return slot;
299 }
300 
301 // static
NewInt32(TranslatedState * container,int32_t value)302 TranslatedValue TranslatedValue::NewInt32(TranslatedState* container,
303                                           int32_t value) {
304   TranslatedValue slot(container, kInt32);
305   slot.int32_value_ = value;
306   return slot;
307 }
308 
309 // static
NewInt64(TranslatedState * container,int64_t value)310 TranslatedValue TranslatedValue::NewInt64(TranslatedState* container,
311                                           int64_t value) {
312   TranslatedValue slot(container, kInt64);
313   slot.int64_value_ = value;
314   return slot;
315 }
316 
317 // static
NewInt64ToBigInt(TranslatedState * container,int64_t value)318 TranslatedValue TranslatedValue::NewInt64ToBigInt(TranslatedState* container,
319                                                   int64_t value) {
320   TranslatedValue slot(container, kInt64ToBigInt);
321   slot.int64_value_ = value;
322   return slot;
323 }
324 
325 // static
NewUInt32(TranslatedState * container,uint32_t value)326 TranslatedValue TranslatedValue::NewUInt32(TranslatedState* container,
327                                            uint32_t value) {
328   TranslatedValue slot(container, kUInt32);
329   slot.uint32_value_ = value;
330   return slot;
331 }
332 
333 // static
NewBool(TranslatedState * container,uint32_t value)334 TranslatedValue TranslatedValue::NewBool(TranslatedState* container,
335                                          uint32_t value) {
336   TranslatedValue slot(container, kBoolBit);
337   slot.uint32_value_ = value;
338   return slot;
339 }
340 
341 // static
NewTagged(TranslatedState * container,Object literal)342 TranslatedValue TranslatedValue::NewTagged(TranslatedState* container,
343                                            Object literal) {
344   TranslatedValue slot(container, kTagged);
345   slot.raw_literal_ = literal;
346   return slot;
347 }
348 
349 // static
NewInvalid(TranslatedState * container)350 TranslatedValue TranslatedValue::NewInvalid(TranslatedState* container) {
351   return TranslatedValue(container, kInvalid);
352 }
353 
isolate() const354 Isolate* TranslatedValue::isolate() const { return container_->isolate(); }
355 
raw_literal() const356 Object TranslatedValue::raw_literal() const {
357   DCHECK_EQ(kTagged, kind());
358   return raw_literal_;
359 }
360 
int32_value() const361 int32_t TranslatedValue::int32_value() const {
362   DCHECK_EQ(kInt32, kind());
363   return int32_value_;
364 }
365 
int64_value() const366 int64_t TranslatedValue::int64_value() const {
367   DCHECK(kInt64 == kind() || kInt64ToBigInt == kind());
368   return int64_value_;
369 }
370 
uint32_value() const371 uint32_t TranslatedValue::uint32_value() const {
372   DCHECK(kind() == kUInt32 || kind() == kBoolBit);
373   return uint32_value_;
374 }
375 
float_value() const376 Float32 TranslatedValue::float_value() const {
377   DCHECK_EQ(kFloat, kind());
378   return float_value_;
379 }
380 
double_value() const381 Float64 TranslatedValue::double_value() const {
382   DCHECK_EQ(kDouble, kind());
383   return double_value_;
384 }
385 
object_length() const386 int TranslatedValue::object_length() const {
387   DCHECK_EQ(kind(), kCapturedObject);
388   return materialization_info_.length_;
389 }
390 
object_index() const391 int TranslatedValue::object_index() const {
392   DCHECK(kind() == kCapturedObject || kind() == kDuplicatedObject);
393   return materialization_info_.id_;
394 }
395 
GetRawValue() const396 Object TranslatedValue::GetRawValue() const {
397   // If we have a value, return it.
398   if (materialization_state() == kFinished) {
399     int smi;
400     if (storage_->IsHeapNumber() &&
401         DoubleToSmiInteger(storage_->Number(), &smi)) {
402       return Smi::FromInt(smi);
403     }
404     return *storage_;
405   }
406 
407   // Otherwise, do a best effort to get the value without allocation.
408   switch (kind()) {
409     case kTagged:
410       return raw_literal();
411 
412     case kInt32: {
413       bool is_smi = Smi::IsValid(int32_value());
414       if (is_smi) {
415         return Smi::FromInt(int32_value());
416       }
417       break;
418     }
419 
420     case kInt64: {
421       bool is_smi = (int64_value() >= static_cast<int64_t>(Smi::kMinValue) &&
422                      int64_value() <= static_cast<int64_t>(Smi::kMaxValue));
423       if (is_smi) {
424         return Smi::FromIntptr(static_cast<intptr_t>(int64_value()));
425       }
426       break;
427     }
428 
429     case kInt64ToBigInt:
430       // Return the arguments marker.
431       break;
432 
433     case kUInt32: {
434       bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue));
435       if (is_smi) {
436         return Smi::FromInt(static_cast<int32_t>(uint32_value()));
437       }
438       break;
439     }
440 
441     case kBoolBit: {
442       if (uint32_value() == 0) {
443         return ReadOnlyRoots(isolate()).false_value();
444       } else {
445         CHECK_EQ(1U, uint32_value());
446         return ReadOnlyRoots(isolate()).true_value();
447       }
448     }
449 
450     case kFloat: {
451       int smi;
452       if (DoubleToSmiInteger(float_value().get_scalar(), &smi)) {
453         return Smi::FromInt(smi);
454       }
455       break;
456     }
457 
458     case kDouble: {
459       int smi;
460       if (DoubleToSmiInteger(double_value().get_scalar(), &smi)) {
461         return Smi::FromInt(smi);
462       }
463       break;
464     }
465 
466     default:
467       break;
468   }
469 
470   // If we could not get the value without allocation, return the arguments
471   // marker.
472   return ReadOnlyRoots(isolate()).arguments_marker();
473 }
474 
set_initialized_storage(Handle<HeapObject> storage)475 void TranslatedValue::set_initialized_storage(Handle<HeapObject> storage) {
476   DCHECK_EQ(kUninitialized, materialization_state());
477   storage_ = storage;
478   materialization_state_ = kFinished;
479 }
480 
GetValue()481 Handle<Object> TranslatedValue::GetValue() {
482   Handle<Object> value(GetRawValue(), isolate());
483   if (materialization_state() == kFinished) return value;
484 
485   if (value->IsSmi()) {
486     // Even though stored as a Smi, this number might instead be needed as a
487     // HeapNumber when materializing a JSObject with a field of HeapObject
488     // representation. Since we don't have this information available here, we
489     // just always allocate a HeapNumber and later extract the Smi again if we
490     // don't need a HeapObject.
491     set_initialized_storage(
492         isolate()->factory()->NewHeapNumber(value->Number()));
493     return value;
494   }
495 
496   if (*value != ReadOnlyRoots(isolate()).arguments_marker()) {
497     set_initialized_storage(Handle<HeapObject>::cast(value));
498     return storage_;
499   }
500 
501   // Otherwise we have to materialize.
502 
503   if (kind() == TranslatedValue::kCapturedObject ||
504       kind() == TranslatedValue::kDuplicatedObject) {
505     // We need to materialize the object (or possibly even object graphs).
506     // To make the object verifier happy, we materialize in two steps.
507 
508     // 1. Allocate storage for reachable objects. This makes sure that for
509     //    each object we have allocated space on heap. The space will be
510     //    a byte array that will be later initialized, or a fully
511     //    initialized object if it is safe to allocate one that will
512     //    pass the verifier.
513     container_->EnsureObjectAllocatedAt(this);
514 
515     // Finish any sweeping so that it becomes safe to overwrite the ByteArray
516     // headers.
517     // TODO(hpayer): Find a cleaner way to support a group of
518     // non-fully-initialized objects.
519     isolate()->heap()->mark_compact_collector()->EnsureSweepingCompleted(
520         MarkCompactCollector::SweepingForcedFinalizationMode::kV8Only);
521 
522     // 2. Initialize the objects. If we have allocated only byte arrays
523     //    for some objects, we now overwrite the byte arrays with the
524     //    correct object fields. Note that this phase does not allocate
525     //    any new objects, so it does not trigger the object verifier.
526     return container_->InitializeObjectAt(this);
527   }
528 
529   double number = 0;
530   Handle<HeapObject> heap_object;
531   switch (kind()) {
532     case TranslatedValue::kInt32:
533       number = int32_value();
534       heap_object = isolate()->factory()->NewHeapNumber(number);
535       break;
536     case TranslatedValue::kInt64:
537       number = int64_value();
538       heap_object = isolate()->factory()->NewHeapNumber(number);
539       break;
540     case TranslatedValue::kInt64ToBigInt:
541       heap_object = BigInt::FromInt64(isolate(), int64_value());
542       break;
543     case TranslatedValue::kUInt32:
544       number = uint32_value();
545       heap_object = isolate()->factory()->NewHeapNumber(number);
546       break;
547     case TranslatedValue::kFloat:
548       number = float_value().get_scalar();
549       heap_object = isolate()->factory()->NewHeapNumber(number);
550       break;
551     case TranslatedValue::kDouble:
552       number = double_value().get_scalar();
553       heap_object = isolate()->factory()->NewHeapNumber(number);
554       break;
555     default:
556       UNREACHABLE();
557   }
558   DCHECK(!IsSmiDouble(number) || kind() == TranslatedValue::kInt64ToBigInt);
559   set_initialized_storage(heap_object);
560   return storage_;
561 }
562 
IsMaterializedObject() const563 bool TranslatedValue::IsMaterializedObject() const {
564   switch (kind()) {
565     case kCapturedObject:
566     case kDuplicatedObject:
567       return true;
568     default:
569       return false;
570   }
571 }
572 
IsMaterializableByDebugger() const573 bool TranslatedValue::IsMaterializableByDebugger() const {
574   // At the moment, we only allow materialization of doubles.
575   return (kind() == kDouble);
576 }
577 
GetChildrenCount() const578 int TranslatedValue::GetChildrenCount() const {
579   if (kind() == kCapturedObject) {
580     return object_length();
581   } else {
582     return 0;
583   }
584 }
585 
GetUInt64Slot(Address fp,int slot_offset)586 uint64_t TranslatedState::GetUInt64Slot(Address fp, int slot_offset) {
587 #if V8_TARGET_ARCH_32_BIT
588   return ReadUnalignedValue<uint64_t>(fp + slot_offset);
589 #else
590   return Memory<uint64_t>(fp + slot_offset);
591 #endif
592 }
593 
GetUInt32Slot(Address fp,int slot_offset)594 uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) {
595   Address address = fp + slot_offset;
596 #if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
597   return Memory<uint32_t>(address + kIntSize);
598 #else
599   return Memory<uint32_t>(address);
600 #endif
601 }
602 
GetFloatSlot(Address fp,int slot_offset)603 Float32 TranslatedState::GetFloatSlot(Address fp, int slot_offset) {
604 #if !V8_TARGET_ARCH_S390X && !V8_TARGET_ARCH_PPC64
605   return Float32::FromBits(GetUInt32Slot(fp, slot_offset));
606 #else
607   return Float32::FromBits(Memory<uint32_t>(fp + slot_offset));
608 #endif
609 }
610 
GetDoubleSlot(Address fp,int slot_offset)611 Float64 TranslatedState::GetDoubleSlot(Address fp, int slot_offset) {
612   return Float64::FromBits(GetUInt64Slot(fp, slot_offset));
613 }
614 
Handlify()615 void TranslatedValue::Handlify() {
616   if (kind() == kTagged && raw_literal().IsHeapObject()) {
617     set_initialized_storage(
618         Handle<HeapObject>(HeapObject::cast(raw_literal()), isolate()));
619     raw_literal_ = Object();
620   }
621 }
622 
UnoptimizedFrame(BytecodeOffset bytecode_offset,SharedFunctionInfo shared_info,int height,int return_value_offset,int return_value_count)623 TranslatedFrame TranslatedFrame::UnoptimizedFrame(
624     BytecodeOffset bytecode_offset, SharedFunctionInfo shared_info, int height,
625     int return_value_offset, int return_value_count) {
626   TranslatedFrame frame(kUnoptimizedFunction, shared_info, height,
627                         return_value_offset, return_value_count);
628   frame.bytecode_offset_ = bytecode_offset;
629   return frame;
630 }
631 
ArgumentsAdaptorFrame(SharedFunctionInfo shared_info,int height)632 TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
633     SharedFunctionInfo shared_info, int height) {
634   return TranslatedFrame(kArgumentsAdaptor, shared_info, height);
635 }
636 
ConstructStubFrame(BytecodeOffset bytecode_offset,SharedFunctionInfo shared_info,int height)637 TranslatedFrame TranslatedFrame::ConstructStubFrame(
638     BytecodeOffset bytecode_offset, SharedFunctionInfo shared_info,
639     int height) {
640   TranslatedFrame frame(kConstructStub, shared_info, height);
641   frame.bytecode_offset_ = bytecode_offset;
642   return frame;
643 }
644 
BuiltinContinuationFrame(BytecodeOffset bytecode_offset,SharedFunctionInfo shared_info,int height)645 TranslatedFrame TranslatedFrame::BuiltinContinuationFrame(
646     BytecodeOffset bytecode_offset, SharedFunctionInfo shared_info,
647     int height) {
648   TranslatedFrame frame(kBuiltinContinuation, shared_info, height);
649   frame.bytecode_offset_ = bytecode_offset;
650   return frame;
651 }
652 
653 #if V8_ENABLE_WEBASSEMBLY
JSToWasmBuiltinContinuationFrame(BytecodeOffset bytecode_offset,SharedFunctionInfo shared_info,int height,base::Optional<wasm::ValueKind> return_kind)654 TranslatedFrame TranslatedFrame::JSToWasmBuiltinContinuationFrame(
655     BytecodeOffset bytecode_offset, SharedFunctionInfo shared_info, int height,
656     base::Optional<wasm::ValueKind> return_kind) {
657   TranslatedFrame frame(kJSToWasmBuiltinContinuation, shared_info, height);
658   frame.bytecode_offset_ = bytecode_offset;
659   frame.return_kind_ = return_kind;
660   return frame;
661 }
662 #endif  // V8_ENABLE_WEBASSEMBLY
663 
JavaScriptBuiltinContinuationFrame(BytecodeOffset bytecode_offset,SharedFunctionInfo shared_info,int height)664 TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationFrame(
665     BytecodeOffset bytecode_offset, SharedFunctionInfo shared_info,
666     int height) {
667   TranslatedFrame frame(kJavaScriptBuiltinContinuation, shared_info, height);
668   frame.bytecode_offset_ = bytecode_offset;
669   return frame;
670 }
671 
JavaScriptBuiltinContinuationWithCatchFrame(BytecodeOffset bytecode_offset,SharedFunctionInfo shared_info,int height)672 TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationWithCatchFrame(
673     BytecodeOffset bytecode_offset, SharedFunctionInfo shared_info,
674     int height) {
675   TranslatedFrame frame(kJavaScriptBuiltinContinuationWithCatch, shared_info,
676                         height);
677   frame.bytecode_offset_ = bytecode_offset;
678   return frame;
679 }
680 
GetValueCount()681 int TranslatedFrame::GetValueCount() {
682   // The function is added to all frame state descriptors in
683   // InstructionSelector::AddInputsToFrameStateDescriptor.
684   static constexpr int kTheFunction = 1;
685 
686   switch (kind()) {
687     case kUnoptimizedFunction: {
688       int parameter_count =
689           raw_shared_info_.internal_formal_parameter_count_with_receiver();
690       static constexpr int kTheContext = 1;
691       static constexpr int kTheAccumulator = 1;
692       return height() + parameter_count + kTheContext + kTheFunction +
693              kTheAccumulator;
694     }
695 
696     case kArgumentsAdaptor:
697       return height() + kTheFunction;
698 
699     case kConstructStub:
700     case kBuiltinContinuation:
701 #if V8_ENABLE_WEBASSEMBLY
702     case kJSToWasmBuiltinContinuation:
703 #endif  // V8_ENABLE_WEBASSEMBLY
704     case kJavaScriptBuiltinContinuation:
705     case kJavaScriptBuiltinContinuationWithCatch: {
706       static constexpr int kTheContext = 1;
707       return height() + kTheContext + kTheFunction;
708     }
709 
710     case kInvalid:
711       UNREACHABLE();
712   }
713   UNREACHABLE();
714 }
715 
Handlify()716 void TranslatedFrame::Handlify() {
717   if (!raw_shared_info_.is_null()) {
718     shared_info_ = Handle<SharedFunctionInfo>(raw_shared_info_,
719                                               raw_shared_info_.GetIsolate());
720     raw_shared_info_ = SharedFunctionInfo();
721   }
722   for (auto& value : values_) {
723     value.Handlify();
724   }
725 }
726 
CreateNextTranslatedFrame(TranslationArrayIterator * iterator,DeoptimizationLiteralArray literal_array,Address fp,FILE * trace_file)727 TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
728     TranslationArrayIterator* iterator,
729     DeoptimizationLiteralArray literal_array, Address fp, FILE* trace_file) {
730   TranslationOpcode opcode = TranslationOpcodeFromInt(iterator->Next());
731   switch (opcode) {
732     case TranslationOpcode::INTERPRETED_FRAME: {
733       BytecodeOffset bytecode_offset = BytecodeOffset(iterator->Next());
734       SharedFunctionInfo shared_info =
735           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
736       int height = iterator->Next();
737       int return_value_offset = iterator->Next();
738       int return_value_count = iterator->Next();
739       if (trace_file != nullptr) {
740         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
741         PrintF(trace_file, "  reading input frame %s", name.get());
742         int arg_count =
743             shared_info.internal_formal_parameter_count_with_receiver();
744         PrintF(trace_file,
745                " => bytecode_offset=%d, args=%d, height=%d, retval=%i(#%i); "
746                "inputs:\n",
747                bytecode_offset.ToInt(), arg_count, height, return_value_offset,
748                return_value_count);
749       }
750       return TranslatedFrame::UnoptimizedFrame(bytecode_offset, shared_info,
751                                                height, return_value_offset,
752                                                return_value_count);
753     }
754 
755     case TranslationOpcode::ARGUMENTS_ADAPTOR_FRAME: {
756       SharedFunctionInfo shared_info =
757           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
758       int height = iterator->Next();
759       if (trace_file != nullptr) {
760         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
761         PrintF(trace_file, "  reading arguments adaptor frame %s", name.get());
762         PrintF(trace_file, " => height=%d; inputs:\n", height);
763       }
764       return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height);
765     }
766 
767     case TranslationOpcode::CONSTRUCT_STUB_FRAME: {
768       BytecodeOffset bytecode_offset = BytecodeOffset(iterator->Next());
769       SharedFunctionInfo shared_info =
770           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
771       int height = iterator->Next();
772       if (trace_file != nullptr) {
773         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
774         PrintF(trace_file, "  reading construct stub frame %s", name.get());
775         PrintF(trace_file, " => bytecode_offset=%d, height=%d; inputs:\n",
776                bytecode_offset.ToInt(), height);
777       }
778       return TranslatedFrame::ConstructStubFrame(bytecode_offset, shared_info,
779                                                  height);
780     }
781 
782     case TranslationOpcode::BUILTIN_CONTINUATION_FRAME: {
783       BytecodeOffset bytecode_offset = BytecodeOffset(iterator->Next());
784       SharedFunctionInfo shared_info =
785           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
786       int height = iterator->Next();
787       if (trace_file != nullptr) {
788         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
789         PrintF(trace_file, "  reading builtin continuation frame %s",
790                name.get());
791         PrintF(trace_file, " => bytecode_offset=%d, height=%d; inputs:\n",
792                bytecode_offset.ToInt(), height);
793       }
794       return TranslatedFrame::BuiltinContinuationFrame(bytecode_offset,
795                                                        shared_info, height);
796     }
797 
798 #if V8_ENABLE_WEBASSEMBLY
799     case TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME: {
800       BytecodeOffset bailout_id = BytecodeOffset(iterator->Next());
801       SharedFunctionInfo shared_info =
802           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
803       int height = iterator->Next();
804       int return_kind_code = iterator->Next();
805       base::Optional<wasm::ValueKind> return_kind;
806       if (return_kind_code != kNoWasmReturnKind) {
807         return_kind = static_cast<wasm::ValueKind>(return_kind_code);
808       }
809       if (trace_file != nullptr) {
810         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
811         PrintF(trace_file, "  reading JS to Wasm builtin continuation frame %s",
812                name.get());
813         PrintF(trace_file,
814                " => bailout_id=%d, height=%d return_type=%d; inputs:\n",
815                bailout_id.ToInt(), height,
816                return_kind.has_value() ? return_kind.value() : -1);
817       }
818       return TranslatedFrame::JSToWasmBuiltinContinuationFrame(
819           bailout_id, shared_info, height, return_kind);
820     }
821 #endif  // V8_ENABLE_WEBASSEMBLY
822 
823     case TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: {
824       BytecodeOffset bytecode_offset = BytecodeOffset(iterator->Next());
825       SharedFunctionInfo shared_info =
826           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
827       int height = iterator->Next();
828       if (trace_file != nullptr) {
829         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
830         PrintF(trace_file, "  reading JavaScript builtin continuation frame %s",
831                name.get());
832         PrintF(trace_file, " => bytecode_offset=%d, height=%d; inputs:\n",
833                bytecode_offset.ToInt(), height);
834       }
835       return TranslatedFrame::JavaScriptBuiltinContinuationFrame(
836           bytecode_offset, shared_info, height);
837     }
838 
839     case TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
840       BytecodeOffset bytecode_offset = BytecodeOffset(iterator->Next());
841       SharedFunctionInfo shared_info =
842           SharedFunctionInfo::cast(literal_array.get(iterator->Next()));
843       int height = iterator->Next();
844       if (trace_file != nullptr) {
845         std::unique_ptr<char[]> name = shared_info.DebugNameCStr();
846         PrintF(trace_file,
847                "  reading JavaScript builtin continuation frame with catch %s",
848                name.get());
849         PrintF(trace_file, " => bytecode_offset=%d, height=%d; inputs:\n",
850                bytecode_offset.ToInt(), height);
851       }
852       return TranslatedFrame::JavaScriptBuiltinContinuationWithCatchFrame(
853           bytecode_offset, shared_info, height);
854     }
855     case TranslationOpcode::UPDATE_FEEDBACK:
856     case TranslationOpcode::BEGIN:
857     case TranslationOpcode::DUPLICATED_OBJECT:
858     case TranslationOpcode::ARGUMENTS_ELEMENTS:
859     case TranslationOpcode::ARGUMENTS_LENGTH:
860     case TranslationOpcode::CAPTURED_OBJECT:
861     case TranslationOpcode::REGISTER:
862     case TranslationOpcode::INT32_REGISTER:
863     case TranslationOpcode::INT64_REGISTER:
864     case TranslationOpcode::UINT32_REGISTER:
865     case TranslationOpcode::BOOL_REGISTER:
866     case TranslationOpcode::FLOAT_REGISTER:
867     case TranslationOpcode::DOUBLE_REGISTER:
868     case TranslationOpcode::STACK_SLOT:
869     case TranslationOpcode::INT32_STACK_SLOT:
870     case TranslationOpcode::INT64_STACK_SLOT:
871     case TranslationOpcode::UINT32_STACK_SLOT:
872     case TranslationOpcode::BOOL_STACK_SLOT:
873     case TranslationOpcode::FLOAT_STACK_SLOT:
874     case TranslationOpcode::DOUBLE_STACK_SLOT:
875     case TranslationOpcode::LITERAL:
876       break;
877   }
878   UNREACHABLE();
879 }
880 
881 // static
AdvanceIterator(std::deque<TranslatedValue>::iterator * iter)882 void TranslatedFrame::AdvanceIterator(
883     std::deque<TranslatedValue>::iterator* iter) {
884   int values_to_skip = 1;
885   while (values_to_skip > 0) {
886     // Consume the current element.
887     values_to_skip--;
888     // Add all the children.
889     values_to_skip += (*iter)->GetChildrenCount();
890 
891     (*iter)++;
892   }
893 }
894 
895 // Creates translated values for an arguments backing store, or the backing
896 // store for rest parameters depending on the given {type}. The TranslatedValue
897 // objects for the fields are not read from the TranslationArrayIterator, but
898 // instead created on-the-fly based on dynamic information in the optimized
899 // frame.
CreateArgumentsElementsTranslatedValues(int frame_index,Address input_frame_pointer,CreateArgumentsType type,FILE * trace_file)900 void TranslatedState::CreateArgumentsElementsTranslatedValues(
901     int frame_index, Address input_frame_pointer, CreateArgumentsType type,
902     FILE* trace_file) {
903   TranslatedFrame& frame = frames_[frame_index];
904   int length =
905       type == CreateArgumentsType::kRestParameter
906           ? std::max(0, actual_argument_count_ - formal_parameter_count_)
907           : actual_argument_count_;
908   int object_index = static_cast<int>(object_positions_.size());
909   int value_index = static_cast<int>(frame.values_.size());
910   if (trace_file != nullptr) {
911     PrintF(trace_file, "arguments elements object #%d (type = %d, length = %d)",
912            object_index, static_cast<uint8_t>(type), length);
913   }
914 
915   object_positions_.push_back({frame_index, value_index});
916   frame.Add(TranslatedValue::NewDeferredObject(
917       this, length + FixedArray::kHeaderSize / kTaggedSize, object_index));
918 
919   ReadOnlyRoots roots(isolate_);
920   frame.Add(TranslatedValue::NewTagged(this, roots.fixed_array_map()));
921   frame.Add(TranslatedValue::NewInt32(this, length));
922 
923   int number_of_holes = 0;
924   if (type == CreateArgumentsType::kMappedArguments) {
925     // If the actual number of arguments is less than the number of formal
926     // parameters, we have fewer holes to fill to not overshoot the length.
927     number_of_holes = std::min(formal_parameter_count_, length);
928   }
929   for (int i = 0; i < number_of_holes; ++i) {
930     frame.Add(TranslatedValue::NewTagged(this, roots.the_hole_value()));
931   }
932   int argc = length - number_of_holes;
933   int start_index = number_of_holes;
934   if (type == CreateArgumentsType::kRestParameter) {
935     start_index = std::max(0, formal_parameter_count_);
936   }
937   for (int i = 0; i < argc; i++) {
938     // Skip the receiver.
939     int offset = i + start_index + 1;
940     Address arguments_frame = offset > formal_parameter_count_
941                                   ? stack_frame_pointer_
942                                   : input_frame_pointer;
943     Address argument_slot = arguments_frame +
944                             CommonFrameConstants::kFixedFrameSizeAboveFp +
945                             offset * kSystemPointerSize;
946 
947     frame.Add(TranslatedValue::NewTagged(this, *FullObjectSlot(argument_slot)));
948   }
949 }
950 
951 // We can't intermix stack decoding and allocations because the deoptimization
952 // infrastracture is not GC safe.
953 // Thus we build a temporary structure in malloced space.
954 // The TranslatedValue objects created correspond to the static translation
955 // instructions from the TranslationArrayIterator, except for
956 // TranslationOpcode::ARGUMENTS_ELEMENTS, where the number and values of the
957 // FixedArray elements depend on dynamic information from the optimized frame.
958 // Returns the number of expected nested translations from the
959 // TranslationArrayIterator.
CreateNextTranslatedValue(int frame_index,TranslationArrayIterator * iterator,DeoptimizationLiteralArray literal_array,Address fp,RegisterValues * registers,FILE * trace_file)960 int TranslatedState::CreateNextTranslatedValue(
961     int frame_index, TranslationArrayIterator* iterator,
962     DeoptimizationLiteralArray literal_array, Address fp,
963     RegisterValues* registers, FILE* trace_file) {
964   disasm::NameConverter converter;
965 
966   TranslatedFrame& frame = frames_[frame_index];
967   int value_index = static_cast<int>(frame.values_.size());
968 
969   TranslationOpcode opcode = TranslationOpcodeFromInt(iterator->Next());
970   switch (opcode) {
971     case TranslationOpcode::BEGIN:
972     case TranslationOpcode::INTERPRETED_FRAME:
973     case TranslationOpcode::ARGUMENTS_ADAPTOR_FRAME:
974     case TranslationOpcode::CONSTRUCT_STUB_FRAME:
975     case TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME:
976     case TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME:
977     case TranslationOpcode::BUILTIN_CONTINUATION_FRAME:
978 #if V8_ENABLE_WEBASSEMBLY
979     case TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME:
980 #endif  // V8_ENABLE_WEBASSEMBLY
981     case TranslationOpcode::UPDATE_FEEDBACK:
982       // Peeled off before getting here.
983       break;
984 
985     case TranslationOpcode::DUPLICATED_OBJECT: {
986       int object_id = iterator->Next();
987       if (trace_file != nullptr) {
988         PrintF(trace_file, "duplicated object #%d", object_id);
989       }
990       object_positions_.push_back(object_positions_[object_id]);
991       TranslatedValue translated_value =
992           TranslatedValue::NewDuplicateObject(this, object_id);
993       frame.Add(translated_value);
994       return translated_value.GetChildrenCount();
995     }
996 
997     case TranslationOpcode::ARGUMENTS_ELEMENTS: {
998       CreateArgumentsType arguments_type =
999           static_cast<CreateArgumentsType>(iterator->Next());
1000       CreateArgumentsElementsTranslatedValues(frame_index, fp, arguments_type,
1001                                               trace_file);
1002       return 0;
1003     }
1004 
1005     case TranslationOpcode::ARGUMENTS_LENGTH: {
1006       if (trace_file != nullptr) {
1007         PrintF(trace_file, "arguments length field (length = %d)",
1008                actual_argument_count_);
1009       }
1010       frame.Add(TranslatedValue::NewInt32(this, actual_argument_count_));
1011       return 0;
1012     }
1013 
1014     case TranslationOpcode::CAPTURED_OBJECT: {
1015       int field_count = iterator->Next();
1016       int object_index = static_cast<int>(object_positions_.size());
1017       if (trace_file != nullptr) {
1018         PrintF(trace_file, "captured object #%d (length = %d)", object_index,
1019                field_count);
1020       }
1021       object_positions_.push_back({frame_index, value_index});
1022       TranslatedValue translated_value =
1023           TranslatedValue::NewDeferredObject(this, field_count, object_index);
1024       frame.Add(translated_value);
1025       return translated_value.GetChildrenCount();
1026     }
1027 
1028     case TranslationOpcode::REGISTER: {
1029       int input_reg = iterator->Next();
1030       if (registers == nullptr) {
1031         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1032         frame.Add(translated_value);
1033         return translated_value.GetChildrenCount();
1034       }
1035       intptr_t value = registers->GetRegister(input_reg);
1036       Address uncompressed_value = DecompressIfNeeded(value);
1037       if (trace_file != nullptr) {
1038         PrintF(trace_file, V8PRIxPTR_FMT " ; %s ", uncompressed_value,
1039                converter.NameOfCPURegister(input_reg));
1040         Object(uncompressed_value).ShortPrint(trace_file);
1041       }
1042       TranslatedValue translated_value =
1043           TranslatedValue::NewTagged(this, Object(uncompressed_value));
1044       frame.Add(translated_value);
1045       return translated_value.GetChildrenCount();
1046     }
1047 
1048     case TranslationOpcode::INT32_REGISTER: {
1049       int input_reg = iterator->Next();
1050       if (registers == nullptr) {
1051         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1052         frame.Add(translated_value);
1053         return translated_value.GetChildrenCount();
1054       }
1055       intptr_t value = registers->GetRegister(input_reg);
1056       if (trace_file != nullptr) {
1057         PrintF(trace_file, "%" V8PRIdPTR " ; %s (int32)", value,
1058                converter.NameOfCPURegister(input_reg));
1059       }
1060       TranslatedValue translated_value =
1061           TranslatedValue::NewInt32(this, static_cast<int32_t>(value));
1062       frame.Add(translated_value);
1063       return translated_value.GetChildrenCount();
1064     }
1065 
1066     case TranslationOpcode::INT64_REGISTER: {
1067       int input_reg = iterator->Next();
1068       if (registers == nullptr) {
1069         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1070         frame.Add(translated_value);
1071         return translated_value.GetChildrenCount();
1072       }
1073       intptr_t value = registers->GetRegister(input_reg);
1074       if (trace_file != nullptr) {
1075         PrintF(trace_file, "%" V8PRIdPTR " ; %s (int64)", value,
1076                converter.NameOfCPURegister(input_reg));
1077       }
1078       TranslatedValue translated_value =
1079           TranslatedValue::NewInt64(this, static_cast<int64_t>(value));
1080       frame.Add(translated_value);
1081       return translated_value.GetChildrenCount();
1082     }
1083 
1084     case TranslationOpcode::UINT32_REGISTER: {
1085       int input_reg = iterator->Next();
1086       if (registers == nullptr) {
1087         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1088         frame.Add(translated_value);
1089         return translated_value.GetChildrenCount();
1090       }
1091       intptr_t value = registers->GetRegister(input_reg);
1092       if (trace_file != nullptr) {
1093         PrintF(trace_file, "%" V8PRIuPTR " ; %s (uint32)", value,
1094                converter.NameOfCPURegister(input_reg));
1095       }
1096       TranslatedValue translated_value =
1097           TranslatedValue::NewUInt32(this, static_cast<uint32_t>(value));
1098       frame.Add(translated_value);
1099       return translated_value.GetChildrenCount();
1100     }
1101 
1102     case TranslationOpcode::BOOL_REGISTER: {
1103       int input_reg = iterator->Next();
1104       if (registers == nullptr) {
1105         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1106         frame.Add(translated_value);
1107         return translated_value.GetChildrenCount();
1108       }
1109       intptr_t value = registers->GetRegister(input_reg);
1110       if (trace_file != nullptr) {
1111         PrintF(trace_file, "%" V8PRIdPTR " ; %s (bool)", value,
1112                converter.NameOfCPURegister(input_reg));
1113       }
1114       TranslatedValue translated_value =
1115           TranslatedValue::NewBool(this, static_cast<uint32_t>(value));
1116       frame.Add(translated_value);
1117       return translated_value.GetChildrenCount();
1118     }
1119 
1120     case TranslationOpcode::FLOAT_REGISTER: {
1121       int input_reg = iterator->Next();
1122       if (registers == nullptr) {
1123         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1124         frame.Add(translated_value);
1125         return translated_value.GetChildrenCount();
1126       }
1127       Float32 value = registers->GetFloatRegister(input_reg);
1128       if (trace_file != nullptr) {
1129         PrintF(trace_file, "%e ; %s (float)", value.get_scalar(),
1130                RegisterName(FloatRegister::from_code(input_reg)));
1131       }
1132       TranslatedValue translated_value = TranslatedValue::NewFloat(this, value);
1133       frame.Add(translated_value);
1134       return translated_value.GetChildrenCount();
1135     }
1136 
1137     case TranslationOpcode::DOUBLE_REGISTER: {
1138       int input_reg = iterator->Next();
1139       if (registers == nullptr) {
1140         TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1141         frame.Add(translated_value);
1142         return translated_value.GetChildrenCount();
1143       }
1144       Float64 value = registers->GetDoubleRegister(input_reg);
1145       if (trace_file != nullptr) {
1146         PrintF(trace_file, "%e ; %s (double)", value.get_scalar(),
1147                RegisterName(DoubleRegister::from_code(input_reg)));
1148       }
1149       TranslatedValue translated_value =
1150           TranslatedValue::NewDouble(this, value);
1151       frame.Add(translated_value);
1152       return translated_value.GetChildrenCount();
1153     }
1154 
1155     case TranslationOpcode::STACK_SLOT: {
1156       int slot_offset =
1157           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1158       intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset));
1159       Address uncompressed_value = DecompressIfNeeded(value);
1160       if (trace_file != nullptr) {
1161         PrintF(trace_file, V8PRIxPTR_FMT " ;  [fp %c %3d]  ",
1162                uncompressed_value, slot_offset < 0 ? '-' : '+',
1163                std::abs(slot_offset));
1164         Object(uncompressed_value).ShortPrint(trace_file);
1165       }
1166       TranslatedValue translated_value =
1167           TranslatedValue::NewTagged(this, Object(uncompressed_value));
1168       frame.Add(translated_value);
1169       return translated_value.GetChildrenCount();
1170     }
1171 
1172     case TranslationOpcode::INT32_STACK_SLOT: {
1173       int slot_offset =
1174           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1175       uint32_t value = GetUInt32Slot(fp, slot_offset);
1176       if (trace_file != nullptr) {
1177         PrintF(trace_file, "%d ; (int32) [fp %c %3d] ",
1178                static_cast<int32_t>(value), slot_offset < 0 ? '-' : '+',
1179                std::abs(slot_offset));
1180       }
1181       TranslatedValue translated_value = TranslatedValue::NewInt32(this, value);
1182       frame.Add(translated_value);
1183       return translated_value.GetChildrenCount();
1184     }
1185 
1186     case TranslationOpcode::INT64_STACK_SLOT: {
1187       int slot_offset =
1188           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1189       uint64_t value = GetUInt64Slot(fp, slot_offset);
1190       if (trace_file != nullptr) {
1191         PrintF(trace_file, "%" V8PRIdPTR " ; (int64) [fp %c %3d] ",
1192                static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
1193                std::abs(slot_offset));
1194       }
1195       TranslatedValue translated_value = TranslatedValue::NewInt64(this, value);
1196       frame.Add(translated_value);
1197       return translated_value.GetChildrenCount();
1198     }
1199 
1200     case TranslationOpcode::UINT32_STACK_SLOT: {
1201       int slot_offset =
1202           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1203       uint32_t value = GetUInt32Slot(fp, slot_offset);
1204       if (trace_file != nullptr) {
1205         PrintF(trace_file, "%u ; (uint32) [fp %c %3d] ", value,
1206                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1207       }
1208       TranslatedValue translated_value =
1209           TranslatedValue::NewUInt32(this, value);
1210       frame.Add(translated_value);
1211       return translated_value.GetChildrenCount();
1212     }
1213 
1214     case TranslationOpcode::BOOL_STACK_SLOT: {
1215       int slot_offset =
1216           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1217       uint32_t value = GetUInt32Slot(fp, slot_offset);
1218       if (trace_file != nullptr) {
1219         PrintF(trace_file, "%u ; (bool) [fp %c %3d] ", value,
1220                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1221       }
1222       TranslatedValue translated_value = TranslatedValue::NewBool(this, value);
1223       frame.Add(translated_value);
1224       return translated_value.GetChildrenCount();
1225     }
1226 
1227     case TranslationOpcode::FLOAT_STACK_SLOT: {
1228       int slot_offset =
1229           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1230       Float32 value = GetFloatSlot(fp, slot_offset);
1231       if (trace_file != nullptr) {
1232         PrintF(trace_file, "%e ; (float) [fp %c %3d] ", value.get_scalar(),
1233                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1234       }
1235       TranslatedValue translated_value = TranslatedValue::NewFloat(this, value);
1236       frame.Add(translated_value);
1237       return translated_value.GetChildrenCount();
1238     }
1239 
1240     case TranslationOpcode::DOUBLE_STACK_SLOT: {
1241       int slot_offset =
1242           OptimizedFrame::StackSlotOffsetRelativeToFp(iterator->Next());
1243       Float64 value = GetDoubleSlot(fp, slot_offset);
1244       if (trace_file != nullptr) {
1245         PrintF(trace_file, "%e ; (double) [fp %c %d] ", value.get_scalar(),
1246                slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1247       }
1248       TranslatedValue translated_value =
1249           TranslatedValue::NewDouble(this, value);
1250       frame.Add(translated_value);
1251       return translated_value.GetChildrenCount();
1252     }
1253 
1254     case TranslationOpcode::LITERAL: {
1255       int literal_index = iterator->Next();
1256       Object value = literal_array.get(literal_index);
1257       if (trace_file != nullptr) {
1258         PrintF(trace_file, V8PRIxPTR_FMT " ; (literal %2d) ", value.ptr(),
1259                literal_index);
1260         value.ShortPrint(trace_file);
1261       }
1262 
1263       TranslatedValue translated_value =
1264           TranslatedValue::NewTagged(this, value);
1265       frame.Add(translated_value);
1266       return translated_value.GetChildrenCount();
1267     }
1268   }
1269 
1270   FATAL("We should never get here - unexpected deopt info.");
1271 }
1272 
DecompressIfNeeded(intptr_t value)1273 Address TranslatedState::DecompressIfNeeded(intptr_t value) {
1274   if (COMPRESS_POINTERS_BOOL) {
1275     return DecompressTaggedAny(isolate(), static_cast<uint32_t>(value));
1276   } else {
1277     return value;
1278   }
1279 }
1280 
TranslatedState(const JavaScriptFrame * frame)1281 TranslatedState::TranslatedState(const JavaScriptFrame* frame)
1282     : purpose_(kFrameInspection) {
1283   int deopt_index = SafepointEntry::kNoDeoptIndex;
1284   DeoptimizationData data =
1285       static_cast<const OptimizedFrame*>(frame)->GetDeoptimizationData(
1286           &deopt_index);
1287   DCHECK(!data.is_null() && deopt_index != SafepointEntry::kNoDeoptIndex);
1288   TranslationArrayIterator it(data.TranslationByteArray(),
1289                               data.TranslationIndex(deopt_index).value());
1290   int actual_argc = frame->GetActualArgumentCount();
1291   Init(frame->isolate(), frame->fp(), frame->fp(), &it, data.LiteralArray(),
1292        nullptr /* registers */, nullptr /* trace file */,
1293        frame->function()
1294            .shared()
1295            .internal_formal_parameter_count_without_receiver(),
1296        actual_argc);
1297 }
1298 
Init(Isolate * isolate,Address input_frame_pointer,Address stack_frame_pointer,TranslationArrayIterator * iterator,DeoptimizationLiteralArray literal_array,RegisterValues * registers,FILE * trace_file,int formal_parameter_count,int actual_argument_count)1299 void TranslatedState::Init(Isolate* isolate, Address input_frame_pointer,
1300                            Address stack_frame_pointer,
1301                            TranslationArrayIterator* iterator,
1302                            DeoptimizationLiteralArray literal_array,
1303                            RegisterValues* registers, FILE* trace_file,
1304                            int formal_parameter_count,
1305                            int actual_argument_count) {
1306   DCHECK(frames_.empty());
1307 
1308   stack_frame_pointer_ = stack_frame_pointer;
1309   formal_parameter_count_ = formal_parameter_count;
1310   actual_argument_count_ = actual_argument_count;
1311   isolate_ = isolate;
1312 
1313   // Read out the 'header' translation.
1314   TranslationOpcode opcode = TranslationOpcodeFromInt(iterator->Next());
1315   CHECK(opcode == TranslationOpcode::BEGIN);
1316 
1317   int count = iterator->Next();
1318   frames_.reserve(count);
1319   iterator->Next();  // Drop JS frames count.
1320   int update_feedback_count = iterator->Next();
1321   CHECK_GE(update_feedback_count, 0);
1322   CHECK_LE(update_feedback_count, 1);
1323 
1324   if (update_feedback_count == 1) {
1325     ReadUpdateFeedback(iterator, literal_array, trace_file);
1326   }
1327 
1328   std::stack<int> nested_counts;
1329 
1330   // Read the frames
1331   for (int frame_index = 0; frame_index < count; frame_index++) {
1332     // Read the frame descriptor.
1333     frames_.push_back(CreateNextTranslatedFrame(
1334         iterator, literal_array, input_frame_pointer, trace_file));
1335     TranslatedFrame& frame = frames_.back();
1336 
1337     // Read the values.
1338     int values_to_process = frame.GetValueCount();
1339     while (values_to_process > 0 || !nested_counts.empty()) {
1340       if (trace_file != nullptr) {
1341         if (nested_counts.empty()) {
1342           // For top level values, print the value number.
1343           PrintF(trace_file,
1344                  "    %3i: ", frame.GetValueCount() - values_to_process);
1345         } else {
1346           // Take care of indenting for nested values.
1347           PrintF(trace_file, "         ");
1348           for (size_t j = 0; j < nested_counts.size(); j++) {
1349             PrintF(trace_file, "  ");
1350           }
1351         }
1352       }
1353 
1354       int nested_count =
1355           CreateNextTranslatedValue(frame_index, iterator, literal_array,
1356                                     input_frame_pointer, registers, trace_file);
1357 
1358       if (trace_file != nullptr) {
1359         PrintF(trace_file, "\n");
1360       }
1361 
1362       // Update the value count and resolve the nesting.
1363       values_to_process--;
1364       if (nested_count > 0) {
1365         nested_counts.push(values_to_process);
1366         values_to_process = nested_count;
1367       } else {
1368         while (values_to_process == 0 && !nested_counts.empty()) {
1369           values_to_process = nested_counts.top();
1370           nested_counts.pop();
1371         }
1372       }
1373     }
1374   }
1375 
1376   CHECK(!iterator->HasNext() ||
1377         TranslationOpcodeFromInt(iterator->Next()) == TranslationOpcode::BEGIN);
1378 }
1379 
Prepare(Address stack_frame_pointer)1380 void TranslatedState::Prepare(Address stack_frame_pointer) {
1381   for (auto& frame : frames_) frame.Handlify();
1382 
1383   if (!feedback_vector_.is_null()) {
1384     feedback_vector_handle_ =
1385         Handle<FeedbackVector>(feedback_vector_, isolate());
1386     feedback_vector_ = FeedbackVector();
1387   }
1388   stack_frame_pointer_ = stack_frame_pointer;
1389 
1390   UpdateFromPreviouslyMaterializedObjects();
1391 }
1392 
GetValueByObjectIndex(int object_index)1393 TranslatedValue* TranslatedState::GetValueByObjectIndex(int object_index) {
1394   CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
1395   TranslatedState::ObjectPosition pos = object_positions_[object_index];
1396   return &(frames_[pos.frame_index_].values_[pos.value_index_]);
1397 }
1398 
InitializeObjectAt(TranslatedValue * slot)1399 Handle<HeapObject> TranslatedState::InitializeObjectAt(TranslatedValue* slot) {
1400   DisallowGarbageCollection no_gc;
1401 
1402   slot = ResolveCapturedObject(slot);
1403   if (slot->materialization_state() != TranslatedValue::kFinished) {
1404     std::stack<int> worklist;
1405     worklist.push(slot->object_index());
1406     slot->mark_finished();
1407 
1408     while (!worklist.empty()) {
1409       int index = worklist.top();
1410       worklist.pop();
1411       InitializeCapturedObjectAt(index, &worklist, no_gc);
1412     }
1413   }
1414   return slot->storage();
1415 }
1416 
InitializeCapturedObjectAt(int object_index,std::stack<int> * worklist,const DisallowGarbageCollection & no_gc)1417 void TranslatedState::InitializeCapturedObjectAt(
1418     int object_index, std::stack<int>* worklist,
1419     const DisallowGarbageCollection& no_gc) {
1420   CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
1421   TranslatedState::ObjectPosition pos = object_positions_[object_index];
1422   int value_index = pos.value_index_;
1423 
1424   TranslatedFrame* frame = &(frames_[pos.frame_index_]);
1425   TranslatedValue* slot = &(frame->values_[value_index]);
1426   value_index++;
1427 
1428   CHECK_EQ(TranslatedValue::kFinished, slot->materialization_state());
1429   CHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
1430 
1431   // Ensure all fields are initialized.
1432   int children_init_index = value_index;
1433   for (int i = 0; i < slot->GetChildrenCount(); i++) {
1434     // If the field is an object that has not been initialized yet, queue it
1435     // for initialization (and mark it as such).
1436     TranslatedValue* child_slot = frame->ValueAt(children_init_index);
1437     if (child_slot->kind() == TranslatedValue::kCapturedObject ||
1438         child_slot->kind() == TranslatedValue::kDuplicatedObject) {
1439       child_slot = ResolveCapturedObject(child_slot);
1440       if (child_slot->materialization_state() != TranslatedValue::kFinished) {
1441         DCHECK_EQ(TranslatedValue::kAllocated,
1442                   child_slot->materialization_state());
1443         worklist->push(child_slot->object_index());
1444         child_slot->mark_finished();
1445       }
1446     }
1447     SkipSlots(1, frame, &children_init_index);
1448   }
1449 
1450   // Read the map.
1451   // The map should never be materialized, so let us check we already have
1452   // an existing object here.
1453   CHECK_EQ(frame->values_[value_index].kind(), TranslatedValue::kTagged);
1454   Handle<Map> map = Handle<Map>::cast(frame->values_[value_index].GetValue());
1455   CHECK(map->IsMap());
1456   value_index++;
1457 
1458   // Handle the special cases.
1459   switch (map->instance_type()) {
1460     case HEAP_NUMBER_TYPE:
1461     case FIXED_DOUBLE_ARRAY_TYPE:
1462       return;
1463 
1464     case FIXED_ARRAY_TYPE:
1465     case AWAIT_CONTEXT_TYPE:
1466     case BLOCK_CONTEXT_TYPE:
1467     case CATCH_CONTEXT_TYPE:
1468     case DEBUG_EVALUATE_CONTEXT_TYPE:
1469     case EVAL_CONTEXT_TYPE:
1470     case FUNCTION_CONTEXT_TYPE:
1471     case MODULE_CONTEXT_TYPE:
1472     case NATIVE_CONTEXT_TYPE:
1473     case SCRIPT_CONTEXT_TYPE:
1474     case WITH_CONTEXT_TYPE:
1475     case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
1476     case HASH_TABLE_TYPE:
1477     case ORDERED_HASH_MAP_TYPE:
1478     case ORDERED_HASH_SET_TYPE:
1479     case NAME_DICTIONARY_TYPE:
1480     case GLOBAL_DICTIONARY_TYPE:
1481     case NUMBER_DICTIONARY_TYPE:
1482     case SIMPLE_NUMBER_DICTIONARY_TYPE:
1483     case PROPERTY_ARRAY_TYPE:
1484     case SCRIPT_CONTEXT_TABLE_TYPE:
1485     case SLOPPY_ARGUMENTS_ELEMENTS_TYPE:
1486       InitializeObjectWithTaggedFieldsAt(frame, &value_index, slot, map, no_gc);
1487       break;
1488 
1489     default:
1490       CHECK(map->IsJSObjectMap());
1491       InitializeJSObjectAt(frame, &value_index, slot, map, no_gc);
1492       break;
1493   }
1494   CHECK_EQ(value_index, children_init_index);
1495 }
1496 
EnsureObjectAllocatedAt(TranslatedValue * slot)1497 void TranslatedState::EnsureObjectAllocatedAt(TranslatedValue* slot) {
1498   slot = ResolveCapturedObject(slot);
1499 
1500   if (slot->materialization_state() == TranslatedValue::kUninitialized) {
1501     std::stack<int> worklist;
1502     worklist.push(slot->object_index());
1503     slot->mark_allocated();
1504 
1505     while (!worklist.empty()) {
1506       int index = worklist.top();
1507       worklist.pop();
1508       EnsureCapturedObjectAllocatedAt(index, &worklist);
1509     }
1510   }
1511 }
1512 
GetSmiValue() const1513 int TranslatedValue::GetSmiValue() const {
1514   Object value = GetRawValue();
1515   CHECK(value.IsSmi());
1516   return Smi::cast(value).value();
1517 }
1518 
MaterializeFixedDoubleArray(TranslatedFrame * frame,int * value_index,TranslatedValue * slot,Handle<Map> map)1519 void TranslatedState::MaterializeFixedDoubleArray(TranslatedFrame* frame,
1520                                                   int* value_index,
1521                                                   TranslatedValue* slot,
1522                                                   Handle<Map> map) {
1523   int length = frame->values_[*value_index].GetSmiValue();
1524   (*value_index)++;
1525   Handle<FixedDoubleArray> array = Handle<FixedDoubleArray>::cast(
1526       isolate()->factory()->NewFixedDoubleArray(length));
1527   CHECK_GT(length, 0);
1528   for (int i = 0; i < length; i++) {
1529     CHECK_NE(TranslatedValue::kCapturedObject,
1530              frame->values_[*value_index].kind());
1531     Handle<Object> value = frame->values_[*value_index].GetValue();
1532     if (value->IsNumber()) {
1533       array->set(i, value->Number());
1534     } else {
1535       CHECK(value.is_identical_to(isolate()->factory()->the_hole_value()));
1536       array->set_the_hole(isolate(), i);
1537     }
1538     (*value_index)++;
1539   }
1540   slot->set_storage(array);
1541 }
1542 
MaterializeHeapNumber(TranslatedFrame * frame,int * value_index,TranslatedValue * slot)1543 void TranslatedState::MaterializeHeapNumber(TranslatedFrame* frame,
1544                                             int* value_index,
1545                                             TranslatedValue* slot) {
1546   CHECK_NE(TranslatedValue::kCapturedObject,
1547            frame->values_[*value_index].kind());
1548   Handle<Object> value = frame->values_[*value_index].GetValue();
1549   CHECK(value->IsNumber());
1550   Handle<HeapNumber> box = isolate()->factory()->NewHeapNumber(value->Number());
1551   (*value_index)++;
1552   slot->set_storage(box);
1553 }
1554 
1555 namespace {
1556 
1557 enum StorageKind : uint8_t {
1558   kStoreTagged,
1559   kStoreHeapObject
1560 };
1561 
1562 }  // namespace
1563 
SkipSlots(int slots_to_skip,TranslatedFrame * frame,int * value_index)1564 void TranslatedState::SkipSlots(int slots_to_skip, TranslatedFrame* frame,
1565                                 int* value_index) {
1566   while (slots_to_skip > 0) {
1567     TranslatedValue* slot = &(frame->values_[*value_index]);
1568     (*value_index)++;
1569     slots_to_skip--;
1570 
1571     if (slot->kind() == TranslatedValue::kCapturedObject) {
1572       slots_to_skip += slot->GetChildrenCount();
1573     }
1574   }
1575 }
1576 
EnsureCapturedObjectAllocatedAt(int object_index,std::stack<int> * worklist)1577 void TranslatedState::EnsureCapturedObjectAllocatedAt(
1578     int object_index, std::stack<int>* worklist) {
1579   CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
1580   TranslatedState::ObjectPosition pos = object_positions_[object_index];
1581   int value_index = pos.value_index_;
1582 
1583   TranslatedFrame* frame = &(frames_[pos.frame_index_]);
1584   TranslatedValue* slot = &(frame->values_[value_index]);
1585   value_index++;
1586 
1587   CHECK_EQ(TranslatedValue::kAllocated, slot->materialization_state());
1588   CHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
1589 
1590   // Read the map.
1591   // The map should never be materialized, so let us check we already have
1592   // an existing object here.
1593   CHECK_EQ(frame->values_[value_index].kind(), TranslatedValue::kTagged);
1594   Handle<Map> map = Handle<Map>::cast(frame->values_[value_index].GetValue());
1595   CHECK(map->IsMap());
1596   value_index++;
1597 
1598   // Handle the special cases.
1599   switch (map->instance_type()) {
1600     case FIXED_DOUBLE_ARRAY_TYPE:
1601       // Materialize (i.e. allocate&initialize) the array and return since
1602       // there is no need to process the children.
1603       return MaterializeFixedDoubleArray(frame, &value_index, slot, map);
1604 
1605     case HEAP_NUMBER_TYPE:
1606       // Materialize (i.e. allocate&initialize) the heap number and return.
1607       // There is no need to process the children.
1608       return MaterializeHeapNumber(frame, &value_index, slot);
1609 
1610     case FIXED_ARRAY_TYPE:
1611     case SCRIPT_CONTEXT_TABLE_TYPE:
1612     case AWAIT_CONTEXT_TYPE:
1613     case BLOCK_CONTEXT_TYPE:
1614     case CATCH_CONTEXT_TYPE:
1615     case DEBUG_EVALUATE_CONTEXT_TYPE:
1616     case EVAL_CONTEXT_TYPE:
1617     case FUNCTION_CONTEXT_TYPE:
1618     case MODULE_CONTEXT_TYPE:
1619     case NATIVE_CONTEXT_TYPE:
1620     case SCRIPT_CONTEXT_TYPE:
1621     case WITH_CONTEXT_TYPE:
1622     case HASH_TABLE_TYPE:
1623     case ORDERED_HASH_MAP_TYPE:
1624     case ORDERED_HASH_SET_TYPE:
1625     case NAME_DICTIONARY_TYPE:
1626     case GLOBAL_DICTIONARY_TYPE:
1627     case NUMBER_DICTIONARY_TYPE:
1628     case SIMPLE_NUMBER_DICTIONARY_TYPE: {
1629       // Check we have the right size.
1630       int array_length = frame->values_[value_index].GetSmiValue();
1631       int instance_size = FixedArray::SizeFor(array_length);
1632       CHECK_EQ(instance_size, slot->GetChildrenCount() * kTaggedSize);
1633 
1634       // Canonicalize empty fixed array.
1635       if (*map == ReadOnlyRoots(isolate()).empty_fixed_array().map() &&
1636           array_length == 0) {
1637         slot->set_storage(isolate()->factory()->empty_fixed_array());
1638       } else {
1639         slot->set_storage(AllocateStorageFor(slot));
1640       }
1641 
1642       // Make sure all the remaining children (after the map) are allocated.
1643       return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
1644                                      &value_index, worklist);
1645     }
1646 
1647     case SLOPPY_ARGUMENTS_ELEMENTS_TYPE: {
1648       // Verify that the arguments size is correct.
1649       int args_length = frame->values_[value_index].GetSmiValue();
1650       int args_size = SloppyArgumentsElements::SizeFor(args_length);
1651       CHECK_EQ(args_size, slot->GetChildrenCount() * kTaggedSize);
1652 
1653       slot->set_storage(AllocateStorageFor(slot));
1654 
1655       // Make sure all the remaining children (after the map) are allocated.
1656       return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
1657                                      &value_index, worklist);
1658     }
1659 
1660     case PROPERTY_ARRAY_TYPE: {
1661       // Check we have the right size.
1662       int length_or_hash = frame->values_[value_index].GetSmiValue();
1663       int array_length = PropertyArray::LengthField::decode(length_or_hash);
1664       int instance_size = PropertyArray::SizeFor(array_length);
1665       CHECK_EQ(instance_size, slot->GetChildrenCount() * kTaggedSize);
1666 
1667       slot->set_storage(AllocateStorageFor(slot));
1668 
1669       // Make sure all the remaining children (after the map) are allocated.
1670       return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
1671                                      &value_index, worklist);
1672     }
1673 
1674     default:
1675       EnsureJSObjectAllocated(slot, map);
1676       int remaining_children_count = slot->GetChildrenCount() - 1;
1677 
1678       TranslatedValue* properties_slot = frame->ValueAt(value_index);
1679       value_index++, remaining_children_count--;
1680       if (properties_slot->kind() == TranslatedValue::kCapturedObject) {
1681         // We are materializing the property array, so make sure we put the
1682         // mutable heap numbers at the right places.
1683         EnsurePropertiesAllocatedAndMarked(properties_slot, map);
1684         EnsureChildrenAllocated(properties_slot->GetChildrenCount(), frame,
1685                                 &value_index, worklist);
1686       } else {
1687         CHECK_EQ(properties_slot->kind(), TranslatedValue::kTagged);
1688       }
1689 
1690       TranslatedValue* elements_slot = frame->ValueAt(value_index);
1691       value_index++, remaining_children_count--;
1692       if (elements_slot->kind() == TranslatedValue::kCapturedObject ||
1693           !map->IsJSArrayMap()) {
1694         // Handle this case with the other remaining children below.
1695         value_index--, remaining_children_count++;
1696       } else {
1697         CHECK_EQ(elements_slot->kind(), TranslatedValue::kTagged);
1698         elements_slot->GetValue();
1699         if (purpose_ == kFrameInspection) {
1700           // We are materializing a JSArray for the purpose of frame inspection.
1701           // If we were to construct it with the above elements value then an
1702           // actual deopt later on might create another JSArray instance with
1703           // the same elements store. That would violate the key assumption
1704           // behind left-trimming.
1705           elements_slot->ReplaceElementsArrayWithCopy();
1706         }
1707       }
1708 
1709       // Make sure all the remaining children (after the map, properties store,
1710       // and possibly elements store) are allocated.
1711       return EnsureChildrenAllocated(remaining_children_count, frame,
1712                                      &value_index, worklist);
1713   }
1714   UNREACHABLE();
1715 }
1716 
ReplaceElementsArrayWithCopy()1717 void TranslatedValue::ReplaceElementsArrayWithCopy() {
1718   DCHECK_EQ(kind(), TranslatedValue::kTagged);
1719   DCHECK_EQ(materialization_state(), TranslatedValue::kFinished);
1720   auto elements = Handle<FixedArrayBase>::cast(GetValue());
1721   DCHECK(elements->IsFixedArray() || elements->IsFixedDoubleArray());
1722   if (elements->IsFixedDoubleArray()) {
1723     DCHECK(!elements->IsCowArray());
1724     set_storage(isolate()->factory()->CopyFixedDoubleArray(
1725         Handle<FixedDoubleArray>::cast(elements)));
1726   } else if (!elements->IsCowArray()) {
1727     set_storage(isolate()->factory()->CopyFixedArray(
1728         Handle<FixedArray>::cast(elements)));
1729   }
1730 }
1731 
EnsureChildrenAllocated(int count,TranslatedFrame * frame,int * value_index,std::stack<int> * worklist)1732 void TranslatedState::EnsureChildrenAllocated(int count, TranslatedFrame* frame,
1733                                               int* value_index,
1734                                               std::stack<int>* worklist) {
1735   // Ensure all children are allocated.
1736   for (int i = 0; i < count; i++) {
1737     // If the field is an object that has not been allocated yet, queue it
1738     // for initialization (and mark it as such).
1739     TranslatedValue* child_slot = frame->ValueAt(*value_index);
1740     if (child_slot->kind() == TranslatedValue::kCapturedObject ||
1741         child_slot->kind() == TranslatedValue::kDuplicatedObject) {
1742       child_slot = ResolveCapturedObject(child_slot);
1743       if (child_slot->materialization_state() ==
1744           TranslatedValue::kUninitialized) {
1745         worklist->push(child_slot->object_index());
1746         child_slot->mark_allocated();
1747       }
1748     } else {
1749       // Make sure the simple values (heap numbers, etc.) are properly
1750       // initialized.
1751       child_slot->GetValue();
1752     }
1753     SkipSlots(1, frame, value_index);
1754   }
1755 }
1756 
EnsurePropertiesAllocatedAndMarked(TranslatedValue * properties_slot,Handle<Map> map)1757 void TranslatedState::EnsurePropertiesAllocatedAndMarked(
1758     TranslatedValue* properties_slot, Handle<Map> map) {
1759   CHECK_EQ(TranslatedValue::kUninitialized,
1760            properties_slot->materialization_state());
1761 
1762   Handle<ByteArray> object_storage = AllocateStorageFor(properties_slot);
1763   properties_slot->mark_allocated();
1764   properties_slot->set_storage(object_storage);
1765 
1766   // Set markers for out-of-object properties.
1767   Handle<DescriptorArray> descriptors(map->instance_descriptors(isolate()),
1768                                       isolate());
1769   for (InternalIndex i : map->IterateOwnDescriptors()) {
1770     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
1771     Representation representation = descriptors->GetDetails(i).representation();
1772     if (!index.is_inobject() &&
1773         (representation.IsDouble() || representation.IsHeapObject())) {
1774       int outobject_index = index.outobject_array_index();
1775       int array_index = outobject_index * kTaggedSize;
1776       object_storage->set(array_index, kStoreHeapObject);
1777     }
1778   }
1779 }
1780 
AllocateStorageFor(TranslatedValue * slot)1781 Handle<ByteArray> TranslatedState::AllocateStorageFor(TranslatedValue* slot) {
1782   int allocate_size =
1783       ByteArray::LengthFor(slot->GetChildrenCount() * kTaggedSize);
1784   // It is important to allocate all the objects tenured so that the marker
1785   // does not visit them.
1786   Handle<ByteArray> object_storage =
1787       isolate()->factory()->NewByteArray(allocate_size, AllocationType::kOld);
1788   for (int i = 0; i < object_storage->length(); i++) {
1789     object_storage->set(i, kStoreTagged);
1790   }
1791   return object_storage;
1792 }
1793 
EnsureJSObjectAllocated(TranslatedValue * slot,Handle<Map> map)1794 void TranslatedState::EnsureJSObjectAllocated(TranslatedValue* slot,
1795                                               Handle<Map> map) {
1796   CHECK(map->IsJSObjectMap());
1797   CHECK_EQ(map->instance_size(), slot->GetChildrenCount() * kTaggedSize);
1798 
1799   Handle<ByteArray> object_storage = AllocateStorageFor(slot);
1800   // Now we handle the interesting (JSObject) case.
1801   Handle<DescriptorArray> descriptors(map->instance_descriptors(isolate()),
1802                                       isolate());
1803 
1804   // Set markers for in-object properties.
1805   for (InternalIndex i : map->IterateOwnDescriptors()) {
1806     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
1807     Representation representation = descriptors->GetDetails(i).representation();
1808     if (index.is_inobject() &&
1809         (representation.IsDouble() || representation.IsHeapObject())) {
1810       CHECK_GE(index.index(), FixedArray::kHeaderSize / kTaggedSize);
1811       int array_index = index.index() * kTaggedSize - FixedArray::kHeaderSize;
1812       object_storage->set(array_index, kStoreHeapObject);
1813     }
1814   }
1815   slot->set_storage(object_storage);
1816 }
1817 
GetResolvedSlot(TranslatedFrame * frame,int value_index)1818 TranslatedValue* TranslatedState::GetResolvedSlot(TranslatedFrame* frame,
1819                                                   int value_index) {
1820   TranslatedValue* slot = frame->ValueAt(value_index);
1821   if (slot->kind() == TranslatedValue::kDuplicatedObject) {
1822     slot = ResolveCapturedObject(slot);
1823   }
1824   CHECK_NE(slot->materialization_state(), TranslatedValue::kUninitialized);
1825   return slot;
1826 }
1827 
GetResolvedSlotAndAdvance(TranslatedFrame * frame,int * value_index)1828 TranslatedValue* TranslatedState::GetResolvedSlotAndAdvance(
1829     TranslatedFrame* frame, int* value_index) {
1830   TranslatedValue* slot = GetResolvedSlot(frame, *value_index);
1831   SkipSlots(1, frame, value_index);
1832   return slot;
1833 }
1834 
GetValueAndAdvance(TranslatedFrame * frame,int * value_index)1835 Handle<Object> TranslatedState::GetValueAndAdvance(TranslatedFrame* frame,
1836                                                    int* value_index) {
1837   TranslatedValue* slot = GetResolvedSlot(frame, *value_index);
1838   SkipSlots(1, frame, value_index);
1839   return slot->GetValue();
1840 }
1841 
InitializeJSObjectAt(TranslatedFrame * frame,int * value_index,TranslatedValue * slot,Handle<Map> map,const DisallowGarbageCollection & no_gc)1842 void TranslatedState::InitializeJSObjectAt(
1843     TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
1844     Handle<Map> map, const DisallowGarbageCollection& no_gc) {
1845   Handle<HeapObject> object_storage = Handle<HeapObject>::cast(slot->storage_);
1846   DCHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
1847   int children_count = slot->GetChildrenCount();
1848 
1849   // The object should have at least a map and some payload.
1850   CHECK_GE(children_count, 2);
1851 
1852   // Notify the concurrent marker about the layout change.
1853   isolate()->heap()->NotifyObjectLayoutChange(*object_storage, no_gc);
1854 
1855   // Fill the property array field.
1856   {
1857     Handle<Object> properties = GetValueAndAdvance(frame, value_index);
1858     WRITE_FIELD(*object_storage, JSObject::kPropertiesOrHashOffset,
1859                 *properties);
1860     WRITE_BARRIER(*object_storage, JSObject::kPropertiesOrHashOffset,
1861                   *properties);
1862   }
1863 
1864   // For all the other fields we first look at the fixed array and check the
1865   // marker to see if we store an unboxed double.
1866   DCHECK_EQ(kTaggedSize, JSObject::kPropertiesOrHashOffset);
1867   for (int i = 2; i < children_count; i++) {
1868     slot = GetResolvedSlotAndAdvance(frame, value_index);
1869     // Read out the marker and ensure the field is consistent with
1870     // what the markers in the storage say (note that all heap numbers
1871     // should be fully initialized by now).
1872     int offset = i * kTaggedSize;
1873     uint8_t marker = object_storage->ReadField<uint8_t>(offset);
1874     if (marker == kStoreHeapObject) {
1875       Handle<HeapObject> field_value = slot->storage();
1876       WRITE_FIELD(*object_storage, offset, *field_value);
1877       WRITE_BARRIER(*object_storage, offset, *field_value);
1878     } else {
1879       CHECK_EQ(kStoreTagged, marker);
1880       Handle<Object> field_value = slot->GetValue();
1881       DCHECK_IMPLIES(field_value->IsHeapNumber(),
1882                      !IsSmiDouble(field_value->Number()));
1883       WRITE_FIELD(*object_storage, offset, *field_value);
1884       WRITE_BARRIER(*object_storage, offset, *field_value);
1885     }
1886   }
1887   object_storage->set_map(*map, kReleaseStore);
1888 }
1889 
InitializeObjectWithTaggedFieldsAt(TranslatedFrame * frame,int * value_index,TranslatedValue * slot,Handle<Map> map,const DisallowGarbageCollection & no_gc)1890 void TranslatedState::InitializeObjectWithTaggedFieldsAt(
1891     TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
1892     Handle<Map> map, const DisallowGarbageCollection& no_gc) {
1893   Handle<HeapObject> object_storage = Handle<HeapObject>::cast(slot->storage_);
1894   int children_count = slot->GetChildrenCount();
1895 
1896   // Skip the writes if we already have the canonical empty fixed array.
1897   if (*object_storage == ReadOnlyRoots(isolate()).empty_fixed_array()) {
1898     CHECK_EQ(2, children_count);
1899     Handle<Object> length_value = GetValueAndAdvance(frame, value_index);
1900     CHECK_EQ(*length_value, Smi::FromInt(0));
1901     return;
1902   }
1903 
1904   // Notify the concurrent marker about the layout change.
1905   isolate()->heap()->NotifyObjectLayoutChange(*object_storage, no_gc);
1906 
1907   // Write the fields to the object.
1908   for (int i = 1; i < children_count; i++) {
1909     slot = GetResolvedSlotAndAdvance(frame, value_index);
1910     int offset = i * kTaggedSize;
1911     uint8_t marker = object_storage->ReadField<uint8_t>(offset);
1912     Handle<Object> field_value;
1913     if (i > 1 && marker == kStoreHeapObject) {
1914       field_value = slot->storage();
1915     } else {
1916       CHECK(marker == kStoreTagged || i == 1);
1917       field_value = slot->GetValue();
1918       DCHECK_IMPLIES(field_value->IsHeapNumber(),
1919                      !IsSmiDouble(field_value->Number()));
1920     }
1921     WRITE_FIELD(*object_storage, offset, *field_value);
1922     WRITE_BARRIER(*object_storage, offset, *field_value);
1923   }
1924 
1925   object_storage->set_map(*map, kReleaseStore);
1926 }
1927 
ResolveCapturedObject(TranslatedValue * slot)1928 TranslatedValue* TranslatedState::ResolveCapturedObject(TranslatedValue* slot) {
1929   while (slot->kind() == TranslatedValue::kDuplicatedObject) {
1930     slot = GetValueByObjectIndex(slot->object_index());
1931   }
1932   CHECK_EQ(TranslatedValue::kCapturedObject, slot->kind());
1933   return slot;
1934 }
1935 
GetFrameFromJSFrameIndex(int jsframe_index)1936 TranslatedFrame* TranslatedState::GetFrameFromJSFrameIndex(int jsframe_index) {
1937   for (size_t i = 0; i < frames_.size(); i++) {
1938     if (frames_[i].kind() == TranslatedFrame::kUnoptimizedFunction ||
1939         frames_[i].kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
1940         frames_[i].kind() ==
1941             TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
1942       if (jsframe_index > 0) {
1943         jsframe_index--;
1944       } else {
1945         return &(frames_[i]);
1946       }
1947     }
1948   }
1949   return nullptr;
1950 }
1951 
GetArgumentsInfoFromJSFrameIndex(int jsframe_index,int * args_count)1952 TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
1953     int jsframe_index, int* args_count) {
1954   for (size_t i = 0; i < frames_.size(); i++) {
1955     if (frames_[i].kind() == TranslatedFrame::kUnoptimizedFunction ||
1956         frames_[i].kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
1957         frames_[i].kind() ==
1958             TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
1959       if (jsframe_index > 0) {
1960         jsframe_index--;
1961       } else {
1962         // We have the JS function frame, now check if it has arguments
1963         // adaptor.
1964         if (i > 0 &&
1965             frames_[i - 1].kind() == TranslatedFrame::kArgumentsAdaptor) {
1966           *args_count = frames_[i - 1].height();
1967           return &(frames_[i - 1]);
1968         }
1969 
1970         // JavaScriptBuiltinContinuation frames that are not preceeded by
1971         // a arguments adapter frame are currently only used by C++ API calls
1972         // from TurboFan. Calls to C++ API functions from TurboFan need
1973         // a special marker frame state, otherwise the API call wouldn't
1974         // be shown in a stack trace.
1975         if (frames_[i].kind() ==
1976                 TranslatedFrame::kJavaScriptBuiltinContinuation &&
1977             frames_[i].shared_info()->IsDontAdaptArguments()) {
1978           DCHECK(frames_[i].shared_info()->IsApiFunction());
1979 
1980           // The argument count for this special case is always the second
1981           // to last value in the TranslatedFrame. It should also always be
1982           // {1}, as the GenericLazyDeoptContinuation builtin has one explicit
1983           // argument (the result).
1984           static constexpr int kTheContext = 1;
1985           const int height = frames_[i].height() + kTheContext;
1986           *args_count = frames_[i].ValueAt(height - 1)->GetSmiValue();
1987           DCHECK_EQ(*args_count, JSParameterCount(1));
1988         } else {
1989           *args_count = frames_[i]
1990                             .shared_info()
1991                             ->internal_formal_parameter_count_with_receiver();
1992         }
1993         return &(frames_[i]);
1994       }
1995     }
1996   }
1997   return nullptr;
1998 }
1999 
StoreMaterializedValuesAndDeopt(JavaScriptFrame * frame)2000 void TranslatedState::StoreMaterializedValuesAndDeopt(JavaScriptFrame* frame) {
2001   MaterializedObjectStore* materialized_store =
2002       isolate_->materialized_object_store();
2003   Handle<FixedArray> previously_materialized_objects =
2004       materialized_store->Get(stack_frame_pointer_);
2005 
2006   Handle<Object> marker = isolate_->factory()->arguments_marker();
2007 
2008   int length = static_cast<int>(object_positions_.size());
2009   bool new_store = false;
2010   if (previously_materialized_objects.is_null()) {
2011     previously_materialized_objects =
2012         isolate_->factory()->NewFixedArray(length, AllocationType::kOld);
2013     for (int i = 0; i < length; i++) {
2014       previously_materialized_objects->set(i, *marker);
2015     }
2016     new_store = true;
2017   }
2018 
2019   CHECK_EQ(length, previously_materialized_objects->length());
2020 
2021   bool value_changed = false;
2022   for (int i = 0; i < length; i++) {
2023     TranslatedState::ObjectPosition pos = object_positions_[i];
2024     TranslatedValue* value_info =
2025         &(frames_[pos.frame_index_].values_[pos.value_index_]);
2026 
2027     CHECK(value_info->IsMaterializedObject());
2028 
2029     // Skip duplicate objects (i.e., those that point to some other object id).
2030     if (value_info->object_index() != i) continue;
2031 
2032     Handle<Object> previous_value(previously_materialized_objects->get(i),
2033                                   isolate_);
2034     Handle<Object> value(value_info->GetRawValue(), isolate_);
2035 
2036     if (value.is_identical_to(marker)) {
2037       DCHECK_EQ(*previous_value, *marker);
2038     } else {
2039       if (*previous_value == *marker) {
2040         if (value->IsSmi()) {
2041           value = isolate()->factory()->NewHeapNumber(value->Number());
2042         }
2043         previously_materialized_objects->set(i, *value);
2044         value_changed = true;
2045       } else {
2046         CHECK(*previous_value == *value ||
2047               (previous_value->IsHeapNumber() && value->IsSmi() &&
2048                previous_value->Number() == value->Number()));
2049       }
2050     }
2051   }
2052 
2053   if (new_store && value_changed) {
2054     materialized_store->Set(stack_frame_pointer_,
2055                             previously_materialized_objects);
2056     CHECK_EQ(frames_[0].kind(), TranslatedFrame::kUnoptimizedFunction);
2057     CHECK_EQ(frame->function(), frames_[0].front().GetRawValue());
2058     Deoptimizer::DeoptimizeFunction(frame->function(), frame->LookupCode());
2059   }
2060 }
2061 
UpdateFromPreviouslyMaterializedObjects()2062 void TranslatedState::UpdateFromPreviouslyMaterializedObjects() {
2063   MaterializedObjectStore* materialized_store =
2064       isolate_->materialized_object_store();
2065   Handle<FixedArray> previously_materialized_objects =
2066       materialized_store->Get(stack_frame_pointer_);
2067 
2068   // If we have no previously materialized objects, there is nothing to do.
2069   if (previously_materialized_objects.is_null()) return;
2070 
2071   Handle<Object> marker = isolate_->factory()->arguments_marker();
2072 
2073   int length = static_cast<int>(object_positions_.size());
2074   CHECK_EQ(length, previously_materialized_objects->length());
2075 
2076   for (int i = 0; i < length; i++) {
2077     // For a previously materialized objects, inject their value into the
2078     // translated values.
2079     if (previously_materialized_objects->get(i) != *marker) {
2080       TranslatedState::ObjectPosition pos = object_positions_[i];
2081       TranslatedValue* value_info =
2082           &(frames_[pos.frame_index_].values_[pos.value_index_]);
2083       CHECK(value_info->IsMaterializedObject());
2084 
2085       if (value_info->kind() == TranslatedValue::kCapturedObject) {
2086         Handle<Object> object(previously_materialized_objects->get(i),
2087                               isolate_);
2088         CHECK(object->IsHeapObject());
2089         value_info->set_initialized_storage(Handle<HeapObject>::cast(object));
2090       }
2091     }
2092   }
2093 }
2094 
VerifyMaterializedObjects()2095 void TranslatedState::VerifyMaterializedObjects() {
2096 #if VERIFY_HEAP
2097   int length = static_cast<int>(object_positions_.size());
2098   for (int i = 0; i < length; i++) {
2099     TranslatedValue* slot = GetValueByObjectIndex(i);
2100     if (slot->kind() == TranslatedValue::kCapturedObject) {
2101       CHECK_EQ(slot, GetValueByObjectIndex(slot->object_index()));
2102       if (slot->materialization_state() == TranslatedValue::kFinished) {
2103         slot->storage()->ObjectVerify(isolate());
2104       } else {
2105         CHECK_EQ(slot->materialization_state(),
2106                  TranslatedValue::kUninitialized);
2107       }
2108     }
2109   }
2110 #endif
2111 }
2112 
DoUpdateFeedback()2113 bool TranslatedState::DoUpdateFeedback() {
2114   if (!feedback_vector_handle_.is_null()) {
2115     CHECK(!feedback_slot_.IsInvalid());
2116     isolate()->CountUsage(v8::Isolate::kDeoptimizerDisableSpeculation);
2117     FeedbackNexus nexus(feedback_vector_handle_, feedback_slot_);
2118     nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
2119     return true;
2120   }
2121   return false;
2122 }
2123 
ReadUpdateFeedback(TranslationArrayIterator * iterator,DeoptimizationLiteralArray literal_array,FILE * trace_file)2124 void TranslatedState::ReadUpdateFeedback(
2125     TranslationArrayIterator* iterator,
2126     DeoptimizationLiteralArray literal_array, FILE* trace_file) {
2127   CHECK_EQ(TranslationOpcode::UPDATE_FEEDBACK,
2128            TranslationOpcodeFromInt(iterator->Next()));
2129   feedback_vector_ = FeedbackVector::cast(literal_array.get(iterator->Next()));
2130   feedback_slot_ = FeedbackSlot(iterator->Next());
2131   if (trace_file != nullptr) {
2132     PrintF(trace_file, "  reading FeedbackVector (slot %d)\n",
2133            feedback_slot_.ToInt());
2134   }
2135 }
2136 
2137 }  // namespace internal
2138 }  // namespace v8
2139 
2140 // Undefine the heap manipulation macros.
2141 #include "src/objects/object-macros-undef.h"
2142