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