v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
translated-state.h
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
5#ifndef V8_DEOPTIMIZER_TRANSLATED_STATE_H_
6#define V8_DEOPTIMIZER_TRANSLATED_STATE_H_
7
8#include <optional>
9#include <stack>
10#include <vector>
11
12#include "src/common/simd128.h"
19
20#if V8_ENABLE_WEBASSEMBLY
21#include "src/wasm/value-type.h"
22#endif // V8_ENABLE_WEBASSEMBLY
23
24namespace v8 {
25namespace internal {
26
27class DeoptimizationLiteral;
28class RegisterValues;
29class TranslatedState;
30
31// TODO(jgruber): This duplicates decoding logic already present in
32// TranslatedState/TranslatedFrame. Deduplicate into one class, e.g. by basing
33// printing off TranslatedFrame.
35 std::ostream& os, TranslationOpcode opcode,
36 DeoptimizationFrameTranslation::Iterator& iterator,
37 Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
39
40// The Translated{Value,Frame,State} class hierarchy are a set of utility
41// functions to work with the combination of translations (built from a
42// DeoptimizationFrameTranslation) and the actual current CPU state (represented
43// by RegisterValues).
44//
45// TranslatedState: describes the entire stack state of the current optimized
46// frame, contains:
47//
48// TranslatedFrame: describes a single unoptimized frame, contains:
49//
50// TranslatedValue: the actual value of some location.
51
53 public:
54 // Allocation-free getter of the value.
55 // Returns ReadOnlyRoots::arguments_marker() if allocation would be necessary
56 // to get the value. In the case of numbers, returns a Smi if possible.
58
59 // Convenience wrapper around GetRawValue (checked).
60 int GetSmiValue() const;
61
62 // Returns the value, possibly materializing it first (and the whole subgraph
63 // reachable from this value). In the case of numbers, returns a Smi if
64 // possible.
66
67 bool IsMaterializedObject() const;
68 bool IsMaterializableByDebugger() const;
69
70 private:
71 friend class TranslatedState;
72 friend class TranslatedFrame;
73 friend class Deoptimizer;
75
76 enum Kind : uint8_t {
90 kCapturedObject, // Object captured by the escape analysis.
91 // The number of nested objects can be obtained
92 // with the DeferredObjectLength() method
93 // (the values of the nested objects follow
94 // this value in the depth-first order.)
95 kDuplicatedObject, // Duplicated object of a deferred object.
97 };
98
99 enum MaterializationState : uint8_t {
101 kAllocated, // Storage for the object has been allocated (or
102 // enqueued for allocation).
103 kFinished, // The object has been initialized (or enqueued for
104 // initialization).
105 };
106
108 : kind_(kind), container_(container) {}
109 Kind kind() const { return kind_; }
113 void Handlify();
114 int GetChildrenCount() const;
115
117 int length, int object_index);
118 static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
119 static TranslatedValue NewStringConcat(TranslatedState* container, int id);
120 static TranslatedValue NewFloat(TranslatedState* container, Float32 value);
121 static TranslatedValue NewDouble(TranslatedState* container, Float64 value);
123 Float64 value);
124 static TranslatedValue NewSimd128(TranslatedState* container, Simd128 value);
125 static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
126 static TranslatedValue NewInt64(TranslatedState* container, int64_t value);
128 int64_t value);
130 uint64_t value);
131 static TranslatedValue NewUint32(TranslatedState* container, uint32_t value);
132 static TranslatedValue NewUint64(TranslatedState* container, uint64_t value);
133 static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
134 static TranslatedValue NewTagged(TranslatedState* container,
136 static TranslatedValue NewInvalid(TranslatedState* container);
137
138 Isolate* isolate() const;
139
144
149
151
154 TranslatedState* container_; // This is only needed for materialization of
155 // objects and constructing handles (to get
156 // to the isolate).
157
158 Handle<HeapObject> storage_; // Contains the materialized value or the
159 // byte-array that will be later morphed into
160 // the materialized object.
161
163 int id_;
164 int length_; // Applies only to kCapturedObject kinds.
165 };
166
167 union {
168 // kind kTagged. After handlification it is always nullptr.
170 // kind is kUInt32 or kBoolBit.
172 // kind is kInt32.
174 // kind is kUint64ToBigInt.
176 // kind is kInt64 or kInt64ToBigInt.
178 // kind is kFloat
180 // kind is kDouble or kHoleyDouble
182 // kind is kDuplicatedObject or kCapturedObject.
184 // kind is kSimd128.
186 };
187
188 // Checked accessors for the union members.
190 int32_t int32_value() const;
191 int64_t int64_value() const;
192 uint32_t uint32_value() const;
193 uint64_t uint64_value() const;
194 Float32 float_value() const;
195 Float64 double_value() const;
196 Simd128 simd_value() const;
197 int object_length() const;
198 int object_index() const;
199 // TODO(dmercadier): use object_index instead of string_concat_index.
201};
202
204 public:
205 enum Kind {
211#if V8_ENABLE_WEBASSEMBLY
212 kWasmInlinedIntoJS,
213 kJSToWasmBuiltinContinuation,
214 kLiftoffFunction,
215#endif // V8_ENABLE_WEBASSEMBLY
219 };
220
221 int GetValueCount() const;
222
223 Kind kind() const { return kind_; }
233
234 // TODO(jgruber): Simplify/clarify the semantics of this field. The name
235 // `height` is slightly misleading. Yes, this value is related to stack frame
236 // height, but must undergo additional mutations to arrive at the real stack
237 // frame height (e.g.: addition/subtraction of context, accumulator, fixed
238 // frame sizes, padding).
239 uint32_t height() const { return height_; }
240
247
253
259
260 class iterator {
261 public:
263 ++input_index_;
265 return *this;
266 }
267
270 ++input_index_;
272 return original;
273 }
274
275 bool operator==(const iterator& other) const {
276 // Ignore {input_index_} for equality.
277 return position_ == other.position_;
278 }
279 bool operator!=(const iterator& other) const { return !(*this == other); }
280
282 TranslatedValue* operator->() { return &(*position_); }
283 const TranslatedValue& operator*() const { return (*position_); }
284 const TranslatedValue* operator->() const { return &(*position_); }
285
286 int input_index() const { return input_index_; }
287
288 private:
290
291 explicit iterator(std::deque<TranslatedValue>::iterator position,
292 int input_index = 0)
294
295 std::deque<TranslatedValue>::iterator position_;
297 };
298
301
302 iterator begin() { return iterator(values_.begin()); }
303 iterator end() { return iterator(values_.end()); }
304
305 reference front() { return values_.front(); }
306 const_reference front() const { return values_.front(); }
307
308#if V8_ENABLE_WEBASSEMBLY
309 // Only for Kind == kJSToWasmBuiltinContinuation
310 std::optional<wasm::ValueKind> wasm_call_return_kind() const {
311 DCHECK_EQ(kind(), kJSToWasmBuiltinContinuation);
312 return return_kind_;
313 }
314
315 int wasm_function_index() const {
316 DCHECK_EQ(kind(), kLiftoffFunction);
317 return wasm_function_index_;
318 }
319#endif // V8_ENABLE_WEBASSEMBLY
320
321 private:
322 friend class TranslatedState;
323 friend class Deoptimizer;
324
325 // Constructor static methods.
334 uint32_t formal_parameter_count);
341 uint32_t height);
342#if V8_ENABLE_WEBASSEMBLY
343 static TranslatedFrame WasmInlinedIntoJSFrame(
345 uint32_t height);
346 static TranslatedFrame JSToWasmBuiltinContinuationFrame(
348 uint32_t height, std::optional<wasm::ValueKind> return_type);
349 static TranslatedFrame LiftoffFrame(BytecodeOffset bailout_id,
350 uint32_t height, uint32_t function_index);
351#endif // V8_ENABLE_WEBASSEMBLY
354 uint32_t height);
357 uint32_t height);
359 return TranslatedFrame(kInvalid, {}, {}, 0);
360 }
361
362 static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter);
363
376
377 void Add(const TranslatedValue& value) { values_.push_back(value); }
378 TranslatedValue* ValueAt(int index) { return &(values_[index]); }
379 void Handlify(Isolate* isolate);
380
383
384 // Object references are stored as either raw pointers (before Handlify is
385 // called) or handles (afterward).
386 union {
389 };
390 union {
393 };
394
395 uint32_t height_;
399
401
402 using ValuesContainer = std::deque<TranslatedValue>;
403
405
406#if V8_ENABLE_WEBASSEMBLY
407 // Only for Kind == kJSToWasmBuiltinContinuation
408 std::optional<wasm::ValueKind> return_kind_;
409 // Only for Kind == kLiftOffFunction
410 int wasm_function_index_ = -1;
411#endif // V8_ENABLE_WEBASSEMBLY
412};
413
415 public:
418
420 std::vector<DeoptimizationLiteral> literals);
421
423 // Prevent expensive copying.
426
427 TranslatedValue Get(TranslatedState* container, int literal_index) const;
428
433
434 private:
436 std::vector<DeoptimizationLiteral> literals_off_heap_;
437};
438
439// Auxiliary class for translating deoptimization values.
440// Typical usage sequence:
441//
442// 1. Construct the instance. This will involve reading out the translations
443// and resolving them to values using the supplied frame pointer and
444// machine state (registers). This phase is guaranteed not to allocate
445// and not to use any HandleScope. Any object pointers will be stored raw.
446//
447// 2. Handlify pointers. This will convert all the raw pointers to handles.
448//
449// 3. Reading out the frame values.
450//
451// Note: After the instance is constructed, it is possible to iterate over
452// the values eagerly.
453
455 public:
456 // There are two constructors, each for a different purpose:
457
458 // The default constructor is for the purpose of deoptimizing an optimized
459 // frame (replacing it with one or several unoptimized frames). It is used by
460 // the Deoptimizer.
462
463 // This constructor is for the purpose of merely inspecting an optimized
464 // frame. It is used by stack trace generation and various debugging features.
465 explicit TranslatedState(const JavaScriptFrame* frame);
466
467 void Prepare(Address stack_frame_pointer);
468
469 // Store newly materialized values into the isolate.
471
472 using iterator = std::vector<TranslatedFrame>::iterator;
473 iterator begin() { return frames_.begin(); }
474 iterator end() { return frames_.end(); }
475
476 using const_iterator = std::vector<TranslatedFrame>::const_iterator;
477 const_iterator begin() const { return frames_.begin(); }
478 const_iterator end() const { return frames_.end(); }
479
480 std::vector<TranslatedFrame>& frames() { return frames_; }
481
482 TranslatedFrame* GetFrameFromJSFrameIndex(int jsframe_index);
484 int* arguments_count);
485
486 Isolate* isolate() { return isolate_; }
487
488 void Init(Isolate* isolate, Address input_frame_pointer,
489 Address stack_frame_pointer, DeoptTranslationIterator* iterator,
490 Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
491 const DeoptimizationLiteralProvider& literal_array,
492 RegisterValues* registers, FILE* trace_file, int parameter_count,
493 int actual_argument_count);
494
496 bool DoUpdateFeedback();
497
498 private:
500
501 // See the description of the constructors for an explanation of the two
502 // purposes. The only actual difference is that in the kFrameInspection case
503 // extra work is needed to not violate assumptions made by left-trimming. For
504 // details, see the code around ReplaceElementsArrayWithCopy.
506
509 Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
510 const DeoptimizationLiteralProvider& literal_array, Address fp,
511 FILE* trace_file);
513 int frame_index, DeoptTranslationIterator* iterator,
514 const DeoptimizationLiteralProvider& literal_array, Address fp,
515 RegisterValues* registers, FILE* trace_file);
516 Address DecompressIfNeeded(intptr_t value);
517 void CreateArgumentsElementsTranslatedValues(int frame_index,
518 Address input_frame_pointer,
520 FILE* trace_file);
521
523 void MaterializeFixedDoubleArray(TranslatedFrame* frame, int* value_index,
524 TranslatedValue* slot,
526 void MaterializeHeapNumber(TranslatedFrame* frame, int* value_index,
527 TranslatedValue* slot);
528
530
531 void SkipSlots(int slots_to_skip, TranslatedFrame* frame, int* value_index);
532
538 int* value_index, std::stack<int>* worklist);
539 void EnsureCapturedObjectAllocatedAt(int object_index,
540 std::stack<int>* worklist);
542 void InitializeCapturedObjectAt(int object_index, std::stack<int>* worklist,
543 const DisallowGarbageCollection& no_gc);
544 void InitializeJSObjectAt(TranslatedFrame* frame, int* value_index,
546 const DisallowGarbageCollection& no_gc);
548 TranslatedFrame* frame, int* value_index, TranslatedValue* slot,
550
552
555 FILE* trace_file);
556
558 TranslatedValue* GetValueByObjectIndex(int object_index);
560 int* value_index);
561 TranslatedValue* GetResolvedSlot(TranslatedFrame* frame, int value_index);
563 int* value_index);
564
565 static uint32_t GetUInt32Slot(Address fp, int slot_index);
566 static uint64_t GetUInt64Slot(Address fp, int slot_index);
567 static Float32 GetFloatSlot(Address fp, int slot_index);
568 static Float64 GetDoubleSlot(Address fp, int slot_index);
569 static Simd128 getSimd128Slot(Address fp, int slot_index);
570
572 std::vector<TranslatedFrame> frames_;
573 Isolate* isolate_ = nullptr;
577
582 std::deque<ObjectPosition> object_positions_;
586};
587
588// Return kind encoding for a Wasm function returning void.
589const int kNoWasmReturnKind = -1;
590
591} // namespace internal
592} // namespace v8
593
594#endif // V8_DEOPTIMIZER_TRANSLATED_STATE_H_
int16_t parameter_count
Definition builtins.cc:67
static constexpr BytecodeOffset None()
Definition utils.h:675
DeoptimizationLiteralProvider(const DeoptimizationLiteralProvider &)=delete
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
void operator=(const DeoptimizationLiteralProvider &)=delete
bool operator==(const iterator &other) const
iterator(std::deque< TranslatedValue >::iterator position, int input_index=0)
std::deque< TranslatedValue >::iterator position_
bool operator!=(const iterator &other) const
const TranslatedValue * operator->() const
const TranslatedValue & operator*() 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
const_reference front() 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< BytecodeArray > raw_bytecode_array() const
Tagged< SharedFunctionInfo > raw_shared_info_
static TranslatedFrame InvalidFrame()
void Handlify(Isolate *isolate)
TranslatedValue const & const_reference
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)
static TranslatedFrame AccessorFrame(Kind kind, Tagged< SharedFunctionInfo > shared_info)
IndirectHandle< SharedFunctionInfo > shared_info_
Tagged< BytecodeArray > raw_bytecode_array_
std::deque< TranslatedValue > ValuesContainer
static TranslatedFrame JavaScriptBuiltinContinuationFrame(BytecodeOffset bailout_id, Tagged< SharedFunctionInfo > shared_info, uint32_t height)
static TranslatedFrame ConstructCreateStubFrame(Tagged< SharedFunctionInfo > shared_info, uint32_t height)
Tagged< SharedFunctionInfo > raw_shared_info() const
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)
const_iterator begin() const
std::vector< TranslatedFrame > & frames()
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)
std::vector< TranslatedFrame >::const_iterator const_iterator
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)
FunctionLiteral * literal
Definition liveedit.cc:294
int position
Definition liveedit.cc:290
RegListBase< RegisterT > registers
const int kNoWasmReturnKind
Tagged(T object) -> Tagged< T >
void DeoptimizationFrameTranslationPrintSingleOpcode(std::ostream &os, TranslationOpcode opcode, DeoptimizationFrameTranslation::Iterator &iterator, Tagged< ProtectedDeoptimizationLiteralArray > protected_literal_array, Tagged< DeoptimizationLiteralArray > literal_array)
static constexpr Address kNullAddress
Definition v8-internal.h:53
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485