#ifndef V8_OBJECTS_DEOPTIMIZATION_DATA_H_
#define V8_OBJECTS_DEOPTIMIZATION_DATA_H_
#include <vector>
#include "src/objects/bytecode-array.h"
#include "src/objects/fixed-array.h"
#include "src/utils/boxed-float.h"
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class DeoptimizationLiteralArray : public TrustedWeakFixedArray {
public:
inline Tagged<Object> get(int index) const;
inline Tagged<Object> get(PtrComprCageBase cage_base, int index) const;
inline Tagged<MaybeObject> get_raw(int index) const;
inline void set(int index, Tagged<Object> value);
};
using ProtectedDeoptimizationLiteralArray = ProtectedFixedArray;
enum class DeoptimizationLiteralKind : uint8_t {
kObject,
kNumber,
kSignedBigInt64,
kUnsignedBigInt64,
kHoleNaN,
kInvalid,
kWasmI31Ref,
kWasmInt32,
kWasmFloat32,
kWasmFloat64,
kWasmInt64 = kSignedBigInt64,
};
class DeoptimizationLiteral {
public:
DeoptimizationLiteral()
: kind_(DeoptimizationLiteralKind::kInvalid), object_() {}
explicit DeoptimizationLiteral(IndirectHandle<Object> object)
: kind_(DeoptimizationLiteralKind::kObject), object_(object) {
CHECK(!object_.is_null());
}
explicit DeoptimizationLiteral(Float32 number)
: kind_(DeoptimizationLiteralKind::kWasmFloat32), float32_(number) {}
explicit DeoptimizationLiteral(Float64 number)
: kind_(DeoptimizationLiteralKind::kWasmFloat64), float64_(number) {}
explicit DeoptimizationLiteral(double number)
: kind_(DeoptimizationLiteralKind::kNumber), number_(number) {}
explicit DeoptimizationLiteral(int64_t signed_bigint64)
: kind_(DeoptimizationLiteralKind::kSignedBigInt64),
int64_(signed_bigint64) {}
explicit DeoptimizationLiteral(uint64_t unsigned_bigint64)
: kind_(DeoptimizationLiteralKind::kUnsignedBigInt64),
uint64_(unsigned_bigint64) {}
explicit DeoptimizationLiteral(int32_t int32)
: kind_(DeoptimizationLiteralKind::kWasmInt32), int32_(int32) {}
explicit DeoptimizationLiteral(Tagged<Smi> smi)
: kind_(DeoptimizationLiteralKind::kWasmI31Ref), int32_(smi.value()) {}
static DeoptimizationLiteral HoleNaN() {
DeoptimizationLiteral literal;
literal.kind_ = DeoptimizationLiteralKind::kHoleNaN;
return literal;
}
IndirectHandle<Object> object() const { return object_; }
bool operator==(const DeoptimizationLiteral& other) const {
if (kind_ != other.kind_) {
return false;
}
switch (kind_) {
case DeoptimizationLiteralKind::kObject:
return object_.equals(other.object_);
case DeoptimizationLiteralKind::kNumber:
return base::bit_cast<uint64_t>(number_) ==
base::bit_cast<uint64_t>(other.number_);
case DeoptimizationLiteralKind::kWasmI31Ref:
case DeoptimizationLiteralKind::kWasmInt32:
return int32_ == other.int32_;
case DeoptimizationLiteralKind::kSignedBigInt64:
return int64_ == other.int64_;
case DeoptimizationLiteralKind::kUnsignedBigInt64:
return uint64_ == other.uint64_;
case DeoptimizationLiteralKind::kHoleNaN:
return other.kind() == DeoptimizationLiteralKind::kHoleNaN;
case DeoptimizationLiteralKind::kInvalid:
return true;
case DeoptimizationLiteralKind::kWasmFloat32:
return float32_.get_bits() == other.float32_.get_bits();
case DeoptimizationLiteralKind::kWasmFloat64:
return float64_.get_bits() == other.float64_.get_bits();
}
UNREACHABLE();
}
DirectHandle<Object> Reify(Isolate* isolate) const;
#if V8_ENABLE_WEBASSEMBLY
Float64 GetFloat64() const {
DCHECK_EQ(kind_, DeoptimizationLiteralKind::kWasmFloat64);
return float64_;
}
Float32 GetFloat32() const {
DCHECK_EQ(kind_, DeoptimizationLiteralKind::kWasmFloat32);
return float32_;
}
int64_t GetInt64() const {
DCHECK_EQ(kind_, DeoptimizationLiteralKind::kWasmInt64);
return int64_;
}
int32_t GetInt32() const {
DCHECK_EQ(kind_, DeoptimizationLiteralKind::kWasmInt32);
return int32_;
}
Tagged<Smi> GetSmi() const {
DCHECK_EQ(kind_, DeoptimizationLiteralKind::kWasmI31Ref);
return Smi::FromInt(int32_);
}
#endif
void Validate() const {
CHECK_NE(kind_, DeoptimizationLiteralKind::kInvalid);
}
DeoptimizationLiteralKind kind() const {
Validate();
return kind_;
}
size_t SerializationSize() const;
size_t Write(base::Vector<uint8_t>) const;
static size_t Read(base::Vector<const uint8_t>, DeoptimizationLiteral* out);
private:
DeoptimizationLiteralKind kind_;
union {
IndirectHandle<Object> object_;
double number_;
Float32 float32_;
Float64 float64_;
int32_t int32_;
int64_t int64_;
uint64_t uint64_;
};
};
enum class TranslationOpcode;
class DeoptimizationFrameTranslation : public TrustedByteArray {
public:
struct FrameCount {
int total_frame_count;
int js_frame_count;
};
class Iterator;
#ifdef V8_USE_ZLIB
static constexpr int kUncompressedSizeOffset = 0;
static constexpr int kUncompressedSizeSize = kInt32Size;
static constexpr int kCompressedDataOffset =
kUncompressedSizeOffset + kUncompressedSizeSize;
static constexpr int kDeoptimizationFrameTranslationElementSize = kInt32Size;
#endif
#ifdef ENABLE_DISASSEMBLER
void PrintFrameTranslation(
std::ostream& os, int index,
Tagged<ProtectedDeoptimizationLiteralArray> protected_literal_array,
Tagged<DeoptimizationLiteralArray> literal_array) const;
#endif
};
class DeoptTranslationIterator {
public:
DeoptTranslationIterator(base::Vector<const uint8_t> buffer, int index);
int32_t NextOperand();
uint32_t NextOperandUnsigned();
DeoptimizationFrameTranslation::FrameCount EnterBeginOpcode();
TranslationOpcode NextOpcode();
TranslationOpcode SeekNextJSFrame();
TranslationOpcode SeekNextFrame();
bool HasNextOpcode() const;
void SkipOperands(int n) {
for (int i = 0; i < n; i++) NextOperand();
}
private:
TranslationOpcode NextOpcodeAtPreviousIndex();
uint32_t NextUnsignedOperandAtPreviousIndex();
void SkipOpcodeAndItsOperandsAtPreviousIndex();
std::vector<int32_t> uncompressed_contents_;
const base::Vector<const uint8_t> buffer_;
int index_;
int remaining_ops_to_use_from_previous_translation_ = 0;
int previous_index_ = 0;
int ops_since_previous_index_was_updated_ = 0;
};
class DeoptimizationFrameTranslation::Iterator
: public DeoptTranslationIterator {
public:
Iterator(Tagged<DeoptimizationFrameTranslation> buffer, int index);
DisallowGarbageCollection no_gc_;
};
class DeoptimizationData : public ProtectedFixedArray {
public:
using SharedFunctionInfoWrapperOrSmi =
UnionOf<Smi, SharedFunctionInfoWrapper>;
static const int kFrameTranslationIndex = 0;
static const int kInlinedFunctionCountIndex = 1;
static const int kProtectedLiteralArrayIndex = 2;
static const int kLiteralArrayIndex = 3;
static const int kOsrBytecodeOffsetIndex = 4;
static const int kOsrPcOffsetIndex = 5;
static const int kOptimizationIdIndex = 6;
static const int kWrappedSharedFunctionInfoIndex = 7;
static const int kInliningPositionsIndex = 8;
static const int kDeoptExitStartIndex = 9;
static const int kEagerDeoptCountIndex = 10;
static const int kLazyDeoptCountIndex = 11;
static const int kFirstDeoptEntryIndex = 12;
static const int kBytecodeOffsetRawOffset = 0;
static const int kTranslationIndexOffset = 1;
static const int kPcOffset = 2;
#ifdef DEBUG
static const int kNodeIdOffset = 3;
static const int kDeoptEntrySize = 4;
#else
static const int kDeoptEntrySize = 3;
#endif
#define DECL_ELEMENT_ACCESSORS(name, type) \
inline type name() const; \
inline void Set##name(type value);
DECL_ELEMENT_ACCESSORS(FrameTranslation,
Tagged<DeoptimizationFrameTranslation>)
DECL_ELEMENT_ACCESSORS(InlinedFunctionCount, Tagged<Smi>)
DECL_ELEMENT_ACCESSORS(ProtectedLiteralArray,
Tagged<ProtectedDeoptimizationLiteralArray>)
DECL_ELEMENT_ACCESSORS(LiteralArray, Tagged<DeoptimizationLiteralArray>)
DECL_ELEMENT_ACCESSORS(OsrBytecodeOffset, Tagged<Smi>)
DECL_ELEMENT_ACCESSORS(OsrPcOffset, Tagged<Smi>)
DECL_ELEMENT_ACCESSORS(OptimizationId, Tagged<Smi>)
DECL_ELEMENT_ACCESSORS(WrappedSharedFunctionInfo,
Tagged<SharedFunctionInfoWrapperOrSmi>)
DECL_ELEMENT_ACCESSORS(InliningPositions,
Tagged<TrustedPodArray<InliningPosition>>)
DECL_ELEMENT_ACCESSORS(DeoptExitStart, Tagged<Smi>)
DECL_ELEMENT_ACCESSORS(EagerDeoptCount, Tagged<Smi>)
DECL_ELEMENT_ACCESSORS(LazyDeoptCount, Tagged<Smi>)
#undef DECL_ELEMENT_ACCESSORS
inline Tagged<SharedFunctionInfo> GetSharedFunctionInfo() const;
#define DECL_ENTRY_ACCESSORS(name, type) \
inline type name(int i) const; \
inline void Set##name(int i, type value);
DECL_ENTRY_ACCESSORS(BytecodeOffsetRaw, Tagged<Smi>)
DECL_ENTRY_ACCESSORS(TranslationIndex, Tagged<Smi>)
DECL_ENTRY_ACCESSORS(Pc, Tagged<Smi>)
#ifdef DEBUG
DECL_ENTRY_ACCESSORS(NodeId, Tagged<Smi>)
#endif
#undef DECL_ENTRY_ACCESSORS
inline BytecodeOffset GetBytecodeOffsetOrBuiltinContinuationId(int i) const;
inline void SetBytecodeOffset(int i, BytecodeOffset value);
inline int DeoptCount() const;
static const int kNotInlinedIndex = -1;
Tagged<SharedFunctionInfo> GetInlinedFunction(int index);
static Handle<DeoptimizationData> New(Isolate* isolate,
int deopt_entry_count);
static Handle<DeoptimizationData> New(LocalIsolate* isolate,
int deopt_entry_count);
V8_EXPORT_PRIVATE static Handle<DeoptimizationData> Empty(Isolate* isolate);
V8_EXPORT_PRIVATE static Handle<DeoptimizationData> Empty(
LocalIsolate* isolate);
#ifdef DEBUG
void Verify(Handle<BytecodeArray> bytecode) const;
#endif
#ifdef ENABLE_DISASSEMBLER
void PrintDeoptimizationData(std::ostream& os) const;
#endif
private:
static int IndexForEntry(int i) {
return kFirstDeoptEntryIndex + (i * kDeoptEntrySize);
}
static int LengthFor(int entry_count) { return IndexForEntry(entry_count); }
};
}
}
#include "src/objects/object-macros-undef.h"
#endif