1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_STRING_H 17 #define ECMASCRIPT_STRING_H 18 19 #include <cstddef> 20 #include <cstdint> 21 #include <cstring> 22 23 #include "common_components/base/utf_helper.h" 24 #include "common_interfaces/objects/base_string.h" 25 #include "common_interfaces/objects/string/line_string.h" 26 #include "common_interfaces/objects/string/sliced_string.h" 27 #include "common_interfaces/objects/string/tree_string.h" 28 #include "common_interfaces/objects/string/base_string-inl1.h" 29 #include "ecmascript/common.h" 30 #include "ecmascript/ecma_macros.h" 31 #include "ecmascript/js_hclass.h" 32 #include "ecmascript/js_tagged_value.h" 33 #include "ecmascript/mem/barriers.h" 34 #include "ecmascript/mem/space.h" 35 #include "ecmascript/mem/tagged_object.h" 36 #include "libpandabase/macros.h" 37 #include "securec.h" 38 #include "unicode/locid.h" 39 40 namespace panda { 41 namespace test { 42 class EcmaStringEqualsTest; 43 class EcmaStringHashTest; 44 } 45 namespace ecmascript { 46 template<typename T> 47 class JSHandle; 48 class JSPandaFile; 49 class EcmaVM; 50 class LineEcmaString; 51 class TreeEcmaString; 52 class SlicedEcmaString; 53 class FlatStringInfo; 54 55 using ::common::BaseString; 56 using ::common::LineString; 57 using ::common::SlicedString; 58 using ::common::TreeString; 59 60 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 61 #define ECMA_STRING_CHECK_LENGTH_AND_TRHOW(vm, length) \ 62 if ((length) >= BaseString::MAX_STRING_LENGTH) { \ 63 THROW_RANGE_ERROR_AND_RETURN((vm)->GetJSThread(), "Invalid string length", nullptr); \ 64 } 65 66 class EcmaString : public TaggedObject { 67 private: 68 using TaggedObject::SIZE; 69 70 public: 71 CAST_CHECK(EcmaString, IsString); 72 ToBaseString()73 BaseString* ToBaseString() 74 { 75 return BaseString::Cast(this); 76 } 77 ToBaseString()78 const BaseString* ToBaseString() const 79 { 80 return BaseString::ConstCast(this); 81 } 82 FromBaseString(BaseString * str)83 static EcmaString* FromBaseString(BaseString* str) 84 { 85 return reinterpret_cast<EcmaString*>(str); 86 } 87 88 enum TrimMode : uint8_t { 89 TRIM, 90 TRIM_START, 91 TRIM_END, 92 }; 93 SetMixHashcode(uint32_t mixHashCode)94 void SetMixHashcode(uint32_t mixHashCode) 95 { 96 ToBaseString()->SetMixHashcode(mixHashCode); 97 } 98 99 private: 100 101 friend class EcmaStringAccessor; 102 friend class LineEcmaString; 103 friend class TreeEcmaString; 104 friend class SlicedEcmaString; 105 friend class FlatStringInfo; 106 friend class NameDictionary; 107 friend class panda::test::EcmaStringEqualsTest; 108 friend class panda::test::EcmaStringHashTest; 109 110 static constexpr size_t ALIGNMENT_8_BYTES = 8; 111 static EcmaString *CreateEmptyString(const EcmaVM *vm); 112 static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, 113 bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 114 static EcmaString *CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle<EcmaString> &string, 115 uint32_t offset, uint32_t utf8Len, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 116 static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, 117 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 118 static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, 119 bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 120 static SlicedEcmaString* CreateSlicedString(const EcmaVM* vm, JSHandle<EcmaString> parent, 121 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 122 static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed); 123 static EcmaString *CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed); 124 static EcmaString *AllocLineString(const EcmaVM* vm, size_t size, MemSpaceType type); 125 static EcmaString *CreateLineStringWithSpaceType(const EcmaVM *vm, 126 size_t length, bool compressed, MemSpaceType type); 127 static EcmaString *CreateTreeString(const EcmaVM *vm, 128 const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right, uint32_t length, bool compressed); 129 static EcmaString *Concat(const EcmaVM *vm, const JSHandle<EcmaString> &left, 130 const JSHandle<EcmaString> &right, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 131 template<typename T1, typename T2> 132 static uint32_t CalculateDataConcatHashCode(const T1 *dataFirst, size_t sizeFirst, 133 const T2 *dataSecond, size_t sizeSecond); 134 static uint32_t CalculateConcatHashCode(const JSThread *thread, 135 const JSHandle<EcmaString> &firstString, 136 const JSHandle<EcmaString> &secondString); 137 138 bool HashIntegerString(uint32_t length, uint32_t *hash, uint32_t hashSeed) const; 139 IsInteger(const JSThread * thread)140 inline bool IsInteger(const JSThread* thread) 141 { 142 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 143 return Barriers::GetTaggedObject(thread, obj, offset); 144 }; 145 return ToBaseString()->IsInteger(std::move(readBarrier)); 146 } 147 148 static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original, 149 uint32_t length, bool compressed); 150 static EcmaString *FastSubString(const EcmaVM *vm, 151 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 152 static bool SubStringIsUtf8(const EcmaVM *vm, 153 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 154 static EcmaString *GetSlicedString(const EcmaVM *vm, 155 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 156 static EcmaString *GetSubString(const EcmaVM *vm, 157 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 158 // require src is LineString 159 // not change src data structure 160 static inline EcmaString *FastSubUtf8String(const EcmaVM *vm, 161 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 162 // require src is LineString 163 // not change src data structure 164 static inline EcmaString *FastSubUtf16String(const EcmaVM *vm, 165 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 166 inline void TrimLineString(uint32_t newLength); 167 IsUtf8()168 inline bool IsUtf8() const 169 { 170 return ToBaseString()->IsUtf8(); 171 } 172 IsUtf16()173 inline bool IsUtf16() const 174 { 175 return ToBaseString()->IsUtf16(); 176 } 177 178 inline const uint8_t *GetDataUtf8() const; 179 inline const uint16_t *GetDataUtf16() const; 180 181 inline Span<const uint8_t> FastToUtf8Span() const; 182 183 // require is LineString 184 inline uint8_t *GetDataUtf8Writable(); 185 inline uint16_t *GetDataUtf16Writable(); 186 GetLength()187 inline uint32_t GetLength() const 188 { 189 return ToBaseString()->GetLength(); 190 } 191 192 inline void InitLengthAndFlags(uint32_t length, bool compressed = false, bool isIntern = false) 193 { 194 ToBaseString()->InitLengthAndFlags(length, compressed, isIntern); 195 } 196 197 inline size_t GetUtf8Length(const JSThread *thread, bool modify = true, bool isGetBufferSize = false) const; 198 SetIsInternString()199 inline void SetIsInternString() 200 { 201 ToBaseString()->SetIsInternString(); 202 } 203 IsInternString()204 inline bool IsInternString() const 205 { 206 return ToBaseString()->IsInternString(); 207 } 208 ClearInternStringFlag()209 inline void ClearInternStringFlag() 210 { 211 ToBaseString()->ClearInternStringFlag(); 212 } 213 TryGetHashCode(uint32_t * hash)214 inline bool TryGetHashCode(uint32_t *hash) 215 { 216 return ToBaseString()->TryGetHashCode(hash); 217 } 218 219 // not change this data structure. 220 // if string is not flat, this func has low efficiency. GetHashcode(const JSThread * thread)221 uint32_t PUBLIC_API GetHashcode(const JSThread *thread) 222 { 223 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 224 return Barriers::GetTaggedObject(thread, obj, offset); 225 }; 226 return ToBaseString()->GetHashcode(std::move(readBarrier)); 227 } 228 229 // not change this data structure. 230 // if string is not flat, this func has low efficiency. ComputeHashcode(const JSThread * thread)231 uint32_t PUBLIC_API ComputeHashcode(const JSThread *thread) const 232 { 233 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 234 return Barriers::GetTaggedObject(thread, obj, offset); 235 }; 236 return ToBaseString()->ComputeHashcode(std::move(readBarrier)); 237 } 238 239 static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress); 240 static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length); 241 242 template<bool verify = true> 243 uint16_t At(const JSThread *thread, int32_t index) const; 244 245 // require is LineString 246 void WriteData(uint32_t index, uint16_t src); 247 248 // can change left and right data structure 249 static int32_t Compare(const EcmaVM *vm, const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right); 250 251 static bool IsSubStringAt(const EcmaVM *vm, const JSHandle<EcmaString>& left, 252 const JSHandle<EcmaString>& right, uint32_t offset); 253 254 // Check that two spans are equal. Should have the same length. 255 /* static */ 256 template<typename T, typename T1> StringsAreEquals(Span<const T> & str1,Span<const T1> & str2)257 static bool StringsAreEquals(Span<const T> &str1, Span<const T1> &str2) 258 { 259 return BaseString::StringsAreEquals(str1, str2); 260 } 261 262 // Compares string1 + string2 by bytes, It doesn't check canonical unicode equivalence. 263 bool EqualToSplicedString(const JSThread *thread, const EcmaString *str1, const EcmaString *str2); 264 // Compares strings by bytes, It doesn't check canonical unicode equivalence. 265 static PUBLIC_API bool StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1, 266 const JSHandle<EcmaString> &str2); 267 // Compares strings by bytes, It doesn't check canonical unicode equivalence. 268 template <RBMode mode = RBMode::DEFAULT_RB> StringsAreEqual(const JSThread * thread,EcmaString * str1,EcmaString * str2)269 static PUBLIC_API bool StringsAreEqual(const JSThread *thread, EcmaString *str1, EcmaString *str2) 270 { 271 auto readBarrier = [thread](const void *obj, size_t offset) -> TaggedObject * { 272 return Barriers::GetTaggedObject<mode>(thread, obj, offset); 273 }; 274 return BaseString::StringsAreEqual(std::move(readBarrier), str1->ToBaseString(), str2->ToBaseString()); 275 } 276 277 // Two strings have the same type of utf encoding format. 278 static bool StringsAreEqualDiffUtfEncoding(const JSThread *thread, EcmaString *str1, EcmaString *str2); 279 static bool StringsAreEqualDiffUtfEncoding(const FlatStringInfo &str1, const FlatStringInfo &str2); 280 // Compares strings by bytes, It doesn't check canonical unicode equivalence. 281 // not change str1 data structure. 282 // if str1 is not flat, this func has low efficiency. 283 static bool StringIsEqualUint8Data(const JSThread *thread, 284 const EcmaString *str1, const uint8_t *dataAddr, uint32_t dataLen, 285 bool canBeCompress); 286 // Compares strings by bytes, It doesn't check canonical unicode equivalence. 287 // not change str1 data structure. 288 // if str1 is not flat, this func has low efficiency. 289 static bool StringsAreEqualUtf16(const JSThread *thread, 290 const EcmaString *str1, const uint16_t *utf16Data, uint32_t utf16Len); 291 292 // can change receiver and search data structure 293 static int32_t IndexOf(const EcmaVM *vm, 294 const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0); 295 296 // can change receiver and search data structure 297 static int32_t LastIndexOf(const EcmaVM *vm, 298 const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0); 299 300 // It allows user to copy into buffer even if maxLength < length 301 size_t WriteUtf8(const JSThread *thread, uint8_t *buf, size_t maxLength, bool isWriteBuffer = false) const; 302 303 // It allows user to copy into buffer even if maxLength < length 304 size_t WriteUtf16(const JSThread *thread, uint16_t *buf, uint32_t targetLength, uint32_t bufLength) const; 305 306 size_t WriteOneByte(const JSThread *thread, uint8_t *buf, size_t maxLength) const; 307 308 uint32_t CopyDataUtf16(const JSThread *thread, uint16_t *buf, uint32_t maxLength) const; 309 310 std::u16string ToU16String(const JSThread *thread, uint32_t len = 0); 311 312 Span<const uint8_t> ToUtf8Span(const JSThread *thread, CVector<uint8_t> &buf, bool modify = true, 313 bool cesu8 = false); 314 315 Span<const uint8_t> DebuggerToUtf8Span(const JSThread *thread, CVector<uint8_t> &buf, bool modify = true); 316 ToUtf16Span(const JSThread * thread,CVector<uint16_t> & buf)317 Span<const uint16_t> ToUtf16Span(const JSThread *thread, CVector<uint16_t> &buf) 318 { 319 Span<const uint16_t> str; 320 uint32_t strLen = GetLength(); 321 if (UNLIKELY(IsUtf16())) { 322 const uint16_t *data = EcmaString::GetUtf16DataFlat(thread, this, buf); 323 str = Span<const uint16_t>(data, strLen); 324 } else { 325 CVector<uint8_t> tmpBuf; 326 const uint8_t *data = EcmaString::GetUtf8DataFlat(thread, this, tmpBuf); 327 buf.reserve(strLen); 328 auto utf16Len = common::utf_helper::ConvertRegionUtf8ToUtf16(data, buf.data(), strLen, strLen); 329 #if !defined(NDEBUG) 330 auto calculatedLen = common::utf_helper::Utf8ToUtf16Size(data, strLen); 331 ASSERT_PRINT(utf16Len == calculatedLen, "Bad utf8 to utf16 conversion!"); 332 #endif 333 str = Span<const uint16_t>(buf.data(), utf16Len); 334 } 335 return str; 336 } 337 338 template <RBMode mode = RBMode::DEFAULT_RB> WriteData(const JSThread * thread,EcmaString * src,uint32_t start,uint32_t destSize,uint32_t length)339 void WriteData(const JSThread *thread, EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length) 340 { 341 auto readBarrier = [thread](const void *obj, size_t offset) -> TaggedObject * { 342 return Barriers::GetTaggedObject<mode>(thread, obj, offset); 343 }; 344 ToBaseString()->WriteData(std::move(readBarrier), src->ToBaseString(), start, destSize, length); 345 } 346 347 static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len); 348 static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len); 349 static bool CanBeCompressed(const EcmaString *string); 350 351 bool PUBLIC_API ToElementIndex(const JSThread *thread, uint32_t *index); 352 353 bool ToInt(const JSThread *thread, int32_t *index, bool *negative); 354 355 bool ToUInt64FromLoopStart(uint64_t *index, uint32_t loopStart, const uint8_t *data); 356 357 bool PUBLIC_API ToTypedArrayIndex(const JSThread *thread, uint32_t *index); 358 359 template<typename T> 360 static EcmaString *TrimBody(const JSThread *thread, const JSHandle<EcmaString> &src, Span<T> &data, TrimMode mode); 361 362 static EcmaString *Trim(const JSThread *thread, const JSHandle<EcmaString> &src, TrimMode mode = TrimMode::TRIM); 363 364 // memory block copy 365 template<typename T> 366 static bool MemCopyChars(Span<T> &dst, size_t dstMax, Span<const T> &src, size_t count); 367 368 template<typename T1, typename T2> 369 static int32_t IndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos, int32_t max); 370 371 template<typename T1, typename T2> 372 static int32_t LastIndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos); 373 374 bool IsFlat(const JSThread *thread) const; 375 IsLineString()376 bool IsLineString() const 377 { 378 return ToBaseString()->IsLineString(); 379 } IsSlicedString()380 bool IsSlicedString() const 381 { 382 return ToBaseString()->IsSlicedString(); 383 } IsTreeString()384 bool IsTreeString() const 385 { 386 return ToBaseString()->IsTreeString(); 387 } 388 NotTreeString()389 bool NotTreeString() const 390 { 391 return !IsTreeString(); 392 } 393 394 template <typename Char> 395 static void WriteToFlat(const JSThread *thread, EcmaString *src, Char *buf, uint32_t maxLength); 396 397 template <typename Char> 398 static void WriteToFlatWithPos(const JSThread *thread, EcmaString *src, Char *buf, uint32_t length, uint32_t pos); 399 400 static const uint8_t *PUBLIC_API GetUtf8DataFlat(const JSThread *thread, const EcmaString *src, 401 CVector<uint8_t> &buf); 402 403 static const uint8_t *PUBLIC_API GetNonTreeUtf8Data(const JSThread *thread, const EcmaString *src); 404 405 static const uint16_t *PUBLIC_API GetUtf16DataFlat(const JSThread *thread, const EcmaString *src, 406 CVector<uint16_t> &buf); 407 408 static const uint16_t *PUBLIC_API GetNonTreeUtf16Data(const JSThread *thread, const EcmaString *src); 409 410 // string must be not flat 411 static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, MemSpaceType type); 412 413 PUBLIC_API static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, 414 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 415 416 static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string, 417 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE); 418 419 static EcmaString *FlattenNoGCForSnapshot(const EcmaVM *vm, EcmaString *string); 420 421 static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src); 422 423 static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src); 424 425 static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale); 426 427 static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale); 428 429 static EcmaString *TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src); 430 431 static EcmaString *TryToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src); 432 433 static EcmaString *ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, 434 bool toLower, uint32_t startIndex = 0); 435 }; 436 437 // The LineEcmaString abstract class captures sequential string values, only LineEcmaString can store chars data 438 class LineEcmaString : public EcmaString { 439 private: 440 using TaggedObject::SIZE; 441 public: ToLineString()442 LineString* ToLineString() 443 { 444 return LineString::Cast(this); 445 } 446 ToLineString()447 const LineString* ToLineString() const 448 { 449 return LineString::ConstCast(this); 450 } 451 452 CAST_CHECK(LineEcmaString, IsLineString); 453 454 DECL_VISIT_ARRAY(LineString::DATA_OFFSET, 0, GetPointerLength()); 455 Cast(EcmaString * str)456 static LineEcmaString* Cast(EcmaString* str) 457 { 458 return static_cast<LineEcmaString *>(str); 459 } 460 Cast(const EcmaString * str)461 static LineEcmaString *Cast(const EcmaString *str) 462 { 463 return LineEcmaString::Cast(const_cast<EcmaString *>(str)); 464 } 465 ComputeSizeUtf8(uint32_t utf8Len)466 static size_t ComputeSizeUtf8(uint32_t utf8Len) 467 { 468 return LineString::ComputeSizeUtf8(utf8Len); 469 } 470 ComputeSizeUtf16(uint32_t utf16Len)471 static size_t ComputeSizeUtf16(uint32_t utf16Len) 472 { 473 return LineString::ComputeSizeUtf16(utf16Len); 474 } 475 ObjectSize(EcmaString * str)476 static size_t ObjectSize(EcmaString *str) 477 { 478 return LineString::ObjectSize(str->ToBaseString()); 479 } 480 DataSize(EcmaString * str)481 static size_t DataSize(EcmaString *str) 482 { 483 return LineString::DataSize(str->ToBaseString()); 484 } 485 GetPointerLength()486 size_t GetPointerLength() 487 { 488 size_t byteSize = DataSize(this); 489 return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType); 490 } 491 492 template<bool verify = true> Get(int32_t index)493 uint16_t Get(int32_t index) const 494 { 495 return ToLineString()->Get<verify>(index); 496 } 497 Set(uint32_t index,uint16_t src)498 void Set(uint32_t index, uint16_t src) 499 { 500 return ToLineString()->Set(index, src); 501 } 502 }; 503 // static_assert((LineString::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 504 505 // The substrings of another string use SlicedString to describe. 506 class SlicedEcmaString : public EcmaString { 507 private: 508 using TaggedObject::SIZE; 509 public: 510 DECL_VISIT_OBJECT(SlicedString::PARENT_OFFSET, SlicedString::STARTINDEX_AND_FLAGS_OFFSET); 511 512 CAST_CHECK(SlicedEcmaString, IsSlicedString); 513 ToSlicedString()514 SlicedString* ToSlicedString() 515 { 516 return SlicedString::Cast(this); 517 } 518 ToSlicedString()519 const SlicedString* ToSlicedString() const 520 { 521 return SlicedString::ConstCast(this); 522 } 523 FromBaseString(SlicedString * str)524 static SlicedEcmaString* FromBaseString(SlicedString* str) 525 { 526 return reinterpret_cast<SlicedEcmaString*>(str); 527 } 528 GetStartIndex()529 uint32_t GetStartIndex() const 530 { 531 return ToSlicedString()->GetStartIndex(); 532 } 533 SetStartIndex(uint32_t startIndex)534 void SetStartIndex(uint32_t startIndex) 535 { 536 ToSlicedString()->SetStartIndex(startIndex); 537 } 538 GetHasBackingStore()539 bool GetHasBackingStore() const 540 { 541 return ToSlicedString()->GetHasBackingStore(); 542 } 543 SetHasBackingStore(bool hasBackingStore)544 void SetHasBackingStore(bool hasBackingStore) 545 { 546 return ToSlicedString()->SetHasBackingStore(hasBackingStore); 547 } 548 GetParent(const JSThread * thread)549 JSTaggedValue GetParent(const JSThread* thread) const 550 { 551 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 552 return Barriers::GetTaggedObject(thread, obj, offset); 553 }; 554 return JSTaggedValue(ToSlicedString()->GetParent<TaggedObject*>(std::move(readBarrier))); 555 } 556 557 template <typename T> 558 void SetParent(const JSThread* thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER) 559 { 560 auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) { 561 if (mode == WRITE_BARRIER) { 562 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str)); 563 } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); } 564 }; 565 ToSlicedString()->SetParent(std::move(writeBarrier), value.GetTaggedValue().GetTaggedObject()); 566 } 567 568 void SetParent(const JSThread* thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER) 569 { 570 auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) { 571 if (mode == WRITE_BARRIER) { 572 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str)); 573 } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); } 574 }; 575 ToSlicedString()->SetParent(std::move(writeBarrier), value.GetTaggedObject()); 576 }; 577 private: 578 friend class EcmaString; Cast(EcmaString * str)579 static SlicedEcmaString *Cast(EcmaString *str) 580 { 581 return static_cast<SlicedEcmaString *>(str); 582 } 583 Cast(const EcmaString * str)584 static SlicedEcmaString *Cast(const EcmaString *str) 585 { 586 return SlicedEcmaString::Cast(const_cast<EcmaString *>(str)); 587 } 588 ObjectSize()589 static size_t ObjectSize() 590 { 591 return SlicedString::SIZE; 592 } 593 594 // Minimum length for a sliced string 595 template<bool verify = true> Get(const JSThread * thread,int32_t index)596 uint16_t Get(const JSThread *thread, int32_t index) const 597 { 598 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 599 return Barriers::GetTaggedObject(thread, obj, offset); 600 }; 601 return ToSlicedString()->Get<verify>(std::move(readBarrier), index); 602 } 603 }; 604 605 class TreeEcmaString : public EcmaString { 606 private: 607 using TaggedObject::SIZE; 608 public: 609 DECL_VISIT_OBJECT(TreeString::FIRST_OFFSET, TreeString::SIZE); 610 611 CAST_CHECK(TreeEcmaString, IsTreeString); 612 Cast(EcmaString * str)613 static TreeEcmaString* Cast(EcmaString* str) 614 { 615 return static_cast<TreeEcmaString*>(str); 616 } 617 Cast(const EcmaString * str)618 static TreeEcmaString* Cast(const EcmaString* str) 619 { 620 return TreeEcmaString::Cast(const_cast<EcmaString*>(str)); 621 } 622 ToTreeString()623 TreeString* ToTreeString() 624 { 625 return TreeString::Cast(this); 626 } 627 ToTreeString()628 const TreeString* ToTreeString() const 629 { 630 return TreeString::ConstCast(this); 631 } 632 FromBaseString(TreeString * str)633 static TreeEcmaString* FromBaseString(TreeString* str) 634 { 635 return reinterpret_cast<TreeEcmaString*>(str); 636 } 637 GetFirst(const JSThread * thread)638 JSTaggedValue GetFirst(const JSThread *thread) const 639 { 640 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 641 return Barriers::GetTaggedObject(thread, obj, offset); 642 }; 643 return JSTaggedValue(ToTreeString()->GetFirst<TaggedObject*>(std::move(readBarrier))); 644 } 645 646 template <typename T> 647 void SetFirst(const JSThread* thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER) 648 { 649 auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) { 650 if (mode == WRITE_BARRIER) { 651 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str)); 652 } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); } 653 }; 654 ToTreeString()->SetFirst(std::move(writeBarrier), value->GetTaggedObject()); 655 } 656 657 void SetFirst(const JSThread* thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER) 658 { 659 auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) { 660 if (mode == WRITE_BARRIER) { 661 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str)); 662 } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); } 663 }; 664 ToTreeString()->SetFirst(std::move(writeBarrier), value.GetTaggedObject()); 665 }; 666 GetSecond(const JSThread * thread)667 JSTaggedValue GetSecond(const JSThread *thread) const 668 { 669 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 670 return Barriers::GetTaggedObject(thread, obj, offset); 671 }; 672 return JSTaggedValue(ToTreeString()->GetSecond<TaggedObject*>(std::move(readBarrier))); 673 } 674 675 template <typename T> 676 void SetSecond(const JSThread* thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER) 677 { 678 auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) { 679 if (mode == WRITE_BARRIER) { 680 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str)); 681 } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); } 682 }; 683 ToTreeString()->SetSecond(std::move(writeBarrier), value->GetTaggedObject()); 684 } 685 686 void SetSecond(const JSThread* thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER) 687 { 688 auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) { 689 if (mode == WRITE_BARRIER) { 690 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str)); 691 } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); } 692 }; 693 ToTreeString()->SetSecond(std::move(writeBarrier), value.GetTaggedObject()); 694 }; 695 IsFlat(const JSThread * thread)696 bool IsFlat(const JSThread *thread) const 697 { 698 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 699 return Barriers::GetTaggedObject(thread, obj, offset); 700 }; 701 return ToTreeString()->IsFlat(std::move(readBarrier)); 702 } 703 704 template<bool verify = true> Get(const JSThread * thread,int32_t index)705 uint16_t Get(const JSThread *thread, int32_t index) const 706 { 707 auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { 708 return Barriers::GetTaggedObject(thread, obj, offset); 709 }; 710 return ToTreeString()->Get<verify>(std::move(readBarrier), index); 711 } 712 }; 713 714 // FlatStringInfo holds an EcmaString* instead of a JSHandle. If a GC occurs during its usage period, 715 // it may cause the pointer to become invalid, necessitating the pointer to be reset. 716 class FlatStringInfo { 717 public: FlatStringInfo(EcmaString * string,uint32_t startIndex,uint32_t length)718 FlatStringInfo(EcmaString *string, uint32_t startIndex, uint32_t length) : string_(string), 719 startIndex_(startIndex), 720 length_(length) {} IsUtf8()721 bool IsUtf8() const 722 { 723 return string_->IsUtf8(); 724 } 725 IsUtf16()726 bool IsUtf16() const 727 { 728 return string_->IsUtf16(); 729 } 730 GetString()731 EcmaString *GetString() const 732 { 733 return string_; 734 } 735 SetString(EcmaString * string)736 void SetString(EcmaString *string) 737 { 738 string_ = string; 739 } 740 GetStartIndex()741 uint32_t GetStartIndex() const 742 { 743 return startIndex_; 744 } 745 SetStartIndex(uint32_t index)746 void SetStartIndex(uint32_t index) 747 { 748 startIndex_ = index; 749 } 750 GetLength()751 uint32_t GetLength() const 752 { 753 return length_; 754 } 755 756 const uint8_t *GetDataUtf8() const; 757 const uint16_t *GetDataUtf16() const; 758 uint8_t *GetDataUtf8Writable() const; 759 uint16_t *GetDataUtf16Writable() const; 760 std::u16string ToU16String(uint32_t len = 0); 761 private: 762 EcmaString *string_ {nullptr}; 763 uint32_t startIndex_ {0}; 764 uint32_t length_ {0}; 765 }; 766 767 // if you want to use functions of EcmaString, please not use directly, 768 // and use functions of EcmaStringAccessor alternatively. 769 // eg: EcmaString *str = ***; str->GetLength() -----> EcmaStringAccessor(str).GetLength() 770 class PUBLIC_API EcmaStringAccessor { 771 public: EcmaStringAccessor(EcmaString * string)772 explicit inline EcmaStringAccessor(EcmaString *string) 773 { 774 ASSERT(string != nullptr); 775 string_ = string; 776 } 777 778 explicit EcmaStringAccessor(TaggedObject *obj); 779 780 explicit EcmaStringAccessor(JSTaggedValue value); 781 782 explicit EcmaStringAccessor(const JSHandle<EcmaString> &strHandle); 783 CalculateAllConcatHashCode(const JSThread * thread,const JSHandle<EcmaString> & firstString,const JSHandle<EcmaString> & secondString)784 static uint32_t CalculateAllConcatHashCode(const JSThread *thread, 785 const JSHandle<EcmaString> &firstString, 786 const JSHandle<EcmaString> &secondString) 787 { 788 return EcmaString::CalculateConcatHashCode(thread, firstString, secondString); 789 } 790 791 static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed); 792 CreateEmptyString(const EcmaVM * vm)793 static EcmaString *CreateEmptyString(const EcmaVM *vm) 794 { 795 return EcmaString::CreateEmptyString(vm); 796 } 797 798 static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, 799 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 800 { 801 return EcmaString::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type); 802 } 803 804 static EcmaString *CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle<EcmaString> &string, 805 uint32_t offset, uint32_t utf8Len, 806 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 807 { 808 return EcmaString::CreateFromUtf8CompressedSubString(vm, string, offset, utf8Len, type); 809 } 810 811 static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, 812 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 813 { 814 return EcmaString::CreateUtf16StringFromUtf8(vm, utf8Data, utf16Len, type); 815 } 816 817 static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, 818 bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 819 { 820 return EcmaString::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, type); 821 } 822 823 static EcmaString *Concat(const EcmaVM *vm, const JSHandle<EcmaString> &str1Handle, 824 const JSHandle<EcmaString> &str2Handle, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 825 { 826 return EcmaString::Concat(vm, str1Handle, str2Handle, type); 827 } 828 CopyStringToOldSpace(const EcmaVM * vm,const JSHandle<EcmaString> & original,uint32_t length,bool compressed)829 static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original, 830 uint32_t length, bool compressed) 831 { 832 return EcmaString::CopyStringToOldSpace(vm, original, length, compressed); 833 } 834 835 // can change src data structure FastSubString(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)836 static EcmaString *FastSubString(const EcmaVM *vm, 837 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length) 838 { 839 return EcmaString::FastSubString(vm, src, start, length); 840 } SubStringIsUtf8(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)841 static bool SubStringIsUtf8(const EcmaVM *vm, 842 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length) 843 { 844 return EcmaString::SubStringIsUtf8(vm, src, start, length); 845 } 846 // get GetSubString(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)847 static EcmaString *GetSubString(const EcmaVM *vm, 848 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length) 849 { 850 return EcmaString::GetSubString(vm, src, start, length); 851 } 852 IsUtf8()853 bool IsUtf8() const 854 { 855 return string_->IsUtf8(); 856 } 857 IsUtf16()858 bool IsUtf16() const 859 { 860 return string_->IsUtf16(); 861 } 862 GetLength()863 uint32_t GetLength() const 864 { 865 return string_->GetLength(); 866 } 867 868 // require is LineString 869 inline size_t GetUtf8Length(const JSThread *thread, bool isGetBufferSize = false) const; 870 ObjectSize()871 size_t ObjectSize() const 872 { 873 if (string_->IsLineString()) { 874 return LineEcmaString::ObjectSize(string_); 875 } else { 876 return TreeString::SIZE; 877 } 878 } 879 880 // For TreeString, the calculation result is size of LineString correspondingly. GetFlatStringSize()881 size_t GetFlatStringSize() const 882 { 883 return LineEcmaString::ObjectSize(string_); 884 } 885 IsInternString()886 bool IsInternString() const 887 { 888 return string_->IsInternString(); 889 } 890 SetInternString()891 void SetInternString() 892 { 893 string_->SetIsInternString(); 894 } 895 ClearInternString()896 void ClearInternString() 897 { 898 string_->ClearInternStringFlag(); 899 } 900 901 // require is LineString 902 // It's Utf8 format, but without 0 in the end. 903 inline const uint8_t *GetDataUtf8(); 904 905 // require is LineString 906 inline const uint16_t *GetDataUtf16(); 907 908 // not change string data structure. 909 // if string is not flat, this func has low efficiency. 910 std::u16string ToU16String(const JSThread *thread, uint32_t len = 0) 911 { 912 return string_->ToU16String(thread, len); 913 } 914 915 916 // not change string data structure. 917 // if string is not flat, this func has low efficiency. ToUtf8Span(const JSThread * thread,CVector<uint8_t> & buf)918 Span<const uint8_t> ToUtf8Span(const JSThread *thread, CVector<uint8_t> &buf) 919 { 920 return string_->ToUtf8Span(thread, buf); 921 } 922 923 // not change string data structure. 924 // if string is not flat, this func has low efficiency. 925 std::string ToStdString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::PRINT); 926 927 // this function convert for Utf8 928 CString Utf8ConvertToString(const JSThread *thread); 929 930 std::string DebuggerToStdString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::PRINT); 931 // not change string data structure. 932 // if string is not flat, this func has low efficiency. 933 CString ToCString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::LOGICOPERATION, 934 bool cesu8 = false); 935 936 #if ENABLE_NEXT_OPTIMIZATION 937 void AppendToCString(const JSThread *thread, CString &str); 938 void AppendToC16String(const JSThread *thread, C16String &str); 939 #endif 940 941 // not change string data structure. 942 // if string is not flat, this func has low efficiency. 943 uint32_t WriteToFlatUtf8(const JSThread *thread, uint8_t *buf, uint32_t maxLength, bool isWriteBuffer = false) 944 { 945 return string_->WriteUtf8(thread, buf, maxLength, isWriteBuffer); 946 } 947 WriteToUtf16(const JSThread * thread,uint16_t * buf,uint32_t bufLength)948 uint32_t WriteToUtf16(const JSThread *thread, uint16_t *buf, uint32_t bufLength) 949 { 950 return string_->WriteUtf16(thread, buf, GetLength(), bufLength); 951 } 952 WriteToOneByte(const JSThread * thread,uint8_t * buf,uint32_t maxLength)953 uint32_t WriteToOneByte(const JSThread *thread, uint8_t *buf, uint32_t maxLength) 954 { 955 return string_->WriteOneByte(thread, buf, maxLength); 956 } 957 958 // not change string data structure. 959 // if string is not flat, this func has low efficiency. WriteToFlatUtf16(const JSThread * thread,uint16_t * buf,uint32_t maxLength)960 uint32_t WriteToFlatUtf16(const JSThread *thread, uint16_t *buf, uint32_t maxLength) const 961 { 962 return string_->CopyDataUtf16(thread, buf, maxLength); 963 } 964 965 template <typename Char> WriteToFlatWithPos(const JSThread * thread,EcmaString * src,Char * buf,uint32_t length,uint32_t pos)966 static void WriteToFlatWithPos(const JSThread *thread, EcmaString *src, Char *buf, uint32_t length, uint32_t pos) 967 { 968 src->WriteToFlatWithPos(thread, src, buf, length, pos); 969 } 970 971 template <typename Char> WriteToFlat(const JSThread * thread,EcmaString * src,Char * buf,uint32_t maxLength)972 static void WriteToFlat(const JSThread *thread, EcmaString *src, Char *buf, uint32_t maxLength) 973 { 974 src->WriteToFlat(thread, src, buf, maxLength); 975 } 976 977 // require dst is LineString 978 // not change src data structure. 979 // if src is not flat, this func has low efficiency. 980 template <RBMode mode = RBMode::DEFAULT_RB> 981 inline static void ReadData(const JSThread *thread, EcmaString *dst, EcmaString *src, uint32_t start, 982 uint32_t destSize, uint32_t length); 983 984 // not change src data structure. 985 // if src is not flat, this func has low efficiency. 986 template<bool verify = true> Get(const JSThread * thread,uint32_t index)987 uint16_t Get(const JSThread *thread, uint32_t index) const 988 { 989 return string_->At<verify>(thread, index); 990 } 991 992 // require string is LineString. Set(uint32_t index,uint16_t src)993 void Set(uint32_t index, uint16_t src) 994 { 995 return string_->WriteData(index, src); 996 } 997 998 // not change src data structure. 999 // if src is not flat, this func has low efficiency. GetHashcode(const JSThread * thread)1000 uint32_t GetHashcode(const JSThread *thread) 1001 { 1002 return string_->GetHashcode(thread); 1003 } 1004 ComputeHashcode(const JSThread * thread)1005 uint32_t ComputeHashcode(const JSThread *thread) 1006 { 1007 return string_->ComputeHashcode(thread); 1008 } 1009 ComputeHashcodeUtf8(const uint8_t * utf8Data,size_t utf8Len,bool canBeCompress)1010 static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress) 1011 { 1012 return EcmaString::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress); 1013 } 1014 ComputeHashcodeUtf16(const uint16_t * utf16Data,uint32_t length)1015 static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length) 1016 { 1017 return EcmaString::ComputeHashcodeUtf16(utf16Data, length); 1018 } 1019 1020 // can change receiver and search data structure 1021 static int32_t IndexOf(const EcmaVM *vm, 1022 const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0) 1023 { 1024 return EcmaString::IndexOf(vm, receiver, search, pos); 1025 } 1026 1027 // can change receiver and search data structure 1028 static int32_t LastIndexOf(const EcmaVM *vm, 1029 const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0) 1030 { 1031 return EcmaString::LastIndexOf(vm, receiver, search, pos); 1032 } 1033 1034 // can change receiver and search data structure Compare(const EcmaVM * vm,const JSHandle<EcmaString> & left,const JSHandle<EcmaString> & right)1035 static int32_t Compare(const EcmaVM *vm, const JSHandle<EcmaString>& left, const JSHandle<EcmaString>& right) 1036 { 1037 return EcmaString::Compare(vm, left, right); 1038 } 1039 1040 1041 // can change receiver and search data structure 1042 static bool IsSubStringAt(const EcmaVM *vm, const JSHandle<EcmaString>& left, 1043 const JSHandle<EcmaString>& right, uint32_t offset = 0) 1044 { 1045 return EcmaString::IsSubStringAt(vm, left, right, offset); 1046 } 1047 1048 // can change str1 and str2 data structure StringsAreEqual(const EcmaVM * vm,const JSHandle<EcmaString> & str1,const JSHandle<EcmaString> & str2)1049 static bool StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1, const JSHandle<EcmaString> &str2) 1050 { 1051 return EcmaString::StringsAreEqual(vm, str1, str2); 1052 } 1053 1054 // not change str1 and str2 data structure. 1055 // if str1 or str2 is not flat, this func has low efficiency. 1056 template <RBMode mode = RBMode::DEFAULT_RB> StringsAreEqual(const JSThread * thread,EcmaString * str1,EcmaString * str2)1057 static bool StringsAreEqual(const JSThread *thread, EcmaString *str1, EcmaString *str2) 1058 { 1059 return EcmaString::StringsAreEqual<mode>(thread, str1, str2); 1060 } 1061 1062 // not change str1 and str2 data structure. 1063 // if str1 or str2 is not flat, this func has low efficiency. StringsAreEqualDiffUtfEncoding(const JSThread * thread,EcmaString * str1,EcmaString * str2)1064 static bool StringsAreEqualDiffUtfEncoding(const JSThread *thread, EcmaString *str1, EcmaString *str2) 1065 { 1066 return EcmaString::StringsAreEqualDiffUtfEncoding(thread, str1, str2); 1067 } 1068 1069 // not change str1 data structure. 1070 // if str1 is not flat, this func has low efficiency. StringIsEqualUint8Data(const JSThread * thread,const EcmaString * str1,const uint8_t * dataAddr,uint32_t dataLen,bool canBeCompress)1071 static bool StringIsEqualUint8Data(const JSThread *thread, 1072 const EcmaString *str1, const uint8_t *dataAddr, uint32_t dataLen, 1073 bool canBeCompress) 1074 { 1075 return EcmaString::StringIsEqualUint8Data(thread, str1, dataAddr, dataLen, canBeCompress); 1076 } 1077 1078 // not change str1 data structure. 1079 // if str1 is not flat, this func has low efficiency. StringsAreEqualUtf16(const JSThread * thread,const EcmaString * str1,const uint16_t * utf16Data,uint32_t utf16Len)1080 static bool StringsAreEqualUtf16(const JSThread *thread, const EcmaString *str1, const uint16_t *utf16Data, 1081 uint32_t utf16Len) 1082 { 1083 return EcmaString::StringsAreEqualUtf16(thread, str1, utf16Data, utf16Len); 1084 } 1085 1086 // require str1 and str2 are LineString. 1087 // not change string data structure. 1088 // if string is not flat, this func has low efficiency. EqualToSplicedString(const JSThread * thread,const EcmaString * str1,const EcmaString * str2)1089 bool EqualToSplicedString(const JSThread *thread, const EcmaString *str1, const EcmaString *str2) 1090 { 1091 return string_->EqualToSplicedString(thread, str1, str2); 1092 } 1093 CanBeCompressed(const uint8_t * utf8Data,uint32_t utf8Len)1094 static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len) 1095 { 1096 return EcmaString::CanBeCompressed(utf8Data, utf8Len); 1097 } 1098 CanBeCompressed(const uint16_t * utf16Data,uint32_t utf16Len)1099 static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len) 1100 { 1101 return EcmaString::CanBeCompressed(utf16Data, utf16Len); 1102 } 1103 1104 // require string is LineString CanBeCompressed(const EcmaString * string)1105 static bool CanBeCompressed(const EcmaString *string) 1106 { 1107 return EcmaString::CanBeCompressed(string); 1108 } 1109 1110 // not change string data structure. 1111 // if string is not flat, this func has low efficiency. ToElementIndex(const JSThread * thread,uint32_t * index)1112 bool ToElementIndex(const JSThread *thread, uint32_t *index) 1113 { 1114 return string_->ToElementIndex(thread, index); 1115 } 1116 1117 // not change string data structure. 1118 // if string is not flat, this func has low efficiency. ToInt(const JSThread * thread,int32_t * index,bool * negative)1119 bool ToInt(const JSThread *thread, int32_t *index, bool *negative) 1120 { 1121 return string_->ToInt(thread, index, negative); 1122 } 1123 1124 // not change string data structure. 1125 // if string is not flat, this func has low efficiency. ToTypedArrayIndex(const JSThread * thread,uint32_t * index)1126 bool PUBLIC_API ToTypedArrayIndex(const JSThread *thread, uint32_t *index) 1127 { 1128 return string_->ToTypedArrayIndex(thread, index); 1129 } 1130 ToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)1131 static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src) 1132 { 1133 return EcmaString::ToLower(vm, src); 1134 } 1135 TryToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)1136 static EcmaString *TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src) 1137 { 1138 return EcmaString::TryToLower(vm, src); 1139 } 1140 TryToUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src)1141 static EcmaString *TryToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src) 1142 { 1143 return EcmaString::TryToUpper(vm, src); 1144 } 1145 ToUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src)1146 static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src) 1147 { 1148 return EcmaString::ToUpper(vm, src); 1149 } 1150 ToLocaleLower(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)1151 static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale) 1152 { 1153 return EcmaString::ToLocaleLower(vm, src, locale); 1154 } 1155 ToLocaleUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)1156 static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale) 1157 { 1158 return EcmaString::ToLocaleUpper(vm, src, locale); 1159 } 1160 1161 static EcmaString *Trim(const JSThread *thread, 1162 const JSHandle<EcmaString> &src, EcmaString::TrimMode mode = EcmaString::TrimMode::TRIM) 1163 { 1164 return EcmaString::Trim(thread, src, mode); 1165 } 1166 IsASCIICharacter(uint16_t data)1167 static bool IsASCIICharacter(uint16_t data) 1168 { 1169 if (data == 0) { 1170 return false; 1171 } 1172 // \0 is not considered ASCII in Ecma-Modified-UTF8 [only modify '\u0000'] 1173 return data <= common::utf_helper::UTF8_1B_MAX; 1174 } 1175 IsFlat(const JSThread * thread)1176 bool IsFlat(const JSThread *thread) const 1177 { 1178 return string_->IsFlat(thread); 1179 } 1180 IsLineString()1181 bool IsLineString() const 1182 { 1183 return string_->IsLineString(); 1184 } 1185 IsSlicedString()1186 bool IsSlicedString() const 1187 { 1188 return string_->IsSlicedString(); 1189 } 1190 IsTreeString()1191 bool IsTreeString() const 1192 { 1193 return string_->IsTreeString(); 1194 } 1195 NotTreeString()1196 bool NotTreeString() const 1197 { 1198 return string_->NotTreeString(); 1199 } 1200 1201 inline Span<const uint8_t> FastToUtf8Span() const; 1202 1203 // the returned string may be a linestring or slicestring!! 1204 PUBLIC_API static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, 1205 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 1206 { 1207 return EcmaString::Flatten(vm, string, type); 1208 } 1209 1210 static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string, 1211 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 1212 { 1213 return EcmaString::FlattenAllString(vm, string, type); 1214 } 1215 1216 static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, 1217 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE) 1218 { 1219 return EcmaString::SlowFlatten(vm, string, type); 1220 } 1221 FlattenNoGCForSnapshot(const EcmaVM * vm,EcmaString * string)1222 static EcmaString *FlattenNoGCForSnapshot(const EcmaVM *vm, EcmaString *string) 1223 { 1224 return EcmaString::FlattenNoGCForSnapshot(vm, string); 1225 } 1226 GetUtf8DataFlat(const JSThread * thread,const EcmaString * src,CVector<uint8_t> & buf)1227 static const uint8_t *GetUtf8DataFlat(const JSThread *thread, const EcmaString *src, CVector<uint8_t> &buf) 1228 { 1229 return EcmaString::GetUtf8DataFlat(thread, src, buf); 1230 } 1231 GetNonTreeUtf8Data(const JSThread * thread,const EcmaString * src)1232 static const uint8_t *GetNonTreeUtf8Data(const JSThread *thread, const EcmaString *src) 1233 { 1234 return EcmaString::GetNonTreeUtf8Data(thread, src); 1235 } 1236 GetUtf16DataFlat(const JSThread * thread,const EcmaString * src,CVector<uint16_t> & buf)1237 static const uint16_t *GetUtf16DataFlat(const JSThread *thread, const EcmaString *src, CVector<uint16_t> &buf) 1238 { 1239 return EcmaString::GetUtf16DataFlat(thread, src, buf); 1240 } 1241 GetNonTreeUtf16Data(const JSThread * thread,const EcmaString * src)1242 static const uint16_t *GetNonTreeUtf16Data(const JSThread *thread, const EcmaString *src) 1243 { 1244 return EcmaString::GetNonTreeUtf16Data(thread, src); 1245 } 1246 1247 static JSTaggedValue StringToList(JSThread *thread, JSHandle<JSTaggedValue> &str); 1248 1249 private: 1250 EcmaString *string_ {nullptr}; 1251 }; 1252 } // namespace ecmascript 1253 } // namespace panda 1254 #endif // ECMASCRIPT_STRING_H 1255