diff --git a/common_components/objects/base_string.cpp b/common_components/objects/base_string.cpp index 3979df3612f4e1362e6a677e60c1a126f4eb9053..7cf754eed8c2cacede6df0e631598c85c7057ac2 100644 --- a/common_components/objects/base_string.cpp +++ b/common_components/objects/base_string.cpp @@ -75,9 +75,8 @@ namespace common { // To change the hash algorithm of BaseString, please modify BaseString::CalculateConcatHashCode // and BaseStringHashHelper::ComputeHashForDataPlatform simultaneously!! - template - uint32_t BaseString::ComputeHashForData(const T* data, size_t size, - uint32_t hashSeed) + template + uint32_t ComputeHashForDataInternal(const T *data, size_t size, uint32_t hashSeed) { if (size <= static_cast(StringHash::MIN_SIZE_FOR_UNROLLING)) { uint32_t hash = hashSeed; @@ -89,30 +88,46 @@ namespace common { return StringHashHelper::ComputeHashForDataPlatform(data, size, hashSeed); } - template - uint32_t BaseString::ComputeHashForData(const uint8_t*, size_t, uint32_t); - template - uint32_t BaseString::ComputeHashForData(const uint16_t*, size_t, uint32_t); + PUBLIC_API uint32_t BaseString::ComputeHashForData(const uint8_t *data, size_t size, uint32_t hashSeed) + { + return ComputeHashForDataInternal(data, size, hashSeed); + } + PUBLIC_API uint32_t BaseString::ComputeHashForData(const uint16_t *data, size_t size, uint32_t hashSeed) + { + return ComputeHashForDataInternal(data, size, hashSeed); + } - /* static */ - uint32_t BaseString::ComputeHashcodeUtf8(const uint8_t* utf8Data, size_t utf8Len, bool canBeCompress) + uint32_t BaseString::ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress) { if (canBeCompress) { - return ComputeHashForData(utf8Data, utf8Len, 0); + uint32_t mixHash = 0; + // String using UTF8 encoding, and length smaller than 10, try to compute integer hash. + if (utf8Len < MAX_ELEMENT_INDEX_LEN && HashIntegerString(utf8Data, utf8Len, &mixHash, 0)) { + return mixHash; + } + uint32_t hash = ComputeHashForData(utf8Data, utf8Len, 0); + return MixHashcode(hash, NOT_INTEGER); } auto utf16Len = UtfUtils::Utf8ToUtf16Size(utf8Data, utf8Len); std::vector tmpBuffer(utf16Len); [[maybe_unused]] auto len = UtfUtils::ConvertRegionUtf8ToUtf16(utf8Data, tmpBuffer.data(), utf8Len, utf16Len); DCHECK_CC(len == utf16Len); - return ComputeHashForData(tmpBuffer.data(), utf16Len, 0); + uint32_t hash = ComputeHashForData(tmpBuffer.data(), utf16Len, 0); + return MixHashcode(hash, NOT_INTEGER); } /* static */ - uint32_t BaseString::ComputeHashcodeUtf16(const uint16_t* utf16Data, uint32_t length) + uint32_t BaseString::ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length) { - return ComputeHashForData(utf16Data, length, 0); + uint32_t mixHash = 0; + // String length smaller than 10, try to compute integer hash. + if (length < MAX_ELEMENT_INDEX_LEN && HashIntegerString(utf16Data, length, &mixHash, 0)) { + return mixHash; + } + uint32_t hash = ComputeHashForData(utf16Data, length, 0); + return MixHashcode(hash, NOT_INTEGER); } @@ -223,7 +238,7 @@ namespace common { { uint32_t totalHash = ComputeHashForData(dataFirst, sizeFirst, 0); totalHash = ComputeHashForData(dataSecond, sizeSecond, totalHash); - return totalHash; + return MixHashcode(totalHash, NOT_INTEGER); } template diff --git a/common_components/objects/base_string_table.cpp b/common_components/objects/base_string_table.cpp index 6c4151f940e5c27e683b2d4c5bdeb7affc9e16f4..d8d3cc807341c5128fd7543f05bd4b95e3e42bf1 100644 --- a/common_components/objects/base_string_table.cpp +++ b/common_components/objects/base_string_table.cpp @@ -92,7 +92,7 @@ BaseString* BaseStringTableInternal::GetOrInternStringFromCompr [holder, string, offset, utf8Len, hashcode, handleCreator, allocator]() { BaseString* str = BaseString::CreateFromUtf8CompressedSubString( std::move(allocator), string, offset, utf8Len); - str->SetRawHashcode(hashcode); + str->SetMixHashcode(hashcode); ASSERT(!str->IsInternString()); ASSERT(str->NotTreeString()); // Strings in string table should not be in the young space. @@ -128,7 +128,7 @@ BaseString* BaseStringTableInternal::GetOrInternString(ThreadHo holder, hashcode, [holder, hashcode, utf8Data, utf8Len, canBeCompress, handleCreator, allocator]() { BaseString* value = BaseString::CreateFromUtf8(std::move(allocator), utf8Data, utf8Len, canBeCompress); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!value->IsInternString()); ASSERT(value->NotTreeString()); ReadOnlyHandle stringHandle = handleCreator(holder, value); @@ -163,7 +163,7 @@ BaseString* BaseStringTableInternal::GetOrInternString( [holder, utf16Data, utf16Len, canBeCompress, hashcode, handleCreator, allocator]() { BaseString* value = BaseString::CreateFromUtf16(std::move(allocator), utf16Data, utf16Len, canBeCompress); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!value->IsInternString()); ASSERT(value->NotTreeString()); // Strings in string table should not be in the young space. diff --git a/common_components/objects/string_table/hashtriemap-inl.h b/common_components/objects/string_table/hashtriemap-inl.h index ff190c9080f6d8b89b5f313feb62b76f2dd1c344..b085d3bf15b107446d9e1b40796eef0cd8eb9c22 100644 --- a/common_components/objects/string_table/hashtriemap-inl.h +++ b/common_components/objects/string_table/hashtriemap-inl.h @@ -101,6 +101,9 @@ BaseString* HashTrieMap::Load(ReadBarrier&& re valuesEqual = true; } if constexpr (IsCheck) { + if (oldValue->GetMixHashcode() != value->GetMixHashcode()) { + continue; + } if (!valuesEqual) { return oldValue; } diff --git a/ecmascript/base/number_helper.cpp b/ecmascript/base/number_helper.cpp index 2e3a331f18344e6981309c4cd4f8e91b07950518..443921f6fdab9acde227bc1488e0fb8c33213c55 100644 --- a/ecmascript/base/number_helper.cpp +++ b/ecmascript/base/number_helper.cpp @@ -859,32 +859,32 @@ int NumberHelper::StringToInt(const uint8_t *start, const uint8_t *end) // only for string is ordinary string and using UTF8 encoding // Fast path for short integer and some special value std::pair NumberHelper::FastStringToNumber(const uint8_t *start, - const uint8_t *end, common::IntegerCache *cache) + const uint8_t *end, JSTaggedValue string) { ASSERT(start < end); + EcmaStringAccessor strAccessor(string); bool minus = (start[0] == '-'); int pos = (minus ? 1 : 0); if (pos == (end - start)) { return {true, JSTaggedNumber(NAN_VALUE)}; - } - if (*(start + pos) > '9') { + } else if (*(start + pos) > '9') { // valid number's codes not longer than '9', except 'I' and non-breaking space. if (*(start + pos) != 'I' && *(start + pos) != 0xA0) { return {true, JSTaggedNumber(NAN_VALUE)}; } } else if ((end - (start + pos)) <= MAX_ELEMENT_INDEX_LEN && IsDigitalString((start + pos), end)) { int num = StringToInt((start + pos), end); - if LIKELY(!minus) { - if (cache != nullptr) { - cache->SetInteger(num); + if (minus) { + if (num == 0) { + return {true, JSTaggedNumber(SignedZero(Sign::NEG))}; + } + num = -num; + } else { + if ((num != 0) || (end - start == 1)) { + strAccessor.TryToSetIntegerHash(num); } - return {true, JSTaggedNumber(num)}; - } - if (num == 0) { - return {true, JSTaggedNumber(SignedZero(Sign::NEG))}; } - num = -num; return {true, JSTaggedNumber(num)}; } diff --git a/ecmascript/base/number_helper.h b/ecmascript/base/number_helper.h index a4df6b6a5e0d5f4d56727bda8225e6a7b5b316d7..030a836721d0782cd6db458292d3b4c38a5cdcd6 100644 --- a/ecmascript/base/number_helper.h +++ b/ecmascript/base/number_helper.h @@ -111,7 +111,6 @@ class NumberHelper { public: // double to string buffer offset static constexpr int BUFFER_OFFSET = 8; - static constexpr size_t MAX_INTEGER_STRING_LENGTH = 10; static const CString NAN_STR; static const CString ZERO_STR; static const CString MINUS_INFINITY_STR; @@ -167,34 +166,6 @@ public: return (number == d) && std::abs(d) <= MAX_SAFE_INTEGER; } - // The result should be less or equal than maxValue, if not, will return false. - // Type T only support uint32_t and int32_t, and don't support negative int. - template - static bool StringToUint(const std::basic_string_view str, T& result, uint64_t maxValue) - { - static_assert(std::is_same_v || std::is_same_v); - static_assert(sizeof(ElemType) == sizeof(uint8_t)); - constexpr T base = 10; - if (str.empty() || str.size() > MAX_INTEGER_STRING_LENGTH) { - return false; - } - if (str.size() > 1 && str[0] == '0') { - return false; - } - uint64_t value = 0; - for (const uint8_t c : str) { - if (c > '9' || c < '0') { - return false; - } - value = value * base + (c - '0'); - } - if UNLIKELY(value > maxValue) { - return false; - } - result = static_cast(value); - return true; - } - static JSTaggedValue DoubleToString(JSThread *thread, double number, int radix); static bool IsEmptyString(const uint8_t *start, const uint8_t *end); static JSHandle IntToEcmaString(const JSThread *thread, int number); @@ -208,7 +179,7 @@ public: static bool IsDigitalString(const uint8_t *start, const uint8_t *end); static int StringToInt(const uint8_t *start, const uint8_t *end); static std::pair FastStringToNumber(const uint8_t *start, - const uint8_t *end, common::IntegerCache *cache); + const uint8_t *end, JSTaggedValue string); static double StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix, uint32_t flags = NO_FLAGS); static int32_t DoubleToInt(double d, size_t bits); static int32_t PUBLIC_API DoubleInRangeInt32(double d); diff --git a/ecmascript/base/tests/number_helper_test.cpp b/ecmascript/base/tests/number_helper_test.cpp index 88d5c3747178dbe3c7063b6f6934aeed427b1753..0a0436ea56a538ec4ba818e84cb56ebc8a7f9f10 100644 --- a/ecmascript/base/tests/number_helper_test.cpp +++ b/ecmascript/base/tests/number_helper_test.cpp @@ -854,82 +854,4 @@ HWTEST_F_L0(NumberHelperTest, DoubleToASCII_002) EXPECT_EQ(EcmaStringAccessor::Compare(instance, handleEcmaStr7, resultStr), 0); } -HWTEST_F_L0(NumberHelperTest, FastStringToInt) -{ - std::vector> inputs = { - {"1", "3", "9", "8", "6", "4", "2", "5", "7", "0"}, - {"14", "39", "78", "21", "53", "86", "95", "62", "47", "18"}, - {"294", "185", "762", "439", "816", "931", "728", "657", "328", "149"}, - {"1837", "2495", "3926", "7812", "9365", "5748", "8129", "6723", "4531", "3184"}, - {"18374", "29583", "71426", "98432", "57613", "83625", "49216", "63841", "73198", "15892"}, - {"918374", "738152", "184729", "627391", "495681", "352716", "816429", "274839", "639182", "517392"}, - {"1983741", "6273918", "5839162", "9127384", "3728195", "6938271", "8491326", "7153962", "2839173", "1982735"}, - {"91837462", "73815294", "18472951", "62739185", "49568124", "35271639", "81642975", "27483916", "63918257", - "51739268"}, - {"4294967295"} - }; - std::vector> expected = { - {1, 3, 9, 8, 6, 4, 2, 5, 7, 0}, - {14, 39, 78, 21, 53, 86, 95, 62, 47, 18}, - {294, 185, 762, 439, 816, 931, 728, 657, 328, 149}, - {1837, 2495, 3926, 7812, 9365, 5748, 8129, 6723, 4531, 3184}, - {18374, 29583, 71426, 98432, 57613, 83625, 49216, 63841, 73198, 15892}, - {918374, 738152, 184729, 627391, 495681, 352716, 816429, 274839, 639182, 517392}, - {1983741, 6273918, 5839162, 9127384, 3728195, 6938271, 8491326, 7153962, 2839173, 1982735}, - {91837462, 73815294, 18472951, 62739185, 49568124, 35271639, 81642975, 27483916, 63918257, 51739268}, - {4294967295} - }; - - for (std::size_t i = 0; i < inputs.size(); ++i) { - const std::vector& group = inputs[i]; - for (std::size_t j = 0; j < group.size(); ++j) { - uint32_t result; - NumberHelper::StringToUint(group[j], result, std::numeric_limits::max()); - EXPECT_EQ(result, expected[i][j]); - } - } -} - -HWTEST_F_L0(NumberHelperTest, FastStringToIntFail) -{ - std::vector inputs = { - "-1", ".3", "09", "8x", "0x6", "c4", "2十一", "0.5", "7.0", "-0", "14000000000", "9000000000", "4294967296" - }; - - for (auto input : inputs) { - uint32_t result; - bool success = NumberHelper::StringToUint(input, result, std::numeric_limits::max()); - EXPECT_FALSE(success); - } -} - -HWTEST_F_L0(NumberHelperTest, FastStringToNumberForLineString) -{ - std::vector inputs = { - "0", "1", "26", "371", "4592", "53100", "642197", "7126573", "81230248", "912331534", - "-12", "-345", "-4578", "-135936383", "1.0", "3.21", "54.98", "abcd", "qwerty", "3.123ab" - }; - std::vector expectedIsSuccess = { - true, true, true, true, true, true, true, true, true, true, - true, true, true, true, false, false, false, true, true, false - }; - std::vector expectedValue = { - 0, 1, 26, 371, 4592, 53100, 642197, 7126573, 81230248, 912331534, - -12, -345, -4578, -135936383, 0, 0, 0, 0, 0, 0, - }; - for (std::size_t i = 0; i < inputs.size(); ++i) { - Span str = Span(reinterpret_cast(inputs[i].data()), inputs[i].length()); - auto ecmaString = EcmaStringAccessor::CreateFromUtf8(instance, str.data(), str.size(), true); - auto baseString = ecmaString->ToBaseString(); - baseString->SetIsInternString(); - common::IntegerCache::InitIntegerCache(baseString); - common::IntegerCache *cache = nullptr; - if (baseString->GetLength() <= common::IntegerCache::MAX_INTEGER_CACHE_SIZE) { - cache = common::IntegerCache::Extract(ecmaString->ToBaseString()); - } - auto resCached = NumberHelper::FastStringToNumber(str.begin(), str.end(), cache); - ASSERT_EQ(resCached.first, expectedIsSuccess[i]); - ASSERT_EQ(resCached.second.ToInt32(), expectedValue[i]); - } -} } // namespace panda::ecmascript diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp index d21230fdc3c6580642f56a4d03109bf1e246a076..343482756f3c6879e17a916ea05ab018dfb64239 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp @@ -513,8 +513,7 @@ void BuiltinsObjectStubBuilder::HasOwnProperty(Variable *result, Label *exit, La BRANCH(TaggedIsString(glue_, prop), &keyIsString, slowPath); // 2 : two args Bind(&keyIsString); { - BuiltinsStringStubBuilder stringStub(this, GetCurrentGlobalEnv()); - GateRef res = stringStub.StringToUint(glue_, prop, JSObject::MAX_ELEMENT_INDEX - 1); + GateRef res = StringToElementIndex(glue_, prop); // -1: not find element index BRANCH(Int64NotEqual(res, Int64(-1)), &isIndex, ¬Index); Bind(&isIndex); diff --git a/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp index 678b948b61581c2d85f86da0caac5f8a244952be..b278428d523698842abe59e9f87da3e824cf00ba 100644 --- a/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_string_stub_builder.cpp @@ -2493,7 +2493,7 @@ GateRef BuiltinsStringStubBuilder::AllocateLineString(GateRef glue, GateRef leng builder_.IntPtr(0), stringClass, MemoryAttribute::NeedBarrierAndAtomic()); InitStringLengthAndFlags(glue, lineString, length, canBeCompressed); builder_.Store(VariableType::INT32(), glue, lineString, - builder_.IntPtr(BaseString::RAW_HASHCODE_OFFSET), builder_.Int32(0)); + builder_.IntPtr(BaseString::MIX_HASHCODE_OFFSET), builder_.Int32(0)); auto ret = builder_.FinishAllocate(lineString); builder_.SubCfgExit(); return ret; @@ -2519,7 +2519,7 @@ GateRef BuiltinsStringStubBuilder::AllocateSlicedString(GateRef glue, GateRef fl builder_.IntPtr(0), stringClass, MemoryAttribute::NeedBarrierAndAtomic()); InitStringLengthAndFlags(glue, slicedString, length, canBeCompressed); builder_.Store(VariableType::INT32(), glue, slicedString, - builder_.IntPtr(BaseString::RAW_HASHCODE_OFFSET), builder_.Int32(0)); + builder_.IntPtr(BaseString::MIX_HASHCODE_OFFSET), builder_.Int32(0)); builder_.Store(VariableType::JS_POINTER(), glue, slicedString, builder_.IntPtr(SlicedString::PARENT_OFFSET), flatString); StoreStartIndexAndBackingStore(glue, slicedString, builder_.Int32(0), builder_.Boolean(true)); @@ -3608,106 +3608,4 @@ void BuiltinsStringStubBuilder::PadEnd(GateRef glue, GateRef thisValue, GateRef } } } - -GateRef BuiltinsStringStubBuilder::StringToUint(GateRef glue, GateRef string, uint64_t maxValue) -{ - auto env = GetEnvironment(); - Label entry(env); - env->SubCfgEntry(&entry); - Label exit(env); - DEFVARIABLE(result, VariableType::INT64(), Int64(-1)); - Label greatThanZero(env); - Label inRange(env); - Label flattenFastPath(env); - auto len = GetLengthFromString(string); - BRANCH_UNLIKELY(Int32Equal(len, Int32(0)), &exit, &greatThanZero); - Bind(&greatThanZero); - BRANCH_NO_WEIGHT(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange); - Bind(&inRange); - { - Label isUtf8(env); - GateRef isUtf16String = IsUtf16String(string); - BRANCH_NO_WEIGHT(isUtf16String, &exit, &isUtf8); - Bind(&isUtf8); - { - FlatStringStubBuilder thisFlat(this); - thisFlat.FlattenString(glue, string, &flattenFastPath); - Bind(&flattenFastPath); - StringInfoGateRef stringInfoGate(&thisFlat); - GateRef dataUtf8 = GetNormalStringData(glue, stringInfoGate); - result = StringDataToUint(dataUtf8, len, maxValue); - Jump(&exit); - } - } - Bind(&exit); - auto ret = *result; - env->SubCfgExit(); - return ret; -} - -// length should be at least 1 -GateRef BuiltinsStringStubBuilder::StringDataToUint(GateRef dataUtf8, GateRef len, uint64_t maxValue) -{ - auto env = GetEnvironment(); - Label entry(env); - env->SubCfgEntry(&entry); - Label exit(env); - DEFVARIABLE(result, VariableType::INT64(), Int64(-1)); - DEFVARIABLE(c, VariableType::INT32(), Int32(0)); - c = ZExtInt8ToInt32(LoadZeroOffsetPrimitive(VariableType::INT8(), dataUtf8)); - Label isDigitZero(env); - Label notDigitZero(env); - BRANCH_NO_WEIGHT(Int32Equal(*c, Int32('0')), &isDigitZero, ¬DigitZero); - Bind(&isDigitZero); - { - Label lengthIsOne(env); - BRANCH_NO_WEIGHT(Int32Equal(len, Int32(1)), &lengthIsOne, &exit); - Bind(&lengthIsOne); - { - result = Int64(0); - Jump(&exit); - } - } - Bind(¬DigitZero); - { - Label loopHead(env); - Label loopEnd(env); - Label afterLoop(env); - DEFVARIABLE(i, VariableType::INT32(), Int32(1)); - DEFVARIABLE(n, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(*c), Int64('0'))); - BRANCH_NO_WEIGHT(IsDigit(*c), &loopHead, &exit); - LoopBegin(&loopHead); - { - Label doCheck(env); - BRANCH_LIKELY(Int32UnsignedLessThan(*i, len), &doCheck, &afterLoop); - Bind(&doCheck); - c = ZExtInt8ToInt32(LoadPrimitive(VariableType::INT8(), dataUtf8, ZExtInt32ToPtr(*i))); - Label isDigit2(env); - BRANCH_NO_WEIGHT(IsDigit(*c), &isDigit2, &exit); - Bind(&isDigit2); - { - // 10 means the base of digit is 10. - n = Int64Add(Int64Mul(*n, Int64(10)), Int64Sub(ZExtInt32ToInt64(*c), Int64('0'))); - Jump(&loopEnd); - } - } - Bind(&loopEnd); - i = Int32Add(*i, Int32(1)); - LoopEnd(&loopHead); - Bind(&afterLoop); - { - Label notGreatThanMaxIndex(env); - BRANCH_UNLIKELY(Int64GreaterThan(*n, Int64(maxValue)), &exit, ¬GreatThanMaxIndex); - Bind(¬GreatThanMaxIndex); - { - result = *n; - Jump(&exit); - } - } - } - Bind(&exit); - auto ret = *result; - env->SubCfgExit(); - return ret; -} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_string_stub_builder.h b/ecmascript/compiler/builtins/builtins_string_stub_builder.h index 5e4eae67416f57106b2419b2b04b088bc7773323..61496752ab714f73e26e0e23f56f61e8ca9a8256 100644 --- a/ecmascript/compiler/builtins/builtins_string_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_string_stub_builder.h @@ -83,8 +83,6 @@ BUILTINS_WITH_STRING_STUB_BUILDER(DECLARE_BUILTINS_SRRING_STUB_BUILDER) const StringInfoGateRef &rStringInfoGate, GateRef pos); GateRef GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len); GateRef GetFastSubString(GateRef glue, GateRef thisValue, GateRef start, GateRef len); - GateRef StringToUint(GateRef glue, GateRef string, uint64_t maxValue); - GateRef StringDataToUint(GateRef dataUtf8, GateRef len, uint64_t maxValue); private: GateRef ChangeStringTaggedPointerToInt64(GateRef x) { @@ -155,9 +153,9 @@ struct StringInfoGateRef { GateRef string_ { Circuit::NullGate() }; GateRef startIndex_ { Circuit::NullGate() }; GateRef length_ { Circuit::NullGate() }; - explicit StringInfoGateRef(FlatStringStubBuilder* flatString) : string_(flatString->GetFlatString()), - startIndex_(flatString->GetStartIndex()), - length_(flatString->GetLength()) {} + StringInfoGateRef(FlatStringStubBuilder *flatString) : string_(flatString->GetFlatString()), + startIndex_(flatString->GetStartIndex()), + length_(flatString->GetLength()) {} GateRef GetString() const { return string_; diff --git a/ecmascript/compiler/builtins_lowering.cpp b/ecmascript/compiler/builtins_lowering.cpp index 1559680368b661c20090ee1344dc56062d81532a..0bc61553b6cf9ed8e449bcb1436eeb3600344ae0 100644 --- a/ecmascript/compiler/builtins_lowering.cpp +++ b/ecmascript/compiler/builtins_lowering.cpp @@ -14,8 +14,6 @@ */ #include "ecmascript/compiler/builtins_lowering.h" - -#include "builtins/builtins_string_stub_builder.h" #include "ecmascript/global_env.h" namespace panda::ecmascript::kungfu { @@ -494,28 +492,25 @@ void BuiltinLowering::LowerNumberConstructor(GateRef gate) } builder_.Bind(¬Number); { - Label isLineUtf8String(env); - Label notLineUtf8String(env); - // only line string can be integer, because length of sliced string and tree string is at least 13 - BRANCH_CIR(builder_.TaggedIsLineUtf8String(glue, param), &isLineUtf8String, ¬LineUtf8String); - builder_.Bind(&isLineUtf8String); + Label isString(env); + Label notString(env); + GateRef glue = acc_.GetGlueFromArgList(); + BRANCH_CIR(builder_.TaggedIsString(glue, param), &isString, ¬String); + builder_.Bind(&isString); { Label nonZeroLength(env); auto length = builder_.GetLengthFromString(param); BRANCH_CIR(builder_.Equal(length, builder_.Int32(0)), &exit, &nonZeroLength); builder_.Bind(&nonZeroLength); Label isInteger(env); - BuiltinsStringStubBuilder stringStub(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache()); - GateRef dataUtf8 = builder_.PtrAdd(param, builder_.IntPtr(LineString::DATA_OFFSET)); - GateRef res = stringStub.StringDataToUint(dataUtf8, length, std::numeric_limits::max()); - BRANCH_CIR(builder_.Int64NotEqual(res, builder_.Int64(-1)), &isInteger, ¬LineUtf8String); + BRANCH_CIR(builder_.IsIntegerString(param), &isInteger, ¬String); builder_.Bind(&isInteger); { - result = IntToTaggedIntPtr(res); + result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param)); builder_.Jump(&exit); } } - builder_.Bind(¬LineUtf8String); + builder_.Bind(¬String); { result = LowerCallRuntime(glue, gate, RTSTUB_ID(ToNumericConvertBigInt), { param }, true); builder_.Jump(&exit); diff --git a/ecmascript/compiler/call_signature.cpp b/ecmascript/compiler/call_signature.cpp index 7e6dd0bdedb650c64f8708f10f6c14e9440e0422..3d0f8417e839237bd7aa66a37e3be42be32c0940 100644 --- a/ecmascript/compiler/call_signature.cpp +++ b/ecmascript/compiler/call_signature.cpp @@ -3808,20 +3808,6 @@ DEF_CALL_SIGNATURE(FindEntryFromNameDictionary) callSign->SetCallConv(CallSignature::CallConv::CCallConv);; } -DEF_CALL_SIGNATURE(ComputeStringHashcode) -{ - constexpr size_t paramCount = 2; - CallSignature ComputeStringHashcode("ComputeStringHashcode", 0, paramCount, ArgumentsOrder::DEFAULT_ORDER, - VariableType::INT32()); - *callSign = ComputeStringHashcode; - std::array params = { - VariableType::NATIVE_POINTER(), // glue - VariableType::JS_ANY(), // string - }; - callSign->SetParameters(params.data()); - callSign->SetCallConv(CallSignature::CallConv::CCallConv);; -} - DEF_CALL_SIGNATURE(JSProxyGetProperty) { constexpr size_t paramCount = 4; diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index 80b1e7ff8ef028b7e4432a5a300118d03524ddee..8f0dced3c18bfb517095c02706f1d0e7476cd5a5 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -828,7 +828,6 @@ public: inline GateRef TaggedIsNativePointer(GateRef glue, GateRef x); inline GateRef TaggedIsBigInt(GateRef glue, GateRef obj); inline GateRef TaggedIsString(GateRef glue, GateRef obj); - inline GateRef TaggedIsLineUtf8String(GateRef glue, GateRef obj); inline GateRef TaggedIsStringIterator(GateRef glue, GateRef obj); inline GateRef TaggedIsSharedObj(GateRef glue, GateRef obj); inline GateRef TaggedIsStableArray(GateRef glue, GateRef obj); @@ -874,13 +873,14 @@ public: GateRef CalcHashcodeForInt(GateRef value); GateRef GetHashcodeFromString(GateRef glue, GateRef value, GateRef hir = Circuit::NullGate()); GateRef TryGetHashcodeFromString(GateRef string); + GateRef IsIntegerString(GateRef string); GateRef CanBeConcat(GateRef glue, GateRef leftString, GateRef rightString, GateRef isValidOpt); GateRef CanBackStore(GateRef glue, GateRef rightString, GateRef isValidOpt); GateRef GetRawHashFromString(GateRef value); void CopyUtf8AsUtf16(GateRef glue, GateRef dst, GateRef src, GateRef sourceLength); void CopyChars(GateRef glue, GateRef dst, GateRef source, GateRef sourceLength, GateRef charSize, VariableType type); - void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode); + void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger); GateRef StringFromSingleCharCode(GateRef gate); GateRef StringCharCodeAt(GateRef thisValue, GateRef posTag); GateRef StringSubstring(std::vector& args); diff --git a/ecmascript/compiler/common_stub_csigns.h b/ecmascript/compiler/common_stub_csigns.h index cefd82cea608037dcd6e28d35231a73287bd4e35..0337728fbd7e1952b4cf09af1bc354b69536a3ff 100644 --- a/ecmascript/compiler/common_stub_csigns.h +++ b/ecmascript/compiler/common_stub_csigns.h @@ -156,7 +156,6 @@ namespace panda::ecmascript::kungfu { V(FindEntryFromNameDictionary) \ V(ReverseBarrier) \ V(GetValueWithBarrier) \ - V(ComputeStringHashcode) \ V(DefineNormalFuncForJit) \ V(DefineArrowFuncForJit) \ V(DefineBaseConstructorForJit) \ diff --git a/ecmascript/compiler/common_stubs.cpp b/ecmascript/compiler/common_stubs.cpp index eb5197e2930305d94af92c172233c87773200dd9..23f3b6cea44ee521869bc9fc702da0987f3e1839 100644 --- a/ecmascript/compiler/common_stubs.cpp +++ b/ecmascript/compiler/common_stubs.cpp @@ -1913,14 +1913,6 @@ void FindEntryFromNameDictionaryStubBuilder::GenerateCircuit() Return(entry); } -void ComputeStringHashcodeStubBuilder::GenerateCircuit() -{ - GateRef glue = PtrArgument(0); - GateRef str = PtrArgument(1); - GateRef hash = ComputeStringHashcode(glue, str); - Return(hash); -} - CallSignature CommonStubCSigns::callSigns_[CommonStubCSigns::NUM_OF_STUBS]; void CommonStubCSigns::Initialize() diff --git a/ecmascript/compiler/mcr_circuit_builder.cpp b/ecmascript/compiler/mcr_circuit_builder.cpp index 4eb4042453647daaad946eab290c5da66a715a43..9143b7e684a6f8d0c12b8ae29416fb0d9ac888ba 100644 --- a/ecmascript/compiler/mcr_circuit_builder.cpp +++ b/ecmascript/compiler/mcr_circuit_builder.cpp @@ -1330,9 +1330,45 @@ GateRef CircuitBuilder::InsertLoadArrayLength(GateRef array, GateRef length, boo return Circuit::NullGate(); } -void CircuitBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode) +GateRef CircuitBuilder::IsIntegerString(GateRef string) { - Store(VariableType::INT32(), glue, str, IntPtr(BaseString::RAW_HASHCODE_OFFSET), rawHashcode); + // compressedStringsEnabled fixed to true constant + GateRef hash = LoadWithoutBarrier(VariableType::INT32(), string, IntPtr(BaseString::MIX_HASHCODE_OFFSET)); + return Int32Equal( + Int32And(hash, Int32(BaseString::IS_INTEGER_MASK)), + Int32(BaseString::IS_INTEGER_MASK)); +} + +GateRef CircuitBuilder::GetRawHashFromString(GateRef value) +{ + GateRef hash = LoadWithoutBarrier(VariableType::INT32(), value, IntPtr(BaseString::MIX_HASHCODE_OFFSET)); + return Int32And(hash, Int32(~BaseString::IS_INTEGER_MASK)); +} + +void CircuitBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger) +{ + Label subentry(env_); + SubCfgEntry(&subentry); + Label integer(env_); + Label notInteger(env_); + Label exit(env_); + + DEFVALUE(hash, env_, VariableType::INT32(), Int32(0)); + BRANCH(isInteger, &integer, ¬Integer); + Bind(&integer); + { + hash = Int32Or(rawHashcode, Int32(BaseString::IS_INTEGER_MASK)); + Jump(&exit); + } + Bind(¬Integer); + { + hash = Int32And(rawHashcode, Int32(~BaseString::IS_INTEGER_MASK)); + Jump(&exit); + } + Bind(&exit); + Store(VariableType::INT32(), glue, str, IntPtr(BaseString::MIX_HASHCODE_OFFSET), *hash); + SubCfgExit(); + return; } GateRef CircuitBuilder::GetLengthFromString(GateRef value) @@ -1385,12 +1421,13 @@ GateRef CircuitBuilder::GetHashcodeFromString(GateRef glue, GateRef value, GateR Label noRawHashcode(env_); Label exit(env_); DEFVALUE(hashcode, env_, VariableType::INT32(), Int32(0)); - hashcode = LoadWithoutBarrier(VariableType::INT32(), value, IntPtr(BaseString::RAW_HASHCODE_OFFSET)); + hashcode = LoadWithoutBarrier(VariableType::INT32(), value, IntPtr(BaseString::MIX_HASHCODE_OFFSET)); BRANCH(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit); Bind(&noRawHashcode); { - hashcode = CallCommonStub(glue, hir, CommonStubCSigns::ComputeStringHashcode, {glue, value}); - Store(VariableType::INT32(), glue, value, IntPtr(BaseString::RAW_HASHCODE_OFFSET), *hashcode); + hashcode = GetInt32OfTInt( + CallRuntime(glue, RTSTUB_ID(ComputeHashcode), Gate::InvalidGateRef, {value}, hir)); + Store(VariableType::INT32(), glue, value, IntPtr(BaseString::MIX_HASHCODE_OFFSET), *hashcode); Jump(&exit); } Bind(&exit); @@ -1407,8 +1444,8 @@ GateRef CircuitBuilder::TryGetHashcodeFromString(GateRef string) Label storeHash(env_); Label exit(env_); DEFVALUE(result, env_, VariableType::INT64(), Int64(-1)); - GateRef hashCode = ZExtInt32ToInt64( - LoadWithoutBarrier(VariableType::INT32(), string, IntPtr(BaseString::RAW_HASHCODE_OFFSET))); + GateRef hashCode = + ZExtInt32ToInt64(LoadWithoutBarrier(VariableType::INT32(), string, IntPtr(BaseString::MIX_HASHCODE_OFFSET))); BRANCH(Int64Equal(hashCode, Int64(0)), &noRawHashcode, &storeHash); Bind(&noRawHashcode); { diff --git a/ecmascript/compiler/mcr_circuit_builder.h b/ecmascript/compiler/mcr_circuit_builder.h index 8b6cf64f0aa4dffc6983ed2f79bdfd0466519cb4..8d15d04357041adaf024564f14cdd6f901c018c5 100644 --- a/ecmascript/compiler/mcr_circuit_builder.h +++ b/ecmascript/compiler/mcr_circuit_builder.h @@ -206,14 +206,6 @@ GateRef CircuitBuilder::TaggedIsString(GateRef glue, GateRef obj) return ret; } -GateRef CircuitBuilder::TaggedIsLineUtf8String(GateRef glue, GateRef obj) -{ - return LogicAndBuilder(env_).And(TaggedIsString(glue, obj)) - .And(IsLineString(glue, obj)) - .And(IsUtf8String(obj)) - .Done(); -} - GateRef CircuitBuilder::TaggedIsStringIterator(GateRef glue, GateRef obj) { Label entry(env_); diff --git a/ecmascript/compiler/new_object_stub_builder.cpp b/ecmascript/compiler/new_object_stub_builder.cpp index 991782114d276df2dbcfed6b74b6fdc3255028d3..edc7e09a1519d27e16088c22b33fdc7a2ac13bfb 100644 --- a/ecmascript/compiler/new_object_stub_builder.cpp +++ b/ecmascript/compiler/new_object_stub_builder.cpp @@ -1964,7 +1964,7 @@ void NewObjectStubBuilder::AllocLineStringObject(Variable *result, Label *exit, Bind(&afterAllocate); StoreHClass(glue_, result->ReadVariable(), stringClass); InitStringLengthAndFlags(glue_, result->ReadVariable(), length, compressed); - SetRawHashcode(glue_, result->ReadVariable(), Int32(0)); + SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False()); Jump(exit); } @@ -1988,7 +1988,7 @@ void NewObjectStubBuilder::AllocSlicedStringObject(Variable *result, Label *exit InitStringLengthAndFlags(glue_, result->ReadVariable(), length, BoolNot(compressedStatus)); // decode compressedStatus to bool - SetRawHashcode(glue_, result->ReadVariable(), Int32(0)); + SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False()); BuiltinsStringStubBuilder builtinsStringStubBuilder(this, GetCurrentGlobalEnv()); builtinsStringStubBuilder.StoreParent(glue_, result->ReadVariable(), flatString->GetFlatString()); builtinsStringStubBuilder.StoreStartIndexAndBackingStore(glue_, result->ReadVariable(), @@ -2011,7 +2011,7 @@ void NewObjectStubBuilder::AllocTreeStringObject(Variable *result, Label *exit, Bind(&afterAllocate); StoreHClass(glue_, result->ReadVariable(), stringClass); InitStringLengthAndFlags(glue_, result->ReadVariable(), length, compressed); - SetRawHashcode(glue_, result->ReadVariable(), Int32(0)); + SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False()); Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(TreeString::FIRST_OFFSET), first); Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(TreeString::SECOND_OFFSET), second); Jump(exit); diff --git a/ecmascript/compiler/object_operator_stub_builder.cpp b/ecmascript/compiler/object_operator_stub_builder.cpp index e2bbcc9abaefe11bf58e8d9a50d38fb43ab34c14..b43748e019ccbc424f22a1a39453a3e7d3e62603 100644 --- a/ecmascript/compiler/object_operator_stub_builder.cpp +++ b/ecmascript/compiler/object_operator_stub_builder.cpp @@ -26,6 +26,40 @@ namespace panda::ecmascript::kungfu { +void ObjectOperatorStubBuilder::TryFastHandleStringKey(GateRef key, Variable *propKey, Variable *elemKey, + Label *isProperty, Label *isElement, Label *tryFailed) +{ + auto env = GetEnvironment(); + Label isInternString(env); + + BRANCH(IsInternalString(key), &isInternString, tryFailed); + + Bind(&isInternString); + { + Label isIntegerString(env); + Label notIntegerString(env); + + BRANCH(IsIntegerString(key), &isIntegerString, ¬IntegerString); + + Bind(&isIntegerString); + { + *elemKey = GetRawHashFromString(key); + Jump(isElement); + } + + Bind(¬IntegerString); + { + Label keyIsProperty(env); + GateRef len = GetLengthFromString(key); + BRANCH(Int32LessThanOrEqual(len, Int32(BaseString::MAX_CACHED_INTEGER_SIZE)), &keyIsProperty, tryFailed); + + Bind(&keyIsProperty); + *propKey = key; + Jump(isProperty); + } + } +} + // ObjectOperator::HandleKey void ObjectOperatorStubBuilder::HandleKey(GateRef glue, GateRef key, Variable *propKey, Variable *elemKey, Label *isProperty, Label *isElement, Label *hasException, GateRef hir) @@ -69,9 +103,12 @@ void ObjectOperatorStubBuilder::HandleKey(GateRef glue, GateRef key, Variable *p Label toInternString(env); Label index64To32(env); Label notInternString(env); + Label tryFailed(env); DEFVARIABLE(index64, VariableType::INT64(), Int64(-1)); - BuiltinsStringStubBuilder stringStub(this, GetCurrentGlobalEnv()); - index64 = stringStub.StringToUint(glue, key, JSObject::MAX_ELEMENT_INDEX - 1); + TryFastHandleStringKey(key, propKey, elemKey, isProperty, isElement, &tryFailed); + + Bind(&tryFailed); + index64 = StringToElementIndex(glue, key); BRANCH(Int64Equal(*index64, Int64(-1)), &toInternString, &index64To32); Bind(&toInternString); { diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 583a5538e198e84a3d3c490705fae229ead2e462..756a232d63ec25ac9533a22d88306a9631e80da7 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -4023,9 +4023,19 @@ inline void StubBuilder::InitStringLengthAndFlags(GateRef glue, GateRef str, Gat Store(VariableType::INT32(), glue, str, IntPtr(BaseString::LENGTH_AND_FLAGS_OFFSET), mixLength); } -inline void StubBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode) +inline GateRef StubBuilder::IsIntegerString(GateRef string) { - env_->GetBuilder()->SetRawHashcode(glue, str, rawHashcode); + return env_->GetBuilder()->IsIntegerString(string); +} + +inline GateRef StubBuilder::GetRawHashFromString(GateRef value) +{ + return env_->GetBuilder()->GetRawHashFromString(value); +} + +inline void StubBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger) +{ + env_->GetBuilder()->SetRawHashcode(glue, str, rawHashcode, isInteger); } inline GateRef StubBuilder::TryGetHashcodeFromString(GateRef string) @@ -4033,6 +4043,11 @@ inline GateRef StubBuilder::TryGetHashcodeFromString(GateRef string) return env_->GetBuilder()->TryGetHashcodeFromString(string); } +inline GateRef StubBuilder::GetMixHashcode(GateRef string) +{ + return LoadPrimitive(VariableType::INT32(), string, IntPtr(BaseString::MIX_HASHCODE_OFFSET)); +} + inline void StubBuilder::SetElementsKindToJSHClass(GateRef glue, GateRef jsHclass, GateRef elementsKind) { GateRef bitfield = LoadPrimitive(VariableType::INT32(), jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); @@ -4387,7 +4402,7 @@ inline GateRef StubBuilder::HashFromHclassAndStringKey([[maybe_unused]] GateRef Int64LSR(hclassRef, Int64(MegaICCache::PRIMARY_LENGTH_BIT)))); // skip 8bytes GateRef keyHash = Load(VariableType::INT32(), glue, key, - IntPtr(BaseString::RAW_HASHCODE_OFFSET)); + IntPtr(BaseString::MIX_HASHCODE_OFFSET)); GateRef temp = Int32Add(clsHash, keyHash); return Int32And(temp, Int32(MegaICCache::PRIMARY_LENGTH_MASK)); } diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 2a39f1a1177aad487a1bb20e89b87b1d252f851d..d8f04789b8f5f5023b331cfca1ab8b3634c1d31e 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -2538,6 +2538,120 @@ GateRef StubBuilder::IsDigit(GateRef ch) Int32GreaterThanOrEqual(ch, Int32('0'))); } +void StubBuilder::TryToGetInteger(GateRef string, Variable *num, Label *success, Label *failed) +{ + auto env = GetEnvironment(); + Label exit(env); + Label inRange(env); + Label isInteger(env); + + GateRef len = GetLengthFromString(string); + BRANCH(Int32LessThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &inRange, failed); + Bind(&inRange); + { + BRANCH(IsIntegerString(string), &isInteger, failed); + Bind(&isInteger); + { + GateRef integerNum = ZExtInt32ToInt64(GetRawHashFromString(string)); + num->WriteVariable(integerNum); + Jump(success); + } + } +} + +GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + Label exit(env); + DEFVARIABLE(result, VariableType::INT64(), Int64(-1)); + Label greatThanZero(env); + Label inRange(env); + Label flattenFastPath(env); + auto len = GetLengthFromString(string); + BRANCH(Int32Equal(len, Int32(0)), &exit, &greatThanZero); + Bind(&greatThanZero); + BRANCH(Int32GreaterThan(len, Int32(MAX_ELEMENT_INDEX_LEN)), &exit, &inRange); + Bind(&inRange); + { + Label isUtf8(env); + GateRef isUtf16String = IsUtf16String(string); + BRANCH(isUtf16String, &exit, &isUtf8); + Bind(&isUtf8); + { + Label getFailed(env); + TryToGetInteger(string, &result, &exit, &getFailed); + Bind(&getFailed); + DEFVARIABLE(c, VariableType::INT32(), Int32(0)); + FlatStringStubBuilder thisFlat(this); + thisFlat.FlattenString(glue, string, &flattenFastPath); + Bind(&flattenFastPath); + StringInfoGateRef stringInfoGate(&thisFlat); + GateRef dataUtf8 = GetNormalStringData(glue, stringInfoGate); + c = ZExtInt8ToInt32(LoadZeroOffsetPrimitive(VariableType::INT8(), dataUtf8)); + Label isDigitZero(env); + Label notDigitZero(env); + BRANCH(Int32Equal(*c, Int32('0')), &isDigitZero, ¬DigitZero); + Bind(&isDigitZero); + { + Label lengthIsOne(env); + BRANCH(Int32Equal(len, Int32(1)), &lengthIsOne, &exit); + Bind(&lengthIsOne); + { + result = Int64(0); + Jump(&exit); + } + } + Bind(¬DigitZero); + { + Label isDigit(env); + DEFVARIABLE(i, VariableType::INT32(), Int32(1)); + DEFVARIABLE(n, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(*c), Int64('0'))); + BRANCH(IsDigit(*c), &isDigit, &exit); + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Bind(&isDigit); + BRANCH(Int32UnsignedLessThan(*i, len), &loopHead, &afterLoop); + LoopBegin(&loopHead); + { + c = ZExtInt8ToInt32(LoadPrimitive(VariableType::INT8(), dataUtf8, ZExtInt32ToPtr(*i))); + Label isDigit2(env); + Label notDigit2(env); + BRANCH(IsDigit(*c), &isDigit2, ¬Digit2); + Bind(&isDigit2); + { + // 10 means the base of digit is 10. + n = Int64Add(Int64Mul(*n, Int64(10)), Int64Sub(ZExtInt32ToInt64(*c), Int64('0'))); + i = Int32Add(*i, Int32(1)); + BRANCH(Int32UnsignedLessThan(*i, len), &loopEnd, &afterLoop); + } + Bind(¬Digit2); + Jump(&exit); + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&afterLoop); + { + Label lessThanMaxIndex(env); + BRANCH(Int64LessThan(*n, Int64(JSObject::MAX_ELEMENT_INDEX)), + &lessThanMaxIndex, &exit); + Bind(&lessThanMaxIndex); + { + result = *n; + Jump(&exit); + } + } + } + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + GateRef StubBuilder::TryToElementsIndex(GateRef glue, GateRef key) { auto env = GetEnvironment(); @@ -2561,8 +2675,7 @@ GateRef StubBuilder::TryToElementsIndex(GateRef glue, GateRef key) BRANCH(TaggedIsString(glue, key), &isString, ¬String); Bind(&isString); { - BuiltinsStringStubBuilder stringStub(this, GetCurrentGlobalEnv()); - resultKey = stringStub.StringToUint(glue, key, JSObject::MAX_ELEMENT_INDEX - 1); + resultKey = StringToElementIndex(glue, key); Jump(&exit); } Bind(¬String); @@ -13333,65 +13446,6 @@ GateRef StubBuilder::ThreeInt64Min(GateRef first, GateRef second, GateRef third) return env_->GetBuilder()->ThreeInt64Min(first, second, third); } -void StubBuilder::ComputeRawHashcode(GateRef glue, Label *exit, Variable* result, StringInfoGateRef stringGate, bool isUtf8) -{ - auto env= GetEnvironment(); - Label loopHead(env); - Label loopEnd(env); - Label doLoop(env); - GateRef hashShift = Int32(static_cast(BaseString::HASH_SHIFT)); - GateRef length = stringGate.GetLength(); - GateRef data = GetNormalStringData(glue, stringGate); - DEFVARIABLE(i, VariableType::INT32(), Int32(0)); - Jump(&loopHead); - LoopBegin(&loopHead); - { - BRANCH_LIKELY(Int32LessThan(*i, length), &doLoop, exit); - Bind(&doLoop); - { - GateRef offset = isUtf8 ? *i : Int32LSL(*i, Int32(1)); - GateRef c = LoadPrimitive(isUtf8 ? VariableType::INT8() : VariableType::INT16(), data, offset); - GateRef u32c = isUtf8 ? ZExtInt8ToInt32(c) : ZExtInt16ToInt32(c); - GateRef preHash = result->ReadVariable(); - result->WriteVariable(Int32Add(Int32Sub(Int32LSL(preHash, hashShift), preHash), u32c)); - Jump(&loopEnd); - } - } - Bind(&loopEnd); - i = Int32Add(*i, Int32(1)); - LoopEnd(&loopHead); -} - -GateRef StubBuilder::ComputeStringHashcode(GateRef glue, GateRef str) -{ - auto env = GetEnvironment(); - Label entry(env); - env->SubCfgEntry(&entry); - Label exit(env); - DEFVARIABLE(result, VariableType::INT32(), Int32(0)); - - FlatStringStubBuilder flatBuilder(this); - Label afterFlatten(env); - flatBuilder.FlattenString(glue, str, &afterFlatten); - Bind(&afterFlatten); - StringInfoGateRef stringInfoGate(&flatBuilder); - Label isUtf8(env); - Label isUtf16(env); - BRANCH(IsUtf8String(stringInfoGate.GetString()), &isUtf8, &isUtf16); - Bind(&isUtf8); - { - ComputeRawHashcode(glue, &exit, &result, stringInfoGate, true); - } - Bind(&isUtf16); - { - ComputeRawHashcode(glue, &exit, &result, stringInfoGate, false); - } - Bind(&exit); - auto ret = *result; - env->SubCfgExit(); - return ret; -} - GateRef StubBuilder::GetCurrentGlobalEnv(GateRef glue, GateRef currentEnv) { auto env0 = GetEnvironment(); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 6522764427ed2487f3d6480dae0ccde54f5e030e..ed4de2cf4901c6f37da9aa8f7d924d2357019240 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -590,8 +590,11 @@ public: void CalcHashcodeForDouble(GateRef value, Variable *res, Label *exit); void CalcHashcodeForObject(GateRef glue, GateRef value, Variable *res, Label *exit); GateRef GetHashcodeFromString(GateRef glue, GateRef value, GateRef hir = Circuit::NullGate()); - inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode); + inline GateRef IsIntegerString(GateRef string); + inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger); + inline GateRef GetRawHashFromString(GateRef value); GateRef TryGetHashcodeFromString(GateRef string); + inline GateRef GetMixHashcode(GateRef string); GateRef GetFirstFromTreeString(GateRef glue, GateRef string); GateRef GetSecondFromTreeString(GateRef glue, GateRef string); GateRef GetIsAllTaggedPropFromHClass(GateRef hclass); @@ -706,6 +709,8 @@ public: GateRef IsUtf8String(GateRef string); GateRef IsInternalString(GateRef string); GateRef IsDigit(GateRef ch); + void TryToGetInteger(GateRef string, Variable *num, Label *success, Label *failed); + GateRef StringToElementIndex(GateRef glue, GateRef string); GateRef ComputeElementCapacity(GateRef oldLength); GateRef ComputeNonInlinedFastPropsCapacity(GateRef glue, GateRef oldLength, GateRef maxNonInlinedFastPropsCapacity); @@ -1067,8 +1072,6 @@ public: void ArrayCopyAndHoleToUndefined(GateRef glue, GateRef srcObj, GateRef srcAddr, GateRef dstObj, GateRef dstAddr, GateRef length, GateRef needBarrier); GateRef ThreeInt64Min(GateRef first, GateRef second, GateRef third); - void ComputeRawHashcode(GateRef glue, Label *exit, Variable* result, StringInfoGateRef stringGate, bool isUtf8); - GateRef ComputeStringHashcode(GateRef glue, GateRef str); void MigrateArrayWithKind(GateRef glue, GateRef object, GateRef oldKind, GateRef newKind); GateRef MigrateFromRawValueToHeapValues(GateRef glue, GateRef object, GateRef needCOW, GateRef isIntKind); GateRef MigrateFromHeapValueToRawValue(GateRef glue, GateRef object, GateRef needCOW, GateRef isIntKind); diff --git a/ecmascript/compiler/typed_native_inline_lowering.cpp b/ecmascript/compiler/typed_native_inline_lowering.cpp index fae19d3617309f9b1f249e9c746f873513f5372a..13666c20f7db8d1f14060e45a8df5efe2cdbcfc6 100644 --- a/ecmascript/compiler/typed_native_inline_lowering.cpp +++ b/ecmascript/compiler/typed_native_inline_lowering.cpp @@ -1170,14 +1170,10 @@ void TypedNativeInlineLowering::LowerNewNumber(GateRef gate) } builder_.Bind(¬Number); { - builder_.DeoptCheck(builder_.TaggedIsLineUtf8String(glue, param), FindFrameState(gate), DeoptType::NOTSTRING1); - auto length = builder_.GetLengthFromString(param); - builder_.DeoptCheck(builder_.NotEqual(length, builder_.Int32(0)), FindFrameState(gate), DeoptType::NOTINT1); - BuiltinsStringStubBuilder stringStub(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache()); - GateRef dataUtf8 = builder_.PtrAdd(param, builder_.IntPtr(LineString::DATA_OFFSET)); - GateRef res = stringStub.StringDataToUint(dataUtf8, length, std::numeric_limits::max()); - builder_.DeoptCheck(builder_.NotEqual(res, builder_.Int64(-1)), FindFrameState(gate), DeoptType::NOTINT1); - result = builder_.ToTaggedIntPtr(res); + builder_.DeoptCheck(builder_.TaggedIsString(glue, param), FindFrameState(gate), DeoptType::NOTSTRING1); + auto isIntString = builder_.IsIntegerString(param); + builder_.DeoptCheck(isIntString, FindFrameState(gate), DeoptType::NOTINT1); + result = builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(builder_.GetRawHashFromString(param))); builder_.Jump(&exit); } builder_.Bind(&exit); @@ -1960,22 +1956,12 @@ void TypedNativeInlineLowering::LowerNumberParseInt(GateRef gate) gate, glue_, builder_.GetState(), builder_.GetDepend(), *result); } -GateRef TypedNativeInlineLowering::CheckAndConvertToUInt(GateRef glue, GateRef msg, Label* notIntegerStr, - Label* nonZeroLength) -{ - auto length = builder_.GetLengthFromString(msg); - BRANCH_CIR(builder_.Equal(length, builder_.Int32(0)), notIntegerStr, nonZeroLength); - builder_.Bind(nonZeroLength); - BuiltinsStringStubBuilder stringStub(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache()); - GateRef dataUtf8 = builder_.PtrAdd(msg, builder_.IntPtr(LineString::DATA_OFFSET)); - return stringStub.StringDataToUint(dataUtf8, length, std::numeric_limits::max()); -} - void TypedNativeInlineLowering::LowerNumberParseFloat(GateRef gate) { Environment env(gate, circuit_, &builder_); DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.HoleConstant()); + Label slowPath(&builder_); Label exit(&builder_); Label definedMsg(&builder_); @@ -1987,21 +1973,14 @@ void TypedNativeInlineLowering::LowerNumberParseFloat(GateRef gate) auto frameState = acc_.GetFrameState(gate); GateRef glue = glue_; builder_.DeoptCheck(builder_.TaggedIsString(glue, msg), frameState, DeoptType::NOTSTRING1); + Label isIntegerStr(&builder_); Label notIntegerStr(&builder_); Label exitIntegerStr(&builder_); - Label isLineUtf8String(&builder_); - BRANCH_CIR(builder_.TaggedIsLineUtf8String(glue, msg), &isLineUtf8String, ¬IntegerStr); - builder_.Bind(&isLineUtf8String); + builder_.Branch(builder_.IsIntegerString(msg), &isIntegerStr, ¬IntegerStr); + builder_.Bind(&isIntegerStr); { - Label isInteger(&builder_); - Label nonZeroLength(&builder_); - GateRef res = CheckAndConvertToUInt(glue, msg, ¬IntegerStr, &nonZeroLength); - BRANCH_CIR(builder_.Int64NotEqual(res, builder_.Int64(-1)), &isInteger, ¬IntegerStr); - builder_.Bind(&isInteger); - { - result = builder_.ChangeInt32ToFloat64(builder_.TruncInt64ToInt32(res)); - builder_.Jump(&exitIntegerStr); - } + result = builder_.ChangeInt32ToFloat64(builder_.GetRawHashFromString(msg)); + builder_.Jump(&exitIntegerStr); } builder_.Bind(¬IntegerStr); { diff --git a/ecmascript/compiler/typed_native_inline_lowering.h b/ecmascript/compiler/typed_native_inline_lowering.h index 48db93a9323959e91b724013c3e9a9bfc2bad94b..757a495ccefb62f0db0639bcea2643a432e03720 100644 --- a/ecmascript/compiler/typed_native_inline_lowering.h +++ b/ecmascript/compiler/typed_native_inline_lowering.h @@ -170,7 +170,6 @@ private: Variable* res, Variable* start, Variable* end); - GateRef CheckAndConvertToUInt(GateRef glue, GateRef msg, Label* notIntegerStr, Label* nonZeroLength); private: Circuit* circuit_ {nullptr}; diff --git a/ecmascript/ecma_string-inl.h b/ecmascript/ecma_string-inl.h index a4fb4c2af70f79be09706a38082afd7bac50fd34..df4380f88f33d8e8fbacfe1cb3c5b27ac81f3910 100644 --- a/ecmascript/ecma_string-inl.h +++ b/ecmascript/ecma_string-inl.h @@ -32,7 +32,7 @@ inline EcmaString *EcmaString::CreateEmptyString(const EcmaVM *vm) { auto string = vm->GetFactory()->AllocNonMovableLineStringObject(BaseString::SIZE); string->InitLengthAndFlags(0, true); - string->SetRawHashcode(0); + string->SetMixHashcode(0); return string; } diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index ffde10ca1c75ebe4d88662aa87a69c59af0a20bd..66983103fc30b6a9fbb518ecb7c628477759f1cf 100755 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -32,8 +32,6 @@ constexpr size_t OFFSET_12POS = 12; constexpr size_t OFFSET_10POS = 10; constexpr size_t OFFSET_6POS = 6; -using NumberHelper = base::NumberHelper; - EcmaString *EcmaString::Concat(const EcmaVM *vm, const JSHandle &left, const JSHandle &right, MemSpaceType type) { @@ -405,27 +403,28 @@ std::u16string EcmaString::ToU16String(const JSThread *thread, uint32_t len) return ToBaseString()->ToU16String(std::move(readBarrier), len); } -// static -#if ENABLE_NEXT_OPTIMIZATION -template -uint32_t EcmaString::CalculateDataConcatHashCode(const T1 *dataFirst, size_t sizeFirst, - const T2 *dataSecond, size_t sizeSecond) -{ - return BaseString::CalculateDataConcatHashCode(dataFirst, sizeFirst, dataSecond, sizeSecond); -} -#else + template uint32_t EcmaString::CalculateDataConcatHashCode(const T1 *dataFirst, size_t sizeFirst, const T2 *dataSecond, size_t sizeSecond) { return BaseString::CalculateDataConcatHashCode(dataFirst, sizeFirst, dataSecond, sizeSecond); } -#endif // static uint32_t EcmaString::CalculateConcatHashCode(const JSThread *thread, const JSHandle &firstString, const JSHandle &secondString) { + uint32_t hashCode; + uint32_t firstLength = firstString->GetLength(); + uint32_t secondLength = secondString->GetLength(); + if ((firstLength + secondLength < BaseString::MAX_ELEMENT_INDEX_LEN) && + firstString->IsUtf8() && secondString->IsUtf8() && + firstString->IsInteger(thread) && secondString->IsInteger(thread)) { + firstString->HashIntegerString(firstLength, &hashCode, 0); + secondString->HashIntegerString(secondLength, &hashCode, hashCode); + return hashCode; + } bool isFirstStringUtf8 = EcmaStringAccessor(firstString).IsUtf8(); bool isSecondStringUtf8 = EcmaStringAccessor(secondString).IsUtf8(); EcmaString *firstStr = *firstString; @@ -460,6 +459,13 @@ uint32_t EcmaString::CalculateConcatHashCode(const JSThread *thread, const JSHan } } +bool EcmaString::HashIntegerString(uint32_t length, uint32_t *hash, const uint32_t hashSeed) const +{ + ASSERT(length >= 0); + Span str = FastToUtf8Span(); + return BaseString::HashIntegerString(str.data(), length, hash, hashSeed); +} + // static bool EcmaString::CanBeCompressed(const EcmaString *string) { @@ -583,15 +589,6 @@ bool EcmaString::MemCopyChars(Span &dst, size_t dstMax, Span &src, s return true; } -// hashSeed only be used when computing two separate strings merged hashcode. -uint32_t EcmaString::ComputeRawHashcode(const JSThread *thread) const -{ - auto readBarrier = [thread](const void *obj, size_t offset) -> TaggedObject * { - return Barriers::GetTaggedObject(thread, obj, offset); - }; - return ToBaseString()->ComputeRawHashcode(std::move(readBarrier)); -} - /* static */ uint32_t EcmaString::ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress) { @@ -614,10 +611,22 @@ bool EcmaString::ToElementIndex(const JSThread *thread, uint32_t *index) return false; } + // fast path: get integer from string's hash value + if (TryToGetInteger(thread, index)) { + return true; + } + CVector buf; const uint8_t *data = EcmaString::GetUtf8DataFlat(thread, this, buf); - constexpr uint64_t maxValue = std::numeric_limits::max() - 1; - if (NumberHelper::StringToUint(std::basic_string_view(data, GetLength()), *index, maxValue)) { + uint32_t c = data[0]; + uint64_t n = 0; + if (c == '0') { + *index = 0; + return len == 1; + } + uint32_t loopStart = 0; + if (ToUInt64FromLoopStart(&n, loopStart, data) && n < JSObject::MAX_ELEMENT_INDEX) { + *index = n; return true; } return false; diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index 11aa38ad600b7955831ea2d30b49268eb2ad8a52..750014bd4d71859569f8af28982a6b4c74ac7d70 100755 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -91,9 +91,9 @@ public: TRIM_END, }; - void SetRawHashcode(uint32_t rawHashCode) + void SetMixHashcode(uint32_t mixHashCode) { - return ToBaseString()->SetRawHashcode(rawHashCode); + return ToBaseString()->SetMixHashcode(mixHashCode); } private: @@ -134,8 +134,11 @@ private: static uint32_t CalculateConcatHashCode(const JSThread *thread, const JSHandle &firstString, const JSHandle &secondString); + + bool HashIntegerString(uint32_t length, uint32_t *hash, uint32_t hashSeed) const; + static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle &original, - uint32_t length, bool compressed); + uint32_t length, bool compressed); static EcmaString *FastSubString(const EcmaVM *vm, const JSHandle &src, uint32_t start, uint32_t length); static bool SubStringIsUtf8(const EcmaVM *vm, @@ -164,6 +167,14 @@ private: return ToBaseString()->IsUtf16(); } + inline bool IsInteger(const JSThread* thread) + { + auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { + return Barriers::GetTaggedObject(thread, obj, offset); + }; + return ToBaseString()->IsInteger(std::move(readBarrier)); + } + inline const uint8_t *GetDataUtf8() const; inline const uint16_t *GetDataUtf16() const; @@ -209,16 +220,21 @@ private: // if string is not flat, this func has low efficiency. uint32_t PUBLIC_API GetHashcode(const JSThread *thread) { - uint32_t hashcode = ToBaseString()->GetRawHashcode(); - // GetLength() == 0 means it's an empty array.No need to computeHashCode again when hashseed is 0. - if (hashcode == 0 && GetLength() != 0) { - hashcode = ComputeRawHashcode(thread); - SetRawHashcode(hashcode); - } - return hashcode; + auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { + return Barriers::GetTaggedObject(thread, obj, offset); + }; + return ToBaseString()->GetHashcode(std::move(readBarrier)); } - uint32_t PUBLIC_API ComputeRawHashcode(const JSThread *thread) const; + // not change this data structure. + // if string is not flat, this func has low efficiency. + uint32_t PUBLIC_API ComputeHashcode(const JSThread *thread) const + { + auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* { + return Barriers::GetTaggedObject(thread, obj, offset); + }; + return ToBaseString()->ComputeHashcode(std::move(readBarrier)); + } static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress); static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length); @@ -328,6 +344,28 @@ private: ToBaseString()->WriteData(std::move(readBarrier), src->ToBaseString(), start, destSize, length); } + bool TryToGetInteger(const JSThread *thread, uint32_t *result) + { + if (!IsInteger(thread)) { + return false; + } + ASSERT(GetLength() <= BaseString::MAX_CACHED_INTEGER_SIZE); + *result = GetIntegerCode(); + return true; + } + + inline uint32_t GetIntegerCode() + { + ASSERT(ToBaseString()->GetMixHashcode() & BaseString::IS_INTEGER_MASK); + return ToBaseString()->GetRawHashcode(); + } + + // using integer number set into hash + inline bool TryToSetIntegerHash(int32_t num) + { + return ToBaseString()->TryToSetIntegerHash(num); + } + static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len); static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len); static bool CanBeCompressed(const EcmaString *string); @@ -904,6 +942,17 @@ public: return string_->ToUtf8Span(thread, buf); } + // Using string's hash to figure out whether the string can be converted to integer + inline bool TryToGetInteger(const JSThread *thread, uint32_t *result) + { + return string_->TryToGetInteger(thread, result); + } + + inline bool TryToSetIntegerHash(int32_t num) + { + return string_->TryToSetIntegerHash(num); + } + // not change string data structure. // if string is not flat, this func has low efficiency. std::string ToStdString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::PRINT); @@ -988,7 +1037,7 @@ public: uint32_t ComputeHashcode(const JSThread *thread) { - return string_->ComputeRawHashcode(thread); + return string_->ComputeHashcode(thread); } static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress) @@ -1172,6 +1221,16 @@ public: return string_->IsSlicedString(); } + bool IsInteger(JSThread* thread) const + { + return string_->IsInteger(thread); + } + + uint32_t GetIntegerCode() const + { + return string_->GetIntegerCode(); + } + bool IsTreeString() const { return string_->IsTreeString(); diff --git a/ecmascript/ecma_string_table.cpp b/ecmascript/ecma_string_table.cpp index b8116c56627ec9e2f16f086ec825bd8c77c96b85..d0715e18a51fb350ff06ea5375e7df4ceb086d39 100644 --- a/ecmascript/ecma_string_table.cpp +++ b/ecmascript/ecma_string_table.cpp @@ -287,7 +287,7 @@ EcmaString *EcmaStringTable::GetOrInternStringFromCompressedSubString(EcmaVM *vm EcmaString *str = EcmaStringAccessor::CreateFromUtf8CompressedSubString(vm, string, offset, utf8Len, MemSpaceType::SHARED_OLD_SPACE); JSHandle strHandle(thread, str); - strHandle->SetRawHashcode(hashcode); + strHandle->SetMixHashcode(hashcode); return AtomicGetOrInternStringImpl(thread, strHandle, hashcode); } @@ -331,7 +331,7 @@ EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const JSHandle flattenConcatHandle(thread, EcmaStringAccessor::Flatten(vm, concatHandle, MemSpaceType::SHARED_OLD_SPACE)); - flattenConcatHandle->SetRawHashcode(hashcode); + flattenConcatHandle->SetMixHashcode(hashcode); return AtomicGetOrInternStringImpl(thread, flattenConcatHandle, hashcode); } @@ -351,7 +351,7 @@ EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const uint8_t *utf8Da } JSHandle strHandle(thread, EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type)); - strHandle->SetRawHashcode(hashcode); + strHandle->SetMixHashcode(hashcode); return AtomicGetOrInternStringImpl(thread, strHandle, hashcode); } @@ -378,7 +378,7 @@ EcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const uint16_t *utf16 } JSHandle strHandle(thread, EcmaStringAccessor::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE)); - strHandle->SetRawHashcode(hashcode); + strHandle->SetMixHashcode(hashcode); return AtomicGetOrInternStringImpl(thread, strHandle, hashcode); } @@ -435,7 +435,7 @@ EcmaString *EcmaStringTable::GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, } EcmaString *str = nullptr; str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type); - str->SetRawHashcode(hashcode); + str->SetMixHashcode(hashcode); InternStringThreadUnsafe(str, hashcode); return str; } @@ -462,7 +462,7 @@ EcmaString *EcmaStringTable::GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, return result; } EcmaString *str = EcmaStringAccessor::CreateFromUtf16(vm, u16Buffer.data(), utf16Len, false, type); - str->SetRawHashcode(hashcode); + str->SetMixHashcode(hashcode); InternStringThreadUnsafe(str, hashcode); return str; } @@ -573,7 +573,7 @@ EcmaString *EcmaStringTable::GetOrInternStringThreadUnsafe(EcmaVM *vm, JSHandle concatHandle(thread, EcmaStringAccessor::Concat(vm, firstFlat, secondFlat, MemSpaceType::SHARED_OLD_SPACE)); EcmaString *concatString = EcmaStringAccessor::Flatten(vm, concatHandle, MemSpaceType::SHARED_OLD_SPACE); - concatString->SetRawHashcode(hashcode); + concatString->SetMixHashcode(hashcode); InternStringThreadUnsafe(concatString, hashcode); return concatString; } @@ -590,7 +590,7 @@ EcmaString *EcmaStringTable::GetOrInternStringThreadUnsafe(EcmaVM *vm, const uin } EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); - str->SetRawHashcode(hashcode); + str->SetMixHashcode(hashcode); InternStringThreadUnsafe(str, hashcode); return str; } diff --git a/ecmascript/ecma_string_table_optimization.cpp b/ecmascript/ecma_string_table_optimization.cpp index eb1c8ea05ad802e34a9101a7e31087bfc5305e29..615cd3d83e087fae99f8de5f8ce59cbafab3cf07 100644 --- a/ecmascript/ecma_string_table_optimization.cpp +++ b/ecmascript/ecma_string_table_optimization.cpp @@ -170,7 +170,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternStringFromCompressedSubStrin [vm, string, offset, utf8Len, hashcode]() -> common::ReadOnlyHandle { EcmaString* str = EcmaStringAccessor::CreateFromUtf8CompressedSubString(vm, string, offset, utf8Len, MemSpaceType::SHARED_OLD_SPACE); - str->SetRawHashcode(hashcode); + str->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(str).IsInternString()); ASSERT(EcmaStringAccessor(str).NotTreeString()); // Strings in string table should not be in the young space. @@ -244,7 +244,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternString(EcmaVM* vm, const JSH JSHandle concatHandle( thread, EcmaStringAccessor::Concat(vm, firstFlat, secondFlat, MemSpaceType::SHARED_OLD_SPACE)); EcmaString *value = EcmaStringAccessor::Flatten(vm, concatHandle, MemSpaceType::SHARED_OLD_SPACE); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(value).IsInternString()); ASSERT(EcmaStringAccessor(value).NotTreeString()); // Strings in string table should not be in the young space. @@ -281,7 +281,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternString(EcmaVM* vm, const uin holder, hashcode, [vm, hashcode, utf8Data, utf8Len, canBeCompress, type]() { EcmaString* value = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(value).IsInternString()); ASSERT(EcmaStringAccessor(value).NotTreeString()); // Strings in string table should not be in the young space. @@ -339,7 +339,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternString(EcmaVM* vm, const uin [vm, utf16Data, utf16Len, canBeCompress, hashcode]() { EcmaString* value = EcmaStringAccessor::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(value).IsInternString()); ASSERT(EcmaStringAccessor(value).NotTreeString()); // Strings in string table should not be in the young space. @@ -387,7 +387,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternStringWithoutJSHandleForJit( [vm, utf8Data, utf8Len, canBeCompress, type, hashcode]() { EcmaString *value = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(value).IsInternString()); ASSERT(EcmaStringAccessor(value).NotTreeString()); // Strings in string table should not be in the young space. @@ -424,7 +424,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternStringWithoutJSHandleForJit( holder, hashcode, [vm, u16Buffer, utf16Len, hashcode, type]() { EcmaString *value = EcmaStringAccessor::CreateFromUtf16(vm, u16Buffer.data(), utf16Len, false, type); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(value).IsInternString()); ASSERT(EcmaStringAccessor(value).NotTreeString()); // Strings in string table should not be in the young space. @@ -500,7 +500,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternStringThreadUnsafe( JSHandle concatHandle( thread, EcmaStringAccessor::Concat(vm, firstFlat, secondFlat, MemSpaceType::SHARED_OLD_SPACE)); EcmaString *concatString = EcmaStringAccessor::Flatten(vm, concatHandle, MemSpaceType::SHARED_OLD_SPACE); - concatString->SetRawHashcode(hashcode); + concatString->SetMixHashcode(hashcode); ASSERT(!EcmaStringAccessor(concatString).IsInternString()); ASSERT(EcmaStringAccessor(concatString).NotTreeString()); // Strings in string table should not be in the young space. @@ -536,7 +536,7 @@ EcmaString* EcmaStringTableImpl::GetOrInternStringThreadUnsafe(EcmaVM* v [vm, utf8Data, utf8Len, canBeCompress, hashcode]() { EcmaString *value = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); - value->SetRawHashcode(hashcode); + value->SetMixHashcode(hashcode); JSThread *thread = vm->GetJSThread(); JSHandle stringHandle(thread, value); return stringHandle; diff --git a/ecmascript/js_tagged_value.cpp b/ecmascript/js_tagged_value.cpp index 384bea36e8648593d2e9664525ec62d7fe2a5842..b0f184e558afa9b5346473b30b350b601baa203f 100644 --- a/ecmascript/js_tagged_value.cpp +++ b/ecmascript/js_tagged_value.cpp @@ -1761,20 +1761,16 @@ JSTaggedNumber JSTaggedValue::StringToNumber(JSThread *thread, JSTaggedValue tag return JSTaggedNumber(0); } if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) { - common::IntegerCache *cache = nullptr; -#if ENABLE_NEXT_OPTIMIZATION - if ((strLen <= common::IntegerCache::MAX_INTEGER_CACHE_SIZE) && strAccessor.IsInternString()) { - cache = common::IntegerCache::Extract(EcmaString::Cast(tagged)->ToBaseString()); - if (cache->IsInteger()) { - return JSTaggedNumber(cache->GetInteger()); - } + uint32_t index; + // fast path: get integer from string's hash value + if (strAccessor.TryToGetInteger(thread, &index)) { + return JSTaggedNumber(index); } -#endif Span str = strAccessor.FastToUtf8Span(); if (strAccessor.GetLength() == 0) { return JSTaggedNumber(0); } - auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), cache); + auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), tagged); if (isSuccess) { return result; } diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index d02157ebe67a5285be7190ee8b94a914d9d8efb8..fc4329139f03329b74fa8d4b4ff7524709dbcbca 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -4436,7 +4436,7 @@ JSHandle ObjectFactory::NewFromUtf8WithoutStringTable(std::string_vi EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress); - str->SetRawHashcode(hashCode); + str->SetMixHashcode(hashCode); return JSHandle(thread_, str); } @@ -4473,7 +4473,7 @@ JSHandle ObjectFactory::NewFromUtf16WithoutStringTable(std::u16strin EcmaString *str = EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf16(const_cast(utf16Data), utf16Len); - str->SetRawHashcode(hashCode); + str->SetMixHashcode(hashCode); return JSHandle(thread_, str); } @@ -4502,7 +4502,7 @@ JSHandle ObjectFactory::NewFromUtf8WithoutStringTable(const uint8_t EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress); - str->SetRawHashcode(hashCode); + str->SetMixHashcode(hashCode); return JSHandle(thread_, str); } @@ -4522,7 +4522,7 @@ JSHandle ObjectFactory::NewFromUtf16WithoutStringTable(const uint16_ EcmaString *str = EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE); uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf16(const_cast(utf16Data), utf16Len); - str->SetRawHashcode(hashCode); + str->SetMixHashcode(hashCode); return JSHandle(thread_, str); } diff --git a/ecmascript/object_operator.cpp b/ecmascript/object_operator.cpp index f6e9881b9e7f4839639db9db72102de7109ed676..e8d84eb1641b19f3cf3275198338da22bb353219 100644 --- a/ecmascript/object_operator.cpp +++ b/ecmascript/object_operator.cpp @@ -15,20 +15,26 @@ #include "ecmascript/object_operator.h" -#include "ecmascript/base/number_helper.h" -#include "ecmascript/ecma_string-inl.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/object_fast_operator-inl.h" namespace panda::ecmascript { -bool ObjectOperator::TryFastHandleStringKey(const JSHandle& key) +bool ObjectOperator::TryFastHandleStringKey(const JSHandle &key) { - EcmaStringAccessor strAcc(key->GetTaggedObject()); - if (strAcc.IsUtf8() && strAcc.IsLineString()) { - const std::basic_string_view strView(strAcc.GetDataUtf8(), strAcc.GetLength()); - constexpr uint64_t maxValue = std::numeric_limits::max() - 1; - return base::NumberHelper::StringToUint(strView, elementIndex_, maxValue); + if (!EcmaStringAccessor(key->GetTaggedObject()).IsInternString()) { + return false; + } + if (EcmaStringAccessor(key->GetTaggedObject()).IsInteger(thread_)) { + elementIndex_ = EcmaStringAccessor(key->GetTaggedObject()).GetIntegerCode(); + return true; + } + if (EcmaStringAccessor(key->GetTaggedObject()).GetLength() <= BaseString::MAX_CACHED_INTEGER_SIZE) { + // Since the range of hash values is of the int32 type, + // the IsInteger() function can only accurately determine + // a string whose length is less than or equal to MAX_CACHED_INTEGER_SIZE is not a number. + key_ = key; + return true; } return false; } @@ -47,6 +53,11 @@ void ObjectOperator::HandleKey(const JSHandle &key) if (key->IsString()) { keyFromStringType_ = true; +#ifdef ENABLE_NEXT_OPTIMIZATION + if (TryFastHandleStringKey(key)) { + return; + } +#endif uint32_t index = 0; if (JSTaggedValue::StringToElementIndex(thread_, key.GetTaggedValue(), &index)) { ASSERT(index < JSObject::MAX_ELEMENT_INDEX); diff --git a/ecmascript/stubs/runtime_stub_list.h b/ecmascript/stubs/runtime_stub_list.h index 37675f8da50281ec595483b329a808d81c6f5ca9..993612e26ee989dd315873315e12a3d3ba2ff5cf 100644 --- a/ecmascript/stubs/runtime_stub_list.h +++ b/ecmascript/stubs/runtime_stub_list.h @@ -547,7 +547,8 @@ namespace panda::ecmascript { V(SlowSharedObjectStoreBarrier) \ V(GetNativePcOfstForBaseline) \ V(AotCallBuiltinTrace) \ - V(NumberBigIntNativePointerToString) + V(NumberBigIntNativePointerToString) \ + V(ComputeHashcode) #define RUNTIME_STUB_WITH_GC_LIST(V) \ diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 5dd40211a3a77086ee6b78d9afb816e7ceb4c396..d6b6548e7e987428f4190e28d1d9c1d07b51359b 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -5034,6 +5034,15 @@ void RuntimeStubs::BatchMarkInBuffer(void* src, size_t count) } } +DEF_RUNTIME_STUBS(ComputeHashcode) +{ + RUNTIME_STUBS_HEADER(ComputeHashcode); + JSTaggedType ecmaString = GetTArg(argv, argc, 0); // 0: means the zeroth parameter + auto string = reinterpret_cast(ecmaString); + uint32_t result = EcmaStringAccessor(string).ComputeHashcode(thread); + return JSTaggedValue(static_cast(result)).GetRawData(); +} + void RuntimeStubs::Initialize(JSThread *thread) { #define DEF_RUNTIME_STUB(name) kungfu::RuntimeStubCSigns::ID_##name diff --git a/ecmascript/tagged_dictionary.cpp b/ecmascript/tagged_dictionary.cpp index bf8a4cfd7e7d0bf4a1014e4bb79469feb6170313..b93c90ef2903379265fd0c4eef81c474094f8e44 100644 --- a/ecmascript/tagged_dictionary.cpp +++ b/ecmascript/tagged_dictionary.cpp @@ -39,7 +39,9 @@ int NameDictionary::Hash(const JSThread *thread, const JSTaggedValue &key) // for ohmurl path to compute hash code int NameDictionary::Hash(const uint8_t* str, int strSize) { - return BaseString::ComputeHashForData(str, strSize, 0); + uint32_t hash = BaseString::ComputeHashForData(str, strSize, 0); + // url path can not be small int. + return BaseString::MixHashcode(hash, BaseString::NOT_INTEGER); } bool NameDictionary::IsMatch([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key, diff --git a/libark_jsruntime.map b/libark_jsruntime.map index 8a073a7fe36d3249d8dcf2b233cf4fb49d31a63b..9eef54c42ea598dcd8e887bc69827bfe2c32f116 100644 --- a/libark_jsruntime.map +++ b/libark_jsruntime.map @@ -107,6 +107,7 @@ common::VisitDynamicThreadPreforwardRoot*; common::VisitDynamicConcurrentRoots*; common::BaseObject::*; + common::BaseString::*; common::VisitJSThread*; common::SynchronizeGCPhaseToJSThread*; common::FillFreeObject*; @@ -184,7 +185,7 @@ panda::ecmascript::EcmaVM::FindOrCreateUnsharedConstpool*; panda::ecmascript::EcmaRuntimeStat::StartCount*; panda::ecmascript::EcmaRuntimeStat::StopCount*; - panda::ecmascript::EcmaString::ComputeRawHashcode*; + panda::ecmascript::EcmaString::ComputeHashcode*; panda::ecmascript::EcmaString::Flatten*; panda::ecmascript::EcmaString::GetUtf16DataFlat*; panda::ecmascript::EcmaString::GetUtf8DataFlat*;