#ifndef V8_OBJECTS_STRING_H_
#define V8_OBJECTS_STRING_H_
#include <memory>
#include <optional>
#include "src/base/bits.h"
#include "src/base/export-template.h"
#include "src/base/small-vector.h"
#include "src/base/strings.h"
#include "src/common/globals.h"
#include "src/heap/heap.h"
#include "src/objects/instance-type.h"
#include "src/objects/map.h"
#include "src/objects/name.h"
#include "src/objects/smi.h"
#include "src/objects/tagged.h"
#include "src/sandbox/external-pointer.h"
#include "src/strings/unicode-decoder.h"
#include "third_party/simdutf/simdutf.h"
#include "src/objects/object-macros.h"
namespace v8::internal {
namespace maglev {
class CheckedInternalizedString;
class BuiltinStringFromCharCode;
class MaglevGraphBuilder;
class VirtualObject;
struct VirtualStringShape;
}
namespace wasm {
namespace baseline {
class LiftoffCompiler;
}
}
class SharedStringAccessGuardIfNeeded;
enum InstanceType : uint16_t;
class StringShape {
public:
V8_INLINE explicit StringShape(const Tagged<String> s);
V8_INLINE explicit StringShape(Tagged<Map> s);
V8_INLINE bool IsOneByte() const;
V8_INLINE bool IsTwoByte() const;
V8_INLINE bool IsSequential() const;
V8_INLINE bool IsExternal() const;
V8_INLINE bool IsCons() const;
V8_INLINE bool IsSliced() const;
V8_INLINE bool IsThin() const;
V8_INLINE bool IsDirect() const;
V8_INLINE bool IsIndirect() const;
V8_INLINE bool IsUncachedExternal() const;
V8_INLINE bool IsExternalOneByte() const;
V8_INLINE bool IsExternalTwoByte() const;
V8_INLINE bool IsSequentialOneByte() const;
V8_INLINE bool IsSequentialTwoByte() const;
V8_INLINE bool IsInternalized() const;
V8_INLINE bool IsShared() const;
#ifdef DEBUG
inline void invalidate() { valid_ = false; }
inline bool valid() const { return valid_; }
#else
inline void invalidate() {}
#endif
template <typename TDispatcher>
V8_INLINE auto DispatchToSpecificType(Tagged<String> str,
TDispatcher&& dispatcher) const;
#ifdef DEBUG
inline bool IsValidFor(Tagged<String> string) const;
#endif
private:
#if V8_STATIC_ROOTS_BOOL
inline Tagged<Map> map_or_type() const;
Tagged<Map> map_;
#else
inline InstanceType map_or_type() const { return type_; }
InstanceType type_;
#endif
#ifdef DEBUG
inline void set_valid() { valid_ = true; }
bool valid_;
#else
inline void set_valid() {}
#endif
};
V8_OBJECT class String : public Name {
public:
enum Encoding { ONE_BYTE_ENCODING, TWO_BYTE_ENCODING };
V8_OBJECT_INNER_CLASS class FlatContent {
public:
inline ~FlatContent();
bool IsFlat() const { return state_ != NON_FLAT; }
bool IsOneByte() const { return state_ == ONE_BYTE; }
bool IsTwoByte() const { return state_ == TWO_BYTE; }
base::Vector<const uint8_t> ToOneByteVector() const {
DCHECK_EQ(ONE_BYTE, state_);
return base::Vector<const uint8_t>(onebyte_start, length_);
}
base::Vector<const base::uc16> ToUC16Vector() const {
DCHECK_EQ(TWO_BYTE, state_);
return base::Vector<const base::uc16>(twobyte_start, length_);
}
base::uc16 Get(uint32_t i) const {
DCHECK(i < length_);
DCHECK(state_ != NON_FLAT);
if (state_ == ONE_BYTE) return onebyte_start[i];
return twobyte_start[i];
}
bool UsesSameString(const FlatContent& other) const {
return onebyte_start == other.onebyte_start;
}
void UnsafeDisableChecksumVerification() {
#ifdef ENABLE_SLOW_DCHECKS
checksum_ = kChecksumVerificationDisabled;
#endif
}
uint32_t length() const { return length_; }
private:
enum State { NON_FLAT, ONE_BYTE, TWO_BYTE };
inline FlatContent(const uint8_t* start, uint32_t length,
const DisallowGarbageCollection& no_gc);
inline FlatContent(const base::uc16* start, uint32_t length,
const DisallowGarbageCollection& no_gc);
explicit FlatContent(const DisallowGarbageCollection& no_gc)
: onebyte_start(nullptr), length_(0), state_(NON_FLAT), no_gc_(no_gc) {}
union {
const uint8_t* onebyte_start;
const base::uc16* twobyte_start;
};
uint32_t length_;
State state_;
const DisallowGarbageCollection& no_gc_;
static constexpr uint32_t kChecksumVerificationDisabled = 0;
#ifdef ENABLE_SLOW_DCHECKS
inline uint32_t ComputeChecksum() const;
uint32_t checksum_;
#endif
friend class String;
friend class IterableSubString;
} V8_OBJECT_INNER_CLASS_END;
template <typename IsolateT>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void MakeThin(IsolateT* isolate, Tagged<String> canonical);
template <typename Char>
V8_INLINE base::Vector<const Char> GetCharVector(
const DisallowGarbageCollection& no_gc);
template <typename Char>
inline const Char* GetDirectStringChars(
const DisallowGarbageCollection& no_gc) const;
template <typename Char>
inline const Char* GetDirectStringChars(
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) const;
const uint8_t* AddressOfCharacterAt(uint32_t start_index,
const DisallowGarbageCollection& no_gc);
inline uint32_t length() const;
inline uint32_t length(AcquireLoadTag) const;
inline void set_length(uint32_t hash);
inline void set_length(uint32_t hash, ReleaseStoreTag);
inline bool IsOneByteRepresentation() const;
inline bool IsTwoByteRepresentation() const;
static inline bool IsOneByteRepresentationUnderneath(Tagged<String> string);
inline void Set(uint32_t index, uint16_t value);
V8_INLINE uint16_t Get(uint32_t index) const;
V8_INLINE uint16_t Get(uint32_t index, Isolate* isolate) const;
V8_INLINE uint16_t Get(uint32_t index, LocalIsolate* local_isolate) const;
V8_INLINE uint16_t
Get(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<String>, DirectHandle<String>>)
static HandleType<Number> ToNumber(Isolate* isolate,
HandleType<String> subject);
template <typename T, template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<T>, DirectHandle<String>>)
static V8_INLINE HandleType<String> Flatten(
Isolate* isolate, HandleType<T> string,
AllocationType allocation = AllocationType::kYoung);
template <typename T, template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<T>, DirectHandle<String>>)
static V8_INLINE HandleType<String> Flatten(
LocalIsolate* isolate, HandleType<T> string,
AllocationType allocation = AllocationType::kYoung);
V8_EXPORT_PRIVATE V8_INLINE FlatContent
GetFlatContent(const DisallowGarbageCollection& no_gc);
V8_EXPORT_PRIVATE V8_INLINE FlatContent
GetFlatContent(const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded&);
inline Tagged<String> GetUnderlying() const;
template <typename T, template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<T>, DirectHandle<String>>)
static inline HandleType<String> Share(Isolate* isolate,
HandleType<T> string);
V8_WARN_UNUSED_RESULT static ComparisonResult Compare(Isolate* isolate,
DirectHandle<String> x,
DirectHandle<String> y);
static Tagged<Object> IndexOf(Isolate* isolate, DirectHandle<Object> receiver,
DirectHandle<Object> search,
DirectHandle<Object> position);
static int IndexOf(Isolate* isolate, DirectHandle<String> receiver,
DirectHandle<String> search, uint32_t start_index);
static Tagged<Object> LastIndexOf(Isolate* isolate,
DirectHandle<Object> receiver,
DirectHandle<Object> search,
DirectHandle<Object> position);
class Match {
public:
virtual DirectHandle<String> GetMatch() = 0;
virtual DirectHandle<String> GetPrefix() = 0;
virtual DirectHandle<String> GetSuffix() = 0;
enum CaptureState { UNMATCHED, MATCHED };
virtual int CaptureCount() = 0;
virtual bool HasNamedCaptures() = 0;
virtual MaybeDirectHandle<String> GetCapture(int i,
bool* capture_exists) = 0;
virtual MaybeDirectHandle<String> GetNamedCapture(DirectHandle<String> name,
CaptureState* state) = 0;
virtual ~Match() = default;
};
V8_WARN_UNUSED_RESULT static MaybeDirectHandle<String> GetSubstitution(
Isolate* isolate, Match* match, DirectHandle<String> replacement,
uint32_t start_index = 0);
inline bool Equals(Tagged<String> other) const;
inline static bool Equals(Isolate* isolate, DirectHandle<String> one,
DirectHandle<String> two);
enum class EqualityType { kWholeString, kPrefix, kNoLengthCheck };
template <EqualityType kEqType = EqualityType::kWholeString, typename Char>
inline bool IsEqualTo(base::Vector<const Char> str, Isolate* isolate) const;
template <EqualityType kEqType = EqualityType::kWholeString>
inline bool IsEqualTo(std::string_view str, Isolate* isolate) const;
template <EqualityType kEqType = EqualityType::kWholeString, typename Char>
inline bool IsEqualTo(base::Vector<const Char> str) const;
template <EqualityType kEqType = EqualityType::kWholeString, typename Char>
inline bool IsEqualTo(base::Vector<const Char> str,
LocalIsolate* isolate) const;
V8_EXPORT_PRIVATE bool HasOneBytePrefix(base::Vector<const char> str);
V8_EXPORT_PRIVATE inline bool IsOneByteEqualTo(base::Vector<const char> str);
static bool IsIdentifier(Isolate* isolate, DirectHandle<String> str);
std::unique_ptr<char[]> ToCString(uint32_t offset, uint32_t length,
size_t* length_output = nullptr);
V8_EXPORT_PRIVATE std::unique_ptr<char[]> ToCString(
size_t* length_output = nullptr);
V8_EXPORT_PRIVATE std::string ToStdString();
template <typename T>
bool MarkForExternalizationDuringGC(Isolate* isolate, T* resource);
template <typename T>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void MakeExternalDuringGC(Isolate* isolate, T* resource);
V8_EXPORT_PRIVATE bool MakeExternal(
Isolate* isolate, v8::String::ExternalStringResource* resource);
V8_EXPORT_PRIVATE bool MakeExternal(
Isolate* isolate, v8::String::ExternalOneByteStringResource* resource);
V8_EXPORT_PRIVATE bool SupportsExternalization(v8::String::Encoding);
inline bool AsArrayIndex(uint32_t* index);
static int32_t ToArrayIndex(Address addr);
inline bool AsIntegerIndex(size_t* index);
enum TrimMode { kTrim, kTrimStart, kTrimEnd };
V8_EXPORT_PRIVATE void PrintOn(FILE* out);
V8_EXPORT_PRIVATE void PrintOn(std::ostream& out);
const char* PrefixForDebugPrint() const;
const char* SuffixForDebugPrint() const;
void StringShortPrint(StringStream* accumulator);
void PrintUC16(std::ostream& os, int start = 0, int end = -1);
void PrintUC16(StringStream* accumulator, int start, int end);
#if defined(DEBUG) || defined(OBJECT_PRINT)
char* ToAsciiArray();
#endif
DECL_PRINTER(String)
DECL_VERIFIER(String)
inline bool IsFlat() const;
inline bool IsShared() const;
static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar;
static const int kMaxUtf16CodeUnit = 0xffff;
static const uint32_t kMaxUtf16CodeUnitU = kMaxUtf16CodeUnit;
static const base::uc32 kMaxCodePoint = 0x10ffff;
static const uint32_t kMaxLength = v8::String::kMaxLength;
static const uint32_t kMaxHashCalcLength = 16383;
static const uint32_t kMaxShortPrintLength = 1024;
template <typename SinkCharT>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
static void WriteToFlat(Tagged<String> source, SinkCharT* sink,
uint32_t start, uint32_t length);
template <typename SinkCharT>
static void WriteToFlat(Tagged<String> source, SinkCharT* sink,
uint32_t start, uint32_t length,
const SharedStringAccessGuardIfNeeded& access_guard);
template <typename SinkCharT>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
static void WriteToFlat2(SinkCharT* dst, Tagged<ConsString> src,
uint32_t src_index, uint32_t length,
const SharedStringAccessGuardIfNeeded& aguard,
const DisallowGarbageCollection& no_gc);
static inline size_t Utf8Length(Isolate* isolate,
DirectHandle<String> string);
enum class Utf8EncodingFlag {
kNoFlags = 0,
kNullTerminate = 1u << 0,
kReplaceInvalid = 1u << 1,
};
using Utf8EncodingFlags = base::Flags<Utf8EncodingFlag>;
static size_t WriteUtf8(Isolate* isolate, DirectHandle<String> string,
char* buffer, size_t capacity,
Utf8EncodingFlags flags,
size_t* processed_characters_return = nullptr);
static inline bool IsWellFormedUnicode(Isolate* isolate,
DirectHandle<String> string);
static inline bool IsAscii(const char* chars, uint32_t length) {
return simdutf::validate_ascii(chars, length);
}
static inline bool IsAscii(const uint8_t* chars, uint32_t length) {
return simdutf::validate_ascii(reinterpret_cast<const char*>(chars),
length);
}
static bool DoesNotContainEscapeCharacters(Tagged<String> string);
static inline uint32_t NonOneByteStart(const base::uc16* chars,
uint32_t length) {
DCHECK(IsAligned(reinterpret_cast<Address>(chars), sizeof(base::uc16)));
const uint16_t* start = chars;
const uint16_t* limit = chars + length;
if (static_cast<size_t>(length) >= kUIntptrSize) {
while (!IsAligned(reinterpret_cast<Address>(chars), kUIntptrSize)) {
if (*chars > unibrow::Latin1::kMaxChar) {
return static_cast<uint32_t>(chars - start);
}
++chars;
}
static_assert(unibrow::Latin1::kMaxChar == 0xFF);
#ifdef V8_TARGET_LITTLE_ENDIAN
const uintptr_t non_one_byte_mask = kUintptrAllBitsSet / 0xFFFF * 0xFF00;
#else
const uintptr_t non_one_byte_mask = kUintptrAllBitsSet / 0xFFFF * 0x00FF;
#endif
while (chars + sizeof(uintptr_t) <= limit) {
if (*reinterpret_cast<const uintptr_t*>(chars) & non_one_byte_mask) {
break;
}
chars += (sizeof(uintptr_t) / sizeof(base::uc16));
}
}
while (chars < limit) {
if (*chars > unibrow::Latin1::kMaxChar) {
return static_cast<uint32_t>(chars - start);
}
++chars;
}
return static_cast<uint32_t>(chars - start);
}
static inline bool IsOneByte(const base::uc16* chars, uint32_t length) {
return NonOneByteStart(chars, length) >= length;
}
template <class Visitor>
static inline Tagged<ConsString> VisitFlat(Visitor* visitor,
Tagged<String> string,
int offset = 0);
template <class Visitor>
static inline Tagged<ConsString> VisitFlat(
Visitor* visitor, Tagged<String> string, int offset,
const SharedStringAccessGuardIfNeeded& access_guard);
static uint32_t constexpr kInlineLineEndsSize = 32;
using LineEndsVector = base::SmallVector<int32_t, kInlineLineEndsSize>;
template <typename IsolateT>
static LineEndsVector CalculateLineEndsVector(IsolateT* isolate,
DirectHandle<String> string,
bool include_ending_line);
template <typename IsolateT>
static Handle<FixedArray> CalculateLineEnds(IsolateT* isolate,
DirectHandle<String> string,
bool include_ending_line);
static inline bool IsInPlaceInternalizable(Tagged<String> string);
static inline bool IsInPlaceInternalizable(InstanceType instance_type);
static inline bool IsInPlaceInternalizableExcludingExternal(
InstanceType instance_type);
template <typename TDispatcher>
V8_INLINE auto DispatchToSpecificType(TDispatcher&& dispatcher) const;
template <typename TDispatcher, typename... TArgs>
static inline auto DispatchToSpecificTypeWithoutCast(
InstanceType instance_type, TArgs&&... args);
private:
friend class Name;
friend class CodeStubAssembler;
friend class StringTableInsertionKey;
friend class SharedStringTableInsertionKey;
friend class SandboxTesting;
friend class InternalizedStringKey;
friend struct OffsetsForDebug;
friend class Accessors;
friend class StringBuiltinsAssembler;
friend class maglev::MaglevAssembler;
friend class maglev::MaglevGraphBuilder;
friend struct maglev::VirtualStringShape;
friend class compiler::AccessBuilder;
friend class wasm::baseline::LiftoffCompiler;
friend class TorqueGeneratedStringAsserts;
V8_INLINE uint16_t
GetImpl(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
template <EqualityType kEqType, typename Char>
V8_INLINE bool IsEqualToImpl(
base::Vector<const Char> str,
const SharedStringAccessGuardIfNeeded& access_guard) const;
template <typename Char>
V8_NOINLINE static bool IsConsStringEqualToImpl(
Tagged<ConsString> string, base::Vector<const Char> str,
const SharedStringAccessGuardIfNeeded& access_guard);
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<String>, DirectHandle<String>>)
V8_EXPORT_PRIVATE inline static HandleType<String> SlowFlatten(
Isolate* isolate, HandleType<ConsString> cons, AllocationType allocation);
V8_EXPORT_PRIVATE V8_INLINE static std::optional<FlatContent>
TryGetFlatContentFromDirectString(const DisallowGarbageCollection& no_gc,
Tagged<String> string, uint32_t offset,
uint32_t length,
const SharedStringAccessGuardIfNeeded&);
V8_EXPORT_PRIVATE FlatContent
SlowGetFlatContent(const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded&);
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<String>, DirectHandle<String>>)
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) static HandleType<
String> SlowShare(Isolate* isolate, HandleType<String> source);
V8_EXPORT_PRIVATE bool SlowEquals(Tagged<String> other) const;
V8_EXPORT_PRIVATE bool SlowEquals(
Tagged<String> other, const SharedStringAccessGuardIfNeeded&) const;
V8_EXPORT_PRIVATE bool SlowEqualsNonThinSameLength(
uint32_t len, Tagged<String> other) const;
V8_EXPORT_PRIVATE bool SlowEqualsNonThinSameLength(
uint32_t len, Tagged<String> other,
const SharedStringAccessGuardIfNeeded&) const;
V8_EXPORT_PRIVATE static bool SlowEquals(Isolate* isolate,
DirectHandle<String> one,
DirectHandle<String> two);
V8_EXPORT_PRIVATE bool SlowAsArrayIndex(uint32_t* index);
V8_EXPORT_PRIVATE bool SlowAsIntegerIndex(size_t* index);
V8_EXPORT_PRIVATE uint32_t ComputeAndSetRawHash();
V8_EXPORT_PRIVATE uint32_t
ComputeAndSetRawHash(const SharedStringAccessGuardIfNeeded&);
public:
uint32_t length_;
} V8_OBJECT_END;
template <>
struct ObjectTraits<String> {
static constexpr int kHeaderSize = sizeof(String);
static_assert(String::kMaxLength <= kSmiMaxValue,
"String length must fit into a Smi");
static_assert(String::kMaxLength * 2 <= kMaxInt,
"String::kMaxLength * 2 must fit into an int32");
static_assert(String::kMaxLength * 2 + kHeaderSize <= kSmiMaxValue,
"String object size in bytes must fit into a Smi");
static_assert(String::kMaxLength * 2 + kHeaderSize <= kMaxInt,
"String object size in bytes must fit into an int");
};
extern template EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void String::WriteToFlat(Tagged<String> source, uint8_t* sink, uint32_t from,
uint32_t to);
extern template EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void String::WriteToFlat(Tagged<String> source, uint16_t* sink, uint32_t from,
uint32_t to);
extern template EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void String::WriteToFlat(Tagged<String> source, uint8_t* sink, uint32_t from,
uint32_t to, const SharedStringAccessGuardIfNeeded&);
extern template EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void String::WriteToFlat(Tagged<String> source, uint16_t* sink, uint32_t from,
uint32_t to, const SharedStringAccessGuardIfNeeded&);
class SubStringRange {
public:
inline SubStringRange(Tagged<String> string,
const DisallowGarbageCollection& no_gc, int first = 0,
int length = -1);
class iterator;
inline iterator begin();
inline iterator end();
private:
Tagged<String> string_;
int first_;
int length_;
const DisallowGarbageCollection& no_gc_;
};
class SeqString : public String {
public:
V8_WARN_UNUSED_RESULT static Handle<String> Truncate(Isolate* isolate,
Handle<SeqString> string,
uint32_t new_length);
struct DataAndPaddingSizes {
const int data_size;
const int padding_size;
bool operator==(const DataAndPaddingSizes& other) const {
return data_size == other.data_size && padding_size == other.padding_size;
}
};
DataAndPaddingSizes GetDataAndPaddingSizes() const;
void ClearPadding();
EXPORT_DECL_VERIFIER(SeqString)
};
V8_OBJECT class InternalizedString : public String {
} V8_OBJECT_END;
V8_OBJECT class SeqOneByteString : public SeqString {
public:
static const bool kHasOneByteEncoding = true;
using Char = uint8_t;
V8_INLINE static constexpr int32_t DataSizeFor(int32_t length);
V8_INLINE static constexpr int32_t SizeFor(int32_t length);
inline uint8_t Get(uint32_t index) const;
inline uint8_t Get(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
inline void SeqOneByteStringSet(uint32_t index, uint16_t value);
inline void SeqOneByteStringSetChars(uint32_t index, const uint8_t* string,
uint32_t length);
inline Address GetCharsAddress() const;
V8_INLINE uint8_t* GetChars(const DisallowGarbageCollection& no_gc);
V8_INLINE uint8_t* GetChars(
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard);
DataAndPaddingSizes GetDataAndPaddingSizes() const;
inline void clear_padding_destructively(uint32_t length);
static const uint32_t kMaxCharsSize = kMaxLength;
inline int AllocatedSize() const;
static inline bool IsCompatibleMap(Tagged<Map> map, ReadOnlyRoots roots);
class BodyDescriptor;
private:
friend struct OffsetsForDebug;
friend class CodeStubAssembler;
friend class ToDirectStringAssembler;
friend class IntlBuiltinsAssembler;
friend class StringBuiltinsAssembler;
friend class StringFromCharCodeAssembler;
friend class SandboxTesting;
friend class maglev::MaglevAssembler;
friend class compiler::AccessBuilder;
friend class TorqueGeneratedSeqOneByteStringAsserts;
FLEXIBLE_ARRAY_MEMBER(Char, chars);
} V8_OBJECT_END;
template <>
struct ObjectTraits<SeqOneByteString> {
using BodyDescriptor = SeqOneByteString::BodyDescriptor;
static constexpr int kHeaderSize = sizeof(SeqOneByteString);
static constexpr int kMaxSize =
OBJECT_POINTER_ALIGN(SeqOneByteString::kMaxCharsSize + kHeaderSize);
static_assert(static_cast<int>((kMaxSize - kHeaderSize) /
sizeof(SeqOneByteString::Char)) >=
String::kMaxLength);
};
V8_OBJECT class SeqTwoByteString : public SeqString {
public:
static const bool kHasOneByteEncoding = false;
using Char = uint16_t;
V8_INLINE static constexpr int32_t DataSizeFor(int32_t length);
V8_INLINE static constexpr int32_t SizeFor(int32_t length);
inline uint16_t Get(
uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
inline void SeqTwoByteStringSet(uint32_t index, uint16_t value);
inline Address GetCharsAddress() const;
inline base::uc16* GetChars(const DisallowGarbageCollection& no_gc);
inline base::uc16* GetChars(
const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard);
DataAndPaddingSizes GetDataAndPaddingSizes() const;
inline void clear_padding_destructively(uint32_t length);
static const uint32_t kMaxCharsSize = kMaxLength * sizeof(Char);
inline int AllocatedSize() const;
static inline bool IsCompatibleMap(Tagged<Map> map, ReadOnlyRoots roots);
class BodyDescriptor;
private:
friend struct OffsetsForDebug;
friend class CodeStubAssembler;
friend class ToDirectStringAssembler;
friend class IntlBuiltinsAssembler;
friend class StringBuiltinsAssembler;
friend class StringFromCharCodeAssembler;
friend class maglev::MaglevAssembler;
friend class maglev::BuiltinStringFromCharCode;
friend class compiler::AccessBuilder;
friend class TorqueGeneratedSeqTwoByteStringAsserts;
FLEXIBLE_ARRAY_MEMBER(Char, chars);
} V8_OBJECT_END;
template <>
struct ObjectTraits<SeqTwoByteString> {
using BodyDescriptor = SeqTwoByteString::BodyDescriptor;
static constexpr int kHeaderSize = sizeof(SeqTwoByteString);
static constexpr int kMaxSize =
OBJECT_POINTER_ALIGN(SeqTwoByteString::kMaxCharsSize + kHeaderSize);
static_assert(static_cast<int>((kMaxSize - kHeaderSize) /
sizeof(SeqTwoByteString::Char)) >=
String::kMaxLength);
};
V8_OBJECT class ConsString : public String {
public:
inline Tagged<String> first() const;
inline void set_first(Tagged<String> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Tagged<String> second() const;
inline void set_second(Tagged<String> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Tagged<Object> unchecked_first() const;
inline Tagged<Object> unchecked_second() const;
V8_INLINE bool IsFlat() const;
V8_EXPORT_PRIVATE uint16_t
Get(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
void PrintTree();
static const uint32_t kMinLength = 13;
static const int kFirstOffset;
static const int kSecondOffset;
DECL_VERIFIER(ConsString)
private:
friend struct ObjectTraits<ConsString>;
friend struct OffsetsForDebug;
friend class V8HeapExplorer;
friend class CodeStubAssembler;
friend class ToDirectStringAssembler;
friend class StringBuiltinsAssembler;
friend class SandboxTesting;
friend class maglev::MaglevAssembler;
friend class maglev::MaglevGraphBuilder;
friend class maglev::VirtualObject;
friend class compiler::AccessBuilder;
friend class TorqueGeneratedConsStringAsserts;
friend Tagged<String> String::GetUnderlying() const;
TaggedMember<String> first_;
TaggedMember<String> second_;
} V8_OBJECT_END;
constexpr int ConsString::kFirstOffset = offsetof(ConsString, first_);
constexpr int ConsString::kSecondOffset = offsetof(ConsString, second_);
template <>
struct ObjectTraits<ConsString> {
using BodyDescriptor =
FixedBodyDescriptor<offsetof(ConsString, first_), sizeof(ConsString),
sizeof(ConsString)>;
};
V8_OBJECT class ThinString : public String {
public:
inline Tagged<String> actual() const;
inline void set_actual(Tagged<String> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Tagged<HeapObject> unchecked_actual() const;
V8_EXPORT_PRIVATE uint16_t
Get(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
DECL_VERIFIER(ThinString)
private:
friend struct ObjectTraits<ThinString>;
friend struct OffsetsForDebug;
friend class V8HeapExplorer;
friend class CodeStubAssembler;
friend class ToDirectStringAssembler;
friend class CollectionsBuiltinsAssembler;
friend class StringBuiltinsAssembler;
friend class maglev::MaglevAssembler;
friend class maglev::CheckedInternalizedString;
friend class compiler::AccessBuilder;
friend class FullStringForwardingTableCleaner;
friend class TorqueGeneratedThinStringAsserts;
friend Tagged<String> String::GetUnderlying() const;
TaggedMember<String> actual_;
} V8_OBJECT_END;
template <>
struct ObjectTraits<ThinString> {
using BodyDescriptor =
FixedBodyDescriptor<offsetof(ThinString, actual_), sizeof(ThinString),
sizeof(ThinString)>;
};
V8_OBJECT class SlicedString : public String {
public:
inline Tagged<String> parent() const;
inline void set_parent(Tagged<String> parent,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline int32_t offset() const;
inline void set_offset(int32_t offset);
V8_EXPORT_PRIVATE uint16_t
Get(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
static const uint32_t kMinLength = 13;
DECL_VERIFIER(SlicedString)
private:
friend struct ObjectTraits<SlicedString>;
friend struct OffsetsForDebug;
friend class V8HeapExplorer;
friend class CodeStubAssembler;
friend class SandboxTesting;
friend class ToDirectStringAssembler;
friend class maglev::MaglevAssembler;
friend class compiler::AccessBuilder;
friend class TorqueGeneratedSlicedStringAsserts;
friend Tagged<String> String::GetUnderlying() const;
TaggedMember<String> parent_;
TaggedMember<Smi> offset_;
} V8_OBJECT_END;
template <>
struct ObjectTraits<SlicedString> {
using BodyDescriptor =
FixedBodyDescriptor<offsetof(SlicedString, parent_), sizeof(SlicedString),
sizeof(SlicedString)>;
};
V8_OBJECT class UncachedExternalString : public String {
protected:
ExternalPointerMember<kExternalStringResourceTag> resource_;
} V8_OBJECT_END;
V8_OBJECT class ExternalString : public UncachedExternalString {
public:
class BodyDescriptor;
DECL_VERIFIER(ExternalString)
inline void InitExternalPointerFields(Isolate* isolate);
inline void VisitExternalPointers(ObjectVisitor* visitor);
inline bool is_uncached() const;
int ExternalPayloadSize() const;
inline Address resource_as_address() const;
inline void set_address_as_resource(Isolate* isolate, Address address);
inline uint32_t GetResourceRefForDeserialization();
inline void SetResourceRefForSerialization(uint32_t ref);
inline void DisposeResource(Isolate* isolate);
void InitExternalPointerFieldsDuringExternalization(Tagged<Map> new_map,
Isolate* isolate);
private:
friend ObjectTraits<ExternalString>;
friend struct OffsetsForDebug;
friend class CodeStubAssembler;
friend class compiler::AccessBuilder;
friend class TorqueGeneratedExternalStringAsserts;
protected:
ExternalPointerMember<kExternalStringResourceDataTag> resource_data_;
} V8_OBJECT_END;
template <>
struct ObjectTraits<ExternalString> {
using BodyDescriptor = ExternalString::BodyDescriptor;
static_assert(offsetof(ExternalString, resource_) ==
Internals::kStringResourceOffset);
};
V8_OBJECT class ExternalOneByteString : public ExternalString {
public:
static const bool kHasOneByteEncoding = true;
using Char = uint8_t;
using Resource = v8::String::ExternalOneByteStringResource;
inline const Resource* resource() const;
inline void SetResource(Isolate* isolate, const Resource* buffer);
inline void set_resource(Isolate* isolate, const Resource* buffer);
inline void update_data_cache(Isolate* isolate);
inline const uint8_t* GetChars() const;
inline uint8_t Get(uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
private:
inline Resource* mutable_resource();
} V8_OBJECT_END;
static_assert(sizeof(ExternalOneByteString) == sizeof(ExternalString));
V8_OBJECT class ExternalTwoByteString : public ExternalString {
public:
static const bool kHasOneByteEncoding = false;
using Char = uint16_t;
using Resource = v8::String::ExternalStringResource;
inline const Resource* resource() const;
inline void SetResource(Isolate* isolate, const Resource* buffer);
inline void set_resource(Isolate* isolate, const Resource* buffer);
inline void update_data_cache(Isolate* isolate);
inline const uint16_t* GetChars() const;
inline uint16_t Get(
uint32_t index,
const SharedStringAccessGuardIfNeeded& access_guard) const;
inline const uint16_t* ExternalTwoByteStringGetData(uint32_t start);
private:
inline Resource* mutable_resource();
} V8_OBJECT_END;
static_assert(sizeof(ExternalTwoByteString) == sizeof(ExternalString));
class V8_EXPORT_PRIVATE FlatStringReader : public Relocatable {
public:
FlatStringReader(Isolate* isolate, DirectHandle<String> str);
void PostGarbageCollection() override;
inline base::uc32 Get(uint32_t index) const;
template <typename Char>
inline Char Get(uint32_t index) const;
uint32_t length() const { return length_; }
private:
DirectHandle<String> str_;
bool is_one_byte_;
uint32_t const length_;
const void* start_;
};
class ConsStringIterator {
public:
inline ConsStringIterator() = default;
inline explicit ConsStringIterator(Tagged<ConsString> cons_string,
int offset = 0) {
Reset(cons_string, offset);
}
ConsStringIterator(const ConsStringIterator&) = delete;
ConsStringIterator& operator=(const ConsStringIterator&) = delete;
inline void Reset(Tagged<ConsString> cons_string, int offset = 0) {
depth_ = 0;
if (cons_string.is_null()) return;
Initialize(cons_string, offset);
}
inline Tagged<String> Next(int* offset_out) {
*offset_out = 0;
if (depth_ == 0) return Tagged<String>();
return Continue(offset_out);
}
private:
static const int kStackSize = 32;
static const int kDepthMask = kStackSize - 1;
static_assert(base::bits::IsPowerOfTwo(kStackSize),
"kStackSize must be power of two");
static inline int OffsetForDepth(int depth);
inline void PushLeft(Tagged<ConsString> string);
inline void PushRight(Tagged<ConsString> string);
inline void AdjustMaximumDepth();
inline void Pop();
inline bool StackBlown() { return maximum_depth_ - depth_ == kStackSize; }
V8_EXPORT_PRIVATE void Initialize(Tagged<ConsString> cons_string, int offset);
V8_EXPORT_PRIVATE Tagged<String> Continue(int* offset_out);
Tagged<String> NextLeaf(bool* blew_stack);
Tagged<String> Search(int* offset_out);
Tagged<ConsString> frames_[kStackSize];
Tagged<ConsString> root_;
int depth_;
int maximum_depth_;
uint32_t consumed_;
};
class StringCharacterStream;
template <typename Char>
struct CharTraits;
template <>
struct CharTraits<uint8_t> {
using String = SeqOneByteString;
using ExternalString = ExternalOneByteString;
};
template <>
struct CharTraits<uint16_t> {
using String = SeqTwoByteString;
using ExternalString = ExternalTwoByteString;
};
}
#include "src/objects/object-macros-undef.h"
#endif