v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
translated-state.cc
Go to the documentation of this file.
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
6
7#include <inttypes.h>
8
9#include <iomanip>
10#include <optional>
11
12#include "src/base/memory.h"
20#include "src/heap/heap.h"
26#include "src/objects/oddball.h"
27
28// Has to be the last include (doesn't have include guards)
30#include "src/objects/string.h"
31
32namespace v8 {
33
34using base::Memory;
36
37namespace internal {
38
40 std::ostream& os, TranslationOpcode opcode,
42 Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
44 disasm::NameConverter converter;
45 switch (opcode) {
46 case TranslationOpcode::BEGIN_WITH_FEEDBACK:
47 case TranslationOpcode::BEGIN_WITHOUT_FEEDBACK:
48 case TranslationOpcode::MATCH_PREVIOUS_TRANSLATION: {
49 iterator.NextOperand(); // Skip the lookback distance.
50 int frame_count = iterator.NextOperand();
51 int jsframe_count = iterator.NextOperand();
52 os << "{frame count=" << frame_count
53 << ", js frame count=" << jsframe_count << "}";
54 break;
55 }
56
57 case TranslationOpcode::INTERPRETED_FRAME_WITH_RETURN:
58 case TranslationOpcode::INTERPRETED_FRAME_WITHOUT_RETURN: {
59 int bytecode_offset = iterator.NextOperand();
60 int shared_info_id = iterator.NextOperand();
61 int bytecode_array_id = iterator.NextOperand();
62 unsigned height = iterator.NextOperand();
63 int return_value_offset = 0;
64 int return_value_count = 0;
65 if (opcode == TranslationOpcode::INTERPRETED_FRAME_WITH_RETURN) {
67 return_value_offset = iterator.NextOperand();
68 return_value_count = iterator.NextOperand();
69 } else {
71 }
72 Tagged<Object> shared_info = literal_array->get(shared_info_id);
73 Tagged<Object> bytecode_array =
74 protected_literal_array->get(bytecode_array_id);
75 os << "{bytecode_offset=" << bytecode_offset << ", function="
76 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get()
77 << ", bytecode=" << Brief(bytecode_array) << ", height=" << height
78 << ", retval=@" << return_value_offset << "(#" << return_value_count
79 << ")}";
80 break;
81 }
82
83#if V8_ENABLE_WEBASSEMBLY
84 case TranslationOpcode::WASM_INLINED_INTO_JS_FRAME: {
86 int bailout_id = iterator.NextOperand();
87 int shared_info_id = iterator.NextOperand();
88 Tagged<Object> shared_info = literal_array->get(shared_info_id);
89 unsigned height = iterator.NextOperand();
90 os << "{bailout_id=" << bailout_id << ", function="
91 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get()
92 << ", height=" << height << "}";
93 break;
94 }
95#endif
96 case TranslationOpcode::CONSTRUCT_CREATE_STUB_FRAME: {
98 int shared_info_id = iterator.NextOperand();
99 Tagged<Object> shared_info = literal_array->get(shared_info_id);
100 unsigned height = iterator.NextOperand();
101 os << "{construct create stub, function="
102 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get()
103 << ", height=" << height << "}";
104 break;
105 }
106
107 case TranslationOpcode::CONSTRUCT_INVOKE_STUB_FRAME: {
109 int shared_info_id = iterator.NextOperand();
110 Tagged<Object> shared_info = literal_array->get(shared_info_id);
111 os << "{construct invoke stub, function="
112 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get() << "}";
113 break;
114 }
115
116 case TranslationOpcode::BUILTIN_CONTINUATION_FRAME:
117 case TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_FRAME:
118 case TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
120 int bailout_id = iterator.NextOperand();
121 int shared_info_id = iterator.NextOperand();
122 Tagged<Object> shared_info = literal_array->get(shared_info_id);
123 unsigned height = iterator.NextOperand();
124 os << "{bailout_id=" << bailout_id << ", function="
125 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get()
126 << ", height=" << height << "}";
127 break;
128 }
129
130#if V8_ENABLE_WEBASSEMBLY
131 case TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME: {
133 int bailout_id = iterator.NextOperand();
134 int shared_info_id = iterator.NextOperand();
135 Tagged<Object> shared_info = literal_array->get(shared_info_id);
136 unsigned height = iterator.NextOperand();
137 int wasm_return_type = iterator.NextOperand();
138 os << "{bailout_id=" << bailout_id << ", function="
139 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get()
140 << ", height=" << height << ", wasm_return_type=" << wasm_return_type
141 << "}";
142 break;
143 }
144
145 case v8::internal::TranslationOpcode::LIFTOFF_FRAME: {
147 int bailout_id = iterator.NextOperand();
148 unsigned height = iterator.NextOperand();
149 unsigned function_id = iterator.NextOperand();
150 os << "{bailout_id=" << bailout_id << ", height=" << height
151 << ", function_id=" << function_id << "}";
152 break;
153 }
154#endif // V8_ENABLE_WEBASSEMBLY
155
156 case TranslationOpcode::INLINED_EXTRA_ARGUMENTS: {
158 int shared_info_id = iterator.NextOperand();
159 Tagged<Object> shared_info = literal_array->get(shared_info_id);
160 unsigned height = iterator.NextOperand();
161 os << "{function="
162 << Cast<SharedFunctionInfo>(shared_info)->DebugNameCStr().get()
163 << ", height=" << height << "}";
164 break;
165 }
166
167 case TranslationOpcode::REGISTER: {
169 int reg_code = iterator.NextOperandUnsigned();
170 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
171 break;
172 }
173
174 case TranslationOpcode::INT32_REGISTER: {
176 int reg_code = iterator.NextOperandUnsigned();
177 os << "{input=" << converter.NameOfCPURegister(reg_code) << " (int32)}";
178 break;
179 }
180
181 case TranslationOpcode::INT64_REGISTER: {
183 int reg_code = iterator.NextOperandUnsigned();
184 os << "{input=" << converter.NameOfCPURegister(reg_code) << " (int64)}";
185 break;
186 }
187
188 case TranslationOpcode::SIGNED_BIGINT64_REGISTER: {
190 int reg_code = iterator.NextOperandUnsigned();
191 os << "{input=" << converter.NameOfCPURegister(reg_code)
192 << " (signed bigint64)}";
193 break;
194 }
195
196 case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER: {
198 int reg_code = iterator.NextOperandUnsigned();
199 os << "{input=" << converter.NameOfCPURegister(reg_code)
200 << " (unsigned bigint64)}";
201 break;
202 }
203
204 case TranslationOpcode::UINT32_REGISTER: {
206 int reg_code = iterator.NextOperandUnsigned();
207 os << "{input=" << converter.NameOfCPURegister(reg_code) << " (uint32)}";
208 break;
209 }
210
211 case TranslationOpcode::BOOL_REGISTER: {
213 int reg_code = iterator.NextOperandUnsigned();
214 os << "{input=" << converter.NameOfCPURegister(reg_code) << " (bool)}";
215 break;
216 }
217
218 case TranslationOpcode::FLOAT_REGISTER: {
220 int reg_code = iterator.NextOperandUnsigned();
221 os << "{input=" << FloatRegister::from_code(reg_code) << "}";
222 break;
223 }
224
225 case TranslationOpcode::DOUBLE_REGISTER: {
227 int reg_code = iterator.NextOperandUnsigned();
228 os << "{input=" << DoubleRegister::from_code(reg_code) << "}";
229 break;
230 }
231
232 case TranslationOpcode::HOLEY_DOUBLE_REGISTER: {
234 int reg_code = iterator.NextOperandUnsigned();
235 os << "{input=" << DoubleRegister::from_code(reg_code) << " (holey)}";
236 break;
237 }
238
239 case TranslationOpcode::SIMD128_REGISTER: {
241 int reg_code = iterator.NextOperandUnsigned();
242 os << "{input=" << Simd128Register::from_code(reg_code) << " (Simd128)}";
243 break;
244 }
245
246 case TranslationOpcode::TAGGED_STACK_SLOT: {
248 int input_slot_index = iterator.NextOperand();
249 os << "{input=" << input_slot_index << "}";
250 break;
251 }
252
253 case TranslationOpcode::INT32_STACK_SLOT: {
255 int input_slot_index = iterator.NextOperand();
256 os << "{input=" << input_slot_index << " (int32)}";
257 break;
258 }
259
260 case TranslationOpcode::INT64_STACK_SLOT: {
262 int input_slot_index = iterator.NextOperand();
263 os << "{input=" << input_slot_index << " (int64)}";
264 break;
265 }
266
267 case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT: {
269 int input_slot_index = iterator.NextOperand();
270 os << "{input=" << input_slot_index << " (signed bigint64)}";
271 break;
272 }
273
274 case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT: {
276 int input_slot_index = iterator.NextOperand();
277 os << "{input=" << input_slot_index << " (unsigned bigint64)}";
278 break;
279 }
280
281 case TranslationOpcode::UINT32_STACK_SLOT: {
283 int input_slot_index = iterator.NextOperand();
284 os << "{input=" << input_slot_index << " (uint32)}";
285 break;
286 }
287
288 case TranslationOpcode::BOOL_STACK_SLOT: {
290 int input_slot_index = iterator.NextOperand();
291 os << "{input=" << input_slot_index << " (bool)}";
292 break;
293 }
294
295 case TranslationOpcode::FLOAT_STACK_SLOT:
296 case TranslationOpcode::DOUBLE_STACK_SLOT:
297 case TranslationOpcode::SIMD128_STACK_SLOT: {
299 int input_slot_index = iterator.NextOperand();
300 os << "{input=" << input_slot_index << "}";
301 break;
302 }
303
304 case TranslationOpcode::HOLEY_DOUBLE_STACK_SLOT: {
306 int input_slot_index = iterator.NextOperand();
307 os << "{input=" << input_slot_index << " (holey)}";
308 break;
309 }
310
311 case TranslationOpcode::OPTIMIZED_OUT: {
313 os << "{optimized_out}}";
314 break;
315 }
316
317 case TranslationOpcode::LITERAL: {
319 int literal_index = iterator.NextOperand();
320 Tagged<Object> literal_value = literal_array->get(literal_index);
321 os << "{literal_id=" << literal_index << " (" << Brief(literal_value)
322 << ")}";
323 break;
324 }
325
326 case TranslationOpcode::DUPLICATED_OBJECT: {
328 int object_index = iterator.NextOperand();
329 os << "{object_index=" << object_index << "}";
330 break;
331 }
332
333 case TranslationOpcode::ARGUMENTS_ELEMENTS: {
335 CreateArgumentsType arguments_type =
336 static_cast<CreateArgumentsType>(iterator.NextOperand());
337 os << "{arguments_type=" << arguments_type << "}";
338 break;
339 }
340 case TranslationOpcode::ARGUMENTS_LENGTH: {
342 os << "{arguments_length}";
343 break;
344 }
345 case TranslationOpcode::REST_LENGTH: {
347 os << "{rest_length}";
348 break;
349 }
350
351 case TranslationOpcode::CAPTURED_OBJECT: {
353 int args_length = iterator.NextOperand();
354 os << "{length=" << args_length << "}";
355 break;
356 }
357
358 case TranslationOpcode::STRING_CONCAT: {
360 os << "{string_concat}";
361 break;
362 }
363
364 case TranslationOpcode::UPDATE_FEEDBACK: {
366 int literal_index = iterator.NextOperand();
367 FeedbackSlot slot(iterator.NextOperand());
368 os << "{feedback={vector_index=" << literal_index << ", slot=" << slot
369 << "}}";
370 break;
371 }
372 }
373 os << "\n";
374}
375
376// static
378 int length,
379 int object_index) {
380 TranslatedValue slot(container, kCapturedObject);
381 slot.materialization_info_ = {object_index, length};
382 return slot;
383}
384
385// static
387 int id) {
388 TranslatedValue slot(container, kDuplicatedObject);
389 slot.materialization_info_ = {id, -1};
390 return slot;
391}
392
393// static
395 int id) {
396 TranslatedValue slot(container, kCapturedStringConcat);
397 slot.materialization_info_ = {id, -1};
398 return slot;
399}
400
401// static
403 Float32 value) {
404 TranslatedValue slot(container, kFloat);
405 slot.float_value_ = value;
406 return slot;
407}
408
409// static
411 Float64 value) {
412 TranslatedValue slot(container, kDouble);
413 slot.double_value_ = value;
414 return slot;
415}
416
417// static
419 Float64 value) {
420 TranslatedValue slot(container, kHoleyDouble);
421 slot.double_value_ = value;
422 return slot;
423}
424
425// static
427 Simd128 value) {
428 TranslatedValue slot(container, kSimd128);
429 slot.simd128_value_ = value;
430 return slot;
431}
432
433// static
435 int32_t value) {
436 TranslatedValue slot(container, kInt32);
437 slot.int32_value_ = value;
438 return slot;
439}
440
441// static
443 int64_t value) {
444 TranslatedValue slot(container, kInt64);
445 slot.int64_value_ = value;
446 return slot;
447}
448
449// static
451 int64_t value) {
452 TranslatedValue slot(container, kInt64ToBigInt);
453 slot.int64_value_ = value;
454 return slot;
455}
456
457// static
459 uint64_t value) {
460 TranslatedValue slot(container, kUint64ToBigInt);
461 slot.uint64_value_ = value;
462 return slot;
463}
464
465// static
467 uint32_t value) {
468 TranslatedValue slot(container, kUint32);
469 slot.uint32_value_ = value;
470 return slot;
471}
472
474 uint64_t value) {
475 TranslatedValue slot(container, kUint64);
476 slot.uint64_value_ = value;
477 return slot;
478}
479
480// static
482 uint32_t value) {
483 TranslatedValue slot(container, kBoolBit);
484 slot.uint32_value_ = value;
485 return slot;
486}
487
488// static
491 TranslatedValue slot(container, kTagged);
492 slot.raw_literal_ = literal;
493 return slot;
494}
495
496// static
500
502
507
510 return int32_value_;
511}
512
514 DCHECK(kInt64 == kind() || kInt64ToBigInt == kind());
515 return int64_value_;
516}
517
520 return uint64_value_;
521}
522
524 DCHECK(kind() == kUint32 || kind() == kBoolBit);
525 return uint32_value_;
526}
527
532
537
542
547
553
555 // If we have a value, return it.
557 int smi;
558 if (IsHeapNumber(*storage_) &&
560 return Smi::FromInt(smi);
561 }
562 return *storage_;
563 }
564
565 // Otherwise, do a best effort to get the value without allocation.
566 switch (kind()) {
567 case kTagged: {
568 Tagged<Object> object = raw_literal();
569 if (IsSlicedString(object)) {
570 // If {object} is a sliced string of length smaller than
571 // SlicedString::kMinLength, then trim the underlying SeqString and
572 // return it. This assumes that such sliced strings are only built by
573 // the fast string builder optimization of Turbofan's
574 // StringBuilderOptimizer/EffectControlLinearizer.
576 if (string->length() < SlicedString::kMinLength) {
577 Tagged<String> backing_store = string->parent();
578 CHECK(IsSeqString(backing_store));
579
580 // Creating filler at the end of the backing store if needed.
581 int string_size =
582 IsSeqOneByteString(backing_store)
583 ? SeqOneByteString::SizeFor(backing_store->length())
584 : SeqTwoByteString::SizeFor(backing_store->length());
585 int needed_size = IsSeqOneByteString(backing_store)
586 ? SeqOneByteString::SizeFor(string->length())
587 : SeqTwoByteString::SizeFor(string->length());
588 if (needed_size < string_size) {
589 Address new_end = backing_store.address() + needed_size;
591 new_end, (string_size - needed_size));
592 }
593
594 // Updating backing store's length, effectively trimming it.
595 backing_store->set_length(string->length());
596
597 // Zeroing the padding bytes of {backing_store}.
599 Cast<SeqString>(backing_store)->GetDataAndPaddingSizes();
600 auto padding =
601 reinterpret_cast<char*>(backing_store.address() + sz.data_size);
602 for (int i = 0; i < sz.padding_size; ++i) {
603 padding[i] = 0;
604 }
605
606 // Overwriting {string} with a filler, so that we don't leave around a
607 // potentially-too-small SlicedString.
608 isolate()->heap()->CreateFillerObjectAt(string.address(),
609 sizeof(SlicedString));
610
611 return backing_store;
612 }
613 }
614 return object;
615 }
616
617 case kInt32: {
618 bool is_smi = Smi::IsValid(int32_value());
619 if (is_smi) {
620 return Smi::FromInt(int32_value());
621 }
622 break;
623 }
624
625 case kInt64: {
626 bool is_smi = (int64_value() >= static_cast<int64_t>(Smi::kMinValue) &&
627 int64_value() <= static_cast<int64_t>(Smi::kMaxValue));
628 if (is_smi) {
629 return Smi::FromIntptr(static_cast<intptr_t>(int64_value()));
630 }
631 break;
632 }
633
634 case kInt64ToBigInt:
635 // Return the arguments marker.
636 break;
637
638 case kUint32: {
639 bool is_smi = (uint32_value() <= static_cast<uintptr_t>(Smi::kMaxValue));
640 if (is_smi) {
641 return Smi::FromInt(static_cast<int32_t>(uint32_value()));
642 }
643 break;
644 }
645
646 case kBoolBit: {
647 if (uint32_value() == 0) {
648 return ReadOnlyRoots(isolate()).false_value();
649 } else {
650 CHECK_EQ(1U, uint32_value());
651 return ReadOnlyRoots(isolate()).true_value();
652 }
653 }
654
655 case kFloat: {
656 int smi;
657 if (DoubleToSmiInteger(float_value().get_scalar(), &smi)) {
658 return Smi::FromInt(smi);
659 }
660 break;
661 }
662
663 case kHoleyDouble:
664 if (double_value().is_hole_nan()) {
665 // Hole NaNs that made it to here represent the undefined value.
666 return ReadOnlyRoots(isolate()).undefined_value();
667 }
668 // If this is not the hole nan, then this is a normal double value, so
669 // fall through to that.
670 [[fallthrough]];
671
672 case kDouble: {
673 int smi;
674 if (DoubleToSmiInteger(double_value().get_scalar(), &smi)) {
675 return Smi::FromInt(smi);
676 }
677 break;
678 }
679
680 default:
681 break;
682 }
683
684 // If we could not get the value without allocation, return the arguments
685 // marker.
686 return ReadOnlyRoots(isolate()).arguments_marker();
687}
688
694
697 if (materialization_state() == kFinished) return value;
698
699 if (IsSmi(*value)) {
700 // Even though stored as a Smi, this number might instead be needed as a
701 // HeapNumber when materializing a JSObject with a field of HeapObject
702 // representation. Since we don't have this information available here, we
703 // just always allocate a HeapNumber and later extract the Smi again if we
704 // don't need a HeapObject.
706 isolate()->factory()->NewHeapNumber(Object::NumberValue(*value)));
707 return value;
708 }
709
710 if (*value != ReadOnlyRoots(isolate()).arguments_marker()) {
712 return storage_;
713 }
714
715 // Otherwise we have to materialize.
716
719 // We need to materialize the object (or possibly even object graphs).
720 // To make the object verifier happy, we materialize in two steps.
721
722 // 1. Allocate storage for reachable objects. This makes sure that for
723 // each object we have allocated space on heap. The space will be
724 // a byte array that will be later initialized, or a fully
725 // initialized object if it is safe to allocate one that will
726 // pass the verifier.
728
729 // 2. Initialize the objects. If we have allocated only byte arrays
730 // for some objects, we now overwrite the byte arrays with the
731 // correct object fields. Note that this phase does not allocate
732 // any new objects, so it does not trigger the object verifier.
733 return container_->InitializeObjectAt(this);
734 }
735
737 // We need to materialize the string concatenation.
738 return container_->ResolveStringConcat(this);
739 }
740
741 double number = 0;
742 Handle<HeapObject> heap_object;
743 switch (kind()) {
745 number = int32_value();
746 heap_object = isolate()->factory()->NewHeapNumber(number);
747 break;
749 number = int64_value();
750 heap_object = isolate()->factory()->NewHeapNumber(number);
751 break;
753 heap_object = BigInt::FromInt64(isolate(), int64_value());
754 break;
756 heap_object = BigInt::FromUint64(isolate(), uint64_value());
757 break;
759 number = uint32_value();
760 heap_object = isolate()->factory()->NewHeapNumber(number);
761 break;
763 number = float_value().get_scalar();
764 heap_object = isolate()->factory()->NewHeapNumber(number);
765 break;
767 // We shouldn't have hole values by now, so treat holey double as normal
768 // double.s
770 number = double_value().get_scalar();
771 heap_object = isolate()->factory()->NewHeapNumber(number);
772 break;
773 default:
774 UNREACHABLE();
775 }
778 set_initialized_storage(heap_object);
779 return storage_;
780}
781
783 switch (kind()) {
784 case kCapturedObject:
787 return true;
788 default:
789 return false;
790 }
791}
792
794 // At the moment, we only allow materialization of doubles.
795 return (kind() == kDouble || kind() == kHoleyDouble);
796}
797
799 if (kind() == kCapturedObject) {
800 return object_length();
801 } else if (kind() == kCapturedStringConcat) {
802 static constexpr int kLeft = 1, kRight = 1;
803 return kLeft + kRight;
804 } else {
805 return 0;
806 }
807}
808
809uint64_t TranslatedState::GetUInt64Slot(Address fp, int slot_offset) {
810#if V8_TARGET_ARCH_32_BIT
811 return ReadUnalignedValue<uint64_t>(fp + slot_offset);
812#else
813 return Memory<uint64_t>(fp + slot_offset);
814#endif
815}
816
817uint32_t TranslatedState::GetUInt32Slot(Address fp, int slot_offset) {
818 Address address = fp + slot_offset;
819#if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT
820 return Memory<uint32_t>(address + kIntSize);
821#else
822 return Memory<uint32_t>(address);
823#endif
824}
825
827#if !V8_TARGET_ARCH_S390X && !V8_TARGET_ARCH_PPC64
828 return Float32::FromBits(GetUInt32Slot(fp, slot_offset));
829#else
830 return Float32::FromBits(Memory<uint32_t>(fp + slot_offset));
831#endif
832}
833
835 return Float64::FromBits(GetUInt64Slot(fp, slot_offset));
836}
837
839 return base::ReadUnalignedValue<Simd128>(fp + slot_offset);
840}
841
849
851 BytecodeOffset bytecode_offset, Tagged<SharedFunctionInfo> shared_info,
852 Tagged<BytecodeArray> bytecode_array, uint32_t height,
853 int return_value_offset, int return_value_count) {
857 return frame;
858}
859
861 Tagged<SharedFunctionInfo> shared_info, uint32_t height,
862 uint32_t formal_parameter_count) {
865 return frame;
866}
867
872
877
879 BytecodeOffset bytecode_offset, Tagged<SharedFunctionInfo> shared_info,
880 uint32_t height) {
883 return frame;
884}
885
886#if V8_ENABLE_WEBASSEMBLY
887TranslatedFrame TranslatedFrame::WasmInlinedIntoJSFrame(
888 BytecodeOffset bytecode_offset, Tagged<SharedFunctionInfo> shared_info,
889 uint32_t height) {
890 TranslatedFrame frame(kWasmInlinedIntoJS, shared_info, {}, height);
892 return frame;
893}
894
895TranslatedFrame TranslatedFrame::JSToWasmBuiltinContinuationFrame(
896 BytecodeOffset bytecode_offset, Tagged<SharedFunctionInfo> shared_info,
897 uint32_t height, std::optional<wasm::ValueKind> return_kind) {
898 TranslatedFrame frame(kJSToWasmBuiltinContinuation, shared_info, {}, height);
899 frame.bytecode_offset_ = bytecode_offset;
900 frame.return_kind_ = return_kind;
901 return frame;
902}
903
904TranslatedFrame TranslatedFrame::LiftoffFrame(BytecodeOffset bytecode_offset,
905 uint32_t height,
906 uint32_t function_index) {
907 // WebAssembly functions do not have a SharedFunctionInfo on the stack.
908 // The deoptimizer has to recover the function-specific data based on the PC.
910 TranslatedFrame frame(kLiftoffFunction, shared_info, {}, height);
911 frame.bytecode_offset_ = bytecode_offset;
912 frame.wasm_function_index_ = function_index;
913 return frame;
914}
915#endif // V8_ENABLE_WEBASSEMBLY
916
925
934
936 // The function is added to all frame state descriptors in
937 // InstructionSelector::AddInputsToFrameStateDescriptor.
938 static constexpr int kTheFunction = 1;
939
940 switch (kind()) {
942 int parameter_count = raw_bytecode_array_->parameter_count();
943 static constexpr int kTheContext = 1;
944 static constexpr int kTheAccumulator = 1;
945 return height() + parameter_count + kTheContext + kTheFunction +
946 kTheAccumulator;
947 }
948
950 return height() + kTheFunction;
951
955#if V8_ENABLE_WEBASSEMBLY
956 case kJSToWasmBuiltinContinuation:
957#endif // V8_ENABLE_WEBASSEMBLY
960 static constexpr int kTheContext = 1;
961 return height() + kTheContext + kTheFunction;
962 }
963#if V8_ENABLE_WEBASSEMBLY
964 case kWasmInlinedIntoJS: {
965 static constexpr int kTheContext = 1;
966 return height() + kTheContext + kTheFunction;
967 }
968 case kLiftoffFunction: {
969 return height();
970 }
971#endif // V8_ENABLE_WEBASSEMBLY
972
973 case kInvalid:
974 UNREACHABLE();
975 }
976 UNREACHABLE();
977}
978
981 if (!raw_shared_info_.is_null()) {
983 }
984 if (!raw_bytecode_array_.is_null()) {
986 }
987 for (auto& value : values_) {
988 value.Handlify();
989 }
991}
992
996
998 std::vector<DeoptimizationLiteral> literals)
999 : literals_off_heap_(std::move(literals)) {}
1000
1002
1004 int literal_index) const {
1005 if (V8_LIKELY(!literals_on_heap_.is_null())) {
1006 return TranslatedValue::NewTagged(container,
1007 literals_on_heap_->get(literal_index));
1008 }
1009#if !V8_ENABLE_WEBASSEMBLY
1010 UNREACHABLE();
1011#else
1012 CHECK(v8_flags.wasm_deopt);
1013 CHECK_LT(literal_index, literals_off_heap_.size());
1014 const DeoptimizationLiteral& literal = literals_off_heap_[literal_index];
1015 switch (literal.kind()) {
1017 return TranslatedValue::NewInt32(container, literal.GetInt32());
1019 return TranslatedValue::NewInt64(container, literal.GetInt64());
1021 return TranslatedValue::NewFloat(container, literal.GetFloat32());
1023 return TranslatedValue::NewDouble(container, literal.GetFloat64());
1025 return TranslatedValue::NewTagged(container, literal.GetSmi());
1026 default:
1027 UNIMPLEMENTED();
1028 }
1029#endif
1030}
1031
1034 Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
1035 const DeoptimizationLiteralProvider& literal_array, Address fp,
1036 FILE* trace_file) {
1037 TranslationOpcode opcode = iterator->NextOpcode();
1038 switch (opcode) {
1039 case TranslationOpcode::INTERPRETED_FRAME_WITH_RETURN:
1040 case TranslationOpcode::INTERPRETED_FRAME_WITHOUT_RETURN: {
1041 BytecodeOffset bytecode_offset = BytecodeOffset(iterator->NextOperand());
1043 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1045 protected_literal_array->get(iterator->NextOperand()));
1046 uint32_t height = iterator->NextOperandUnsigned();
1047 int return_value_offset = 0;
1048 int return_value_count = 0;
1049 if (opcode == TranslationOpcode::INTERPRETED_FRAME_WITH_RETURN) {
1050 return_value_offset = iterator->NextOperand();
1051 return_value_count = iterator->NextOperand();
1052 }
1053 if (trace_file != nullptr) {
1054 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1055 PrintF(trace_file, " reading input frame %s", name.get());
1056 int arg_count = bytecode_array->parameter_count();
1057 PrintF(trace_file,
1058 " => bytecode_offset=%d, args=%d, height=%u, retval=%i(#%i); "
1059 "inputs:\n",
1060 bytecode_offset.ToInt(), arg_count, height, return_value_offset,
1061 return_value_count);
1062 }
1064 bytecode_offset, shared_info, bytecode_array, height,
1065 return_value_offset, return_value_count);
1066 }
1067
1068 case TranslationOpcode::INLINED_EXTRA_ARGUMENTS: {
1070 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1071 uint32_t height = iterator->NextOperandUnsigned();
1072 uint32_t parameter_count = iterator->NextOperandUnsigned();
1073 if (trace_file != nullptr) {
1074 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1075 PrintF(trace_file, " reading inlined arguments frame %s", name.get());
1076 PrintF(trace_file, " => height=%u, parameter_count=%u; inputs:\n",
1077 height, parameter_count);
1078 }
1079 return TranslatedFrame::InlinedExtraArguments(shared_info, height,
1081 }
1082
1083 case TranslationOpcode::CONSTRUCT_CREATE_STUB_FRAME: {
1085 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1086 uint32_t height = iterator->NextOperandUnsigned();
1087 if (trace_file != nullptr) {
1088 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1089 PrintF(trace_file,
1090 " reading construct create stub frame %s => height = %d; "
1091 "inputs:\n",
1092 name.get(), height);
1093 }
1094 return TranslatedFrame::ConstructCreateStubFrame(shared_info, height);
1095 }
1096
1097 case TranslationOpcode::CONSTRUCT_INVOKE_STUB_FRAME: {
1099 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1100 if (trace_file != nullptr) {
1101 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1102 PrintF(trace_file,
1103 " reading construct invoke stub frame %s, inputs:\n",
1104 name.get());
1105 }
1107 }
1108
1109 case TranslationOpcode::BUILTIN_CONTINUATION_FRAME: {
1110 BytecodeOffset bytecode_offset = BytecodeOffset(iterator->NextOperand());
1112 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1113 uint32_t height = iterator->NextOperandUnsigned();
1114 if (trace_file != nullptr) {
1115 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1116 PrintF(trace_file, " reading builtin continuation frame %s",
1117 name.get());
1118 PrintF(trace_file, " => bytecode_offset=%d, height=%u; inputs:\n",
1119 bytecode_offset.ToInt(), height);
1120 }
1121 return TranslatedFrame::BuiltinContinuationFrame(bytecode_offset,
1122 shared_info, height);
1123 }
1124
1125#if V8_ENABLE_WEBASSEMBLY
1126 case TranslationOpcode::WASM_INLINED_INTO_JS_FRAME: {
1127 BytecodeOffset bailout_id = BytecodeOffset(iterator->NextOperand());
1129 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1130 uint32_t height = iterator->NextOperandUnsigned();
1131 if (trace_file != nullptr) {
1132 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1133 PrintF(trace_file, " reading Wasm inlined into JS frame %s",
1134 name.get());
1135 PrintF(trace_file, " => bailout_id=%d, height=%u ; inputs:\n",
1136 bailout_id.ToInt(), height);
1137 }
1138 return TranslatedFrame::WasmInlinedIntoJSFrame(bailout_id, shared_info,
1139 height);
1140 }
1141
1142 case TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME: {
1143 BytecodeOffset bailout_id = BytecodeOffset(iterator->NextOperand());
1145 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1146 uint32_t height = iterator->NextOperandUnsigned();
1147 int return_kind_code = iterator->NextOperand();
1148 std::optional<wasm::ValueKind> return_kind;
1149 if (return_kind_code != kNoWasmReturnKind) {
1150 return_kind = static_cast<wasm::ValueKind>(return_kind_code);
1151 }
1152 if (trace_file != nullptr) {
1153 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1154 PrintF(trace_file, " reading JS to Wasm builtin continuation frame %s",
1155 name.get());
1156 PrintF(trace_file,
1157 " => bailout_id=%d, height=%u return_type=%d; inputs:\n",
1158 bailout_id.ToInt(), height,
1159 return_kind.has_value() ? return_kind.value() : -1);
1160 }
1161 return TranslatedFrame::JSToWasmBuiltinContinuationFrame(
1162 bailout_id, shared_info, height, return_kind);
1163 }
1164
1165 case TranslationOpcode::LIFTOFF_FRAME: {
1166 BytecodeOffset bailout_id = BytecodeOffset(iterator->NextOperand());
1167 uint32_t height = iterator->NextOperandUnsigned();
1168 uint32_t function_id = iterator->NextOperandUnsigned();
1169 if (trace_file != nullptr) {
1170 PrintF(trace_file, " reading input for liftoff frame");
1171 PrintF(trace_file,
1172 " => bailout_id=%d, height=%u, function_id=%u ; inputs:\n",
1173 bailout_id.ToInt(), height, function_id);
1174 }
1175 return TranslatedFrame::LiftoffFrame(bailout_id, height, function_id);
1176 }
1177#endif // V8_ENABLE_WEBASSEMBLY
1178
1179 case TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_FRAME: {
1180 BytecodeOffset bytecode_offset = BytecodeOffset(iterator->NextOperand());
1182 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1183 uint32_t height = iterator->NextOperandUnsigned();
1184 if (trace_file != nullptr) {
1185 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1186 PrintF(trace_file, " reading JavaScript builtin continuation frame %s",
1187 name.get());
1188 PrintF(trace_file, " => bytecode_offset=%d, height=%u; inputs:\n",
1189 bytecode_offset.ToInt(), height);
1190 }
1192 bytecode_offset, shared_info, height);
1193 }
1194
1195 case TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
1196 BytecodeOffset bytecode_offset = BytecodeOffset(iterator->NextOperand());
1198 literal_array.get_on_heap_literals()->get(iterator->NextOperand()));
1199 uint32_t height = iterator->NextOperandUnsigned();
1200 if (trace_file != nullptr) {
1201 std::unique_ptr<char[]> name = shared_info->DebugNameCStr();
1202 PrintF(trace_file,
1203 " reading JavaScript builtin continuation frame with catch %s",
1204 name.get());
1205 PrintF(trace_file, " => bytecode_offset=%d, height=%u; inputs:\n",
1206 bytecode_offset.ToInt(), height);
1207 }
1209 bytecode_offset, shared_info, height);
1210 }
1211 case TranslationOpcode::UPDATE_FEEDBACK:
1212 case TranslationOpcode::BEGIN_WITH_FEEDBACK:
1213 case TranslationOpcode::BEGIN_WITHOUT_FEEDBACK:
1214 case TranslationOpcode::DUPLICATED_OBJECT:
1215 case TranslationOpcode::ARGUMENTS_ELEMENTS:
1216 case TranslationOpcode::ARGUMENTS_LENGTH:
1217 case TranslationOpcode::REST_LENGTH:
1218 case TranslationOpcode::CAPTURED_OBJECT:
1219 case TranslationOpcode::STRING_CONCAT:
1220 case TranslationOpcode::REGISTER:
1221 case TranslationOpcode::INT32_REGISTER:
1222 case TranslationOpcode::INT64_REGISTER:
1223 case TranslationOpcode::SIGNED_BIGINT64_REGISTER:
1224 case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER:
1225 case TranslationOpcode::UINT32_REGISTER:
1226 case TranslationOpcode::BOOL_REGISTER:
1227 case TranslationOpcode::FLOAT_REGISTER:
1228 case TranslationOpcode::DOUBLE_REGISTER:
1229 case TranslationOpcode::HOLEY_DOUBLE_REGISTER:
1230 case TranslationOpcode::SIMD128_REGISTER:
1231 case TranslationOpcode::TAGGED_STACK_SLOT:
1232 case TranslationOpcode::INT32_STACK_SLOT:
1233 case TranslationOpcode::INT64_STACK_SLOT:
1234 case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT:
1235 case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT:
1236 case TranslationOpcode::UINT32_STACK_SLOT:
1237 case TranslationOpcode::BOOL_STACK_SLOT:
1238 case TranslationOpcode::FLOAT_STACK_SLOT:
1239 case TranslationOpcode::DOUBLE_STACK_SLOT:
1240 case TranslationOpcode::SIMD128_STACK_SLOT:
1241 case TranslationOpcode::HOLEY_DOUBLE_STACK_SLOT:
1242 case TranslationOpcode::LITERAL:
1243 case TranslationOpcode::OPTIMIZED_OUT:
1244 case TranslationOpcode::MATCH_PREVIOUS_TRANSLATION:
1245 break;
1246 }
1247 UNREACHABLE();
1248}
1249
1250// static
1252 std::deque<TranslatedValue>::iterator* iter) {
1253 int values_to_skip = 1;
1254 while (values_to_skip > 0) {
1255 // Consume the current element.
1256 values_to_skip--;
1257 // Add all the children.
1258 values_to_skip += (*iter)->GetChildrenCount();
1259
1260 (*iter)++;
1261 }
1262}
1263
1264// Creates translated values for an arguments backing store, or the backing
1265// store for rest parameters depending on the given {type}. The TranslatedValue
1266// objects for the fields are not read from the
1267// DeoptimizationFrameTranslation::Iterator, but instead created on-the-fly
1268// based on dynamic information in the optimized frame.
1270 int frame_index, Address input_frame_pointer, CreateArgumentsType type,
1271 FILE* trace_file) {
1272 TranslatedFrame& frame = frames_[frame_index];
1273 int length =
1277 int object_index = static_cast<int>(object_positions_.size());
1278 int value_index = static_cast<int>(frame.values_.size());
1279 if (trace_file != nullptr) {
1280 PrintF(trace_file, "arguments elements object #%d (type = %d, length = %d)",
1281 object_index, static_cast<uint8_t>(type), length);
1282 }
1283
1284 object_positions_.push_back({frame_index, value_index});
1287 object_index));
1288
1289 ReadOnlyRoots roots(isolate_);
1290 frame.Add(TranslatedValue::NewTagged(this, roots.fixed_array_map()));
1291 frame.Add(TranslatedValue::NewInt32(this, length));
1292
1293 int number_of_holes = 0;
1295 // If the actual number of arguments is less than the number of formal
1296 // parameters, we have fewer holes to fill to not overshoot the length.
1297 number_of_holes = std::min(formal_parameter_count_, length);
1298 }
1299 for (int i = 0; i < number_of_holes; ++i) {
1300 frame.Add(TranslatedValue::NewTagged(this, roots.the_hole_value()));
1301 }
1302 int argc = length - number_of_holes;
1303 int start_index = number_of_holes;
1305 start_index = std::max(0, formal_parameter_count_);
1306 }
1307 for (int i = 0; i < argc; i++) {
1308 // Skip the receiver.
1309 int offset = i + start_index + 1;
1310 Address arguments_frame = offset > formal_parameter_count_
1312 : input_frame_pointer;
1313 Address argument_slot = arguments_frame +
1316
1317 frame.Add(TranslatedValue::NewTagged(this, *FullObjectSlot(argument_slot)));
1318 }
1319}
1320
1321// We can't intermix stack decoding and allocations because the deoptimization
1322// infrastructure is not GC safe.
1323// Thus we build a temporary structure in malloced space.
1324// The TranslatedValue objects created correspond to the static translation
1325// instructions from the DeoptTranslationIterator, except for
1326// TranslationOpcode::ARGUMENTS_ELEMENTS, where the number and values of the
1327// FixedArray elements depend on dynamic information from the optimized frame.
1328// Returns the number of expected nested translations from the
1329// DeoptTranslationIterator.
1331 int frame_index, DeoptTranslationIterator* iterator,
1332 const DeoptimizationLiteralProvider& literal_array, Address fp,
1333 RegisterValues* registers, FILE* trace_file) {
1334 disasm::NameConverter converter;
1335
1336 TranslatedFrame& frame = frames_[frame_index];
1337 int value_index = static_cast<int>(frame.values_.size());
1338
1339 TranslationOpcode opcode = iterator->NextOpcode();
1340 switch (opcode) {
1341 case TranslationOpcode::BEGIN_WITH_FEEDBACK:
1342 case TranslationOpcode::BEGIN_WITHOUT_FEEDBACK:
1343 case TranslationOpcode::INTERPRETED_FRAME_WITH_RETURN:
1344 case TranslationOpcode::INTERPRETED_FRAME_WITHOUT_RETURN:
1345 case TranslationOpcode::INLINED_EXTRA_ARGUMENTS:
1346 case TranslationOpcode::CONSTRUCT_CREATE_STUB_FRAME:
1347 case TranslationOpcode::CONSTRUCT_INVOKE_STUB_FRAME:
1348 case TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_FRAME:
1349 case TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME:
1350 case TranslationOpcode::BUILTIN_CONTINUATION_FRAME:
1351#if V8_ENABLE_WEBASSEMBLY
1352 case TranslationOpcode::WASM_INLINED_INTO_JS_FRAME:
1353 case TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME:
1354 case TranslationOpcode::LIFTOFF_FRAME:
1355#endif // V8_ENABLE_WEBASSEMBLY
1356 case TranslationOpcode::UPDATE_FEEDBACK:
1357 case TranslationOpcode::MATCH_PREVIOUS_TRANSLATION:
1358 // Peeled off before getting here.
1359 break;
1360
1361 case TranslationOpcode::DUPLICATED_OBJECT: {
1362 int object_id = iterator->NextOperand();
1363 if (trace_file != nullptr) {
1364 PrintF(trace_file, "duplicated object #%d", object_id);
1365 }
1366 object_positions_.push_back(object_positions_[object_id]);
1367 TranslatedValue translated_value =
1368 TranslatedValue::NewDuplicateObject(this, object_id);
1369 frame.Add(translated_value);
1370 return translated_value.GetChildrenCount();
1371 }
1372
1373 case TranslationOpcode::ARGUMENTS_ELEMENTS: {
1374 CreateArgumentsType arguments_type =
1375 static_cast<CreateArgumentsType>(iterator->NextOperand());
1376 CreateArgumentsElementsTranslatedValues(frame_index, fp, arguments_type,
1377 trace_file);
1378 return 0;
1379 }
1380
1381 case TranslationOpcode::ARGUMENTS_LENGTH: {
1382 if (trace_file != nullptr) {
1383 PrintF(trace_file, "arguments length field (length = %d)",
1385 }
1387 return 0;
1388 }
1389
1390 case TranslationOpcode::REST_LENGTH: {
1391 int rest_length =
1393 if (trace_file != nullptr) {
1394 PrintF(trace_file, "rest length field (length = %d)", rest_length);
1395 }
1396 frame.Add(TranslatedValue::NewInt32(this, rest_length));
1397 return 0;
1398 }
1399
1400 case TranslationOpcode::CAPTURED_OBJECT: {
1401 int field_count = iterator->NextOperand();
1402 int object_index = static_cast<int>(object_positions_.size());
1403 if (trace_file != nullptr) {
1404 PrintF(trace_file, "captured object #%d (length = %d)", object_index,
1405 field_count);
1406 }
1407 object_positions_.push_back({frame_index, value_index});
1408 TranslatedValue translated_value =
1409 TranslatedValue::NewDeferredObject(this, field_count, object_index);
1410 frame.Add(translated_value);
1411 return translated_value.GetChildrenCount();
1412 }
1413
1414 case TranslationOpcode::STRING_CONCAT: {
1415 int object_index = static_cast<int>(object_positions_.size());
1416 if (trace_file != nullptr) {
1417 PrintF(trace_file, "string concatenation #%d", object_index);
1418 }
1419
1420 object_positions_.push_back({frame_index, value_index});
1421 TranslatedValue translated_value =
1422 TranslatedValue::NewStringConcat(this, object_index);
1423 frame.Add(translated_value);
1424 return translated_value.GetChildrenCount();
1425 }
1426
1427 case TranslationOpcode::REGISTER: {
1428 int input_reg = iterator->NextOperandUnsigned();
1429 if (registers == nullptr) {
1430 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1431 frame.Add(translated_value);
1432 return translated_value.GetChildrenCount();
1433 }
1434 intptr_t value = registers->GetRegister(input_reg);
1435 Address uncompressed_value = DecompressIfNeeded(value);
1436 if (trace_file != nullptr) {
1437 PrintF(trace_file, V8PRIxPTR_FMT " ; %s ", uncompressed_value,
1438 converter.NameOfCPURegister(input_reg));
1439 ShortPrint(Tagged<Object>(uncompressed_value), trace_file);
1440 }
1441 TranslatedValue translated_value =
1442 TranslatedValue::NewTagged(this, Tagged<Object>(uncompressed_value));
1443 frame.Add(translated_value);
1444 return translated_value.GetChildrenCount();
1445 }
1446
1447 case TranslationOpcode::INT32_REGISTER: {
1448 int input_reg = iterator->NextOperandUnsigned();
1449 if (registers == nullptr) {
1450 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1451 frame.Add(translated_value);
1452 return translated_value.GetChildrenCount();
1453 }
1454 intptr_t value = registers->GetRegister(input_reg);
1455 if (trace_file != nullptr) {
1456 PrintF(trace_file, "%" V8PRIdPTR " ; %s (int32)", value,
1457 converter.NameOfCPURegister(input_reg));
1458 }
1459 TranslatedValue translated_value =
1460 TranslatedValue::NewInt32(this, static_cast<int32_t>(value));
1461 frame.Add(translated_value);
1462 return translated_value.GetChildrenCount();
1463 }
1464
1465 case TranslationOpcode::INT64_REGISTER: {
1466 int input_reg = iterator->NextOperandUnsigned();
1467 if (registers == nullptr) {
1468 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1469 frame.Add(translated_value);
1470 return translated_value.GetChildrenCount();
1471 }
1472 intptr_t value = registers->GetRegister(input_reg);
1473 if (trace_file != nullptr) {
1474 PrintF(trace_file, "%" V8PRIdPTR " ; %s (int64)", value,
1475 converter.NameOfCPURegister(input_reg));
1476 }
1477 TranslatedValue translated_value =
1478 TranslatedValue::NewInt64(this, static_cast<int64_t>(value));
1479 frame.Add(translated_value);
1480 return translated_value.GetChildrenCount();
1481 }
1482
1483 case TranslationOpcode::SIGNED_BIGINT64_REGISTER: {
1484 int input_reg = iterator->NextOperandUnsigned();
1485 if (registers == nullptr) {
1486 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1487 frame.Add(translated_value);
1488 return translated_value.GetChildrenCount();
1489 }
1490 intptr_t value = registers->GetRegister(input_reg);
1491 if (trace_file != nullptr) {
1492 PrintF(trace_file, "%" V8PRIdPTR " ; %s (signed bigint64)", value,
1493 converter.NameOfCPURegister(input_reg));
1494 }
1495 TranslatedValue translated_value =
1497 frame.Add(translated_value);
1498 return translated_value.GetChildrenCount();
1499 }
1500
1501 case TranslationOpcode::UNSIGNED_BIGINT64_REGISTER: {
1502 int input_reg = iterator->NextOperandUnsigned();
1503 if (registers == nullptr) {
1504 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1505 frame.Add(translated_value);
1506 return translated_value.GetChildrenCount();
1507 }
1508 intptr_t value = registers->GetRegister(input_reg);
1509 if (trace_file != nullptr) {
1510 PrintF(trace_file, "%" V8PRIdPTR " ; %s (unsigned bigint64)", value,
1511 converter.NameOfCPURegister(input_reg));
1512 }
1513 TranslatedValue translated_value =
1515 frame.Add(translated_value);
1516 return translated_value.GetChildrenCount();
1517 }
1518
1519 case TranslationOpcode::UINT32_REGISTER: {
1520 int input_reg = iterator->NextOperandUnsigned();
1521 if (registers == nullptr) {
1522 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1523 frame.Add(translated_value);
1524 return translated_value.GetChildrenCount();
1525 }
1526 intptr_t value = registers->GetRegister(input_reg);
1527 if (trace_file != nullptr) {
1528 PrintF(trace_file, "%" V8PRIuPTR " ; %s (uint32)", value,
1529 converter.NameOfCPURegister(input_reg));
1530 }
1531 TranslatedValue translated_value =
1532 TranslatedValue::NewUint32(this, static_cast<uint32_t>(value));
1533 frame.Add(translated_value);
1534 return translated_value.GetChildrenCount();
1535 }
1536
1537 case TranslationOpcode::BOOL_REGISTER: {
1538 int input_reg = iterator->NextOperandUnsigned();
1539 if (registers == nullptr) {
1540 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1541 frame.Add(translated_value);
1542 return translated_value.GetChildrenCount();
1543 }
1544 intptr_t value = registers->GetRegister(input_reg);
1545 if (trace_file != nullptr) {
1546 PrintF(trace_file, "%" V8PRIdPTR " ; %s (bool)", value,
1547 converter.NameOfCPURegister(input_reg));
1548 }
1549 TranslatedValue translated_value =
1550 TranslatedValue::NewBool(this, static_cast<uint32_t>(value));
1551 frame.Add(translated_value);
1552 return translated_value.GetChildrenCount();
1553 }
1554
1555 case TranslationOpcode::FLOAT_REGISTER: {
1556 int input_reg = iterator->NextOperandUnsigned();
1557 if (registers == nullptr) {
1558 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1559 frame.Add(translated_value);
1560 return translated_value.GetChildrenCount();
1561 }
1562 Float32 value = registers->GetFloatRegister(input_reg);
1563 if (trace_file != nullptr) {
1564 PrintF(trace_file, "%e ; %s (float)", value.get_scalar(),
1565 RegisterName(FloatRegister::from_code(input_reg)));
1566 }
1567 TranslatedValue translated_value = TranslatedValue::NewFloat(this, value);
1568 frame.Add(translated_value);
1569 return translated_value.GetChildrenCount();
1570 }
1571
1572 case TranslationOpcode::DOUBLE_REGISTER: {
1573 int input_reg = iterator->NextOperandUnsigned();
1574 if (registers == nullptr) {
1575 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1576 frame.Add(translated_value);
1577 return translated_value.GetChildrenCount();
1578 }
1579 Float64 value = registers->GetDoubleRegister(input_reg);
1580 if (trace_file != nullptr) {
1581 PrintF(trace_file, "%e ; %s (double)", value.get_scalar(),
1582 RegisterName(DoubleRegister::from_code(input_reg)));
1583 }
1584 TranslatedValue translated_value =
1585 TranslatedValue::NewDouble(this, value);
1586 frame.Add(translated_value);
1587 return translated_value.GetChildrenCount();
1588 }
1589
1590 case TranslationOpcode::HOLEY_DOUBLE_REGISTER: {
1591 int input_reg = iterator->NextOperandUnsigned();
1592 if (registers == nullptr) {
1593 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1594 frame.Add(translated_value);
1595 return translated_value.GetChildrenCount();
1596 }
1597 Float64 value = registers->GetDoubleRegister(input_reg);
1598 if (trace_file != nullptr) {
1599 if (value.is_hole_nan()) {
1600 PrintF(trace_file, "the hole");
1601 } else {
1602 PrintF(trace_file, "%e", value.get_scalar());
1603 }
1604 PrintF(trace_file, " ; %s (holey double)",
1605 RegisterName(DoubleRegister::from_code(input_reg)));
1606 }
1607 TranslatedValue translated_value =
1609 frame.Add(translated_value);
1610 return translated_value.GetChildrenCount();
1611 }
1612
1613 case TranslationOpcode::SIMD128_REGISTER: {
1614 int input_reg = iterator->NextOperandUnsigned();
1615 if (registers == nullptr) {
1616 TranslatedValue translated_value = TranslatedValue::NewInvalid(this);
1617 frame.Add(translated_value);
1618 return translated_value.GetChildrenCount();
1619 }
1620 Simd128 value = registers->GetSimd128Register(input_reg);
1621 if (trace_file != nullptr) {
1622 int8x16 val = value.to_i8x16();
1623 PrintF(trace_file,
1624 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
1625 "%02x %02x %02x %02x ; %s (Simd128)",
1626 val.val[0], val.val[1], val.val[2], val.val[3], val.val[4],
1627 val.val[5], val.val[6], val.val[7], val.val[8], val.val[9],
1628 val.val[10], val.val[11], val.val[12], val.val[13], val.val[14],
1629 val.val[15], RegisterName(DoubleRegister::from_code(input_reg)));
1630 }
1631 TranslatedValue translated_value =
1632 TranslatedValue::NewSimd128(this, value);
1633 frame.Add(translated_value);
1634 return translated_value.GetChildrenCount();
1635 }
1636
1637 case TranslationOpcode::TAGGED_STACK_SLOT: {
1639 iterator->NextOperand());
1640 intptr_t value = *(reinterpret_cast<intptr_t*>(fp + slot_offset));
1641 Address uncompressed_value = DecompressIfNeeded(value);
1642 if (trace_file != nullptr) {
1643 PrintF(trace_file, V8PRIxPTR_FMT " ; [fp %c %3d] ",
1644 uncompressed_value, slot_offset < 0 ? '-' : '+',
1645 std::abs(slot_offset));
1646 ShortPrint(Tagged<Object>(uncompressed_value), trace_file);
1647 }
1648 TranslatedValue translated_value =
1649 TranslatedValue::NewTagged(this, Tagged<Object>(uncompressed_value));
1650 frame.Add(translated_value);
1651 return translated_value.GetChildrenCount();
1652 }
1653
1654 case TranslationOpcode::INT32_STACK_SLOT: {
1656 iterator->NextOperand());
1657 uint32_t value = GetUInt32Slot(fp, slot_offset);
1658 if (trace_file != nullptr) {
1659 PrintF(trace_file, "%d ; (int32) [fp %c %3d] ",
1660 static_cast<int32_t>(value), slot_offset < 0 ? '-' : '+',
1661 std::abs(slot_offset));
1662 }
1663 TranslatedValue translated_value = TranslatedValue::NewInt32(this, value);
1664 frame.Add(translated_value);
1665 return translated_value.GetChildrenCount();
1666 }
1667
1668 case TranslationOpcode::INT64_STACK_SLOT: {
1670 iterator->NextOperand());
1671 uint64_t value = GetUInt64Slot(fp, slot_offset);
1672 if (trace_file != nullptr) {
1673 PrintF(trace_file, "%" V8PRIdPTR " ; (int64) [fp %c %3d] ",
1674 static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
1675 std::abs(slot_offset));
1676 }
1677 TranslatedValue translated_value = TranslatedValue::NewInt64(this, value);
1678 frame.Add(translated_value);
1679 return translated_value.GetChildrenCount();
1680 }
1681
1682 case TranslationOpcode::SIGNED_BIGINT64_STACK_SLOT: {
1684 iterator->NextOperand());
1685 uint64_t value = GetUInt64Slot(fp, slot_offset);
1686 if (trace_file != nullptr) {
1687 PrintF(trace_file, "%" V8PRIdPTR " ; (signed bigint64) [fp %c %3d] ",
1688 static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
1689 std::abs(slot_offset));
1690 }
1691 TranslatedValue translated_value =
1693 frame.Add(translated_value);
1694 return translated_value.GetChildrenCount();
1695 }
1696
1697 case TranslationOpcode::UNSIGNED_BIGINT64_STACK_SLOT: {
1699 iterator->NextOperand());
1700 uint64_t value = GetUInt64Slot(fp, slot_offset);
1701 if (trace_file != nullptr) {
1702 PrintF(trace_file, "%" V8PRIdPTR " ; (unsigned bigint64) [fp %c %3d] ",
1703 static_cast<intptr_t>(value), slot_offset < 0 ? '-' : '+',
1704 std::abs(slot_offset));
1705 }
1706 TranslatedValue translated_value =
1708 frame.Add(translated_value);
1709 return translated_value.GetChildrenCount();
1710 }
1711
1712 case TranslationOpcode::UINT32_STACK_SLOT: {
1714 iterator->NextOperand());
1715 uint32_t value = GetUInt32Slot(fp, slot_offset);
1716 if (trace_file != nullptr) {
1717 PrintF(trace_file, "%u ; (uint32) [fp %c %3d] ", value,
1718 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1719 }
1720 TranslatedValue translated_value =
1721 TranslatedValue::NewUint32(this, value);
1722 frame.Add(translated_value);
1723 return translated_value.GetChildrenCount();
1724 }
1725
1726 case TranslationOpcode::BOOL_STACK_SLOT: {
1728 iterator->NextOperand());
1729 uint32_t value = GetUInt32Slot(fp, slot_offset);
1730 if (trace_file != nullptr) {
1731 PrintF(trace_file, "%u ; (bool) [fp %c %3d] ", value,
1732 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1733 }
1734 TranslatedValue translated_value = TranslatedValue::NewBool(this, value);
1735 frame.Add(translated_value);
1736 return translated_value.GetChildrenCount();
1737 }
1738
1739 case TranslationOpcode::FLOAT_STACK_SLOT: {
1741 iterator->NextOperand());
1742 Float32 value = GetFloatSlot(fp, slot_offset);
1743 if (trace_file != nullptr) {
1744 PrintF(trace_file, "%e ; (float) [fp %c %3d] ", value.get_scalar(),
1745 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1746 }
1747 TranslatedValue translated_value = TranslatedValue::NewFloat(this, value);
1748 frame.Add(translated_value);
1749 return translated_value.GetChildrenCount();
1750 }
1751
1752 case TranslationOpcode::DOUBLE_STACK_SLOT: {
1754 iterator->NextOperand());
1755 Float64 value = GetDoubleSlot(fp, slot_offset);
1756 if (trace_file != nullptr) {
1757 PrintF(trace_file, "%e ; (double) [fp %c %d] ", value.get_scalar(),
1758 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1759 }
1760 TranslatedValue translated_value =
1761 TranslatedValue::NewDouble(this, value);
1762 frame.Add(translated_value);
1763 return translated_value.GetChildrenCount();
1764 }
1765
1766 case TranslationOpcode::SIMD128_STACK_SLOT: {
1768 iterator->NextOperand());
1769 Simd128 value = getSimd128Slot(fp, slot_offset);
1770 if (trace_file != nullptr) {
1771 int8x16 val = value.to_i8x16();
1772 PrintF(trace_file,
1773 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
1774 "%02x %02x %02x %02x ; (Simd128) [fp %c %d]",
1775 val.val[0], val.val[1], val.val[2], val.val[3], val.val[4],
1776 val.val[5], val.val[6], val.val[7], val.val[8], val.val[9],
1777 val.val[10], val.val[11], val.val[12], val.val[13], val.val[14],
1778 val.val[15], slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1779 }
1780 TranslatedValue translated_value =
1781 TranslatedValue::NewSimd128(this, value);
1782 frame.Add(translated_value);
1783 return translated_value.GetChildrenCount();
1784 }
1785
1786 case TranslationOpcode::HOLEY_DOUBLE_STACK_SLOT: {
1788 iterator->NextOperand());
1789 Float64 value = GetDoubleSlot(fp, slot_offset);
1790 if (trace_file != nullptr) {
1791 if (value.is_hole_nan()) {
1792 PrintF(trace_file, "the hole");
1793 } else {
1794 PrintF(trace_file, "%e", value.get_scalar());
1795 }
1796 PrintF(trace_file, " ; (holey double) [fp %c %d] ",
1797 slot_offset < 0 ? '-' : '+', std::abs(slot_offset));
1798 }
1799 TranslatedValue translated_value =
1801 frame.Add(translated_value);
1802 return translated_value.GetChildrenCount();
1803 }
1804
1805 case TranslationOpcode::LITERAL: {
1806 int literal_index = iterator->NextOperand();
1807 TranslatedValue translated_value = literal_array.Get(this, literal_index);
1808 if (trace_file != nullptr) {
1809 if (translated_value.kind() == TranslatedValue::Kind::kTagged) {
1810 PrintF(trace_file, V8PRIxPTR_FMT " ; (literal %2d) ",
1811 translated_value.raw_literal().ptr(), literal_index);
1812 ShortPrint(translated_value.raw_literal(), trace_file);
1813 } else {
1814 switch (translated_value.kind()) {
1816 if (translated_value.double_value().is_nan()) {
1817 PrintF(trace_file, "(wasm double literal %f 0x%" PRIx64 ")",
1818 translated_value.double_value().get_scalar(),
1819 translated_value.double_value().get_bits());
1820 } else {
1821 PrintF(trace_file, "(wasm double literal %f)",
1822 translated_value.double_value().get_scalar());
1823 }
1824 break;
1826 if (translated_value.float_value().is_nan()) {
1827 PrintF(trace_file, "(wasm float literal %f 0x%x)",
1828 translated_value.float_value().get_scalar(),
1829 translated_value.float_value().get_bits());
1830 } else {
1831 PrintF(trace_file, "(wasm float literal %f)",
1832 translated_value.float_value().get_scalar());
1833 }
1834 break;
1836 PrintF(trace_file, "(wasm int64 literal %" PRId64 ")",
1837 translated_value.int64_value());
1838 break;
1840 PrintF(trace_file, "(wasm int32 literal %d)",
1841 translated_value.int32_value());
1842 break;
1843 default:
1844 PrintF(trace_file, " (wasm literal) ");
1845 break;
1846 }
1847 }
1848 }
1849 frame.Add(translated_value);
1850 return translated_value.GetChildrenCount();
1851 }
1852
1853 case TranslationOpcode::OPTIMIZED_OUT: {
1854 if (trace_file != nullptr) {
1855 PrintF(trace_file, "(optimized out)");
1856 }
1857
1859 this, ReadOnlyRoots(isolate_).optimized_out());
1860 frame.Add(translated_value);
1861 return translated_value.GetChildrenCount();
1862 }
1863 }
1864
1865 FATAL("We should never get here - unexpected deopt info.");
1866}
1867
1870#ifdef V8_TARGET_ARCH_LOONG64
1871 // The 32-bit compressed values are supposed to be sign-extended on
1872 // loongarch64.
1873 is_int32(value)) {
1874#else
1875 static_cast<uintptr_t>(value) <= std::numeric_limits<uint32_t>::max()) {
1876#endif
1878 isolate(), static_cast<uint32_t>(value));
1879 } else {
1880 return value;
1881 }
1882}
1883
1886 int deopt_index = SafepointEntry::kNoDeoptIndex;
1887 Tagged<Code> code = frame->LookupCode();
1889 static_cast<const OptimizedJSFrame*>(frame)->GetDeoptimizationData(
1890 code, &deopt_index);
1891 DCHECK(!data.is_null() && deopt_index != SafepointEntry::kNoDeoptIndex);
1893 data->FrameTranslation(), data->TranslationIndex(deopt_index).value());
1894 int actual_argc = frame->GetActualArgumentCount();
1895 DeoptimizationLiteralProvider literals(data->LiteralArray());
1896 Init(frame->isolate(), frame->fp(), frame->fp(), &it,
1897 data->ProtectedLiteralArray(), literals, nullptr /* registers */,
1898 nullptr /* trace file */, code->parameter_count_without_receiver(),
1899 actual_argc);
1900}
1901
1903 Isolate* isolate, Address input_frame_pointer, Address stack_frame_pointer,
1905 Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
1906 const DeoptimizationLiteralProvider& literal_array,
1907 RegisterValues* registers, FILE* trace_file, int formal_parameter_count,
1908 int actual_argument_count) {
1909 DCHECK(frames_.empty());
1910
1911 stack_frame_pointer_ = stack_frame_pointer;
1912 formal_parameter_count_ = formal_parameter_count;
1913 actual_argument_count_ = actual_argument_count;
1914 isolate_ = isolate;
1915
1916 // Read out the 'header' translation.
1917 TranslationOpcode opcode = iterator->NextOpcode();
1919 iterator->NextOperand(); // Skip the lookback distance.
1920 int count = iterator->NextOperand();
1921 frames_.reserve(count);
1922 iterator->NextOperand(); // Drop JS frames count.
1923
1924 if (opcode == TranslationOpcode::BEGIN_WITH_FEEDBACK) {
1926 trace_file);
1927 }
1928
1929 std::stack<int> nested_counts;
1930
1931 // Read the frames
1932 for (int frame_index = 0; frame_index < count; frame_index++) {
1933 // Read the frame descriptor.
1935 iterator, protected_literal_array, literal_array, input_frame_pointer,
1936 trace_file));
1937 TranslatedFrame& frame = frames_.back();
1938
1939 // Read the values.
1940 int values_to_process = frame.GetValueCount();
1941 while (values_to_process > 0 || !nested_counts.empty()) {
1942 if (trace_file != nullptr) {
1943 if (nested_counts.empty()) {
1944 // For top level values, print the value number.
1945 PrintF(trace_file,
1946 " %3i: ", frame.GetValueCount() - values_to_process);
1947 } else {
1948 // Take care of indenting for nested values.
1949 PrintF(trace_file, " ");
1950 for (size_t j = 0; j < nested_counts.size(); j++) {
1951 PrintF(trace_file, " ");
1952 }
1953 }
1954 }
1955
1956 int nested_count =
1957 CreateNextTranslatedValue(frame_index, iterator, literal_array,
1958 input_frame_pointer, registers, trace_file);
1959
1960 if (trace_file != nullptr) {
1961 PrintF(trace_file, "\n");
1962 }
1963
1964 // Update the value count and resolve the nesting.
1965 values_to_process--;
1966 if (nested_count > 0) {
1967 nested_counts.push(values_to_process);
1968 values_to_process = nested_count;
1969 } else {
1970 while (values_to_process == 0 && !nested_counts.empty()) {
1971 values_to_process = nested_counts.top();
1972 nested_counts.pop();
1973 }
1974 }
1975 }
1976 }
1977
1978 CHECK(!iterator->HasNextOpcode() ||
1979 TranslationOpcodeIsBegin(iterator->NextOpcode()));
1980}
1981
1982void TranslatedState::Prepare(Address stack_frame_pointer) {
1983 for (auto& frame : frames_) {
1984 frame.Handlify(isolate());
1985 }
1986
1987 if (!feedback_vector_.is_null()) {
1990 }
1991 stack_frame_pointer_ = stack_frame_pointer;
1992
1994}
1995
1997 CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
1999 return &(frames_[pos.frame_index_].values_[pos.value_index_]);
2000}
2001
2004 return slot->storage();
2005 }
2006
2008
2009 int index = slot->object_index();
2011 int value_index = pos.value_index_;
2012
2013 TranslatedFrame* frame = &(frames_[pos.frame_index_]);
2014 CHECK_EQ(slot, &(frame->values_[value_index]));
2015
2016 // TODO(dmercadier): try to avoid the recursive GetValue call.
2017 value_index++;
2018 TranslatedValue* left_slot = &(frame->values_[value_index]);
2019 Handle<Object> left = left_slot->GetValue();
2020
2021 // Skipping the left input that we've just processed. Note that we can't just
2022 // do `value_index++`, because the left input could itself be a dematerialized
2023 // string concatenation, in which case it will occupy multiple slots.
2024 SkipSlots(1, frame, &value_index);
2025
2026 TranslatedValue* right_slot = &(frame->values_[value_index]);
2027 Handle<Object> right = right_slot->GetValue();
2028
2030 isolate()
2031 ->factory()
2032 ->NewConsString(Cast<String>(left), Cast<String>(right))
2033 .ToHandleChecked();
2034
2036 return result;
2037}
2038
2041
2042 slot = ResolveCapturedObject(slot);
2044 std::stack<int> worklist;
2045 worklist.push(slot->object_index());
2046 slot->mark_finished();
2047
2048 while (!worklist.empty()) {
2049 int index = worklist.top();
2050 worklist.pop();
2051 InitializeCapturedObjectAt(index, &worklist, no_gc);
2052 }
2053 }
2054 return slot->storage();
2055}
2056
2058 int object_index, std::stack<int>* worklist,
2059 const DisallowGarbageCollection& no_gc) {
2060 CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
2062 int value_index = pos.value_index_;
2063
2064 TranslatedFrame* frame = &(frames_[pos.frame_index_]);
2065 TranslatedValue* slot = &(frame->values_[value_index]);
2066 value_index++;
2067
2068 // Note that we cannot reach this point with kCapturedStringConcats slots,
2069 // since they have been already finalized in EnsureObjectAllocatedAt and
2070 // EnsureCapturedObjectAllocatedAt.
2073
2074 // Ensure all fields are initialized.
2075 int children_init_index = value_index;
2076 for (int i = 0; i < slot->GetChildrenCount(); i++) {
2077 // If the field is an object that has not been initialized yet, queue it
2078 // for initialization (and mark it as such).
2079 TranslatedValue* child_slot = frame->ValueAt(children_init_index);
2080 if (child_slot->kind() == TranslatedValue::kCapturedObject ||
2081 child_slot->kind() == TranslatedValue::kDuplicatedObject) {
2082 child_slot = ResolveCapturedObject(child_slot);
2085 child_slot->materialization_state());
2086 worklist->push(child_slot->object_index());
2087 child_slot->mark_finished();
2088 }
2089 }
2090 SkipSlots(1, frame, &children_init_index);
2091 }
2092
2093 // Read the map.
2094 // The map should never be materialized, so let us check we already have
2095 // an existing object here.
2096 CHECK_EQ(frame->values_[value_index].kind(), TranslatedValue::kTagged);
2097 auto map = Cast<Map>(frame->values_[value_index].GetValue());
2098 CHECK(IsMap(*map));
2099 value_index++;
2100
2101 // Handle the special cases.
2102 switch (map->instance_type()) {
2103 case HEAP_NUMBER_TYPE:
2104 case FIXED_DOUBLE_ARRAY_TYPE:
2105 return;
2106
2107 case FIXED_ARRAY_TYPE:
2108 case AWAIT_CONTEXT_TYPE:
2109 case BLOCK_CONTEXT_TYPE:
2110 case CATCH_CONTEXT_TYPE:
2111 case DEBUG_EVALUATE_CONTEXT_TYPE:
2112 case EVAL_CONTEXT_TYPE:
2113 case FUNCTION_CONTEXT_TYPE:
2114 case MODULE_CONTEXT_TYPE:
2115 case NATIVE_CONTEXT_TYPE:
2116 case SCRIPT_CONTEXT_TYPE:
2117 case WITH_CONTEXT_TYPE:
2118 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
2119 case HASH_TABLE_TYPE:
2120 case ORDERED_HASH_MAP_TYPE:
2121 case ORDERED_HASH_SET_TYPE:
2122 case NAME_DICTIONARY_TYPE:
2123 case GLOBAL_DICTIONARY_TYPE:
2124 case NUMBER_DICTIONARY_TYPE:
2125 case SIMPLE_NUMBER_DICTIONARY_TYPE:
2126 case PROPERTY_ARRAY_TYPE:
2127 case SCRIPT_CONTEXT_TABLE_TYPE:
2128 case SLOPPY_ARGUMENTS_ELEMENTS_TYPE:
2129 InitializeObjectWithTaggedFieldsAt(frame, &value_index, slot, map, no_gc);
2130 break;
2131
2132 default:
2133 CHECK(IsJSObjectMap(*map));
2134 InitializeJSObjectAt(frame, &value_index, slot, map, no_gc);
2135 break;
2136 }
2137 CHECK_EQ(value_index, children_init_index);
2138}
2139
2141 slot = ResolveCapturedObject(slot);
2142
2144 ResolveStringConcat(slot);
2145 return;
2146 }
2147
2149 std::stack<int> worklist;
2150 worklist.push(slot->object_index());
2151 slot->mark_allocated();
2152
2153 while (!worklist.empty()) {
2154 int index = worklist.top();
2155 worklist.pop();
2156 EnsureCapturedObjectAllocatedAt(index, &worklist);
2157 }
2158 }
2159}
2160
2162 Tagged<Object> value = GetRawValue();
2163 CHECK(IsSmi(value));
2164 return Cast<Smi>(value).value();
2165}
2166
2168 int* value_index,
2169 TranslatedValue* slot,
2170 DirectHandle<Map> map) {
2171 int length = frame->values_[*value_index].GetSmiValue();
2172 (*value_index)++;
2174 Cast<FixedDoubleArray>(isolate()->factory()->NewFixedDoubleArray(length));
2175 CHECK_GT(length, 0);
2176 for (int i = 0; i < length; i++) {
2178 frame->values_[*value_index].kind());
2179 DirectHandle<Object> value = frame->values_[*value_index].GetValue();
2180 if (IsNumber(*value)) {
2181 array->set(i, Object::NumberValue(*value));
2182 } else {
2183 CHECK(value.is_identical_to(isolate()->factory()->the_hole_value()));
2184 array->set_the_hole(isolate(), i);
2185 }
2186 (*value_index)++;
2187 }
2188 slot->set_storage(array);
2189}
2190
2192 int* value_index,
2193 TranslatedValue* slot) {
2195 frame->values_[*value_index].kind());
2196 DirectHandle<Object> value = frame->values_[*value_index].GetValue();
2197 CHECK(IsNumber(*value));
2198 Handle<HeapNumber> box =
2200 (*value_index)++;
2201 slot->set_storage(box);
2202}
2203
2204namespace {
2205
2206enum StorageKind : uint8_t { kStoreTagged, kStoreHeapObject };
2207
2208} // namespace
2209
2210void TranslatedState::SkipSlots(int slots_to_skip, TranslatedFrame* frame,
2211 int* value_index) {
2212 while (slots_to_skip > 0) {
2213 TranslatedValue* slot = &(frame->values_[*value_index]);
2214 (*value_index)++;
2215 slots_to_skip--;
2216
2217 if (slot->kind() == TranslatedValue::kCapturedObject ||
2219 slots_to_skip += slot->GetChildrenCount();
2220 }
2221 }
2222}
2223
2225 int object_index, std::stack<int>* worklist) {
2226 CHECK_LT(static_cast<size_t>(object_index), object_positions_.size());
2228 int value_index = pos.value_index_;
2229
2230 TranslatedFrame* frame = &(frames_[pos.frame_index_]);
2231 TranslatedValue* slot = &(frame->values_[value_index]);
2232 value_index++;
2233
2236
2237 // Read the map.
2238 // The map should never be materialized, so let us check we already have
2239 // an existing object here.
2240 CHECK_EQ(frame->values_[value_index].kind(), TranslatedValue::kTagged);
2241 auto map = Cast<Map>(frame->values_[value_index].GetValue());
2242 CHECK(IsMap(*map));
2243 value_index++;
2244
2245 // Handle the special cases.
2246 switch (map->instance_type()) {
2247 case FIXED_DOUBLE_ARRAY_TYPE:
2248 // Materialize (i.e. allocate&initialize) the array and return since
2249 // there is no need to process the children.
2250 return MaterializeFixedDoubleArray(frame, &value_index, slot, map);
2251
2252 case HEAP_NUMBER_TYPE:
2253 // Materialize (i.e. allocate&initialize) the heap number and return.
2254 // There is no need to process the children.
2255 return MaterializeHeapNumber(frame, &value_index, slot);
2256
2257 case FIXED_ARRAY_TYPE:
2258 case SCRIPT_CONTEXT_TABLE_TYPE:
2259 case AWAIT_CONTEXT_TYPE:
2260 case BLOCK_CONTEXT_TYPE:
2261 case CATCH_CONTEXT_TYPE:
2262 case DEBUG_EVALUATE_CONTEXT_TYPE:
2263 case EVAL_CONTEXT_TYPE:
2264 case FUNCTION_CONTEXT_TYPE:
2265 case MODULE_CONTEXT_TYPE:
2266 case NATIVE_CONTEXT_TYPE:
2267 case SCRIPT_CONTEXT_TYPE:
2268 case WITH_CONTEXT_TYPE:
2269 case HASH_TABLE_TYPE:
2270 case ORDERED_HASH_MAP_TYPE:
2271 case ORDERED_HASH_SET_TYPE:
2272 case NAME_DICTIONARY_TYPE:
2273 case GLOBAL_DICTIONARY_TYPE:
2274 case NUMBER_DICTIONARY_TYPE:
2275 case SIMPLE_NUMBER_DICTIONARY_TYPE: {
2276 // Check we have the right size.
2277 int array_length = frame->values_[value_index].GetSmiValue();
2278 int instance_size = FixedArray::SizeFor(array_length);
2279 CHECK_EQ(instance_size, slot->GetChildrenCount() * kTaggedSize);
2280
2281 // Canonicalize empty fixed array.
2282 if (*map == ReadOnlyRoots(isolate()).empty_fixed_array()->map() &&
2283 array_length == 0) {
2284 slot->set_storage(isolate()->factory()->empty_fixed_array());
2285 } else {
2286 slot->set_storage(AllocateStorageFor(slot));
2287 }
2288
2289 // Make sure all the remaining children (after the map) are allocated.
2290 return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
2291 &value_index, worklist);
2292 }
2293
2294 case SLOPPY_ARGUMENTS_ELEMENTS_TYPE: {
2295 // Verify that the arguments size is correct.
2296 int args_length = frame->values_[value_index].GetSmiValue();
2297 int args_size = SloppyArgumentsElements::SizeFor(args_length);
2298 CHECK_EQ(args_size, slot->GetChildrenCount() * kTaggedSize);
2299
2300 slot->set_storage(AllocateStorageFor(slot));
2301
2302 // Make sure all the remaining children (after the map) are allocated.
2303 return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
2304 &value_index, worklist);
2305 }
2306
2307 case PROPERTY_ARRAY_TYPE: {
2308 // Check we have the right size.
2309 int length_or_hash = frame->values_[value_index].GetSmiValue();
2310 int array_length = PropertyArray::LengthField::decode(length_or_hash);
2311 int instance_size = PropertyArray::SizeFor(array_length);
2312 CHECK_EQ(instance_size, slot->GetChildrenCount() * kTaggedSize);
2313
2314 slot->set_storage(AllocateStorageFor(slot));
2315
2316 // Make sure all the remaining children (after the map) are allocated.
2317 return EnsureChildrenAllocated(slot->GetChildrenCount() - 1, frame,
2318 &value_index, worklist);
2319 }
2320
2321 default:
2322 EnsureJSObjectAllocated(slot, map);
2323 int remaining_children_count = slot->GetChildrenCount() - 1;
2324
2325 TranslatedValue* properties_slot = frame->ValueAt(value_index);
2326 value_index++, remaining_children_count--;
2327 if (properties_slot->kind() == TranslatedValue::kCapturedObject) {
2328 // We are materializing the property array, so make sure we put the
2329 // mutable heap numbers at the right places.
2330 EnsurePropertiesAllocatedAndMarked(properties_slot, map);
2331 EnsureChildrenAllocated(properties_slot->GetChildrenCount(), frame,
2332 &value_index, worklist);
2333 } else {
2334 CHECK_EQ(properties_slot->kind(), TranslatedValue::kTagged);
2335 }
2336
2337 TranslatedValue* elements_slot = frame->ValueAt(value_index);
2338 value_index++, remaining_children_count--;
2339 if (elements_slot->kind() == TranslatedValue::kCapturedObject ||
2340 !IsJSArrayMap(*map)) {
2341 // Handle this case with the other remaining children below.
2342 value_index--, remaining_children_count++;
2343 } else {
2344 CHECK_EQ(elements_slot->kind(), TranslatedValue::kTagged);
2345 elements_slot->GetValue();
2346 if (purpose_ == kFrameInspection) {
2347 // We are materializing a JSArray for the purpose of frame inspection.
2348 // If we were to construct it with the above elements value then an
2349 // actual deopt later on might create another JSArray instance with
2350 // the same elements store. That would violate the key assumption
2351 // behind left-trimming.
2352 elements_slot->ReplaceElementsArrayWithCopy();
2353 }
2354 }
2355
2356 // Make sure all the remaining children (after the map, properties store,
2357 // and possibly elements store) are allocated.
2358 return EnsureChildrenAllocated(remaining_children_count, frame,
2359 &value_index, worklist);
2360 }
2361 UNREACHABLE();
2362}
2363
2367 auto elements = Cast<FixedArrayBase>(GetValue());
2368 DCHECK(IsFixedArray(*elements) || IsFixedDoubleArray(*elements));
2369 if (IsFixedDoubleArray(*elements)) {
2370 DCHECK(!elements->IsCowArray());
2371 set_storage(isolate()->factory()->CopyFixedDoubleArray(
2372 Cast<FixedDoubleArray>(elements)));
2373 } else if (!elements->IsCowArray()) {
2375 isolate()->factory()->CopyFixedArray(Cast<FixedArray>(elements)));
2376 }
2377}
2378
2380 int* value_index,
2381 std::stack<int>* worklist) {
2382 // Ensure all children are allocated.
2383 for (int i = 0; i < count; i++) {
2384 // If the field is an object that has not been allocated yet, queue it
2385 // for initialization (and mark it as such).
2386 TranslatedValue* child_slot = frame->ValueAt(*value_index);
2387 if (child_slot->kind() == TranslatedValue::kCapturedObject ||
2388 child_slot->kind() == TranslatedValue::kDuplicatedObject) {
2389 child_slot = ResolveCapturedObject(child_slot);
2390
2391 if (child_slot->kind() == TranslatedValue::kCapturedStringConcat) {
2392 ResolveStringConcat(child_slot);
2393 } else if (child_slot->materialization_state() ==
2395 worklist->push(child_slot->object_index());
2396 child_slot->mark_allocated();
2397 }
2398 } else {
2399 // Make sure the simple values (heap numbers, etc.) are properly
2400 // initialized.
2401 child_slot->GetValue();
2402 }
2403 SkipSlots(1, frame, value_index);
2404 }
2405}
2406
2408 TranslatedValue* properties_slot, DirectHandle<Map> map) {
2410 properties_slot->materialization_state());
2411
2412 Handle<ByteArray> object_storage = AllocateStorageFor(properties_slot);
2413 properties_slot->mark_allocated();
2414 properties_slot->set_storage(object_storage);
2415
2417 Tagged<Map> raw_map = *map;
2418 Tagged<ByteArray> raw_object_storage = *object_storage;
2419
2420 // Set markers for out-of-object properties.
2421 Tagged<DescriptorArray> descriptors = map->instance_descriptors(isolate());
2422 for (InternalIndex i : map->IterateOwnDescriptors()) {
2423 FieldIndex index = FieldIndex::ForDescriptor(raw_map, i);
2424 Representation representation = descriptors->GetDetails(i).representation();
2425 if (!index.is_inobject() &&
2426 (representation.IsDouble() || representation.IsHeapObject())) {
2427 int outobject_index = index.outobject_array_index();
2428 int array_index = outobject_index * kTaggedSize;
2429 raw_object_storage->set(array_index, kStoreHeapObject);
2430 }
2431 }
2432}
2433
2435 int allocate_size =
2437 // It is important to allocate all the objects tenured so that the marker
2438 // does not visit them.
2439 Handle<ByteArray> object_storage =
2440 isolate()->factory()->NewByteArray(allocate_size, AllocationType::kOld);
2442 Tagged<ByteArray> raw_object_storage = *object_storage;
2443 for (int i = 0; i < object_storage->length(); i++) {
2444 raw_object_storage->set(i, kStoreTagged);
2445 }
2446 return object_storage;
2447}
2448
2450 DirectHandle<Map> map) {
2451 CHECK(IsJSObjectMap(*map));
2452 CHECK_EQ(map->instance_size(), slot->GetChildrenCount() * kTaggedSize);
2453
2454 Handle<ByteArray> object_storage = AllocateStorageFor(slot);
2455
2456 // Now we handle the interesting (JSObject) case.
2458 Tagged<Map> raw_map = *map;
2459 Tagged<ByteArray> raw_object_storage = *object_storage;
2460 Tagged<DescriptorArray> descriptors = map->instance_descriptors(isolate());
2461
2462 // Set markers for in-object properties.
2463 for (InternalIndex i : raw_map->IterateOwnDescriptors()) {
2464 FieldIndex index = FieldIndex::ForDescriptor(raw_map, i);
2465 Representation representation = descriptors->GetDetails(i).representation();
2466 if (index.is_inobject() &&
2467 (representation.IsDouble() || representation.IsHeapObject())) {
2469 int array_index =
2470 index.index() * kTaggedSize - OFFSET_OF_DATA_START(FixedArray);
2471 raw_object_storage->set(array_index, kStoreHeapObject);
2472 }
2473 }
2474 slot->set_storage(object_storage);
2475}
2476
2478 int value_index) {
2479 TranslatedValue* slot = frame->ValueAt(value_index);
2481 slot = ResolveCapturedObject(slot);
2482 }
2484 return slot;
2485}
2486
2488 TranslatedFrame* frame, int* value_index) {
2489 TranslatedValue* slot = GetResolvedSlot(frame, *value_index);
2490 SkipSlots(1, frame, value_index);
2491 return slot;
2492}
2493
2495 int* value_index) {
2496 TranslatedValue* slot = GetResolvedSlot(frame, *value_index);
2497 SkipSlots(1, frame, value_index);
2498 return slot->GetValue();
2499}
2500
2502 TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
2503 DirectHandle<Map> map, const DisallowGarbageCollection& no_gc) {
2504 auto object_storage = Cast<HeapObject>(slot->storage_);
2506 int children_count = slot->GetChildrenCount();
2507
2508 // The object should have at least a map and some payload.
2509 CHECK_GE(children_count, 2);
2510
2511#if DEBUG
2512 // No need to invalidate slots in object because no slot was recorded yet.
2513 // Verify this here.
2514 Address object_start = object_storage->address();
2515 Address object_end = object_start + children_count * kTaggedSize;
2516 isolate()->heap()->VerifySlotRangeHasNoRecordedSlots(object_start,
2517 object_end);
2518#endif // DEBUG
2519
2520 // Notify the concurrent marker about the layout change.
2522 *object_storage, no_gc, InvalidateRecordedSlots::kNo,
2524
2525 // Finish any sweeping so that it becomes safe to overwrite the ByteArray
2526 // headers. See chromium:1228036.
2527 isolate()->heap()->EnsureSweepingCompletedForObject(*object_storage);
2528
2529 // Fill the property array field.
2530 {
2531 DirectHandle<Object> properties = GetValueAndAdvance(frame, value_index);
2532 WRITE_FIELD(*object_storage, JSObject::kPropertiesOrHashOffset,
2533 *properties);
2534 WRITE_BARRIER(*object_storage, JSObject::kPropertiesOrHashOffset,
2535 *properties);
2536 }
2537
2538 // For all the other fields we first look at the fixed array and check the
2539 // marker to see if we store an unboxed double.
2540 DCHECK_EQ(kTaggedSize, JSObject::kPropertiesOrHashOffset);
2541 for (int i = 2; i < children_count; i++) {
2542 slot = GetResolvedSlotAndAdvance(frame, value_index);
2543 // Read out the marker and ensure the field is consistent with
2544 // what the markers in the storage say (note that all heap numbers
2545 // should be fully initialized by now).
2546 int offset = i * kTaggedSize;
2547 uint8_t marker = object_storage->ReadField<uint8_t>(offset);
2548 InstanceType instance_type = map->instance_type();
2549 USE(instance_type);
2550#ifdef V8_ENABLE_LEAPTIERING
2551 if (InstanceTypeChecker::IsJSFunction(instance_type) &&
2552 offset == JSFunction::kDispatchHandleOffset) {
2553 // The JSDispatchHandle will be materialized as a number, but we need
2554 // the raw value here. TODO(saelo): can we implement "proper" support
2555 // for JSDispatchHandles in the deoptimizer?
2556 DirectHandle<Object> field_value = slot->GetValue();
2557 CHECK(IsNumber(*field_value));
2559 object_storage->WriteField<JSDispatchHandle::underlying_type>(
2560 JSFunction::kDispatchHandleOffset, handle.value());
2561 continue;
2562 }
2563#endif // V8_ENABLE_LEAPTIERING
2564#ifdef V8_ENABLE_SANDBOX
2565 if (InstanceTypeChecker::IsJSRegExp(instance_type) &&
2566 offset == JSRegExp::kDataOffset) {
2567 DirectHandle<HeapObject> field_value = slot->storage();
2568 // If the value comes from the DeoptimizationLiteralArray, it is a
2569 // RegExpDataWrapper as we can't store TrustedSpace values in a FixedArray
2570 // directly.
2572 if (Is<RegExpDataWrapper>(*field_value)) {
2573 value = Cast<RegExpDataWrapper>(*field_value)->data(isolate());
2574 } else {
2575 CHECK(IsRegExpData(*field_value));
2576 value = Cast<RegExpData>(*field_value);
2577 }
2578 object_storage
2579 ->RawIndirectPointerField(offset, kRegExpDataIndirectPointerTag)
2580 .Relaxed_Store(value);
2581 INDIRECT_POINTER_WRITE_BARRIER(*object_storage, offset,
2582 kRegExpDataIndirectPointerTag, value);
2583 continue;
2584 }
2585#endif // V8_ENABLE_SANDBOX
2586 if (marker == kStoreHeapObject) {
2587 DirectHandle<HeapObject> field_value = slot->storage();
2588 WRITE_FIELD(*object_storage, offset, *field_value);
2589 WRITE_BARRIER(*object_storage, offset, *field_value);
2590 continue;
2591 }
2592
2593 CHECK_EQ(kStoreTagged, marker);
2594 DirectHandle<Object> field_value = slot->GetValue();
2595 DCHECK_IMPLIES(IsHeapNumber(*field_value),
2596 !IsSmiDouble(Object::NumberValue(*field_value)));
2597 WRITE_FIELD(*object_storage, offset, *field_value);
2598 WRITE_BARRIER(*object_storage, offset, *field_value);
2599 }
2600 object_storage->set_map(isolate(), *map, kReleaseStore);
2601}
2602
2604 TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
2605 DirectHandle<Map> map, const DisallowGarbageCollection& no_gc) {
2606 auto object_storage = Cast<HeapObject>(slot->storage_);
2607 int children_count = slot->GetChildrenCount();
2608
2609 // Skip the writes if we already have the canonical empty fixed array.
2610 if (*object_storage == ReadOnlyRoots(isolate()).empty_fixed_array()) {
2611 CHECK_EQ(2, children_count);
2612 DirectHandle<Object> length_value = GetValueAndAdvance(frame, value_index);
2613 CHECK_EQ(*length_value, Smi::FromInt(0));
2614 return;
2615 }
2616
2617#if DEBUG
2618 // No need to invalidate slots in object because no slot was recorded yet.
2619 // Verify this here.
2620 Address object_start = object_storage->address();
2621 Address object_end = object_start + children_count * kTaggedSize;
2622 isolate()->heap()->VerifySlotRangeHasNoRecordedSlots(object_start,
2623 object_end);
2624#endif // DEBUG
2625
2626 // Notify the concurrent marker about the layout change.
2628 *object_storage, no_gc, InvalidateRecordedSlots::kNo,
2630
2631 // Finish any sweeping so that it becomes safe to overwrite the ByteArray
2632 // headers. See chromium:1228036.
2633 isolate()->heap()->EnsureSweepingCompletedForObject(*object_storage);
2634
2635 // Write the fields to the object.
2636 for (int i = 1; i < children_count; i++) {
2637 slot = GetResolvedSlotAndAdvance(frame, value_index);
2638 int offset = i * kTaggedSize;
2639 uint8_t marker = object_storage->ReadField<uint8_t>(offset);
2640 DirectHandle<Object> field_value;
2641 if (i > 1 && marker == kStoreHeapObject) {
2642 field_value = slot->storage();
2643 } else {
2644 CHECK(marker == kStoreTagged || i == 1);
2645 field_value = slot->GetValue();
2646 DCHECK_IMPLIES(IsHeapNumber(*field_value),
2647 !IsSmiDouble(Object::NumberValue(*field_value)));
2648 }
2649 WRITE_FIELD(*object_storage, offset, *field_value);
2650 WRITE_BARRIER(*object_storage, offset, *field_value);
2651 }
2652
2653 object_storage->set_map(isolate(), *map, kReleaseStore);
2654}
2655
2664
2666 for (size_t i = 0; i < frames_.size(); i++) {
2669 frames_[i].kind() ==
2671 if (jsframe_index > 0) {
2672 jsframe_index--;
2673 } else {
2674 return &(frames_[i]);
2675 }
2676 }
2677 }
2678 return nullptr;
2679}
2680
2682 int jsframe_index, int* args_count) {
2683 for (size_t i = 0; i < frames_.size(); i++) {
2686 frames_[i].kind() ==
2688 if (jsframe_index > 0) {
2689 jsframe_index--;
2690 } else {
2691 // We have the JS function frame, now check if it has arguments
2692 // adaptor.
2693 if (i > 0 &&
2695 *args_count = frames_[i - 1].height();
2696 return &(frames_[i - 1]);
2697 }
2698
2699 // JavaScriptBuiltinContinuation frames that are not preceded by
2700 // a arguments adapter frame are currently only used by C++ API calls
2701 // from TurboFan. Calls to C++ API functions from TurboFan need
2702 // a special marker frame state, otherwise the API call wouldn't
2703 // be shown in a stack trace.
2704 if (frames_[i].kind() ==
2706 DCHECK(frames_[i].shared_info()->IsDontAdaptArguments());
2707 DCHECK(frames_[i].shared_info()->IsApiFunction());
2708
2709 // The argument count for this special case is always the second
2710 // to last value in the TranslatedFrame. It should also always be
2711 // {1}, as the GenericLazyDeoptContinuation builtin has one explicit
2712 // argument (the result).
2713 static constexpr int kTheContext = 1;
2714 const uint32_t height = frames_[i].height() + kTheContext;
2715 *args_count = frames_[i].ValueAt(height - 1)->GetSmiValue();
2716 DCHECK_EQ(*args_count, JSParameterCount(1));
2717 return &(frames_[i]);
2718 }
2719
2721 *args_count = frames_[i].bytecode_array()->parameter_count();
2722 return &(frames_[i]);
2723 }
2724 }
2725 }
2726 return nullptr;
2727}
2728
2730 MaterializedObjectStore* materialized_store =
2732 DirectHandle<FixedArray> previously_materialized_objects =
2733 materialized_store->Get(stack_frame_pointer_);
2734
2735 Handle<Object> marker = isolate_->factory()->arguments_marker();
2736
2737 int length = static_cast<int>(object_positions_.size());
2738 bool new_store = false;
2739 if (previously_materialized_objects.is_null()) {
2740 previously_materialized_objects =
2742 for (int i = 0; i < length; i++) {
2743 previously_materialized_objects->set(i, *marker);
2744 }
2745 new_store = true;
2746 }
2747
2748 CHECK_EQ(length, previously_materialized_objects->length());
2749
2750 bool value_changed = false;
2751 for (int i = 0; i < length; i++) {
2753 TranslatedValue* value_info =
2754 &(frames_[pos.frame_index_].values_[pos.value_index_]);
2755
2756 CHECK(value_info->IsMaterializedObject());
2757
2758 // Skip duplicate objects (i.e., those that point to some other object id).
2759 if (value_info->object_index() != i) continue;
2760
2761 DirectHandle<Object> previous_value(previously_materialized_objects->get(i),
2762 isolate_);
2764
2765 if (value.is_identical_to(marker)) {
2766 DCHECK_EQ(*previous_value, *marker);
2767 } else {
2768 if (*previous_value == *marker) {
2769 if (IsSmi(*value)) {
2770 value =
2772 }
2773 previously_materialized_objects->set(i, *value);
2774 value_changed = true;
2775 } else {
2776 CHECK(*previous_value == *value ||
2777 (IsHeapNumber(*previous_value) && IsSmi(*value) &&
2778 Object::NumberValue(*previous_value) ==
2779 Object::NumberValue(*value)));
2780 }
2781 }
2782 }
2783
2784 if (new_store && value_changed) {
2785 materialized_store->Set(stack_frame_pointer_,
2786 previously_materialized_objects);
2788 CHECK_EQ(frame->function(), frames_[0].front().GetRawValue());
2790 frame->function(), LazyDeoptimizeReason::kFrameValueMaterialized,
2791 frame->LookupCode());
2792 }
2793}
2794
2796 MaterializedObjectStore* materialized_store =
2798 DirectHandle<FixedArray> previously_materialized_objects =
2799 materialized_store->Get(stack_frame_pointer_);
2800
2801 // If we have no previously materialized objects, there is nothing to do.
2802 if (previously_materialized_objects.is_null()) return;
2803
2804 DirectHandle<Object> marker = isolate_->factory()->arguments_marker();
2805
2806 int length = static_cast<int>(object_positions_.size());
2807 CHECK_EQ(length, previously_materialized_objects->length());
2808
2809 for (int i = 0; i < length; i++) {
2810 // For a previously materialized objects, inject their value into the
2811 // translated values.
2812 if (previously_materialized_objects->get(i) != *marker) {
2814 TranslatedValue* value_info =
2815 &(frames_[pos.frame_index_].values_[pos.value_index_]);
2816 CHECK(value_info->IsMaterializedObject());
2817
2818 if (value_info->kind() == TranslatedValue::kCapturedObject ||
2820 Handle<Object> object(previously_materialized_objects->get(i),
2821 isolate_);
2822 CHECK(IsHeapObject(*object));
2823 value_info->set_initialized_storage(Cast<HeapObject>(object));
2824 }
2825 }
2826 }
2827}
2828
2830#if VERIFY_HEAP
2831 if (!v8_flags.verify_heap) return;
2832 int length = static_cast<int>(object_positions_.size());
2833 for (int i = 0; i < length; i++) {
2835 if (slot->kind() == TranslatedValue::kCapturedObject ||
2839 Object::ObjectVerify(*slot->storage(), isolate());
2840 } else {
2843 }
2844 }
2845 }
2846#endif
2847}
2848
2859
2862 Tagged<DeoptimizationLiteralArray> literal_array, FILE* trace_file) {
2863 CHECK_EQ(TranslationOpcode::UPDATE_FEEDBACK, iterator->NextOpcode());
2865 Cast<FeedbackVector>(literal_array->get(iterator->NextOperand()));
2866 feedback_slot_ = FeedbackSlot(iterator->NextOperand());
2867 if (trace_file != nullptr) {
2868 PrintF(trace_file, " reading FeedbackVector (slot %d)\n",
2870 }
2871}
2872
2873} // namespace internal
2874} // namespace v8
2875
2876// Undefine the heap manipulation macros.
int16_t parameter_count
Definition builtins.cc:67
Builtins::Kind kind
Definition builtins.cc:40
SourcePosition pos
virtual const char * NameOfCPURegister(int reg) const
@ kDeoptimizerDisableSpeculation
Definition v8-isolate.h:516
static constexpr T decode(U value)
Definition bit-field.h:66
UnderlyingType underlying_type
static V8_EXPORT_PRIVATE Handle< BigInt > FromUint64(Isolate *isolate, uint64_t n)
Definition bigint.cc:1355
static V8_EXPORT_PRIVATE Handle< BigInt > FromInt64(Isolate *isolate, int64_t n)
Definition bigint.cc:1333
static constexpr int LengthFor(int size_in_bytes)
constexpr int ToInt() const
Definition utils.h:673
static constexpr int kFixedFrameSizeAboveFp
Tagged< DeoptimizationLiteralArray > get_on_heap_literals() const
DeoptimizationLiteralProvider(Tagged< DeoptimizationLiteralArray > literal_array)
std::vector< DeoptimizationLiteral > literals_off_heap_
Tagged< DeoptimizationLiteralArray > literals_on_heap_
TranslatedValue Get(TranslatedState *container, int literal_index) const
static void DeoptimizeFunction(Tagged< JSFunction > function, LazyDeoptimizeReason reason, Tagged< Code > code={})
V8_INLINE bool is_null() const
Definition handles.h:693
V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType NewConsString(HandleType< String > left, HandleType< String > right, AllocationType allocation=AllocationType::kYoung)
Handle< HeapNumber > NewHeapNumber(double value)
Handle< ByteArray > NewByteArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
void SetSpeculationMode(SpeculationMode mode)
bool IsInvalid() const
Definition utils.h:649
static FieldIndex ForDescriptor(Tagged< Map > map, InternalIndex descriptor_index)
bool is_nan() const
Definition boxed-float.h:40
float get_scalar() const
Definition boxed-float.h:38
uint32_t get_bits() const
Definition boxed-float.h:36
bool is_nan() const
Definition boxed-float.h:83
uint64_t get_bits() const
Definition boxed-float.h:80
double get_scalar() const
Definition boxed-float.h:81
void NotifyObjectLayoutChange(Tagged< HeapObject > object, const DisallowGarbageCollection &, InvalidateRecordedSlots invalidate_recorded_slots, InvalidateExternalPointerSlots invalidate_external_pointer_slots, int new_size=0)
Definition heap.cc:3984
V8_EXPORT_PRIVATE void CreateFillerObjectAt(Address addr, int size, ClearFreedMemoryMode clear_memory_mode=ClearFreedMemoryMode::kDontClearFreedMemory)
Definition heap.cc:3202
void EnsureSweepingCompletedForObject(Tagged< HeapObject > object)
Definition heap.cc:2417
MaterializedObjectStore * materialized_object_store() const
Definition isolate.h:1385
void CountUsage(v8::Isolate::UseCounterFeature feature)
Definition isolate.cc:7028
v8::internal::Factory * factory()
Definition isolate.h:1527
Tagged< JSFunction > function() const override
Definition frames.cc:2492
int GetActualArgumentCount() const override
Definition frames.cc:2632
DirectHandle< FixedArray > Get(Address fp)
void Set(Address fp, DirectHandle< FixedArray > materialized_objects)
static double NumberValue(Tagged< Number > obj)
static int StackSlotOffsetRelativeToFp(int slot_index)
Definition frames.cc:3275
Tagged< DeoptimizationData > GetDeoptimizationData(Tagged< Code > code, int *deopt_index) const
Definition frames.cc:3208
static constexpr int SizeFor(int length)
static constexpr SwVfpRegister from_code(int8_t code)
constexpr bool IsHeapObject() const
constexpr bool IsDouble() const
static V8_INLINE constexpr int32_t SizeFor(int32_t length)
static V8_INLINE constexpr int32_t SizeFor(int32_t length)
static const uint32_t kMinLength
Definition string.h:1130
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > FromIntptr(intptr_t value)
Definition smi.h:43
static bool constexpr IsValid(T value)
Definition smi.h:67
static constexpr int kMinValue
Definition smi.h:100
static constexpr int kMaxValue
Definition smi.h:101
V8_EXPORT_PRIVATE Tagged< Code > LookupCode() const
Definition frames.cc:757
Isolate * isolate() const
Definition frames.h:376
Address fp() const
Definition frames.h:297
V8_INLINE constexpr StorageType ptr() const
BytecodeOffset bytecode_offset() const
TranslatedFrame(Kind kind, Tagged< SharedFunctionInfo > raw_shared_info, Tagged< BytecodeArray > raw_bytecode_array, uint32_t height, int return_value_offset=0, int return_value_count=0)
DirectHandle< SharedFunctionInfo > shared_info() const
static TranslatedFrame UnoptimizedJSFrame(BytecodeOffset bytecode_offset, Tagged< SharedFunctionInfo > shared_info, Tagged< BytecodeArray > bytecode_array, uint32_t height, int return_value_offset, int return_value_count)
IndirectHandle< BytecodeArray > bytecode_array_
void Add(const TranslatedValue &value)
Tagged< SharedFunctionInfo > raw_shared_info_
void Handlify(Isolate *isolate)
static TranslatedFrame BuiltinContinuationFrame(BytecodeOffset bailout_id, Tagged< SharedFunctionInfo > shared_info, uint32_t height)
static TranslatedFrame ConstructInvokeStubFrame(Tagged< SharedFunctionInfo > shared_info)
DirectHandle< BytecodeArray > bytecode_array() const
static TranslatedFrame InlinedExtraArguments(Tagged< SharedFunctionInfo > shared_info, uint32_t height, uint32_t formal_parameter_count)
static TranslatedFrame JavaScriptBuiltinContinuationWithCatchFrame(BytecodeOffset bailout_id, Tagged< SharedFunctionInfo > shared_info, uint32_t height)
IndirectHandle< SharedFunctionInfo > shared_info_
Tagged< BytecodeArray > raw_bytecode_array_
static TranslatedFrame JavaScriptBuiltinContinuationFrame(BytecodeOffset bailout_id, Tagged< SharedFunctionInfo > shared_info, uint32_t height)
static TranslatedFrame ConstructCreateStubFrame(Tagged< SharedFunctionInfo > shared_info, uint32_t height)
static void AdvanceIterator(std::deque< TranslatedValue >::iterator *iter)
enum v8::internal::TranslatedFrame::HandleState handle_state_
TranslatedValue * ValueAt(int index)
static Float64 GetDoubleSlot(Address fp, int slot_index)
void SkipSlots(int slots_to_skip, TranslatedFrame *frame, int *value_index)
static uint64_t GetUInt64Slot(Address fp, int slot_index)
TranslatedValue * ResolveCapturedObject(TranslatedValue *slot)
int CreateNextTranslatedValue(int frame_index, DeoptTranslationIterator *iterator, const DeoptimizationLiteralProvider &literal_array, Address fp, RegisterValues *registers, FILE *trace_file)
void ReadUpdateFeedback(DeoptTranslationIterator *iterator, Tagged< DeoptimizationLiteralArray > literal_array, FILE *trace_file)
void EnsureCapturedObjectAllocatedAt(int object_index, std::stack< int > *worklist)
TranslatedValue * GetResolvedSlot(TranslatedFrame *frame, int value_index)
void EnsureChildrenAllocated(int count, TranslatedFrame *frame, int *value_index, std::stack< int > *worklist)
void MaterializeHeapNumber(TranslatedFrame *frame, int *value_index, TranslatedValue *slot)
void MaterializeFixedDoubleArray(TranslatedFrame *frame, int *value_index, TranslatedValue *slot, DirectHandle< Map > map)
TranslatedFrame * GetArgumentsInfoFromJSFrameIndex(int jsframe_index, int *arguments_count)
void CreateArgumentsElementsTranslatedValues(int frame_index, Address input_frame_pointer, CreateArgumentsType type, FILE *trace_file)
Address DecompressIfNeeded(intptr_t value)
void EnsureJSObjectAllocated(TranslatedValue *slot, DirectHandle< Map > map)
Handle< HeapObject > InitializeObjectAt(TranslatedValue *slot)
void StoreMaterializedValuesAndDeopt(JavaScriptFrame *frame)
void EnsureObjectAllocatedAt(TranslatedValue *slot)
TranslatedValue * GetResolvedSlotAndAdvance(TranslatedFrame *frame, int *value_index)
void Init(Isolate *isolate, Address input_frame_pointer, Address stack_frame_pointer, DeoptTranslationIterator *iterator, Tagged< ProtectedDeoptimizationLiteralArray > protected_literal_array, const DeoptimizationLiteralProvider &literal_array, RegisterValues *registers, FILE *trace_file, int parameter_count, int actual_argument_count)
void InitializeCapturedObjectAt(int object_index, std::stack< int > *worklist, const DisallowGarbageCollection &no_gc)
void InitializeObjectWithTaggedFieldsAt(TranslatedFrame *frame, int *value_index, TranslatedValue *slot, DirectHandle< Map > map, const DisallowGarbageCollection &no_gc)
std::deque< ObjectPosition > object_positions_
TranslatedValue * GetValueByObjectIndex(int object_index)
Tagged< FeedbackVector > feedback_vector_
static Simd128 getSimd128Slot(Address fp, int slot_index)
Handle< HeapObject > ResolveStringConcat(TranslatedValue *slot)
TranslatedFrame CreateNextTranslatedFrame(DeoptTranslationIterator *iterator, Tagged< ProtectedDeoptimizationLiteralArray > protected_literal_array, const DeoptimizationLiteralProvider &literal_array, Address fp, FILE *trace_file)
Handle< FeedbackVector > feedback_vector_handle_
void EnsurePropertiesAllocatedAndMarked(TranslatedValue *properties_slot, DirectHandle< Map > map)
std::vector< TranslatedFrame > frames_
static Float32 GetFloatSlot(Address fp, int slot_index)
TranslatedFrame * GetFrameFromJSFrameIndex(int jsframe_index)
DirectHandle< Object > GetValueAndAdvance(TranslatedFrame *frame, int *value_index)
Handle< ByteArray > AllocateStorageFor(TranslatedValue *slot)
std::vector< TranslatedFrame >::iterator iterator
void Prepare(Address stack_frame_pointer)
void InitializeJSObjectAt(TranslatedFrame *frame, int *value_index, TranslatedValue *slot, DirectHandle< Map > map, const DisallowGarbageCollection &no_gc)
static uint32_t GetUInt32Slot(Address fp, int slot_index)
static TranslatedValue NewUint64ToBigInt(TranslatedState *container, uint64_t value)
static TranslatedValue NewDouble(TranslatedState *container, Float64 value)
Handle< HeapObject > storage()
Tagged< Object > GetRawValue() const
static TranslatedValue NewDuplicateObject(TranslatedState *container, int id)
static TranslatedValue NewInt64ToBigInt(TranslatedState *container, int64_t value)
static TranslatedValue NewHoleyDouble(TranslatedState *container, Float64 value)
static TranslatedValue NewBool(TranslatedState *container, uint32_t value)
void set_initialized_storage(Handle< HeapObject > storage)
void set_storage(Handle< HeapObject > storage)
static TranslatedValue NewInvalid(TranslatedState *container)
static TranslatedValue NewSimd128(TranslatedState *container, Simd128 value)
static TranslatedValue NewInt32(TranslatedState *container, int32_t value)
MaterializationState materialization_state_
Tagged< Object > raw_literal() const
TranslatedValue(TranslatedState *container, Kind kind)
static TranslatedValue NewInt64(TranslatedState *container, int64_t value)
static TranslatedValue NewUint32(TranslatedState *container, uint32_t value)
MaterializationState materialization_state() const
MaterializedObjectInfo materialization_info_
static TranslatedValue NewFloat(TranslatedState *container, Float32 value)
static TranslatedValue NewStringConcat(TranslatedState *container, int id)
static TranslatedValue NewTagged(TranslatedState *container, Tagged< Object > literal)
static TranslatedValue NewDeferredObject(TranslatedState *container, int length, int object_index)
static TranslatedValue NewUint64(TranslatedState *container, uint64_t value)
static V8_INLINE Address DecompressTagged(TOnHeapAddress on_heap_addr, Tagged_t raw_value)
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
uint32_t count
int32_t offset
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
FunctionLiteral * literal
Definition liveedit.cc:294
RegListBase< RegisterT > registers
STL namespace.
static V ReadUnalignedValue(Address p)
Definition memory.h:28
T & Memory(Address addr)
Definition memory.h:18
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr int kIntSize
Definition globals.h:400
const int kNoWasmReturnKind
constexpr int kTaggedSize
Definition globals.h:542
bool TranslationOpcodeIsBegin(TranslationOpcode o)
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
bool DoubleToSmiInteger(double value, int *smi_int_value)
bool IsNumber(Tagged< Object > obj)
void PrintF(const char *format,...)
Definition utils.cc:39
bool IsSmiDouble(double value)
Tagged(T object) -> Tagged< T >
int TranslationOpcodeOperandCount(TranslationOpcode o)
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
constexpr int kSystemPointerSize
Definition globals.h:410
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
void DeoptimizationFrameTranslationPrintSingleOpcode(std::ostream &os, TranslationOpcode opcode, DeoptimizationFrameTranslation::Iterator &iterator, Tagged< ProtectedDeoptimizationLiteralArray > protected_literal_array, Tagged< DeoptimizationLiteralArray > literal_array)
V8_INLINE constexpr bool IsHeapObject(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:669
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr int JSParameterCount(int param_count_without_receiver)
Definition globals.h:2782
return value
Definition map-inl.h:893
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr ReleaseStoreTag kReleaseStore
Definition globals.h:2910
#define WRITE_FIELD(p, offset, value)
#define WRITE_BARRIER(object, offset, value)
#define INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value)
#define FATAL(...)
Definition logging.h:47
#define CHECK_GE(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define CHECK_GT(lhs, rhs)
#define CHECK_LT(lhs, rhs)
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define V8PRIuPTR
Definition macros.h:333
#define V8PRIdPTR
Definition macros.h:332
#define V8PRIxPTR_FMT
Definition macros.h:340
#define OFFSET_OF_DATA_START(Type)
#define V8_LIKELY(condition)
Definition v8config.h:661