From 2e50c3380f6bbaa8f1a5b0ff32fde899b733a981 Mon Sep 17 00:00:00 2001 From: hewei Date: Tue, 26 Aug 2025 16:27:06 +0800 Subject: [PATCH] fix bug in objectliteral cache Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICUOIF Signed-off-by: hewei Change-Id: I33bc43185c9e2440a32f42fcc482d54a9d8ffb1f --- ecmascript/js_hclass.cpp | 11 +- test/aottest/BUILD.gn | 13 + test/aottest/object_literal_double/BUILD.gn | 19 ++ .../object_literal_double/expect_output.txt | 12 + .../object_literal_double.js | 34 +++ .../pgo_expect_output.txt | 12 + test/test_helper.gni | 243 ++++++++++++++++++ 7 files changed, 342 insertions(+), 2 deletions(-) create mode 100644 test/aottest/object_literal_double/BUILD.gn create mode 100644 test/aottest/object_literal_double/expect_output.txt create mode 100644 test/aottest/object_literal_double/object_literal_double.js create mode 100644 test/aottest/object_literal_double/pgo_expect_output.txt diff --git a/ecmascript/js_hclass.cpp b/ecmascript/js_hclass.cpp index fefffb8052..415345db96 100644 --- a/ecmascript/js_hclass.cpp +++ b/ecmascript/js_hclass.cpp @@ -1506,7 +1506,6 @@ JSHandle JSHClass::CreateChildHClassFromPGO(const JSThread* thread, JSHandle newJsHClass = JSHClass::Clone(thread, parent); newJsHClass->SetAOT(true); - ASSERT(newJsHClass->GetInlinedProperties() >= (numOfProps + 1)); uint32_t offset = numOfProps; { JSMutableHandle layoutInfoHandle(thread, newJsHClass->GetLayout(thread)); @@ -1524,7 +1523,15 @@ JSHandle JSHClass::CreateChildHClassFromPGO(const JSThread* thread, newJsHClass->SetIsAllTaggedProp(false); } attributes.SetOffset(offset); - attributes.SetIsInlinedProps(true); + // We use the object literal cache for optimization. However, in very rare cases, there may be + // two identical object literals associated with two different PGO root types, and the transition + // chains of the two roots are inconsistent. This leads to retrieving an HClass from the cache with + // an incorrect number of inlined properties, which needs to be fixed. + if UNLIKELY(newJsHClass->NumberOfProps() + 1 > newJsHClass->GetInlinedProperties()) { + attributes.SetIsInlinedProps(false); + } else { + attributes.SetIsInlinedProps(true); + } layoutInfoHandle->AddKey(thread, offset, key.GetTaggedValue(), attributes); newJsHClass->IncNumberOfProps(); AddTransitions(thread, parent, newJsHClass, key, attributes); diff --git a/test/aottest/BUILD.gn b/test/aottest/BUILD.gn index 08f8ccbd1e..156ce3dc17 100644 --- a/test/aottest/BUILD.gn +++ b/test/aottest/BUILD.gn @@ -482,6 +482,18 @@ group("ark_aot_ts_assert_test") { } } +group("ark_aot_js_double_pgo_test") { + testonly = true + test_list = [ + "object_literal_double", + ] + + deps = [] + foreach(test, test_list) { + deps += [ "${test}:${test}AotAction" ] + } +} + group("ark_aot_test") { testonly = true deps = [ @@ -489,6 +501,7 @@ group("ark_aot_test") { ":ark_aot_js_test", ":ark_aot_ts_assert_test", ":ark_aot_ts_test", + ":ark_aot_js_double_pgo_test", "analyze_property:analyze_property_test", "aot_compatibility_test:aot_compatibility_test", "aot_multi_constantpool_test:aot_multi_constantpool_test", diff --git a/test/aottest/object_literal_double/BUILD.gn b/test/aottest/object_literal_double/BUILD.gn new file mode 100644 index 0000000000..ddbc2025bf --- /dev/null +++ b/test/aottest/object_literal_double/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright (c) 2025 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_aot_js_double_pgo_test_action("object_literal_double") { + deps = [] + log_option = " --log-info=fatal" +} diff --git a/test/aottest/object_literal_double/expect_output.txt b/test/aottest/object_literal_double/expect_output.txt new file mode 100644 index 0000000000..f6f89a09ae --- /dev/null +++ b/test/aottest/object_literal_double/expect_output.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2025 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. diff --git a/test/aottest/object_literal_double/object_literal_double.js b/test/aottest/object_literal_double/object_literal_double.js new file mode 100644 index 0000000000..c5fd050488 --- /dev/null +++ b/test/aottest/object_literal_double/object_literal_double.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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. + */ + +function test() { + if (Math.random() > 0.5) { + let obj = { + a : 1, + b : 2, + c : 4 + } + } else { + let obj1 = { + a : 3, + b : 41, + c : 34 + } + obj1.d = 5; + ArkTools.print("", obj1); + } +} + +test(); diff --git a/test/aottest/object_literal_double/pgo_expect_output.txt b/test/aottest/object_literal_double/pgo_expect_output.txt new file mode 100644 index 0000000000..f6f89a09ae --- /dev/null +++ b/test/aottest/object_literal_double/pgo_expect_output.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2025 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. diff --git a/test/test_helper.gni b/test/test_helper.gni index 784cfd364b..fd89eea167 100644 --- a/test/test_helper.gni +++ b/test/test_helper.gni @@ -5412,3 +5412,246 @@ template("host_baseline_jit_test_action") { outputs = [ "$target_out_dir/${_target_name_}/" ] } } + +template("host_aot_js_double_pgo_test_action") { + _target_name_ = "${target_name}" + _deps_ = invoker.deps + + _test_ts_path_ = "./${_target_name_}.js" + _test_abc_path_ = "$target_out_dir/${_target_name_}.abc" + _test_aot_path_ = "$target_out_dir/${_target_name_}.an" + _test_aot_snapshot_path_ = "$target_out_dir/${_target_name_}.ai" + _test_aot_arg_ = "$target_out_dir/${_target_name_}" + _test_aot_log_level = "info" + _test_expect_path_ = "./expect_output.txt" + _test_pgo_expect_path_ = "./pgo_expect_output.txt" + + extra_args = [ "--module" ] + extra_args += [ "--merge-abc" ] + + es2abc_gen_newest_abc("gen_${_target_name_}_abc") { + extra_visibility = [ ":*" ] # Only targets in this file can depend on this. + extra_dependencies = _deps_ + src_js = rebase_path(_test_ts_path_) + dst_file = rebase_path(_test_abc_path_) + + in_puts = [ + _test_ts_path_, + _test_expect_path_, + ] + out_puts = [ _test_abc_path_ ] + } + + _script_args_ = rebase_path(_test_abc_path_) + + action("${_target_name_}FirstPgoExecute") { + testonly = true + _host_jsvm_target_ = + "$js_root/ecmascript/js_vm:ark_js_vm(${host_toolchain})" + _root_out_dir_ = get_label_info(_host_jsvm_target_, "root_out_dir") + + deps = [ + ":gen_${_target_name_}_abc", + _host_jsvm_target_, + ] + deps += _deps_ + + script = "$js_root/script/run_ark_executable.py" + + _aot_run_options_ = + " --asm-interpreter=true" + " --entry-point=${_target_name_}" + + " --enable-pgo-profiler=true" + " --compiler-pgo-profiler-path=" + + rebase_path(_test_aot_arg_) + "/modules.ap" + + if (defined(invoker.log_option)) { + _aot_run_options_ += invoker.log_option + } + + _aot_run_options_ += " --enable-ark-tools=true" + _aot_run_options_ += " --enable-force-gc=false" + _aot_run_options_ += common_options + + args = [ + "--script-file", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_js_vm", + "--script-options", + _aot_run_options_, + "--script-args", + _script_args_, + "--expect-file", + rebase_path(_test_pgo_expect_path_), + "--env-path", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime:" + + rebase_path(_root_out_dir_) + "/${_icu_path_}:" + + rebase_path(_root_out_dir_) + "/thirdparty/zlib:" + + rebase_path(_root_out_dir_) + "/resourceschedule/frame_aware_sched:" + + rebase_path(_root_out_dir_) + "/hiviewdfx/hilog:" + + rebase_path(_root_out_dir_) + + "/thirdparty/bounds_checking_function:" + + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib:") + + rebase_path(_root_out_dir_) + "/hmosbundlemanager/zlib_override/", + ] + + inputs = [ _test_abc_path_ ] + + outputs = [ "$target_out_dir/${_target_name_}/firstpgo" ] + } + + action("${_target_name_}SecondPgoExecute") { + testonly = true + _host_jsvm_target_ = + "$js_root/ecmascript/js_vm:ark_js_vm(${host_toolchain})" + _root_out_dir_ = get_label_info(_host_jsvm_target_, "root_out_dir") + + deps = [ + ":gen_${_target_name_}_abc", + _host_jsvm_target_, + ":${_target_name_}FirstPgoExecute", + ] + deps += _deps_ + + script = "$js_root/script/run_ark_executable.py" + + _aot_run_options_ = + " --asm-interpreter=true" + " --entry-point=${_target_name_}" + + " --enable-pgo-profiler=true" + " --compiler-pgo-profiler-path=" + + rebase_path(_test_aot_arg_) + "/modules.ap" + + _aot_run_options_ += " --enable-ark-tools=true" + _aot_run_options_ += " --enable-force-gc=false" + _aot_run_options_ += common_options + if (defined(invoker.log_option)) { + _aot_run_options_ += invoker.log_option + } + + args = [ + "--script-file", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_js_vm", + "--script-options", + _aot_run_options_, + "--script-args", + _script_args_, + "--expect-file", + rebase_path(_test_pgo_expect_path_), + "--env-path", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime:" + + rebase_path(_root_out_dir_) + "/${_icu_path_}:" + + rebase_path(_root_out_dir_) + "/thirdparty/zlib:" + + rebase_path(_root_out_dir_) + "/resourceschedule/frame_aware_sched:" + + rebase_path(_root_out_dir_) + "/hiviewdfx/hilog:" + + rebase_path(_root_out_dir_) + + "/thirdparty/bounds_checking_function:" + + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib:") + + rebase_path(_root_out_dir_) + "/hmosbundlemanager/zlib_override/", + ] + + inputs = [ _test_abc_path_ ] + + outputs = [ "$target_out_dir/${_target_name_}/secondpgo" ] + } + + action("${_target_name_}AotCompileAction") { + testonly = true + + _host_aot_target_ = "//arkcompiler/ets_runtime/ecmascript/compiler:ark_aot_compiler(${host_toolchain})" + _root_out_dir_ = get_label_info(_host_aot_target_, "root_out_dir") + deps = [ + ":gen_${_target_name_}_abc", + _host_aot_target_, + ":${_target_name_}SecondPgoExecute", + ] + deps += _deps_ + + script = "//arkcompiler/ets_runtime/script/run_ark_executable.py" + + _aot_compile_options_ = " --aot-file=" + rebase_path(_test_aot_arg_) + + " --log-level=" + _test_aot_log_level + " --log-components=compiler --compiler-opt-type-lowering=false --compiler-opt-inlining=false" + " --compiler-opt-loop-peeling=true" + _aot_compile_options_ += " --compiler-pgo-profiler-path=" + + rebase_path(_test_aot_arg_) + "/modules.ap" + _aot_compile_options_ += common_options + + args = [ + "--script-file", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_aot_compiler", + "--script-options", + _aot_compile_options_, + "--script-args", + _script_args_, + "--expect-sub-output", + "ts aot compile success", + "--env-path", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime:" + + rebase_path(_root_out_dir_) + "/${_icu_path_}:" + + rebase_path(_root_out_dir_) + "/thirdparty/zlib:" + + rebase_path(_root_out_dir_) + "/resourceschedule/frame_aware_sched:" + + rebase_path(_root_out_dir_) + "/hiviewdfx/hilog:" + + rebase_path(_root_out_dir_) + + "/thirdparty/bounds_checking_function:" + + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib:") + + rebase_path(_root_out_dir_) + "/hmosbundlemanager/zlib_override/", + ] + + inputs = [ _test_abc_path_ ] + + outputs = [ + _test_aot_path_, + _test_aot_snapshot_path_, + ] + } + + action("${_target_name_}AotAction") { + testonly = true + + _host_jsvm_target_ = "//arkcompiler/ets_runtime/ecmascript/js_vm:ark_js_vm(${host_toolchain})" + _root_out_dir_ = get_label_info(_host_jsvm_target_, "root_out_dir") + + deps = [ + ":${_target_name_}AotCompileAction", + ":gen_${_target_name_}_abc", + _host_jsvm_target_, + ] + deps += _deps_ + + script = "//arkcompiler/ets_runtime/script/run_ark_executable.py" + + _aot_run_options_ = + " --aot-file=" + rebase_path(_test_aot_arg_) + + " --asm-interpreter=true" + " --entry-point=${_target_name_}" + + if (defined(invoker.log_option)) { + _aot_run_options_ += invoker.log_option + } + _aot_run_options_ += " --enable-ark-tools=true" + _aot_run_options_ += " --enable-force-gc=false" + _aot_run_options_ += common_options + + _icu_data_path_options_ = + " --icu-data-path=" + rebase_path("//third_party/icu/ohos_icu4j/data") + _aot_run_options_ += _icu_data_path_options_ + + args = [ + "--script-file", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_js_vm", + "--script-options", + _aot_run_options_, + "--script-args", + _script_args_, + "--expect-file", + rebase_path(_test_expect_path_), + "--env-path", + rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime:" + + rebase_path(_root_out_dir_) + "/${_icu_path_}:" + + rebase_path(_root_out_dir_) + "/thirdparty/zlib:" + + rebase_path(_root_out_dir_) + "/resourceschedule/frame_aware_sched:" + + rebase_path(_root_out_dir_) + "/hiviewdfx/hilog:" + + rebase_path(_root_out_dir_) + + "/thirdparty/bounds_checking_function:" + + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib:") + + rebase_path(_root_out_dir_) + "/hmosbundlemanager/zlib_override/", + ] + + inputs = [ _test_abc_path_ ] + + outputs = [ "$target_out_dir/${_target_name_}/" ] + } +} \ No newline at end of file -- Gitee