diff --git a/ecmascript/ecma_string_table.cpp b/ecmascript/ecma_string_table.cpp index 53f3288412..f3740ef2ce 100644 --- a/ecmascript/ecma_string_table.cpp +++ b/ecmascript/ecma_string_table.cpp @@ -482,6 +482,31 @@ EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(EcmaVM *vm, const ui return str; } +// used in jit thread, which unsupport create jshandle +EcmaString *EcmaStringTable::GetOrInternStringWithSpaceTypeWithoutJSHandle(EcmaVM *vm, const uint8_t *utf8Data, + uint32_t utf16Len, MemSpaceType type) +{ + ASSERT(IsSMemSpace(type)); + type = (type == MemSpaceType::SHARED_NON_MOVABLE) ? type : MemSpaceType::SHARED_OLD_SPACE; + CVector u16Buffer(utf16Len); + utf::ConvertRegionMUtf8ToUtf16(utf8Data, u16Buffer.data(), utf::Mutf8Size(utf8Data), utf16Len, 0); + auto hashcode = EcmaStringAccessor::ComputeHashcodeUtf16(u16Buffer.data(), utf16Len); + RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_); +#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT + if (vm->IsCollectingScopeLockStats()) { + vm->IncreaseStringTableLockCount(); + } +#endif + auto result = GetStringThreadUnsafe(u16Buffer.data(), utf16Len, hashcode); + if (result.first != nullptr) { + return result.first; + } + EcmaString *str = EcmaStringAccessor::CreateFromUtf16(vm, u16Buffer.data(), utf16Len, false, type); + str->SetMixHashcode(hashcode); + InternStringThreadUnsafe(str, hashcode); + return str; +} + void EcmaStringTable::SweepWeakRef(const WeakRootVisitor &visitor) { // No need lock here, only shared gc will sweep string table, meanwhile other threads are suspended. diff --git a/ecmascript/ecma_string_table.h b/ecmascript/ecma_string_table.h index 9d901300bc..f7bf329630 100644 --- a/ecmascript/ecma_string_table.h +++ b/ecmascript/ecma_string_table.h @@ -128,6 +128,8 @@ public: bool canBeCompress, MemSpaceType type, bool isConstantString, uint32_t idOffset); EcmaString *GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type); + EcmaString *GetOrInternStringWithSpaceTypeWithoutJSHandle(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, + MemSpaceType type); EcmaString *TryGetInternString(JSThread *thread, const JSHandle &string); void InsertStringToTableWithHashThreadUnsafe(EcmaString* string, uint32_t hashcode); EcmaString *InsertStringToTable(EcmaVM *vm, const JSHandle &strHandle); diff --git a/ecmascript/jspandafile/program_object.cpp b/ecmascript/jspandafile/program_object.cpp index fb5b10f11b..f8bb9b9a43 100644 --- a/ecmascript/jspandafile/program_object.cpp +++ b/ecmascript/jspandafile/program_object.cpp @@ -86,7 +86,7 @@ JSTaggedValue ConstantPool::GetStringFromCacheForJit(JSThread *thread, JSTaggedV auto foundStr = jsPandaFile->GetStringData(id); EcmaVM *vm = thread->GetEcmaVM(); ObjectFactory *factory = vm->GetFactory(); - auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::SHARED_OLD_SPACE, + auto string = factory->GetRawStringFromStringTableWithoutJSHandle(foundStr, MemSpaceType::SHARED_OLD_SPACE, jsPandaFile->IsFirstMergedAbc(), id.GetOffset()); val = JSTaggedValue(string); } diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 5dab146880..de722fe7ee 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -3275,6 +3275,26 @@ EcmaString *ObjectFactory::GetRawStringFromStringTable(StringData sd, MemSpaceTy return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(vm_, mutf8Data, utf16Len, type); } +// used in jit thread, which unsupport create jshandle +EcmaString *ObjectFactory::GetRawStringFromStringTableWithoutJSHandle(StringData sd, MemSpaceType type, + bool isConstantString, uint32_t idOffset) const +{ + NewObjectHook(); + uint32_t utf16Len = sd.utf16_length; + if (UNLIKELY(utf16Len == 0)) { + return *GetEmptyString(); + } + + bool canBeCompressed = sd.is_ascii; + const uint8_t *mutf8Data = sd.data; + if (canBeCompressed) { + // This branch will use constant string, which has a pointer at the string in the pandafile. + return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceType(vm_, mutf8Data, utf16Len, true, type, + isConstantString, idOffset); + } + return vm_->GetEcmaStringTable()->GetOrInternStringWithSpaceTypeWithoutJSHandle(vm_, mutf8Data, utf16Len, type); +} + JSHandle ObjectFactory::NewPropertyBox(const JSHandle &value) { NewObjectHook(); diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index 9666785be5..eb666e658a 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -954,6 +954,10 @@ private: EcmaString *PUBLIC_API GetRawStringFromStringTable(StringData sd, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, bool isConstantString = false, uint32_t idOffset = 0) const; + EcmaString *GetRawStringFromStringTableWithoutJSHandle(StringData sd, + MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE, + bool isConstantString = false, + uint32_t idOffset = 0) const; JSHandle GetStringFromStringTable(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress) const; diff --git a/test/jittest/BUILD.gn b/test/jittest/BUILD.gn index 4602932a23..5e31113f76 100644 --- a/test/jittest/BUILD.gn +++ b/test/jittest/BUILD.gn @@ -33,6 +33,7 @@ group("ark_jit_ts_test") { "ts_inline", "proxy_fast_call", "fuzz_exception", + "utf16key", "throw_error", "compiler_inline", "uint32_array", diff --git a/test/jittest/utf16key/BUILD.gn b/test/jittest/utf16key/BUILD.gn new file mode 100644 index 0000000000..288b9b3438 --- /dev/null +++ b/test/jittest/utf16key/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/ets_runtime/test/test_helper.gni") + +host_jit_test_action("utf16key") { + deps = [] +} diff --git a/test/jittest/utf16key/expect_output.txt b/test/jittest/utf16key/expect_output.txt new file mode 100644 index 0000000000..e8a583802f --- /dev/null +++ b/test/jittest/utf16key/expect_output.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +true diff --git a/test/jittest/utf16key/utf16key.ts b/test/jittest/utf16key/utf16key.ts new file mode 100644 index 0000000000..43302f3c16 --- /dev/null +++ b/test/jittest/utf16key/utf16key.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class Utf16key { + constructor() { + this.鸿蒙 = '鸿蒙' + } +} + +function LoadValueByName(o) { + return o.鸿蒙; +} + +const o = new Utf16key(); + +for (let i = 0; i < 3; i++) { + LoadValueByName(o) +} + +ArkTools.jitCompileAsync(LoadValueByName); +let res = ArkTools.waitJitCompileFinish(LoadValueByName); +print(res); +try { + LoadValueByName(o) +} catch(err) { + print("catch") +}